From 28d0147d0988917a8b9d85441b8836453e0f222e Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Fri, 20 Oct 2023 15:41:26 +0800 Subject: [PATCH 01/99] Introduction of classes ColorRGB and ColorRGBA to unify color data definition and manipulation (cherry picked from commit prusa3d/PrusaSlicer@d0bff2d9968439845340eadb274fe1197944aded ) --- src/OrcaSlicer.cpp | 21 +- src/libslic3r/CMakeLists.txt | 2 + src/libslic3r/Color.cpp | 412 ++++++++++++++++++ src/libslic3r/Color.hpp | 170 ++++++++ src/slic3r/GUI/3DBed.cpp | 31 +- src/slic3r/GUI/3DBed.hpp | 6 +- src/slic3r/GUI/3DScene.cpp | 261 +++++------ src/slic3r/GUI/3DScene.hpp | 54 +-- src/slic3r/GUI/AboutDialog.cpp | 7 +- src/slic3r/GUI/BitmapCache.cpp | 41 -- src/slic3r/GUI/BitmapCache.hpp | 9 +- src/slic3r/GUI/ConfigWizard.cpp | 7 +- src/slic3r/GUI/Field.cpp | 3 +- src/slic3r/GUI/GCodeViewer.cpp | 160 +++---- src/slic3r/GUI/GCodeViewer.hpp | 37 +- src/slic3r/GUI/GLCanvas3D.cpp | 156 +++---- src/slic3r/GUI/GLCanvas3D.hpp | 18 +- src/slic3r/GUI/GLModel.cpp | 2 +- src/slic3r/GUI/GLModel.hpp | 7 +- src/slic3r/GUI/GLShader.cpp | 145 +++--- src/slic3r/GUI/GLShader.hpp | 55 ++- src/slic3r/GUI/GUI_App.cpp | 7 +- src/slic3r/GUI/GUI_Colors.hpp | 8 +- src/slic3r/GUI/GUI_ObjectTable.cpp | 6 +- src/slic3r/GUI/GUI_Utils.hpp | 33 +- src/slic3r/GUI/Gizmos/GLGizmoAdvancedCut.cpp | 18 +- src/slic3r/GUI/Gizmos/GLGizmoAdvancedCut.hpp | 6 +- src/slic3r/GUI/Gizmos/GLGizmoBase.cpp | 86 ++-- src/slic3r/GUI/Gizmos/GLGizmoBase.hpp | 46 +- src/slic3r/GUI/Gizmos/GLGizmoCut.cpp | 7 +- src/slic3r/GUI/Gizmos/GLGizmoCut.hpp | 1 - src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp | 2 +- src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp | 24 +- .../GUI/Gizmos/GLGizmoMmuSegmentation.cpp | 32 +- .../GUI/Gizmos/GLGizmoMmuSegmentation.hpp | 4 +- src/slic3r/GUI/Gizmos/GLGizmoMove.cpp | 4 +- src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp | 23 +- src/slic3r/GUI/Gizmos/GLGizmoPainterBase.hpp | 18 +- src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp | 2 +- src/slic3r/GUI/Gizmos/GLGizmoSeam.cpp | 2 +- src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp | 7 +- src/slic3r/GUI/Gizmos/GLGizmoText.cpp | 4 +- src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp | 4 +- src/slic3r/GUI/IMSlider.cpp | 18 +- src/slic3r/GUI/IMSlider_Utils.hpp | 198 --------- src/slic3r/GUI/ImGuiWrapper.cpp | 25 +- src/slic3r/GUI/ImGuiWrapper.hpp | 12 +- src/slic3r/GUI/MsgDialog.cpp | 7 +- src/slic3r/GUI/PartPlate.cpp | 110 ++--- src/slic3r/GUI/PartPlate.hpp | 38 +- src/slic3r/GUI/PresetComboBoxes.cpp | 1 + src/slic3r/GUI/SelectMachine.cpp | 8 +- src/slic3r/GUI/Selection.cpp | 29 +- src/slic3r/GUI/SendSystemInfoDialog.cpp | 6 +- src/slic3r/GUI/SysInfoDialog.cpp | 5 +- src/slic3r/GUI/TickCode.cpp | 31 +- src/slic3r/GUI/TickCode.hpp | 3 +- src/slic3r/GUI/UnsavedChangesDialog.cpp | 8 +- src/slic3r/GUI/WipeTowerDialog.cpp | 7 +- src/slic3r/Utils/CalibUtils.cpp | 6 +- 60 files changed, 1288 insertions(+), 1172 deletions(-) create mode 100644 src/libslic3r/Color.cpp create mode 100644 src/libslic3r/Color.hpp diff --git a/src/OrcaSlicer.cpp b/src/OrcaSlicer.cpp index 3ab0342d2c6..8ee2d442bab 100644 --- a/src/OrcaSlicer.cpp +++ b/src/OrcaSlicer.cpp @@ -2279,12 +2279,12 @@ int CLI::run(int argc, char **argv) else colors.push_back("#FFFFFF"); - std::vector> colors_out(colors.size()); - unsigned char rgb_color[3] = {}; + std::vector colors_out(colors.size()); + ColorRGBA rgb_color; for (const std::string& color : colors) { - Slic3r::GUI::BitmapCache::parse_color(color, rgb_color); + Slic3r::decode_color(color, rgb_color); size_t color_idx = &color - &colors.front(); - colors_out[color_idx] = { float(rgb_color[0]) / 255.f, float(rgb_color[1]) / 255.f, float(rgb_color[2]) / 255.f, 1.f }; + colors_out[color_idx] = rgb_color; } int gl_major, gl_minor, gl_verbos; @@ -2357,15 +2357,12 @@ int CLI::run(int argc, char **argv) //glvolume_collection.volumes.back()->geometry_id = key.geometry_id; std::string color = filament_color?filament_color->get_at(extruder_id - 1):"#00FF00"; - unsigned char rgb_color[3] = {}; - Slic3r::GUI::BitmapCache::parse_color(color, rgb_color); - glvolume_collection.volumes.back()->set_render_color( float(rgb_color[0]) / 255.f, float(rgb_color[1]) / 255.f, float(rgb_color[2]) / 255.f, 1.f); + ColorRGBA rgb_color; + Slic3r::decode_color(color, rgb_color); + glvolume_collection.volumes.back()->set_render_color(rgb_color); - std::array new_color; - new_color[0] = float(rgb_color[0]) / 255.f; - new_color[1] = float(rgb_color[1]) / 255.f; - new_color[2] = float(rgb_color[2]) / 255.f; - new_color[3] = 1.f; + ColorRGBA new_color; + new_color = rgb_color; glvolume_collection.volumes.back()->set_color(new_color); glvolume_collection.volumes.back()->printable = model_instance.printable; } diff --git a/src/libslic3r/CMakeLists.txt b/src/libslic3r/CMakeLists.txt index 3cfb82b0733..0a840db87f3 100644 --- a/src/libslic3r/CMakeLists.txt +++ b/src/libslic3r/CMakeLists.txt @@ -56,6 +56,8 @@ set(lisbslic3r_sources Clipper2Utils.cpp Clipper2Utils.hpp ClipperZUtils.hpp + Color.cpp + Color.hpp Config.cpp Config.hpp CurveAnalyzer.cpp diff --git a/src/libslic3r/Color.cpp b/src/libslic3r/Color.cpp new file mode 100644 index 00000000000..b911d170e3b --- /dev/null +++ b/src/libslic3r/Color.cpp @@ -0,0 +1,412 @@ +#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() == '#') || (color.size() == 9 && color.front() == '#'); +} + +bool decode_color(const std::string& color_in, ColorRGB& color_out) +{ + ColorRGBA rgba; + if (!decode_color(color_in, rgba)) + return false; + + color_out = to_rgb(rgba); + return true; +} + +bool decode_color(const std::string& color_in, ColorRGBA& 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 = ColorRGBA::BLACK(); + if (can_decode_color(color_in)) { + const char *c = color_in.data() + 1; + if (color_in.size() == 7) { + 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 { + for (unsigned int i = 0; i < 4; ++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); + assert(0.0f <= color_out.a() && color_out.a() <= 1.0f); + 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 00000000000..fce0c67e000 --- /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/slic3r/GUI/3DBed.cpp b/src/slic3r/GUI/3DBed.cpp index a7b6e050ebc..0c29cdc195c 100644 --- a/src/slic3r/GUI/3DBed.cpp +++ b/src/slic3r/GUI/3DBed.cpp @@ -26,9 +26,11 @@ #endif static const float GROUND_Z = -0.04f; -static const std::array DEFAULT_MODEL_COLOR = { 0.3255f, 0.337f, 0.337f, 1.0f }; -static const std::array DEFAULT_MODEL_COLOR_DARK = { 0.255f, 0.255f, 0.283f, 1.0f }; -static const std::array PICKING_MODEL_COLOR = { 0.0f, 0.0f, 0.0f, 1.0f }; +static const Slic3r::ColorRGBA DEFAULT_MODEL_COLOR = { 0.3255f, 0.337f, 0.337f, 1.0f }; +static const Slic3r::ColorRGBA DEFAULT_MODEL_COLOR_DARK = { 0.255f, 0.255f, 0.283f, 1.0f }; +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 { @@ -137,22 +139,22 @@ const float Bed3D::Axes::DefaultStemLength = 25.0f; const float Bed3D::Axes::DefaultTipRadius = 2.5f * Bed3D::Axes::DefaultStemRadius; const float Bed3D::Axes::DefaultTipLength = 5.0f; -std::array Bed3D::AXIS_X_COLOR = decode_color_to_float_array("#FF0000"); -std::array Bed3D::AXIS_Y_COLOR = decode_color_to_float_array("#00FF00"); -std::array Bed3D::AXIS_Z_COLOR = decode_color_to_float_array("#0000FF"); +ColorRGBA Bed3D::AXIS_X_COLOR = ColorRGBA::X(); +ColorRGBA Bed3D::AXIS_Y_COLOR = ColorRGBA::Y(); +ColorRGBA Bed3D::AXIS_Z_COLOR = ColorRGBA::Z(); void Bed3D::update_render_colors() { - Bed3D::AXIS_X_COLOR = GLColor(RenderColor::colors[RenderCol_Axis_X]); - Bed3D::AXIS_Y_COLOR = GLColor(RenderColor::colors[RenderCol_Axis_Y]); - Bed3D::AXIS_Z_COLOR = GLColor(RenderColor::colors[RenderCol_Axis_Z]); + Bed3D::AXIS_X_COLOR = ImGuiWrapper::from_ImVec4(RenderColor::colors[RenderCol_Axis_X]); + Bed3D::AXIS_Y_COLOR = ImGuiWrapper::from_ImVec4(RenderColor::colors[RenderCol_Axis_Y]); + Bed3D::AXIS_Z_COLOR = ImGuiWrapper::from_ImVec4(RenderColor::colors[RenderCol_Axis_Z]); } void Bed3D::load_render_colors() { - RenderColor::colors[RenderCol_Axis_X] = IMColor(Bed3D::AXIS_X_COLOR); - RenderColor::colors[RenderCol_Axis_Y] = IMColor(Bed3D::AXIS_Y_COLOR); - RenderColor::colors[RenderCol_Axis_Z] = IMColor(Bed3D::AXIS_Z_COLOR); + RenderColor::colors[RenderCol_Axis_X] = ImGuiWrapper::to_ImVec4(Bed3D::AXIS_X_COLOR); + RenderColor::colors[RenderCol_Axis_Y] = ImGuiWrapper::to_ImVec4(Bed3D::AXIS_Y_COLOR); + RenderColor::colors[RenderCol_Axis_Z] = ImGuiWrapper::to_ImVec4(Bed3D::AXIS_Z_COLOR); } void Bed3D::Axes::render() const @@ -724,10 +726,7 @@ void Bed3D::render_default(bool bottom) 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, default_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/3DBed.hpp b/src/slic3r/GUI/3DBed.hpp index f6daadddf13..d1af27f4255 100644 --- a/src/slic3r/GUI/3DBed.hpp +++ b/src/slic3r/GUI/3DBed.hpp @@ -42,9 +42,9 @@ class GeometryBuffer class Bed3D { public: - static std::array AXIS_X_COLOR; - static std::array AXIS_Y_COLOR; - static std::array AXIS_Z_COLOR; + static ColorRGBA AXIS_X_COLOR; + static ColorRGBA AXIS_Y_COLOR; + static ColorRGBA AXIS_Z_COLOR; static void update_render_colors(); static void load_render_colors(); diff --git a/src/slic3r/GUI/3DScene.cpp b/src/slic3r/GUI/3DScene.cpp index be821f64fed..f94bba6c4fa 100644 --- a/src/slic3r/GUI/3DScene.cpp +++ b/src/slic3r/GUI/3DScene.cpp @@ -70,36 +70,27 @@ void glAssertRecentCallImpl(const char* file_name, unsigned int line, const char #endif // HAS_GLSAFE // BBS -std::vector> get_extruders_colors() +std::vector get_extruders_colors() { - unsigned char rgba_color[4] = {}; - std::vector colors = Slic3r::GUI::wxGetApp().plater()->get_extruder_colors_from_plater_config(); - std::vector> colors_out(colors.size()); + Slic3r::ColorRGBA rgba_color; + std::vector colors = Slic3r::GUI::wxGetApp().plater()->get_extruder_colors_from_plater_config(); + std::vector colors_out(colors.size()); for (const std::string &color : colors) { - Slic3r::GUI::BitmapCache::parse_color4(color, rgba_color); + Slic3r::decode_color(color, rgba_color); size_t color_idx = &color - &colors.front(); - colors_out[color_idx] = { - float(rgba_color[0]) / 255.f, - float(rgba_color[1]) / 255.f, - float(rgba_color[2]) / 255.f, - float(rgba_color[3]) / 255.f, - }; + colors_out[color_idx] = rgba_color; } return colors_out; } float FullyTransparentMaterialThreshold = 0.1f; float FullTransparentModdifiedToFixAlpha = 0.3f; -std::array adjust_color_for_rendering(const std::array &colors) -{ - if (colors[3] < FullyTransparentMaterialThreshold) { // completely transparent - std::array new_color; - new_color[0] = 1; - new_color[1] = 1; - new_color[2] = 1; - new_color[3] = FullTransparentModdifiedToFixAlpha; - return new_color; - } + +Slic3r::ColorRGBA adjust_color_for_rendering(const Slic3r::ColorRGBA &colors) +{ + if (colors.a() < FullyTransparentMaterialThreshold) { // completely transparent + return {1, 1, 1, FullTransparentModdifiedToFixAlpha}; + } return colors; } @@ -383,21 +374,21 @@ void GLVolume::SinkingContours::update() m_model.reset(); } -std::array GLVolume::DISABLED_COLOR = { 0.25f, 0.25f, 0.25f, 1.0f }; -std::array GLVolume::SLA_SUPPORT_COLOR = { 0.75f, 0.75f, 0.75f, 1.0f }; -std::array GLVolume::SLA_PAD_COLOR = { 0.0f, 0.2f, 0.0f, 1.0f }; +ColorRGBA GLVolume::DISABLED_COLOR = ColorRGBA::DARK_GRAY(); +ColorRGBA GLVolume::SLA_SUPPORT_COLOR = ColorRGBA::LIGHT_GRAY(); +ColorRGBA GLVolume::SLA_PAD_COLOR = { 0.0f, 0.2f, 0.0f, 1.0f }; // BBS -std::array GLVolume::NEUTRAL_COLOR = { 0.8f, 0.8f, 0.8f, 1.0f }; -std::array GLVolume::UNPRINTABLE_COLOR = { 0.0f, 0.0f, 0.0f, 0.5f }; +ColorRGBA GLVolume::NEUTRAL_COLOR = { 0.8f, 0.8f, 0.8f, 1.0f }; +ColorRGBA GLVolume::UNPRINTABLE_COLOR = { 0.0f, 0.0f, 0.0f, 0.5f }; -std::array GLVolume::MODEL_MIDIFIER_COL = {1.0f, 1.0f, 0.0f, 0.6f}; -std::array GLVolume::MODEL_NEGTIVE_COL = {0.3f, 0.3f, 0.3f, 0.4f}; -std::array GLVolume::SUPPORT_ENFORCER_COL = {0.3f, 0.3f, 1.0f, 0.4f}; -std::array GLVolume::SUPPORT_BLOCKER_COL = {1.0f, 0.3f, 0.3f, 0.4f}; +ColorRGBA GLVolume::MODEL_MIDIFIER_COL = {1.0f, 1.0f, 0.0f, 0.6f}; +ColorRGBA GLVolume::MODEL_NEGTIVE_COL = {0.3f, 0.3f, 0.3f, 0.4f}; +ColorRGBA GLVolume::SUPPORT_ENFORCER_COL = {0.3f, 0.3f, 1.0f, 0.4f}; +ColorRGBA GLVolume::SUPPORT_BLOCKER_COL = {1.0f, 0.3f, 0.3f, 0.4f}; -std::array GLVolume::MODEL_HIDDEN_COL = {0.f, 0.f, 0.f, 0.3f}; +ColorRGBA GLVolume::MODEL_HIDDEN_COL = {0.f, 0.f, 0.f, 0.3f}; -std::array, 5> GLVolume::MODEL_COLOR = { { +std::array 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 }, @@ -407,25 +398,25 @@ std::array, 5> GLVolume::MODEL_COLOR = { { void GLVolume::update_render_colors() { - GLVolume::DISABLED_COLOR = GLColor(RenderColor::colors[RenderCol_Model_Disable]); - GLVolume::NEUTRAL_COLOR = GLColor(RenderColor::colors[RenderCol_Model_Neutral]); - GLVolume::MODEL_COLOR[0] = GLColor(RenderColor::colors[RenderCol_Modifier]); - GLVolume::MODEL_COLOR[1] = GLColor(RenderColor::colors[RenderCol_Negtive_Volume]); - GLVolume::MODEL_COLOR[2] = GLColor(RenderColor::colors[RenderCol_Support_Enforcer]); - GLVolume::MODEL_COLOR[3] = GLColor(RenderColor::colors[RenderCol_Support_Blocker]); - GLVolume::UNPRINTABLE_COLOR = GLColor(RenderColor::colors[RenderCol_Model_Unprintable]); + GLVolume::DISABLED_COLOR = GUI::ImGuiWrapper::from_ImVec4(RenderColor::colors[RenderCol_Model_Disable]); + GLVolume::NEUTRAL_COLOR = GUI::ImGuiWrapper::from_ImVec4(RenderColor::colors[RenderCol_Model_Neutral]); + GLVolume::MODEL_COLOR[0] = GUI::ImGuiWrapper::from_ImVec4(RenderColor::colors[RenderCol_Modifier]); + GLVolume::MODEL_COLOR[1] = GUI::ImGuiWrapper::from_ImVec4(RenderColor::colors[RenderCol_Negtive_Volume]); + GLVolume::MODEL_COLOR[2] = GUI::ImGuiWrapper::from_ImVec4(RenderColor::colors[RenderCol_Support_Enforcer]); + GLVolume::MODEL_COLOR[3] = GUI::ImGuiWrapper::from_ImVec4(RenderColor::colors[RenderCol_Support_Blocker]); + GLVolume::UNPRINTABLE_COLOR = GUI::ImGuiWrapper::from_ImVec4(RenderColor::colors[RenderCol_Model_Unprintable]); } void GLVolume::load_render_colors() { - RenderColor::colors[RenderCol_Model_Disable] = IMColor(GLVolume::DISABLED_COLOR); - RenderColor::colors[RenderCol_Model_Neutral] = IMColor(GLVolume::NEUTRAL_COLOR); - RenderColor::colors[RenderCol_Modifier] = IMColor(GLVolume::MODEL_COLOR[0]); - RenderColor::colors[RenderCol_Negtive_Volume] = IMColor(GLVolume::MODEL_COLOR[1]); - RenderColor::colors[RenderCol_Support_Enforcer] = IMColor(GLVolume::MODEL_COLOR[2]); - RenderColor::colors[RenderCol_Support_Blocker] = IMColor(GLVolume::MODEL_COLOR[3]); - RenderColor::colors[RenderCol_Model_Unprintable]= IMColor(GLVolume::UNPRINTABLE_COLOR); + RenderColor::colors[RenderCol_Model_Disable] = GUI::ImGuiWrapper::to_ImVec4(GLVolume::DISABLED_COLOR); + RenderColor::colors[RenderCol_Model_Neutral] = GUI::ImGuiWrapper::to_ImVec4(GLVolume::NEUTRAL_COLOR); + RenderColor::colors[RenderCol_Modifier] = GUI::ImGuiWrapper::to_ImVec4(GLVolume::MODEL_COLOR[0]); + RenderColor::colors[RenderCol_Negtive_Volume] = GUI::ImGuiWrapper::to_ImVec4(GLVolume::MODEL_COLOR[1]); + RenderColor::colors[RenderCol_Support_Enforcer] = GUI::ImGuiWrapper::to_ImVec4(GLVolume::MODEL_COLOR[2]); + RenderColor::colors[RenderCol_Support_Blocker] = GUI::ImGuiWrapper::to_ImVec4(GLVolume::MODEL_COLOR[3]); + RenderColor::colors[RenderCol_Model_Unprintable] = GUI::ImGuiWrapper::to_ImVec4(GLVolume::UNPRINTABLE_COLOR); } GLVolume::GLVolume(float r, float g, float b, float a) @@ -459,25 +450,11 @@ GLVolume::GLVolume(float r, float g, float b, float a) mmuseg_ts = 0; } -void GLVolume::set_color(const std::array& rgba) -{ - color = rgba; -} // BBS float GLVolume::explosion_ratio = 1.0; float GLVolume::last_explosion_ratio = 1.0; -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(); @@ -514,57 +491,45 @@ void GLVolume::set_render_color() #endif else { //to make black not too hard too see - std::array new_color = adjust_color_for_rendering(color); + ColorRGBA new_color = adjust_color_for_rendering(color); set_render_color(new_color); } } if (force_transparent) { - if (color[3] < FullyTransparentMaterialThreshold) { - render_color[3] = FullTransparentModdifiedToFixAlpha; + if (color.a() < FullyTransparentMaterialThreshold) { + render_color.a(FullTransparentModdifiedToFixAlpha); } else { - render_color[3] = color[3]; + render_color.a(color.a()); } } //BBS set unprintable color if (!printable) { - render_color[0] = UNPRINTABLE_COLOR[0]; - render_color[1] = UNPRINTABLE_COLOR[1]; - render_color[2] = UNPRINTABLE_COLOR[2]; - render_color[3] = UNPRINTABLE_COLOR[3]; + render_color = UNPRINTABLE_COLOR; } //BBS set invisible color if (!visible) { - render_color[0] = MODEL_HIDDEN_COL[0]; - render_color[1] = MODEL_HIDDEN_COL[1]; - render_color[2] = MODEL_HIDDEN_COL[2]; - render_color[3] = MODEL_HIDDEN_COL[3]; + render_color = MODEL_HIDDEN_COL; } } -std::array color_from_model_volume(const ModelVolume& model_volume) +ColorRGBA color_from_model_volume(const ModelVolume& model_volume) { - std::array color = {0.0f, 0.0f, 0.0f, 1.0f}; - if (model_volume.is_negative_volume()) { + ColorRGBA color; + if (model_volume.is_negative_volume()) return GLVolume::MODEL_NEGTIVE_COL; - } - else if (model_volume.is_modifier()) { + else if (model_volume.is_modifier()) #if ENABLE_MODIFIERS_ALWAYS_TRANSPARENT return GLVolume::MODEL_MIDIFIER_COL; #else - color[0] = 0.2f; - color[1] = 1.0f; - color[2] = 0.2f; + color = { 0.2f, 1.0f, 0.2f, 1.0f }; #endif // ENABLE_MODIFIERS_ALWAYS_TRANSPARENT - } - else if (model_volume.is_support_blocker()) { + else if (model_volume.is_support_blocker()) return GLVolume::SUPPORT_BLOCKER_COL; - } - else if (model_volume.is_support_enforcer()) { + else if (model_volume.is_support_enforcer()) return GLVolume::SUPPORT_ENFORCER_COL; - } return color; } @@ -713,12 +678,12 @@ void GLVolume::render(bool with_outline) const if (color_volume) { GLShaderProgram* shader = GUI::wxGetApp().get_current_shader(); - std::vector> colors = get_extruders_colors(); + std::vector colors = get_extruders_colors(); //when force_transparent, we need to keep the alpha - if (force_native_color && (render_color[3] < 1.0)) { - for (int index = 0; index < colors.size(); index ++) - colors[index][3] = render_color[3]; + if (force_native_color && (render_color.is_transparent())) { + for (int index = 0; index < colors.size(); index++) + colors[index].a(render_color.a()); } glsafe(::glMultMatrixd(world_matrix().data())); for (int idx = 0; idx < mmuseg_ivas.size(); idx++) { @@ -733,20 +698,20 @@ void GLVolume::render(bool with_outline) const int extruder_id = mv->extruder_id(); //shader->set_uniform("uniform_color", colors[extruder_id - 1]); //to make black not too hard too see - std::array new_color = adjust_color_for_rendering(colors[extruder_id - 1]); + ColorRGBA new_color = adjust_color_for_rendering(colors[extruder_id - 1]); shader->set_uniform("uniform_color", new_color); } else { if (idx <= colors.size()) { //shader->set_uniform("uniform_color", colors[idx - 1]); //to make black not too hard too see - std::array new_color = adjust_color_for_rendering(colors[idx - 1]); + ColorRGBA new_color = adjust_color_for_rendering(colors[idx - 1]); shader->set_uniform("uniform_color", new_color); } else { //shader->set_uniform("uniform_color", colors[0]); //to make black not too hard too see - std::array new_color = adjust_color_for_rendering(colors[0]); + ColorRGBA new_color = adjust_color_for_rendering(colors[0]); shader->set_uniform("uniform_color", new_color); } } @@ -794,7 +759,7 @@ void GLVolume::render(bool with_outline) const shader->stop_using(); outline_shader->start_using(); //float scale_ratio = 1.02f; - std::array outline_color = { 0.0f, 1.0f, 0.0f, 1.0f }; + ColorRGBA outline_color = { 0.0f, 1.0f, 0.0f, 1.0f }; outline_shader->set_uniform("uniform_color", outline_color);*/ #if 0 //dump stencil buffer @@ -868,7 +833,7 @@ void GLVolume::render(bool with_outline) const glStencilFunc(GL_NOTEQUAL, 0xff, 0xFF); glStencilMask(0x00); float scale = 1.02f; - std::array body_color = { 1.0f, 1.0f, 1.0f, 1.0f }; //red + ColorRGBA body_color = { 1.0f, 1.0f, 1.0f, 1.0f }; //red shader->set_uniform("uniform_color", body_color); shader->set_uniform("is_outline", true); @@ -900,7 +865,7 @@ void GLVolume::render(bool with_outline) const } //BBS add render for simple case -void GLVolume::simple_render(GLShaderProgram* shader, ModelObjectPtrs& model_objects, std::vector>& extruder_colors) const +void GLVolume::simple_render(GLShaderProgram* shader, ModelObjectPtrs& model_objects, std::vector& extruder_colors) const { if (this->is_left_handed()) glFrontFace(GL_CW); @@ -947,20 +912,20 @@ void GLVolume::simple_render(GLShaderProgram* shader, ModelObjectPtrs& model_obj if (idx == 0) { int extruder_id = model_volume->extruder_id(); //to make black not too hard too see - std::array new_color = adjust_color_for_rendering(extruder_colors[extruder_id - 1]); + ColorRGBA new_color = adjust_color_for_rendering(extruder_colors[extruder_id - 1]); shader->set_uniform("uniform_color", new_color); } else { if (idx <= extruder_colors.size()) { //shader->set_uniform("uniform_color", extruder_colors[idx - 1]); //to make black not too hard too see - std::array new_color = adjust_color_for_rendering(extruder_colors[idx - 1]); + ColorRGBA new_color = adjust_color_for_rendering(extruder_colors[idx - 1]); shader->set_uniform("uniform_color", new_color); } else { //shader->set_uniform("uniform_color", extruder_colors[0]); //to make black not too hard too see - std::array new_color = adjust_color_for_rendering(extruder_colors[0]); + ColorRGBA new_color = adjust_color_for_rendering(extruder_colors[0]); shader->set_uniform("uniform_color", new_color); } } @@ -999,7 +964,7 @@ void GLVolume::render_sinking_contours() m_sinking_contours.render(); } -GLWipeTowerVolume::GLWipeTowerVolume(const std::vector>& colors) +GLWipeTowerVolume::GLWipeTowerVolume(const std::vector& colors) : GLVolume() { m_colors = colors; @@ -1022,7 +987,7 @@ void GLWipeTowerVolume::render(bool with_outline) const GLShaderProgram* shader = GUI::wxGetApp().get_current_shader(); for (int i = 0; i < m_colors.size(); i++) { if (shader) { - std::array new_color = adjust_color_for_rendering(m_colors[i]); + ColorRGBA new_color = adjust_color_for_rendering(m_colors[i]); shader->set_uniform("uniform_color", new_color); } this->iva_per_colors[i].render(); @@ -1035,7 +1000,7 @@ void GLWipeTowerVolume::render(bool with_outline) const bool GLWipeTowerVolume::IsTransparent() { for (size_t i = 0; i < m_colors.size(); i++) { - if (m_colors[i][3] < 1.0f) { + if (m_colors[i].is_transparent()) { return true; } } @@ -1070,8 +1035,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() ? 0.7f : 0.4f; + ColorRGBA color = GLVolume::MODEL_COLOR[((color_by == "volume") ? volume_idx : obj_idx) % 4]; + color.a(model_volume->is_model_part() ? 0.7f : 0.4f); this->volumes.emplace_back(new GLVolume(color)); GLVolume& v = *this->volumes.back(); v.set_color(color_from_model_volume(*model_volume)); @@ -1164,8 +1129,8 @@ int GLVolumeCollection::load_wipe_tower_preview( if (height == 0.0f) height = 0.1f; - std::vector> extruder_colors = get_extruders_colors(); - std::vector> colors; + std::vector extruder_colors = get_extruders_colors(); + std::vector colors; GUI::PartPlateList& ppl = GUI::wxGetApp().plater()->get_partplate_list(); std::vector plate_extruders = ppl.get_plate(plate_idx)->get_extruders(true); TriangleMesh wipe_tower_shell = make_cube(width, depth, height); @@ -1185,7 +1150,7 @@ int GLVolumeCollection::load_wipe_tower_preview( // Orca: make it transparent for(auto& color : colors) - color[3] = 0.66f; + color.a(0.66f); volumes.emplace_back(new GLWipeTowerVolume(colors)); GLWipeTowerVolume& v = *dynamic_cast(volumes.back()); v.iva_per_colors.resize(colors.size()); @@ -1208,14 +1173,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; @@ -1232,7 +1197,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(); auto tempGlwipeTowerVolume = dynamic_cast(volume); if (tempGlwipeTowerVolume) { is_transparent = tempGlwipeTowerVolume->IsTransparent(); @@ -1539,83 +1504,53 @@ void GLVolumeCollection::reset_outside_state() void GLVolumeCollection::update_colors_by_extruder(const DynamicPrintConfig *config, bool is_update_alpha) { - static const float inv_255 = 1.0f / 255.0f; - - struct Color - { - std::string text; - unsigned char rgba[4]; - - Color() - : text("") - { - rgba[0] = 255; - rgba[1] = 255; - rgba[2] = 255; - rgba[3] = 255; - } - - void set(const std::string& text, unsigned char* rgba) - { - this->text = text; - ::memcpy((void*)this->rgba, (const void*)rgba, 4 * sizeof(unsigned char)); - } - }; - - if (config == nullptr) - return; - - unsigned char rgba[4]; - std::vector colors; + + using ColorItem = std::pair; + 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_color4(txt_color, rgba)) { - colors.resize(1); - colors[0].set(txt_color, rgba); - } + ColorRGBA rgba; + if (decode_color(txt_color, rgba)) + colors.push_back({ txt_color, rgba }); } - else - { + else { const ConfigOptionStrings* filamemts_opt = dynamic_cast(config->option("filament_colour")); if (filamemts_opt == nullptr) return; - unsigned int colors_count = (unsigned int)filamemts_opt->values.size(); + size_t colors_count = (size_t)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("filament_colour", i); - if (Slic3r::GUI::BitmapCache::parse_color4(txt_color, rgba)) - colors[i].set(txt_color, rgba); + ColorRGBA rgba; + 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 < 4; ++i) { - if (is_update_alpha == false) { - if (i < 3) { - volume->color[i] = (float) color.rgba[i] * inv_255; - } - continue; - } - volume->color[i] = (float) color.rgba[i] * inv_255; - } - } + const ColorItem& color = colors[extruder_id]; + if (!color.first.empty()) { + if (!is_update_alpha) { + float old_a = color.second.a(); + volume->color = color.second; + volume->color.a(old_a); + } + volume->color = color.second; + } } } @@ -1625,7 +1560,7 @@ void GLVolumeCollection::set_transparency(float alpha) if (volume == nullptr || volume->is_modifier || volume->is_wipe_tower || (volume->volume_idx() < 0)) continue; - volume->color[3] = alpha; + volume->color.a(alpha); } } diff --git a/src/slic3r/GUI/3DScene.hpp b/src/slic3r/GUI/3DScene.hpp index c850884da84..b9030ac4f7e 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" // BBS #include "libslic3r/ObjectID.hpp" @@ -30,10 +31,10 @@ #define glsafe(cmd) cmd #define glcheck() #endif // HAS_GLSAFE -extern std::vector> get_extruders_colors(); -extern float FullyTransparentMaterialThreshold; -extern float FullTransparentModdifiedToFixAlpha; -extern std::array adjust_color_for_rendering(const std::array &colors); +extern std::vector get_extruders_colors(); +extern float FullyTransparentMaterialThreshold; +extern float FullTransparentModdifiedToFixAlpha; +extern Slic3r::ColorRGBA adjust_color_for_rendering(const Slic3r::ColorRGBA &colors); namespace Slic3r { @@ -54,7 +55,7 @@ enum ModelInstanceEPrintVolumeState : unsigned char; using ModelObjectPtrs = std::vector; // 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. @@ -261,17 +262,17 @@ class GLVolume { public: std::string name; - static std::array DISABLED_COLOR; - static std::array SLA_SUPPORT_COLOR; - static std::array SLA_PAD_COLOR; - static std::array NEUTRAL_COLOR; - static std::array UNPRINTABLE_COLOR; - static std::array, 5> MODEL_COLOR; - static std::array MODEL_MIDIFIER_COL; - static std::array MODEL_NEGTIVE_COL; - static std::array SUPPORT_ENFORCER_COL; - static std::array SUPPORT_BLOCKER_COL; - static std::array MODEL_HIDDEN_COL; + static ColorRGBA DISABLED_COLOR; + static ColorRGBA SLA_SUPPORT_COLOR; + static ColorRGBA SLA_PAD_COLOR; + static ColorRGBA NEUTRAL_COLOR; + static ColorRGBA UNPRINTABLE_COLOR; + static std::array MODEL_COLOR; + static ColorRGBA MODEL_MIDIFIER_COL; + static ColorRGBA MODEL_NEGTIVE_COL; + static ColorRGBA SUPPORT_ENFORCER_COL; + static ColorRGBA SUPPORT_BLOCKER_COL; + static ColorRGBA MODEL_HIDDEN_COL; static void update_render_colors(); static void load_render_colors(); @@ -288,7 +289,7 @@ class GLVolume { }; 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(const ColorRGBA& color) : GLVolume(color.r(), color.g(), color.b(), color.a()) {} virtual ~GLVolume() = default; // BBS @@ -329,9 +330,9 @@ class GLVolume { 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) {} @@ -426,9 +427,8 @@ class GLVolume { 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 @@ -525,7 +525,7 @@ class GLVolume { virtual void render(bool with_outline = false) const; //BBS: add simple render function for thumbnail - void simple_render(GLShaderProgram* shader, ModelObjectPtrs& model_objects, std::vector>& extruder_colors) const; + void simple_render(GLShaderProgram* shader, ModelObjectPtrs& model_objects, std::vector& extruder_colors) const; void finalize_geometry(bool opengl_initialized) { this->indexed_vertex_array.finalize_geometry(opengl_initialized); } void release_geometry() { this->indexed_vertex_array.release_geometry(); } @@ -556,14 +556,14 @@ class GLVolume { // BBS class GLWipeTowerVolume : public GLVolume { public: - GLWipeTowerVolume(const std::vector>& colors); + GLWipeTowerVolume(const std::vector& colors); virtual void render(bool with_outline = false) const; std::vector iva_per_colors; bool IsTransparent(); private: - std::vector> m_colors; + std::vector m_colors; }; typedef std::vector GLVolumePtrs; @@ -657,8 +657,8 @@ class GLVolumeCollection 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); int get_selection_support_threshold_angle(bool&) const; // Render the volumes by OpenGL. diff --git a/src/slic3r/GUI/AboutDialog.cpp b/src/slic3r/GUI/AboutDialog.cpp index 74f5efbe6ec..e8f21416afd 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" @@ -127,10 +128,10 @@ 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();// wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT); - 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") + "© "; wxString text = wxString::Format( "" diff --git a/src/slic3r/GUI/BitmapCache.cpp b/src/slic3r/GUI/BitmapCache.cpp index 999d09a7c54..a0edea0711a 100644 --- a/src/slic3r/GUI/BitmapCache.cpp +++ b/src/slic3r/GUI/BitmapCache.cpp @@ -431,46 +431,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) -{ - if (scolor.size() == 9) { - unsigned char rgba[4]; - parse_color4(scolor, rgba); - rgb_out[0] = rgba[0]; - rgb_out[1] = rgba[1]; - rgb_out[2] = rgba[2]; - return true; - } - 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; -} - -bool BitmapCache::parse_color4(const std::string& scolor, unsigned char* rgba_out) -{ - rgba_out[0] = rgba_out[1] = rgba_out[2] = 0; rgba_out[3] = 255; - if ((scolor.size() != 7 && scolor.size() != 9) || scolor.front() != '#') - return false; - const char* c = scolor.data() + 1; - for (size_t i = 0; i < scolor.size() / 2; ++i) { - int digit1 = hex_digit_to_int(*c++); - int digit2 = hex_digit_to_int(*c++); - if (digit1 == -1 || digit2 == -1) - return false; - rgba_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 4803fa961d8..a5748acac21 100644 --- a/src/slic3r/GUI/BitmapCache.hpp +++ b/src/slic3r/GUI/BitmapCache.hpp @@ -9,9 +9,11 @@ #include #endif +#include "libslic3r/Color.hpp" struct NSVGimage; -namespace Slic3r { namespace GUI { +namespace Slic3r { +namespace GUI { class BitmapCache { @@ -44,12 +46,9 @@ class BitmapCache 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 = "", const float scale_in_center = 0.f); 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); - static bool parse_color4(const std::string& scolor, unsigned char* rgba_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/ConfigWizard.cpp b/src/slic3r/GUI/ConfigWizard.cpp index 572fb829f56..a34a7cd46ea 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" @@ -777,9 +778,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) { diff --git a/src/slic3r/GUI/Field.cpp b/src/slic3r/GUI/Field.cpp index 091a60b45f9..3565a40b956 100644 --- a/src/slic3r/GUI/Field.cpp +++ b/src/slic3r/GUI/Field.cpp @@ -1619,8 +1619,7 @@ boost::any& ColourPicker::get_value() 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(); + m_value = encode_color(ColorRGB(colour.Red(), colour.Green(), colour.Blue())); } return m_value; } diff --git a/src/slic3r/GUI/GCodeViewer.cpp b/src/slic3r/GUI/GCodeViewer.cpp index 3d0e4f2b9cd..082e7b84dfa 100644 --- a/src/slic3r/GUI/GCodeViewer.cpp +++ b/src/slic3r/GUI/GCodeViewer.cpp @@ -90,42 +90,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; - } - } - else if (color.size() == 9 && color.front() == '#') { - for (size_t j = 0; j < 4; ++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) @@ -263,7 +227,7 @@ void GCodeViewer::TBuffer::add_path(const GCodeProcessorResult::MoveVertex& move move.volumetric_rate(), move.layer_duration, move.extruder_id, move.cp_color_id, { { endpoint, endpoint } } }); } -GCodeViewer::Color GCodeViewer::Extrusions::Range::get_color_at(float value) const +ColorRGBA GCodeViewer::Extrusions::Range::get_color_at(float value) const { // Input value scaled to the colors range const float step = step_size(); @@ -280,15 +244,8 @@ GCodeViewer::Color GCodeViewer::Extrusions::Range::get_color_at(float value) con 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)); } float GCodeViewer::Extrusions::Range::step_size() const { @@ -584,11 +541,11 @@ void GCodeViewer::SequentialView::GCodeWindow::render(float top, float bottom, f 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 || !wxGetApp().show_gcode_window() || m_filename.empty() || m_lines_ends.empty() || curr_line_id == 0) return; @@ -728,7 +685,7 @@ if (has_render_path) gcode_window.render(legend_height + 2, std::max(10.f, (float)canvas_height - 40), (float)canvas_width - (float)right_margin, 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 @@ -750,7 +707,7 @@ const std::vector GCodeViewer::Extrusion_Role_Colors {{ { 0.37f, 0.82f, 0.58f, 1.0f } // erCustom }}; -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 @@ -760,7 +717,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 @@ -768,7 +725,7 @@ const std::vector GCodeViewer::Travel_Colors {{ // Normal ranges // blue to red -const std::vector GCodeViewer::Range_Colors{{ +const std::vector GCodeViewer::Range_Colors{ { decode_color_to_float_array("#0b2c7a"), // bluish decode_color_to_float_array("#135985"), decode_color_to_float_array("#1c8891"), @@ -782,8 +739,8 @@ const std::vector GCodeViewer::Range_Colors{{ decode_color_to_float_array("#942616") // reddish }}; -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() { @@ -1140,13 +1097,13 @@ 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_tools.m_tool_colors = decode_colors(gcode_result.extruder_colors); + decode_colors(gcode_result.extruder_colors, m_tools.m_tool_colors); m_tools.m_tool_visibles = std::vector(m_tools.m_tool_colors.size()); for (auto item: m_tools.m_tool_visibles) item = true; } else { // update tool colors - m_tools.m_tool_colors = decode_colors(str_tool_colors); + decode_colors(str_tool_colors, m_tools.m_tool_colors); m_tools.m_tool_visibles = std::vector(m_tools.m_tool_colors.size()); for (auto item : m_tools.m_tool_visibles) item = true; } @@ -1154,9 +1111,11 @@ void GCodeViewer::refresh(const GCodeProcessorResult& gcode_result, const std::v for (int i = 0; i < m_tools.m_tool_colors.size(); i++) { m_tools.m_tool_colors[i] = adjust_color_for_rendering(m_tools.m_tool_colors[i]); } - // ensure there are enough colors defined + ColorRGBA default_color; + decode_color("#FF8000", default_color); + // ensure there are enough colors defined while (m_tools.m_tool_colors.size() < std::max(size_t(1), gcode_result.extruders_count)) { - m_tools.m_tool_colors.push_back(decode_color("#FF8000")); + m_tools.m_tool_colors.push_back(default_color); m_tools.m_tool_visibles.push_back(true); } @@ -1247,7 +1206,7 @@ void GCodeViewer::reset() m_paths_bounding_box = BoundingBoxf3(); m_max_bounding_box = BoundingBoxf3(); m_max_print_height = 0.0f; - m_tools.m_tool_colors = std::vector(); + m_tools.m_tool_colors = std::vector(); m_tools.m_tool_visibles = std::vector(); m_extruders_count = 0; m_extruder_ids = std::vector(); @@ -1904,7 +1863,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); } @@ -1926,10 +1885,10 @@ void GCodeViewer::export_toolpaths_to_obj(const char* filename) const fprintf(fp, "# Generated by %s-%s based on Slic3r\n", SLIC3R_APP_NAME, SoftFever_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"); } @@ -1990,7 +1949,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); @@ -3231,7 +3190,7 @@ void GCodeViewer::load_shells(const Print& print, bool initialized, bool force_p for (GLVolume* volume : m_shells.volumes.volumes) { volume->zoom_to_volumes = false; - volume->color[3] = 0.5f; + volume->color.a(0.5f); volume->force_native_color = true; volume->set_render_color(); //BBS: add shell bounding box logic @@ -3254,7 +3213,7 @@ void GCodeViewer::refresh_render_paths(bool keep_sequential_current_first, bool BOOST_LOG_TRIVIAL(debug) << __FUNCTION__ << boost::format(": enter, m_buffers size %1%!")%m_buffers.size(); 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; } @@ -3269,7 +3228,7 @@ void GCodeViewer::refresh_render_paths(bool keep_sequential_current_first, bool case EViewType::Tool: { color = m_tools.m_tool_colors[path.extruder_id]; break; } case EViewType::ColorPrint: { if (path.cp_color_id >= static_cast(m_tools.m_tool_colors.size())) - color = { 0.5f, 0.5f, 0.5f, 1.0f }; + color = ColorRGBA::GRAY(); else { color = m_tools.m_tool_colors[path.cp_color_id]; color = adjust_color_for_rendering(color); @@ -3282,7 +3241,7 @@ void GCodeViewer::refresh_render_paths(bool keep_sequential_current_first, bool color = {id, role, id, 1.0f}; break; } - default: { color = { 1.0f, 1.0f, 1.0f, 1.0f }; break; } + default: { color = ColorRGBA::WHITE(); break; } } return color; @@ -3515,7 +3474,7 @@ m_no_render_path = false; 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: @@ -4168,7 +4127,8 @@ void GCodeViewer::render_all_plates_stats(const std::vector filament_diameters = gcode_result_list.front()->filament_diameters; std::vector filament_densities = gcode_result_list.front()->filament_densities; - std::vector filament_colors = decode_colors(wxGetApp().plater()->get_extruder_colors_from_plater_config(gcode_result_list.back())); + std::vector filament_colors; + decode_colors(wxGetApp().plater()->get_extruder_colors_from_plater_config(gcode_result_list.back()), filament_colors); for (int i = 0; i < filament_colors.size(); i++) { filament_colors[i] = adjust_color_for_rendering(filament_colors[i]); @@ -4213,13 +4173,13 @@ void GCodeViewer::render_all_plates_stats(const std::vector>& columns_offsets) + auto append_item = [icon_size, &imgui, imperial_units, &window_padding, &draw_list, this](const ColorRGBA& color, const std::vector>& columns_offsets) { // render icon ImVec2 pos = ImVec2(ImGui::GetCursorScreenPos().x + window_padding * 3, ImGui::GetCursorScreenPos().y); draw_list->AddRectFilled({ pos.x + 1.0f * m_scale, pos.y + 3.0f * m_scale }, { pos.x + icon_size - 1.0f * m_scale, pos.y + icon_size + 1.0f * m_scale }, - ImGui::GetColorU32({ color[0], color[1], color[2], 1.0f })); + ImGuiWrapper::to_ImU32(color)); ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(20.0 * m_scale, 6.0 * m_scale)); @@ -4425,7 +4385,7 @@ void GCodeViewer::render_legend(float &legend_height, int canvas_width, int canv auto append_item = [icon_size, &imgui, imperial_units, &window_padding, &draw_list, this]( EItemType type, - const Color& color, + const ColorRGBA& color, const std::vector>& columns_offsets, bool checkbox = true, bool visible = true, @@ -4437,21 +4397,21 @@ void GCodeViewer::render_legend(float &legend_height, int canvas_width, int canv default: case EItemType::Rect: { draw_list->AddRectFilled({ pos.x + 1.0f * m_scale, pos.y + 3.0f * m_scale }, { pos.x + icon_size - 1.0f * m_scale, pos.y + icon_size + 1.0f * m_scale }, - 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 + 5.0f)); - 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 + 5.0f)); - 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 + 2 }, { pos.x + icon_size - 1, pos.y + 4 }, ImGui::GetColorU32({ color[0], color[1], color[2], 1.0f }), 3.0f); + draw_list->AddLine({ pos.x + 1, pos.y + icon_size + 2 }, { pos.x + icon_size - 1, pos.y + 4 }, ImGuiWrapper::to_ImU32(color), 3.0f); break; case EItemType::None: break; @@ -4567,7 +4527,7 @@ void GCodeViewer::render_legend(float &legend_height, int canvas_width, int canv }; 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) { @@ -4587,7 +4547,11 @@ void GCodeViewer::render_legend(float &legend_height, int canvas_width, int canv // 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 } }); + { + ColorRGBA color; + decode_color(item.color, color); + ret.push_back({ color, { previous_z, current_z } }); + } } return ret; @@ -4834,7 +4798,7 @@ void GCodeViewer::render_legend(float &legend_height, int canvas_width, int canv } auto append_option_item = [this, append_item](EMoveType type, std::vector offsets) { - auto append_option_item_with_type = [this, offsets, append_item](EMoveType type, const Color& color, const std::string& label, bool visible) { + auto append_option_item_with_type = [this, offsets, append_item](EMoveType type, const ColorRGBA& color, const std::string& label, bool visible) { append_item(EItemType::Rect, color, {{ label , offsets[0] }}, true, visible, [this, type, visible]() { m_buffers[buffer_id(type)].visible = !m_buffers[buffer_id(type)].visible; // update buffers' render paths @@ -4958,7 +4922,7 @@ void GCodeViewer::render_legend(float &legend_height, int canvas_width, int canv if (need_scrollable) ImGui::BeginChild("color_prints", { -1.0f, child_height }, false); if (m_extruder_ids.size() == 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()); auto extruder_idx = m_extruder_ids[0]; if (items_cnt == 0) { // There are no color changes, but there are some pause print or custom Gcode @@ -4990,7 +4954,7 @@ void GCodeViewer::render_legend(float &legend_height, int canvas_width, int canv // shows only extruders actually used size_t i = 0; for (auto extruder_idx : m_extruder_ids) { - const std::vector>> cp_values = color_print_ranges(extruder_idx, custom_gcode_per_print_z); + const std::vector>> cp_values = color_print_ranges(extruder_idx, 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 const bool filament_visible = m_tools.m_tool_visibles[extruder_idx]; @@ -5119,8 +5083,8 @@ void GCodeViewer::render_legend(float &legend_height, int canvas_width, int canv }; EType type; int extruder_id; - Color color1; - Color color2; + ColorRGBA color1; + ColorRGBA color2; Times times; std::pair used_filament {0.0f, 0.0f}; }; @@ -5131,7 +5095,7 @@ void GCodeViewer::render_legend(float &legend_height, int canvas_width, int canv //BBS: replace model custom gcode with current plate custom gcode std::vector custom_gcode_per_print_z = wxGetApp().is_editor() ? wxGetApp().plater()->model().get_curr_plate_custom_gcodes().gcodes : m_custom_gcode_per_print_z; - std::vector last_color(m_extruders_count); + std::vector last_color(m_extruders_count); for (size_t i = 0; i < m_extruders_count; ++i) { last_color[i] = m_tools.m_tool_colors[i]; } @@ -5143,8 +5107,8 @@ void GCodeViewer::render_legend(float &legend_height, int canvas_width, int canv 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; @@ -5152,14 +5116,16 @@ void GCodeViewer::render_legend(float &legend_height, int canvas_width, int canv 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; } @@ -5170,7 +5136,7 @@ void GCodeViewer::render_legend(float &legend_height, int canvas_width, int canv 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(); @@ -5180,16 +5146,16 @@ void GCodeViewer::render_legend(float &legend_height, int canvas_width, int canv 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(); @@ -5199,7 +5165,7 @@ void GCodeViewer::render_legend(float &legend_height, int canvas_width, int canv 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))); @@ -5713,7 +5679,7 @@ void GCodeViewer::log_memory_used(const std::string& label, int64_t additional) } } -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 818f3a3e5eb..4c0f0809749 100644 --- a/src/slic3r/GUI/GCodeViewer.hpp +++ b/src/slic3r/GUI/GCodeViewer.hpp @@ -34,7 +34,6 @@ static const float SLIDER_BOTTOM_MARGIN = 64.0f; class GCodeViewer { using IBufferType = unsigned short; - using Color = std::array; using VertexBuffer = std::vector; using MultiVertexBuffer = std::vector; using IndexBuffer = std::vector; @@ -43,12 +42,12 @@ class GCodeViewer using InstanceIdBuffer = std::vector; using InstancesOffsets = std::vector; - static const std::vector Extrusion_Role_Colors; - static const std::vector Options_Colors; - static const std::vector Travel_Colors; - static const std::vector Range_Colors; - static const Color Wipe_Color; - static const Color Neutral_Color; + static const std::vector Extrusion_Role_Colors; + static const std::vector Options_Colors; + static const std::vector Travel_Colors; + static const std::vector Range_Colors; + static const ColorRGBA Wipe_Color; + static const ColorRGBA Neutral_Color; enum class EOptionsColors : unsigned char { @@ -133,7 +132,7 @@ class GCodeViewer // vbo id unsigned int vbo{ 0 }; // Color to apply to the instances - Color color; + ColorRGBA color; }; std::vector ranges; @@ -256,7 +255,7 @@ class GCodeViewer // Index of the parent tbuffer unsigned char tbuffer_id; // Render path property - Color color; + ColorRGBA color; // Index of the buffer in TBuffer::indices unsigned int ibuffer_id; // Render path content @@ -276,12 +275,10 @@ class GCodeViewer bool operator() (const RenderPath &l, const RenderPath &r) const { if (l.tbuffer_id < r.tbuffer_id) return true; - for (int i = 0; i < 3; ++i) { - if (l.color[i] < r.color[i]) - return true; - else if (l.color[i] > r.color[i]) - return false; - } + if (l.color < r.color) + return true; + else if (l.color > r.color) + return false; return l.ibuffer_id < r.ibuffer_id; } }; @@ -312,7 +309,7 @@ class GCodeViewer struct Model { GLModel model; - Color color; + ColorRGBA color; InstanceVBuffer instances; GLModel::InitializationData data; @@ -416,7 +413,7 @@ class GCodeViewer void reset(bool log = false) { min = FLT_MAX; max = -FLT_MAX; count = 0; log_scale = log; } float step_size() const; - Color get_color_at(float value) const; + ColorRGBA get_color_at(float value) const; float get_value_at_step(int step) const; }; @@ -519,7 +516,7 @@ Range layer_duration_log; TBuffer* buffer{ nullptr }; unsigned int ibo{ 0 }; unsigned int vbo{ 0 }; - Color color; + ColorRGBA color; ~SequentialRangeCap(); bool is_renderable() const { return buffer != nullptr; } @@ -717,7 +714,7 @@ Range layer_duration_log; struct ETools { - std::vector m_tool_colors; + std::vector m_tool_colors; std::vector m_tool_visibles; }; @@ -920,7 +917,7 @@ mutable bool m_no_render_path { false }; } bool is_visible(const Path& path) const { return is_visible(path.role); } void log_memory_used(const std::string& label, int64_t additional = 0) const; - Color option_color(EMoveType move_type) const; + ColorRGBA option_color(EMoveType move_type) const; }; } // namespace GUI diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 036e7cbb340..15c343d585b 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -78,23 +78,25 @@ static constexpr const float TRACKBALLSIZE = 0.8f; -float GLCanvas3D::DEFAULT_BG_LIGHT_COLOR[3] = { 0.906f, 0.906f, 0.906f }; -float GLCanvas3D::DEFAULT_BG_LIGHT_COLOR_DARK[3] = { 0.329f, 0.329f, 0.353f }; -float GLCanvas3D::ERROR_BG_LIGHT_COLOR[3] = { 0.753f, 0.192f, 0.039f }; -float GLCanvas3D::ERROR_BG_LIGHT_COLOR_DARK[3] = { 0.753f, 0.192f, 0.039f }; +static Slic3r::ColorRGB DEFAULT_BG_LIGHT_COLOR = {0.906f, 0.906f, 0.906f}; +static Slic3r::ColorRGB DEFAULT_BG_LIGHT_COLOR_DARK = {0.329f, 0.329f, 0.353f}; +static Slic3r::ColorRGB ERROR_BG_LIGHT_COLOR = {0.753f, 0.192f, 0.039f}; +static Slic3r::ColorRGB ERROR_BG_LIGHT_COLOR_DARK = {0.753f, 0.192f, 0.039f}; void GLCanvas3D::update_render_colors() { - GLCanvas3D::DEFAULT_BG_LIGHT_COLOR[0] = RenderColor::colors[RenderCol_3D_Background].x; - GLCanvas3D::DEFAULT_BG_LIGHT_COLOR[1] = RenderColor::colors[RenderCol_3D_Background].y; - GLCanvas3D::DEFAULT_BG_LIGHT_COLOR[2] = RenderColor::colors[RenderCol_3D_Background].z; + DEFAULT_BG_LIGHT_COLOR = { + RenderColor::colors[RenderCol_3D_Background].x, + RenderColor::colors[RenderCol_3D_Background].y, + RenderColor::colors[RenderCol_3D_Background].z, + }; } void GLCanvas3D::load_render_colors() { - RenderColor::colors[RenderCol_3D_Background] = ImVec4(GLCanvas3D::DEFAULT_BG_LIGHT_COLOR[0], - GLCanvas3D::DEFAULT_BG_LIGHT_COLOR[1], - GLCanvas3D::DEFAULT_BG_LIGHT_COLOR[2], + RenderColor::colors[RenderCol_3D_Background] = ImVec4(DEFAULT_BG_LIGHT_COLOR.r(), + DEFAULT_BG_LIGHT_COLOR.g(), + DEFAULT_BG_LIGHT_COLOR.b(), 1.0f); } @@ -967,8 +969,8 @@ void GLCanvas3D::SequentialPrintClearance::set_polygons(const Polygons& polygons void GLCanvas3D::SequentialPrintClearance::render() { - std::array FILL_COLOR = { 0.7f, 0.7f, 1.0f, 0.5f }; - std::array NO_FILL_COLOR = { 0.75f, 0.75f, 0.75f, 0.75f }; + const ColorRGBA FILL_COLOR = { 0.7f, 0.7f, 1.0f, 0.5f }; + const ColorRGBA NO_FILL_COLOR = { 0.75f, 0.75f, 0.75f, 0.75f }; GLShaderProgram* shader = wxGetApp().get_shader("gouraud_light"); if (shader == nullptr) @@ -2068,7 +2070,7 @@ void GLCanvas3D::render_thumbnail(ThumbnailData& thumbnail_data, unsigned int w, { GLShaderProgram* shader = wxGetApp().get_shader("thumbnail"); ModelObjectPtrs& model_objects = GUI::wxGetApp().model().objects; - std::vector> colors = ::get_extruders_colors(); + std::vector colors = ::get_extruders_colors(); switch (OpenGLManager::get_framebuffers_type()) { case OpenGLManager::EFramebufferType::Arb: @@ -2130,8 +2132,8 @@ void GLCanvas3D::set_selected_visible(bool visible) for (unsigned int i : m_selection.get_volume_idxs()) { GLVolume* volume = const_cast(m_selection.get_volume(i)); volume->visible = visible; - volume->color[3] = visible ? 1.f : GLVolume::MODEL_HIDDEN_COL[3]; - volume->render_color[3] = volume->color[3]; + volume->color.a(visible ? 1.f : GLVolume::MODEL_HIDDEN_COL.a()); + volume->render_color.a(volume->color.a()); volume->force_native_color = !visible; } } @@ -5526,7 +5528,7 @@ static void debug_output_thumbnail(const ThumbnailData& thumbnail_data) #endif // ENABLE_THUMBNAIL_GENERATOR_DEBUG_OUTPUT void GLCanvas3D::render_thumbnail_internal(ThumbnailData& thumbnail_data, const ThumbnailsParams& thumbnail_params, - PartPlateList& partplate_list, ModelObjectPtrs& model_objects, const GLVolumeCollection& volumes, std::vector>& extruder_colors, + PartPlateList& partplate_list, ModelObjectPtrs& model_objects, const GLVolumeCollection& volumes, std::vector& extruder_colors, GLShaderProgram* shader, Camera::EType camera_type, bool use_top_view, bool for_picking) { //BBS modify visible calc function @@ -5563,9 +5565,7 @@ void GLCanvas3D::render_thumbnail_internal(ThumbnailData& thumbnail_data, const return ret; }; - static std::array curr_color; - static const std::array orange = { 0.923f, 0.504f, 0.264f, 1.0f }; - static const std::array gray = { 0.64f, 0.64f, 0.64f, 1.0f }; + static ColorRGBA curr_color; GLVolumePtrs visible_volumes; @@ -5702,12 +5702,9 @@ void GLCanvas3D::render_thumbnail_internal(ThumbnailData& thumbnail_data, const shader->set_uniform("emission_factor", 0.1f); for (GLVolume* vol : visible_volumes) { //BBS set render color for thumbnails - curr_color[0] = vol->color[0]; - curr_color[1] = vol->color[1]; - curr_color[2] = vol->color[2]; - curr_color[3] = vol->color[3]; + curr_color = vol->color; - std::array new_color = adjust_color_for_rendering(curr_color); + ColorRGBA new_color = adjust_color_for_rendering(curr_color); shader->set_uniform("uniform_color", new_color); shader->set_uniform("volume_world_matrix", vol->world_matrix()); //BBS set all volume to orange @@ -5739,7 +5736,7 @@ void GLCanvas3D::render_thumbnail_internal(ThumbnailData& thumbnail_data, const } void GLCanvas3D::render_thumbnail_framebuffer(ThumbnailData& thumbnail_data, unsigned int w, unsigned int h, const ThumbnailsParams& thumbnail_params, - PartPlateList& partplate_list, ModelObjectPtrs& model_objects, const GLVolumeCollection& volumes, std::vector>& extruder_colors, + PartPlateList& partplate_list, ModelObjectPtrs& model_objects, const GLVolumeCollection& volumes, std::vector& extruder_colors, GLShaderProgram* shader, Camera::EType camera_type, bool use_top_view, bool for_picking) { thumbnail_data.set(w, h); @@ -5847,7 +5844,7 @@ void GLCanvas3D::render_thumbnail_framebuffer(ThumbnailData& thumbnail_data, uns } void GLCanvas3D::render_thumbnail_framebuffer_ext(ThumbnailData& thumbnail_data, unsigned int w, unsigned int h, const ThumbnailsParams& thumbnail_params, - PartPlateList& partplate_list, ModelObjectPtrs& model_objects, const GLVolumeCollection& volumes, std::vector>& extruder_colors, + PartPlateList& partplate_list, ModelObjectPtrs& model_objects, const GLVolumeCollection& volumes, std::vector& extruder_colors, GLShaderProgram* shader, Camera::EType camera_type, bool use_top_view, bool for_picking) { thumbnail_data.set(w, h); @@ -5949,7 +5946,7 @@ void GLCanvas3D::render_thumbnail_framebuffer_ext(ThumbnailData& thumbnail_data, // glsafe(::glDisable(GL_MULTISAMPLE)); } -void GLCanvas3D::render_thumbnail_legacy(ThumbnailData& thumbnail_data, unsigned int w, unsigned int h, const ThumbnailsParams& thumbnail_params, PartPlateList &partplate_list, ModelObjectPtrs& model_objects, const GLVolumeCollection& volumes, std::vector>& extruder_colors, GLShaderProgram* shader, Camera::EType camera_type) +void GLCanvas3D::render_thumbnail_legacy(ThumbnailData& thumbnail_data, unsigned int w, unsigned int h, const ThumbnailsParams& thumbnail_params, PartPlateList &partplate_list, ModelObjectPtrs& model_objects, const GLVolumeCollection& volumes, std::vector& extruder_colors, GLShaderProgram* shader, Camera::EType camera_type) { // check that thumbnail size does not exceed the default framebuffer size const Size& cnv_size = get_canvas_size(); @@ -6519,21 +6516,22 @@ void GLCanvas3D::_picking_pass() int volume_id = -1; int gizmo_id = -1; - GLubyte color[4] = { 0, 0, 0, 0 }; + std::array color = { 0, 0, 0, 0 }; const Size& cnv_size = get_canvas_size(); bool inside = 0 <= m_mouse.position(0) && m_mouse.position(0) < cnv_size.get_width() && 0 <= m_mouse.position(1) && m_mouse.position(1) < cnv_size.get_height(); if (inside) { - glsafe(::glReadPixels(m_mouse.position(0), cnv_size.get_height() - m_mouse.position(1) - 1, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, (void*)color)); + glsafe(::glReadPixels(m_mouse.position(0), cnv_size.get_height() - m_mouse.position.y() - 1, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, (void*)color.data())); if (picking_checksum_alpha_channel(color[0], color[1], color[2]) == color[3]) { // Only non-interpolated colors are valid, those have their lowest three bits zeroed. // we reserve color = (0,0,0) for occluders (as the printbed) // volumes' id are shifted by 1 // see: _render_volumes_for_picking() + unsigned int id = picking_encode(color[0], color[1], color[2]); //BBS: remove the bed picking logic - //volume_id = color[0] + (color[1] << 8) + (color[2] << 16) - 1; - volume_id = color[0] + (color[1] << 8) + (color[2] << 16); + //volume_id = id - 1; + volume_id = id; // gizmos' id are instead properly encoded by the color - gizmo_id = color[0] + (color[1] << 8) + (color[2] << 16); + gizmo_id = id; } } else @@ -6676,21 +6674,21 @@ void GLCanvas3D::_render_background() const ::glBegin(GL_QUADS); - float* background_color = m_is_dark ? DEFAULT_BG_LIGHT_COLOR_DARK : DEFAULT_BG_LIGHT_COLOR; - float* error_background_color = m_is_dark ? ERROR_BG_LIGHT_COLOR_DARK : ERROR_BG_LIGHT_COLOR; + ColorRGB background_color = m_is_dark ? DEFAULT_BG_LIGHT_COLOR_DARK : DEFAULT_BG_LIGHT_COLOR; + ColorRGB error_background_color = m_is_dark ? ERROR_BG_LIGHT_COLOR_DARK : ERROR_BG_LIGHT_COLOR; if (use_error_color) - ::glColor3fv(error_background_color); + ::glColor3fv(error_background_color.data()); else - ::glColor3fv(background_color); + ::glColor3fv(background_color.data()); ::glVertex2f(-1.0f, -1.0f); ::glVertex2f(1.0f, -1.0f); if (use_error_color) - ::glColor3fv(error_background_color); + ::glColor3fv(error_background_color.data()); else - ::glColor3fv(background_color); + ::glColor3fv(background_color.data()); ::glVertex2f(1.0f, 1.0f); ::glVertex2f(-1.0f, 1.0f); @@ -7249,8 +7247,6 @@ void GLCanvas3D::_render_style_editor() void GLCanvas3D::_render_volumes_for_picking() const { - static const GLfloat INV_255 = 1.0f / 255.0f; - // do not cull backfaces to show broken geometry, if any glsafe(::glDisable(GL_CULL_FACE)); @@ -7266,13 +7262,9 @@ void GLCanvas3D::_render_volumes_for_picking() const // we reserve color = (0,0,0) for occluders (as the printbed) // so we shift volumes' id by 1 to get the proper color //BBS: remove the bed picking logic - unsigned int id = volume.second.first; - //unsigned int id = 1 + volume.second.first; - unsigned int r = (id & (0x000000FF << 0)) << 0; - unsigned int g = (id & (0x000000FF << 8)) >> 8; - unsigned int b = (id & (0x000000FF << 16)) >> 16; - unsigned int a = picking_checksum_alpha_channel(r, g, b); - glsafe(::glColor4f((GLfloat)r * INV_255, (GLfloat)g * INV_255, (GLfloat)b * INV_255, (GLfloat)a * INV_255)); + const unsigned int id = volume.second.first; + //const unsigned int id = 1 + volume.second.first; + glsafe(::glColor4fv(picking_decode(id).data())); volume.first->render(); } } @@ -7870,15 +7862,15 @@ void GLCanvas3D::_render_paint_toolbar() const ImDrawList* draw_list = ImGui::GetWindowDrawList(); ImGuiContext& context = *GImGui; bool disabled = !wxGetApp().plater()->can_fillcolor(); - unsigned char rgb[3]; + ColorRGBA rgba; for (int i = 0; i < extruder_num; i++) { if (i > 0) ImGui::SameLine(); - Slic3r::GUI::BitmapCache::parse_color(colors[i], rgb); - ImGui::PushStyleColor(ImGuiCol_Button, ImColor(rgb[0], rgb[1], rgb[2]).Value); - ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImColor(rgb[0], rgb[1], rgb[2]).Value); - ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImColor(rgb[0], rgb[1], rgb[2]).Value); + decode_color(colors[i], rgba); + ImGui::PushStyleColor(ImGuiCol_Button, ImGuiWrapper::to_ImVec4(rgba)); + ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImGuiWrapper::to_ImVec4(rgba)); + ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImGuiWrapper::to_ImVec4(rgba)); if (disabled) ImGui::PushItemFlag(ImGuiItemFlags_Disabled, true); if (ImGui::Button(("##filament_button" + std::to_string(i)).c_str(), button_size)) { @@ -7899,9 +7891,9 @@ void GLCanvas3D::_render_paint_toolbar() const } const float text_offset_y = 4.0f * em_unit * f_scale; - for (int i = 0; i < extruder_num; i++){ - Slic3r::GUI::BitmapCache::parse_color(colors[i], rgb); - float gray = 0.299 * rgb[0] + 0.587 * rgb[1] + 0.114 * rgb[2]; + for (int i = 0; i < extruder_num; i++) { + decode_color(colors[i], rgba); + float gray = 0.299 * rgba.r_uchar() + 0.587 * rgba.g_uchar() + 0.114 * rgba.b_uchar(); ImVec4 text_color = gray < 80 ? ImVec4(1.0f, 1.0f, 1.0f, 1.0f) : ImVec4(0, 0, 0, 1.0f); imgui.push_bold_font(); @@ -8375,7 +8367,7 @@ void GLCanvas3D::_load_print_toolpaths(const BuildVolume &build_volume) if (!print->has_skirt() && !print->has_brim()) return; - const std::array color = { 0.5f, 1.0f, 0.5f, 1.0f }; // greenish + const ColorRGBA color = ColorRGBA::GREENISH(); // number of skirt layers size_t total_layer_count = 0; @@ -8421,7 +8413,8 @@ void GLCanvas3D::_load_print_toolpaths(const BuildVolume &build_volume) void GLCanvas3D::_load_print_object_toolpaths(const PrintObject& print_object, const BuildVolume& build_volume, const std::vector& str_tool_colors, const std::vector& color_print_values) { - std::vector> tool_colors = _parse_colors(str_tool_colors); + std::vector tool_colors; + decode_colors(str_tool_colors, tool_colors); struct Ctxt { @@ -8430,20 +8423,20 @@ void GLCanvas3D::_load_print_object_toolpaths(const PrintObject& print_object, c bool has_perimeters; bool has_infill; bool has_support; - const std::vector>* tool_colors; + const std::vector* tool_colors; bool is_single_material_print; int filaments_cnt; const std::vector* color_print_values; - static const std::array& color_perimeters() { static std::array color = { 1.0f, 1.0f, 0.0f, 1.f }; return color; } // yellow - static const std::array& color_infill() { static std::array color = { 1.0f, 0.5f, 0.5f, 1.f }; return color; } // redish - static const std::array& color_support() { static std::array color = { 0.5f, 1.0f, 0.5f, 1.f }; return color; } // greenish - static const std::array& color_pause_or_custom_code() { static std::array color = { 0.5f, 0.5f, 0.5f, 1.f }; return color; } // gray + static ColorRGBA color_perimeters() { return ColorRGBA::YELLOW(); } + static ColorRGBA color_infill() { return ColorRGBA::REDISH(); } + static ColorRGBA color_support() { return ColorRGBA::GREENISH(); } + static ColorRGBA color_pause_or_custom_code() { return ColorRGBA::GRAY(); } // For cloring by a tool, return a parsed color. bool color_by_tool() const { return tool_colors != nullptr; } size_t number_tools() const { return color_by_tool() ? tool_colors->size() : 0; } - const std::array& color_tool(size_t tool) const { return (*tool_colors)[tool]; } + const ColorRGBA& color_tool(size_t tool) const { return (*tool_colors)[tool]; } // For coloring by a color_print(M600), return a parsed color. bool color_by_color_print() const { return color_print_values!=nullptr; } @@ -8583,7 +8576,7 @@ void GLCanvas3D::_load_print_object_toolpaths(const PrintObject& print_object, c //FIXME Improve the heuristics for a grain size. size_t grain_size = std::max(ctxt.layers.size() / 16, size_t(1)); tbb::spin_mutex new_volume_mutex; - auto new_volume = [this, &new_volume_mutex](const std::array& color) { + auto new_volume = [this, &new_volume_mutex](const ColorRGBA& color) { // Allocate the volume before locking. GLVolume *volume = new GLVolume(color); volume->is_extrusion_path = true; @@ -8725,21 +8718,22 @@ void GLCanvas3D::_load_wipe_tower_toolpaths(const BuildVolume& build_volume, con if (!print->is_step_done(psWipeTower)) return; - std::vector> tool_colors = _parse_colors(str_tool_colors); + std::vector tool_colors; + decode_colors(str_tool_colors, tool_colors); struct Ctxt { const Print *print; - const std::vector>* tool_colors; + const std::vector* tool_colors; Vec2f wipe_tower_pos; float wipe_tower_angle; - static const std::array& color_support() { static std::array color = { 0.5f, 1.0f, 0.5f, 1.f }; return color; } // greenish + static ColorRGBA color_support() { return ColorRGBA::GREENISH(); } // For cloring by a tool, return a parsed color. bool color_by_tool() const { return tool_colors != nullptr; } size_t number_tools() const { return this->color_by_tool() ? tool_colors->size() : 0; } - const std::array& color_tool(size_t tool) const { return (*tool_colors)[tool]; } + const ColorRGBA& color_tool(size_t tool) const { return (*tool_colors)[tool]; } int volume_idx(int tool, int feature) const { return this->color_by_tool() ? std::min(this->number_tools() - 1, std::max(tool, 0)) : feature; } @@ -8779,7 +8773,7 @@ void GLCanvas3D::_load_wipe_tower_toolpaths(const BuildVolume& build_volume, con size_t n_items = print->wipe_tower_data().tool_changes.size() + (ctxt.priming.empty() ? 0 : 1); size_t grain_size = std::max(n_items / 128, size_t(1)); tbb::spin_mutex new_volume_mutex; - auto new_volume = [this, &new_volume_mutex](const std::array& color) { + auto new_volume = [this, &new_volume_mutex](const ColorRGBA& color) { auto *volume = new GLVolume(color); volume->is_extrusion_path = true; tbb::spin_mutex::scoped_lock lock; @@ -8898,7 +8892,7 @@ void GLCanvas3D::_load_sla_shells() return; auto add_volume = [this](const SLAPrintObject &object, int volume_id, const SLAPrintObject::Instance& instance, - const TriangleMesh& mesh, const std::array& color, bool outside_printer_detection_enabled) { + const TriangleMesh& mesh, const ColorRGBA& color, bool outside_printer_detection_enabled) { m_volumes.volumes.emplace_back(new GLVolume(color)); GLVolume& v = *m_volumes.volumes.back(); #if ENABLE_SMOOTH_NORMALS @@ -8970,28 +8964,6 @@ void GLCanvas3D::_set_warning_notification_if_needed(EWarning warning) _set_warning_notification(warning, show); } -std::vector> GLCanvas3D::_parse_colors(const std::vector& colors) -{ - static const float INV_255 = 1.0f / 255.0f; - - std::vector> output(colors.size(), { 1.0f, 1.0f, 1.0f, 1.0f }); - for (size_t i = 0; i < colors.size(); ++i) { - const std::string& color = colors[i]; - 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; - - output[i][j] = float(digit1 * 16 + digit2) * INV_255; - } - } - } - return output; -} - void GLCanvas3D::_set_warning_notification(EWarning warning, bool state) { enum ErrorType{ diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp index fb1780c7bce..7f03f00f3c5 100644 --- a/src/slic3r/GUI/GLCanvas3D.hpp +++ b/src/slic3r/GUI/GLCanvas3D.hpp @@ -199,14 +199,6 @@ class GLCanvas3D static const double DefaultCameraZoomToBedMarginFactor; static const double DefaultCameraZoomToPlateMarginFactor; - - static float DEFAULT_BG_LIGHT_COLOR[3]; - static float ERROR_BG_LIGHT_COLOR[3]; - static float DEFAULT_BG_LIGHT_COLOR_LIGHT[3]; - static float ERROR_BG_LIGHT_COLOR_LIGHT[3]; - static float DEFAULT_BG_LIGHT_COLOR_DARK[3]; - static float ERROR_BG_LIGHT_COLOR_DARK[3]; - static void update_render_colors(); static void load_render_colors(); @@ -857,15 +849,15 @@ class GLCanvas3D void render_thumbnail(ThumbnailData& thumbnail_data, unsigned int w, unsigned int h, const ThumbnailsParams& thumbnail_params, const GLVolumeCollection& volumes, Camera::EType camera_type, bool use_top_view = false, bool for_picking = false); static void render_thumbnail_internal(ThumbnailData& thumbnail_data, const ThumbnailsParams& thumbnail_params, PartPlateList& partplate_list, ModelObjectPtrs& model_objects, - const GLVolumeCollection& volumes, std::vector>& extruder_colors, + const GLVolumeCollection& volumes, std::vector& extruder_colors, GLShaderProgram* shader, Camera::EType camera_type, bool use_top_view = false, bool for_picking = false); // render thumbnail using an off-screen framebuffer static void render_thumbnail_framebuffer(ThumbnailData& thumbnail_data, unsigned int w, unsigned int h, const ThumbnailsParams& thumbnail_params, - PartPlateList& partplate_list, ModelObjectPtrs& model_objects, const GLVolumeCollection& volumes, std::vector>& extruder_colors, + PartPlateList& partplate_list, ModelObjectPtrs& model_objects, const GLVolumeCollection& volumes, std::vector& extruder_colors, GLShaderProgram* shader, Camera::EType camera_type, bool use_top_view = false, bool for_picking = false); // render thumbnail using an off-screen framebuffer when GLEW_EXT_framebuffer_object is supported static void render_thumbnail_framebuffer_ext(ThumbnailData& thumbnail_data, unsigned int w, unsigned int h, const ThumbnailsParams& thumbnail_params, - PartPlateList& partplate_list, ModelObjectPtrs& model_objects, const GLVolumeCollection& volumes, std::vector>& extruder_colors, + PartPlateList& partplate_list, ModelObjectPtrs& model_objects, const GLVolumeCollection& volumes, std::vector& extruder_colors, GLShaderProgram* shader, Camera::EType camera_type, bool use_top_view = false, bool for_picking = false); //BBS use gcoder viewer render calibration thumbnails @@ -1155,7 +1147,7 @@ class GLCanvas3D bool _render_orient_menu(float left, float right, float bottom, float top); bool _render_arrange_menu(float left, float right, float bottom, float top); // render thumbnail using the default framebuffer - void render_thumbnail_legacy(ThumbnailData& thumbnail_data, unsigned int w, unsigned int h, const ThumbnailsParams& thumbnail_params, PartPlateList& partplate_list, ModelObjectPtrs& model_objects, const GLVolumeCollection& volumes, std::vector>& extruder_colors, GLShaderProgram* shader, Camera::EType camera_type); + void render_thumbnail_legacy(ThumbnailData& thumbnail_data, unsigned int w, unsigned int h, const ThumbnailsParams& thumbnail_params, PartPlateList& partplate_list, ModelObjectPtrs& model_objects, const GLVolumeCollection& volumes, std::vector& extruder_colors, GLShaderProgram* shader, Camera::EType camera_type); void _update_volumes_hover_state(); @@ -1201,8 +1193,6 @@ class GLCanvas3D // BBS FIXME float get_overlay_window_width() { return 0; /*LayersEditing::get_overlay_window_width();*/ } - - static std::vector> _parse_colors(const std::vector& colors); }; } // namespace GUI diff --git a/src/slic3r/GUI/GLModel.cpp b/src/slic3r/GUI/GLModel.cpp index 422b6540807..fa804efc2f3 100644 --- a/src/slic3r/GUI/GLModel.cpp +++ b/src/slic3r/GUI/GLModel.cpp @@ -165,7 +165,7 @@ bool GLModel::init_from_file(const std::string& filename) return true; } -void GLModel::set_color(int entity_id, const std::array& color) +void GLModel::set_color(int entity_id, const ColorRGBA& color) { for (size_t i = 0; i < m_render_data.size(); ++i) { if (entity_id == -1 || static_cast(i) == entity_id) diff --git a/src/slic3r/GUI/GLModel.hpp b/src/slic3r/GUI/GLModel.hpp index d47c56fd93c..62722b18cf2 100644 --- a/src/slic3r/GUI/GLModel.hpp +++ b/src/slic3r/GUI/GLModel.hpp @@ -3,6 +3,7 @@ #include "libslic3r/Point.hpp" #include "libslic3r/BoundingBox.hpp" +#include "libslic3r/Color.hpp" #include #include @@ -33,7 +34,7 @@ namespace GUI { unsigned int vbo_id{ 0 }; unsigned int ibo_id{ 0 }; size_t indices_count{ 0 }; - std::array color{ 1.0f, 1.0f, 1.0f, 1.0f }; + ColorRGBA color; }; struct InitializationData @@ -44,7 +45,7 @@ namespace GUI { std::vector positions; std::vector normals; std::vector indices; - std::array color{ 1.0f, 1.0f, 1.0f, 1.0f }; + ColorRGBA color; }; std::vector entities; @@ -74,7 +75,7 @@ namespace GUI { bool init_from_file(const std::string& filename); // if entity_id == -1 set the color of all entities - void set_color(int entity_id, const std::array& color); + void set_color(int entity_id, const ColorRGBA& color); void reset(); void render() const; diff --git a/src/slic3r/GUI/GLShader.cpp b/src/slic3r/GUI/GLShader.cpp index 9c1e936525e..32b3d596014 100644 --- a/src/slic3r/GUI/GLShader.cpp +++ b/src/slic3r/GUI/GLShader.cpp @@ -4,6 +4,7 @@ #include "3DScene.hpp" #include "libslic3r/Utils.hpp" #include "libslic3r/format.hpp" +#include "libslic3r/Color.hpp" #include #include @@ -206,154 +207,114 @@ void GLShaderProgram::stop_using() const glsafe(::glUseProgram(0)); } -bool GLShaderProgram::set_uniform(const char* name, int value) const +void GLShaderProgram::set_uniform(int id, int value) const { - int id = get_uniform_location(name); - if (id >= 0) { - glsafe(::glUniform1i(id, static_cast(value))); - return true; - } - return false; + if (id >= 0) + glsafe(::glUniform1i(id, value)); } -bool GLShaderProgram::set_uniform(const char* name, bool value) const +void GLShaderProgram::set_uniform(int id, bool value) const { - return set_uniform(name, value ? 1 : 0); + set_uniform(id, value ? 1 : 0); } -bool GLShaderProgram::set_uniform(const char* name, float value) const +void GLShaderProgram::set_uniform(int id, float value) const { - int id = get_uniform_location(name); - if (id >= 0) { - glsafe(::glUniform1f(id, static_cast(value))); - return true; - } - return false; + if (id >= 0) + glsafe(::glUniform1f(id, value)); } -bool GLShaderProgram::set_uniform(const char* name, double value) const +void GLShaderProgram::set_uniform(int id, double value) const { - return set_uniform(name, static_cast(value)); + set_uniform(id, static_cast(value)); } -bool GLShaderProgram::set_uniform(const char* name, const std::array& value) const +void GLShaderProgram::set_uniform(int id, const std::array& value) const { - int id = get_uniform_location(name); - if (id >= 0) { + if (id >= 0) glsafe(::glUniform2iv(id, 1, static_cast(value.data()))); - return true; - } - return false; } -bool GLShaderProgram::set_uniform(const char* name, const std::array& value) const +void GLShaderProgram::set_uniform(int id, const std::array& value) const { - int id = get_uniform_location(name); - if (id >= 0) { + if (id >= 0) glsafe(::glUniform3iv(id, 1, static_cast(value.data()))); - return true; - } - return false; } -bool GLShaderProgram::set_uniform(const char* name, const std::array& value) const +void GLShaderProgram::set_uniform(int id, const std::array& value) const { - int id = get_uniform_location(name); - if (id >= 0) { + if (id >= 0) glsafe(::glUniform4iv(id, 1, static_cast(value.data()))); - return true; - } - return false; } -bool GLShaderProgram::set_uniform(const char* name, const std::array& value) const +void GLShaderProgram::set_uniform(int id, const std::array& value) const { - int id = get_uniform_location(name); - if (id >= 0) { + if (id >= 0) glsafe(::glUniform2fv(id, 1, static_cast(value.data()))); - return true; - } - return false; } -bool GLShaderProgram::set_uniform(const char* name, const std::array& value) const +void GLShaderProgram::set_uniform(int id, const std::array& value) const { - int id = get_uniform_location(name); - if (id >= 0) { + if (id >= 0) glsafe(::glUniform3fv(id, 1, static_cast(value.data()))); - return true; - } - return false; } -bool GLShaderProgram::set_uniform(const char* name, const std::array& value) const +void GLShaderProgram::set_uniform(int id, const std::array& value) const { - int id = get_uniform_location(name); - if (id >= 0) { + if (id >= 0) glsafe(::glUniform4fv(id, 1, static_cast(value.data()))); - return true; - } - return false; } -bool GLShaderProgram::set_uniform(const char* name, const float* value, size_t size) const +void GLShaderProgram::set_uniform(int id, const float* value, size_t size) const { - if (size == 1) - return set_uniform(name, value[0]); - else if (size < 5) { - int id = get_uniform_location(name); - if (id >= 0) { - if (size == 2) - glsafe(::glUniform2fv(id, 1, static_cast(value))); - else if (size == 3) - glsafe(::glUniform3fv(id, 1, static_cast(value))); - else - glsafe(::glUniform4fv(id, 1, static_cast(value))); - - return true; - } + if (id >= 0) { + if (size == 1) + set_uniform(id, value[0]); + else if (size == 2) + glsafe(::glUniform2fv(id, 1, static_cast(value))); + else if (size == 3) + glsafe(::glUniform3fv(id, 1, static_cast(value))); + else if (size == 4) + glsafe(::glUniform4fv(id, 1, static_cast(value))); } - return false; } -bool GLShaderProgram::set_uniform(const char* name, const Transform3f& value) const +void GLShaderProgram::set_uniform(int id, const Transform3f& value) const { - int id = get_uniform_location(name); - if (id >= 0) { + if (id >= 0) glsafe(::glUniformMatrix4fv(id, 1, GL_FALSE, static_cast(value.matrix().data()))); - return true; - } - return false; } -bool GLShaderProgram::set_uniform(const char* name, const Transform3d& value) const +void GLShaderProgram::set_uniform(int id, const Transform3d& value) const { - return set_uniform(name, value.cast()); + set_uniform(id, value.cast()); } -bool GLShaderProgram::set_uniform(const char* name, const Matrix3f& value) const +void GLShaderProgram::set_uniform(int id, const Matrix3f& value) const { - int id = get_uniform_location(name); - if (id >= 0) { + if (id >= 0) glsafe(::glUniformMatrix3fv(id, 1, GL_FALSE, static_cast(value.data()))); - return true; - } - return false; } -bool GLShaderProgram::set_uniform(const char* name, const Vec3f& value) const +void GLShaderProgram::set_uniform(int id, const Vec3f& value) const { - int id = get_uniform_location(name); - if (id >= 0) { + if (id >= 0) glsafe(::glUniform3fv(id, 1, static_cast(value.data()))); - return true; - } - return false; } -bool GLShaderProgram::set_uniform(const char* name, const Vec3d& value) const +void GLShaderProgram::set_uniform(int id, const Vec3d& value) const +{ + set_uniform(id, static_cast(value.cast())); +} + +void GLShaderProgram::set_uniform(int id, const ColorRGB& value) const +{ + set_uniform(id, value.data(), 3); +} + +void GLShaderProgram::set_uniform(int id, const ColorRGBA& value) const { - return set_uniform(name, static_cast(value.cast())); + set_uniform(id, value.data(), 4); } int GLShaderProgram::get_attrib_location(const char* name) const diff --git a/src/slic3r/GUI/GLShader.hpp b/src/slic3r/GUI/GLShader.hpp index d7b92000dfc..975c12c24ad 100644 --- a/src/slic3r/GUI/GLShader.hpp +++ b/src/slic3r/GUI/GLShader.hpp @@ -9,6 +9,8 @@ namespace Slic3r { +class ColorRGB; +class ColorRGBA; class GLShaderProgram { public: @@ -44,22 +46,43 @@ class GLShaderProgram void start_using() const; void stop_using() const; - bool set_uniform(const char* name, int value) const; - bool set_uniform(const char* name, bool value) const; - bool set_uniform(const char* name, float value) const; - bool set_uniform(const char* name, double value) const; - bool set_uniform(const char* name, const std::array& value) const; - bool set_uniform(const char* name, const std::array& value) const; - bool set_uniform(const char* name, const std::array& value) const; - bool set_uniform(const char* name, const std::array& value) const; - bool set_uniform(const char* name, const std::array& value) const; - bool set_uniform(const char* name, const std::array& value) const; - bool set_uniform(const char* name, const float* value, size_t size) const; - bool set_uniform(const char* name, const Transform3f& value) const; - bool set_uniform(const char* name, const Transform3d& value) const; - bool set_uniform(const char* name, const Matrix3f& value) const; - bool set_uniform(const char* name, const Vec3f& value) const; - bool set_uniform(const char* name, const Vec3d& value) const; + void set_uniform(const char* name, int value) const { set_uniform(get_uniform_location(name), value); } + void set_uniform(const char* name, bool value) const { set_uniform(get_uniform_location(name), value); } + void set_uniform(const char* name, float value) const { set_uniform(get_uniform_location(name), value); } + void set_uniform(const char* name, double value) const { set_uniform(get_uniform_location(name), value); } + void set_uniform(const char* name, const std::array& value) const { set_uniform(get_uniform_location(name), value); } + void set_uniform(const char* name, const std::array& value) const { set_uniform(get_uniform_location(name), value); } + void set_uniform(const char* name, const std::array& value) const { set_uniform(get_uniform_location(name), value); } + void set_uniform(const char* name, const std::array& value) const { set_uniform(get_uniform_location(name), value); } + void set_uniform(const char* name, const std::array& value) const { set_uniform(get_uniform_location(name), value); } + void set_uniform(const char* name, const std::array& value) const { set_uniform(get_uniform_location(name), value); } + void set_uniform(const char* name, const float* value, size_t size) const { set_uniform(get_uniform_location(name), value, size); } + void set_uniform(const char* name, const Transform3f& value) const { set_uniform(get_uniform_location(name), value); } + void set_uniform(const char* name, const Transform3d& value) const { set_uniform(get_uniform_location(name), value); } + void set_uniform(const char* name, const Matrix3f& value) const { set_uniform(get_uniform_location(name), value); } + void set_uniform(const char* name, const Vec3f& value) const { set_uniform(get_uniform_location(name), value); } + void set_uniform(const char* name, const Vec3d& value) const { set_uniform(get_uniform_location(name), value); } + void set_uniform(const char* name, const ColorRGB& value) const { set_uniform(get_uniform_location(name), value); } + void set_uniform(const char* name, const ColorRGBA& value) const { set_uniform(get_uniform_location(name), value); } + + void set_uniform(int id, int value) const; + void set_uniform(int id, bool value) const; + void set_uniform(int id, float value) const; + void set_uniform(int id, double value) const; + void set_uniform(int id, const std::array& value) const; + void set_uniform(int id, const std::array& value) const; + void set_uniform(int id, const std::array& value) const; + void set_uniform(int id, const std::array& value) const; + void set_uniform(int id, const std::array& value) const; + void set_uniform(int id, const std::array& value) const; + void set_uniform(int id, const float* value, size_t size) const; + void set_uniform(int id, const Transform3f& value) const; + void set_uniform(int id, const Transform3d& value) const; + void set_uniform(int id, const Matrix3f& value) const; + void set_uniform(int id, const Vec3f& value) const; + void set_uniform(int id, const Vec3d& value) const; + void set_uniform(int id, const ColorRGB& value) const; + void set_uniform(int id, const ColorRGBA& value) const; // returns -1 if not found int get_attrib_location(const char* name) const; diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp index dcbf17321a0..3e6b699878c 100644 --- a/src/slic3r/GUI/GUI_App.cpp +++ b/src/slic3r/GUI/GUI_App.cpp @@ -56,6 +56,7 @@ #include "libslic3r/Thread.hpp" #include "libslic3r/miniz_extension.hpp" #include "libslic3r/Utils.hpp" +#include "libslic3r/Color.hpp" #include "GUI.hpp" #include "GUI_Utils.hpp" @@ -3228,8 +3229,7 @@ void GUI_App::set_label_clr_modified(const wxColour& clr) if (m_color_label_modified == clr) return; m_color_label_modified = clr; - auto clr_str = wxString::Format(wxT("#%02X%02X%02X"), clr.Red(), clr.Green(), clr.Blue()); - std::string str = clr_str.ToStdString(); + const std::string str = encode_color(ColorRGB(clr.Red(), clr.Green(), clr.Blue())); app_config->save(); */ } @@ -3242,8 +3242,7 @@ void GUI_App::set_label_clr_sys(const wxColour& clr) if (m_color_label_sys == clr) return; m_color_label_sys = clr; - auto clr_str = wxString::Format(wxT("#%02X%02X%02X"), clr.Red(), clr.Green(), clr.Blue()); - std::string str = clr_str.ToStdString(); + const std::string str = encode_color(ColorRGB(clr.Red(), clr.Green(), clr.Blue())); app_config->save(); */ } diff --git a/src/slic3r/GUI/GUI_Colors.hpp b/src/slic3r/GUI/GUI_Colors.hpp index 32a03991816..0395e997c06 100644 --- a/src/slic3r/GUI/GUI_Colors.hpp +++ b/src/slic3r/GUI/GUI_Colors.hpp @@ -2,6 +2,7 @@ #define slic3r_GUI_Colors_hpp_ #include "imgui/imgui.h" +#include "libslic3r/Color.hpp" enum RenderCol_ { RenderCol_3D_Background = 0, @@ -38,13 +39,6 @@ class RenderColor { static ImVec4 colors[RenderCol_Count]; }; const char* GetRenderColName(RenderCol idx); -inline std::array GLColor(ImVec4 color) { - return {color.x, color.y, color.z, color.w }; -} - -inline ImVec4 IMColor(std::array color) { - return ImVec4(color[0], color[1], color[2], color[3]); -} } diff --git a/src/slic3r/GUI/GUI_ObjectTable.cpp b/src/slic3r/GUI/GUI_ObjectTable.cpp index 3f194ec4e68..eda7c15b71a 100644 --- a/src/slic3r/GUI/GUI_ObjectTable.cpp +++ b/src/slic3r/GUI/GUI_ObjectTable.cpp @@ -2812,13 +2812,13 @@ int ObjectTablePanel::init_filaments_and_colors() } unsigned int i = 0; - unsigned char rgb[3]; + ColorRGB rgb; while (i < m_filaments_count) { const std::string& txt_color = global_config->opt_string("filament_colour", i); if (i < color_count) { - if (Slic3r::GUI::BitmapCache::parse_color(txt_color, rgb)) + if (decode_color(txt_color, rgb)) { - m_filaments_colors[i] = wxColour(rgb[0], rgb[1], rgb[2]); + m_filaments_colors[i] = wxColour(rgb.r_uchar(), rgb.g_uchar(), rgb.b_uchar()); } else { diff --git a/src/slic3r/GUI/GUI_Utils.hpp b/src/slic3r/GUI/GUI_Utils.hpp index bf2c4277b88..ab3d2fd7946 100644 --- a/src/slic3r/GUI/GUI_Utils.hpp +++ b/src/slic3r/GUI/GUI_Utils.hpp @@ -23,6 +23,7 @@ #include "Event.hpp" #include "../libslic3r/libslic3r_version.h" #include "../libslic3r/Utils.hpp" +#include "libslic3r/Color.hpp" class wxCheckBox; @@ -39,28 +40,10 @@ inline int hex_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; } -static std::array decode_color_to_float_array(const std::string color) +static ColorRGBA decode_color_to_float_array(const std::string color) { - // set alpha to 1.0f by default - std::array ret = {0, 0, 0, 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_to_int(*c++); - int digit2 = hex_to_int(*c++); - if (digit1 == -1 || digit2 == -1) break; - ret[j] = float(digit1 * 16 + digit2) / 255.0f; - } - } - else if (color.size() == 9 && color.front() == '#') { - for (size_t j = 0; j < 4; ++j) { - int digit1 = hex_to_int(*c++); - int digit2 = hex_to_int(*c++); - if (digit1 == -1 || digit2 == -1) break; - - ret[j] = float(digit1 * 16 + digit2) / 255.0f; - } - } + ColorRGBA ret = ColorRGBA::BLACK(); + decode_color(color, ret); return ret; } @@ -470,14 +453,6 @@ class WindowMetrics std::ostream& operator<<(std::ostream &os, const WindowMetrics& metrics); -inline int 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; -} - class TaskTimer { std::chrono::milliseconds start_timer; diff --git a/src/slic3r/GUI/Gizmos/GLGizmoAdvancedCut.cpp b/src/slic3r/GUI/Gizmos/GLGizmoAdvancedCut.cpp index ba978050134..bc1ff411a15 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoAdvancedCut.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoAdvancedCut.cpp @@ -28,8 +28,6 @@ const float UndefFloat = -999.f; // connector colors -using ColorRGBA = std::array; - 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}; } @@ -103,8 +101,8 @@ static void rotate_z_3d(std::array& verts, float radian_angle) const double GLGizmoAdvancedCut::Offset = 10.0; const double GLGizmoAdvancedCut::Margin = 20.0; -const std::array GLGizmoAdvancedCut::GrabberColor = { 1.0, 1.0, 0.0, 1.0 }; -const std::array GLGizmoAdvancedCut::GrabberHoverColor = { 0.7, 0.7, 0.0, 1.0}; +const ColorRGBA GLGizmoAdvancedCut::GrabberColor = { 1.0f, 1.0f, 0.0f, 1.0f }; +const ColorRGBA GLGizmoAdvancedCut::GrabberHoverColor = { 0.7f, 0.7f, 0.0f, 1.0f }; GLGizmoAdvancedCut::GLGizmoAdvancedCut(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id) : GLGizmoRotate3D(parent, icon_filename, sprite_id, nullptr) @@ -525,11 +523,7 @@ void GLGizmoAdvancedCut::on_render_for_picking() float mean_size = (float)((box.size().x() + box.size().y() + box.size().z()) / 3.0); #endif - std::array color = picking_color_component(0); - m_move_grabber.color[0] = color[0]; - m_move_grabber.color[1] = color[1]; - m_move_grabber.color[2] = color[2]; - m_move_grabber.color[3] = color[3]; + m_move_grabber.color = picking_color_component(0); m_move_grabber.render_for_picking(mean_size); glsafe(::glEnable(GL_DEPTH_TEST)); @@ -564,7 +558,7 @@ void GLGizmoAdvancedCut::on_render_for_picking() const Transform3d view_model_matrix = translate_tf * m_rotate_matrix * scale_tf; - std::array color = picking_color_component(i+1); + ColorRGBA color = picking_color_component(i+1); render_connector_model(m_shapes[connectors[i].attribs], color, view_model_matrix, true); } } @@ -919,7 +913,7 @@ void GLGizmoAdvancedCut::render_cut_plane_and_grabbers() // m_move_grabber.hover_color = GrabberHoverColor; // m_move_grabber.render(m_hover_id == get_group_id(), (float)((box.size()(0) + box.size()(1) + box.size()(2)) / 3.0)); bool hover = (m_hover_id == get_group_id()); - std::array render_color; + ColorRGBA render_color; if (hover) { render_color = GrabberHoverColor; } @@ -1036,7 +1030,7 @@ void GLGizmoAdvancedCut::render_cut_line() glDisable(GL_LINE_STIPPLE); } -void GLGizmoAdvancedCut::render_connector_model(GLModel &model, const std::array &color, Transform3d view_model_matrix, bool for_picking) +void GLGizmoAdvancedCut::render_connector_model(GLModel &model, const ColorRGBA &color, Transform3d view_model_matrix, bool for_picking) { glPushMatrix(); GLShaderProgram *shader = nullptr; diff --git a/src/slic3r/GUI/Gizmos/GLGizmoAdvancedCut.hpp b/src/slic3r/GUI/Gizmos/GLGizmoAdvancedCut.hpp index 5cb9e765cc0..38abb30c3fe 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoAdvancedCut.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoAdvancedCut.hpp @@ -27,8 +27,8 @@ struct Rotate_data { private: static const double Offset; static const double Margin; - static const std::array GrabberColor; - static const std::array GrabberHoverColor; + static const ColorRGBA GrabberColor; + static const ColorRGBA GrabberHoverColor; mutable double m_movement; mutable double m_height; // height of cut plane to heatbed @@ -201,7 +201,7 @@ struct Rotate_data { void render_connectors(); void render_clipper_cut(); void render_cut_line(); - void render_connector_model(GLModel &model, const std::array& color, Transform3d view_model_matrix, bool for_picking = false); + void render_connector_model(GLModel &model, const ColorRGBA& color, Transform3d view_model_matrix, bool for_picking = false); void clear_selection(); void init_connector_shapes(); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoBase.cpp b/src/slic3r/GUI/Gizmos/GLGizmoBase.cpp index b1d98d3dc2f..75efc8902b5 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoBase.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoBase.cpp @@ -21,51 +21,51 @@ const float GLGizmoBase::Grabber::FixedGrabberSize = 16.0f; const float GLGizmoBase::Grabber::FixedRadiusSize = 80.0f; -std::array GLGizmoBase::DEFAULT_BASE_COLOR = { 0.625f, 0.625f, 0.625f, 1.0f }; -std::array GLGizmoBase::DEFAULT_DRAG_COLOR = { 1.0f, 1.0f, 1.0f, 1.0f }; -std::array GLGizmoBase::DEFAULT_HIGHLIGHT_COLOR = { 1.0f, 0.38f, 0.0f, 1.0f }; -std::array, 3> GLGizmoBase::AXES_HOVER_COLOR = {{ +ColorRGBA GLGizmoBase::DEFAULT_BASE_COLOR = { 0.625f, 0.625f, 0.625f, 1.0f }; +ColorRGBA GLGizmoBase::DEFAULT_DRAG_COLOR = { 1.0f, 1.0f, 1.0f, 1.0f }; +ColorRGBA GLGizmoBase::DEFAULT_HIGHLIGHT_COLOR = {1.0f, 0.38f, 0.0f, 1.0f}; +std::array GLGizmoBase::AXES_HOVER_COLOR = {{ { 0.7f, 0.0f, 0.0f, 1.0f }, { 0.0f, 0.7f, 0.0f, 1.0f }, { 0.0f, 0.0f, 0.7f, 1.0f } }}; -std::array, 3> GLGizmoBase::AXES_COLOR = { { +std::array GLGizmoBase::AXES_COLOR = {{ { 1.0, 0.0f, 0.0f, 1.0f }, { 0.0f, 1.0f, 0.0f, 1.0f }, { 0.0f, 0.0f, 1.0f, 1.0f } }}; -std::array GLGizmoBase::CONSTRAINED_COLOR = { 0.5f, 0.5f, 0.5f, 1.0f }; -std::array GLGizmoBase::FLATTEN_COLOR = { 0.96f, 0.93f, 0.93f, 0.5f }; -std::array GLGizmoBase::FLATTEN_HOVER_COLOR = { 1.0f, 1.0f, 1.0f, 0.75f }; +ColorRGBA GLGizmoBase::CONSTRAINED_COLOR = {0.5f, 0.5f, 0.5f, 1.0f}; +ColorRGBA GLGizmoBase::FLATTEN_COLOR = {0.96f, 0.93f, 0.93f, 0.5f}; +ColorRGBA GLGizmoBase::FLATTEN_HOVER_COLOR = {1.0f, 1.0f, 1.0f, 0.75f}; // new style color -std::array GLGizmoBase::GRABBER_NORMAL_COL = {1.0f, 1.0f, 1.0f, 1.0f}; -std::array GLGizmoBase::GRABBER_HOVER_COL = {0.863f, 0.125f, 0.063f, 1.0f}; -std::array GLGizmoBase::GRABBER_UNIFORM_COL = {0, 1.0, 1.0, 1.0f}; -std::array GLGizmoBase::GRABBER_UNIFORM_HOVER_COL = {0, 0.7, 0.7, 1.0f}; +ColorRGBA GLGizmoBase::GRABBER_NORMAL_COL = {1.0f, 1.0f, 1.0f, 1.0f}; +ColorRGBA GLGizmoBase::GRABBER_HOVER_COL = {0.863f, 0.125f, 0.063f, 1.0f}; +ColorRGBA GLGizmoBase::GRABBER_UNIFORM_COL = {0, 1.0, 1.0, 1.0f}; +ColorRGBA GLGizmoBase::GRABBER_UNIFORM_HOVER_COL = {0, 0.7, 0.7, 1.0f}; void GLGizmoBase::update_render_colors() { GLGizmoBase::AXES_COLOR = { { - GLColor(RenderColor::colors[RenderCol_Grabber_X]), - GLColor(RenderColor::colors[RenderCol_Grabber_Y]), - GLColor(RenderColor::colors[RenderCol_Grabber_Z]) + ImGuiWrapper::from_ImVec4(RenderColor::colors[RenderCol_Grabber_X]), + ImGuiWrapper::from_ImVec4(RenderColor::colors[RenderCol_Grabber_Y]), + ImGuiWrapper::from_ImVec4(RenderColor::colors[RenderCol_Grabber_Z]) } }; - GLGizmoBase::FLATTEN_COLOR = GLColor(RenderColor::colors[RenderCol_Flatten_Plane]); - GLGizmoBase::FLATTEN_HOVER_COLOR = GLColor(RenderColor::colors[RenderCol_Flatten_Plane_Hover]); + GLGizmoBase::FLATTEN_COLOR = ImGuiWrapper::from_ImVec4(RenderColor::colors[RenderCol_Flatten_Plane]); + GLGizmoBase::FLATTEN_HOVER_COLOR = ImGuiWrapper::from_ImVec4(RenderColor::colors[RenderCol_Flatten_Plane_Hover]); } void GLGizmoBase::load_render_colors() { - RenderColor::colors[RenderCol_Grabber_X] = IMColor(GLGizmoBase::AXES_COLOR[0]); - RenderColor::colors[RenderCol_Grabber_Y] = IMColor(GLGizmoBase::AXES_COLOR[1]); - RenderColor::colors[RenderCol_Grabber_Z] = IMColor(GLGizmoBase::AXES_COLOR[2]); - RenderColor::colors[RenderCol_Flatten_Plane] = IMColor(GLGizmoBase::FLATTEN_COLOR); - RenderColor::colors[RenderCol_Flatten_Plane_Hover] = IMColor(GLGizmoBase::FLATTEN_HOVER_COLOR); + RenderColor::colors[RenderCol_Grabber_X] = ImGuiWrapper::to_ImVec4(GLGizmoBase::AXES_COLOR[0]); + RenderColor::colors[RenderCol_Grabber_Y] = ImGuiWrapper::to_ImVec4(GLGizmoBase::AXES_COLOR[1]); + RenderColor::colors[RenderCol_Grabber_Z] = ImGuiWrapper::to_ImVec4(GLGizmoBase::AXES_COLOR[2]); + RenderColor::colors[RenderCol_Flatten_Plane] = ImGuiWrapper::to_ImVec4(GLGizmoBase::FLATTEN_COLOR); + RenderColor::colors[RenderCol_Flatten_Plane_Hover] = ImGuiWrapper::to_ImVec4(GLGizmoBase::FLATTEN_HOVER_COLOR); } GLGizmoBase::Grabber::Grabber() @@ -80,7 +80,7 @@ GLGizmoBase::Grabber::Grabber() void GLGizmoBase::Grabber::render(bool hover, float size) const { - std::array render_color; + ColorRGBA render_color; if (hover) { render_color = hover_color; } @@ -113,7 +113,7 @@ const GLModel& GLGizmoBase::Grabber::get_cube() const return cube; } -void GLGizmoBase::Grabber::render(float size, const std::array& render_color, bool picking) const +void GLGizmoBase::Grabber::render(float size, const ColorRGBA& render_color, bool picking) const { if (! cube_initialized) { // This cannot be done in constructor, OpenGL is not yet @@ -179,10 +179,6 @@ void GLGizmoBase::set_hover_id(int id) } } -void GLGizmoBase::set_highlight_color(const std::array& color) -{ - m_highlight_color = color; -} void GLGizmoBase::enable_grabber(unsigned int id) { @@ -265,22 +261,13 @@ void GLGizmoBase::GizmoImguiSetNextWIndowPos(float &x, float y, int flag, float m_imgui->set_next_window_pos(x, y, flag, pivot_x, pivot_y); } -std::array GLGizmoBase::picking_color_component(unsigned int id) const +ColorRGBA GLGizmoBase::picking_color_component(unsigned int id) const { - static const float INV_255 = 1.0f / 255.0f; - id = BASE_ID - id; - if (m_group_id > -1) id -= m_group_id; - // color components are encoded to match the calculation of volume_id made into GLCanvas3D::_picking_pass() - return std::array { - 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 - }; + return picking_decode(id); } void GLGizmoBase::render_grabbers(const BoundingBoxf3& box) const @@ -316,8 +303,7 @@ void GLGizmoBase::render_grabbers_for_picking(const BoundingBoxf3& box) const for (unsigned int i = 0; i < (unsigned int)m_grabbers.size(); ++i) { if (m_grabbers[i].enabled) { - std::array color = picking_color_component(i); - m_grabbers[i].color = color; + m_grabbers[i].color = picking_color_component(i); m_grabbers[i].render_for_picking(mean_size); } } @@ -354,23 +340,5 @@ std::string GLGizmoBase::get_name(bool include_shortcut) const return out; } - - -// 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. -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 GUI } // namespace Slic3r diff --git a/src/slic3r/GUI/Gizmos/GLGizmoBase.hpp b/src/slic3r/GUI/Gizmos/GLGizmoBase.hpp index c725809bbae..1dea8f08d46 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoBase.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoBase.hpp @@ -2,6 +2,7 @@ #define slic3r_GLGizmoBase_hpp_ #include "libslic3r/Point.hpp" +#include "libslic3r/Color.hpp" #include "slic3r/GUI/I18N.hpp" #include "slic3r/GUI/GLModel.hpp" @@ -38,18 +39,18 @@ class GLGizmoBase static float INV_ZOOM; //BBS colors - static std::array DEFAULT_BASE_COLOR; - static std::array DEFAULT_DRAG_COLOR; - static std::array DEFAULT_HIGHLIGHT_COLOR; - static std::array, 3> AXES_COLOR; - static std::array, 3> AXES_HOVER_COLOR; - static std::array CONSTRAINED_COLOR; - static std::array FLATTEN_COLOR; - static std::array FLATTEN_HOVER_COLOR; - static std::array GRABBER_NORMAL_COL; - static std::array GRABBER_HOVER_COL; - static std::array GRABBER_UNIFORM_COL; - static std::array GRABBER_UNIFORM_HOVER_COL; + static ColorRGBA DEFAULT_BASE_COLOR; + static ColorRGBA DEFAULT_DRAG_COLOR; + static ColorRGBA DEFAULT_HIGHLIGHT_COLOR; + static std::array AXES_COLOR; + static std::array AXES_HOVER_COLOR; + static ColorRGBA CONSTRAINED_COLOR; + static ColorRGBA FLATTEN_COLOR; + static ColorRGBA FLATTEN_HOVER_COLOR; + static ColorRGBA GRABBER_NORMAL_COL; + static ColorRGBA GRABBER_HOVER_COL; + static ColorRGBA GRABBER_UNIFORM_COL; + static ColorRGBA GRABBER_UNIFORM_HOVER_COL; static void update_render_colors(); static void load_render_colors(); @@ -65,8 +66,8 @@ class GLGizmoBase Vec3d center; Vec3d angles; - std::array color; - std::array hover_color; + ColorRGBA color; + ColorRGBA hover_color; bool enabled; bool dragging; @@ -80,7 +81,7 @@ class GLGizmoBase const GLModel& get_cube() const; private: - void render(float size, const std::array& render_color, bool picking) const; + void render(float size, const ColorRGBA& render_color, bool picking) const; GLModel cube; bool cube_initialized = false; @@ -114,9 +115,9 @@ class GLGizmoBase unsigned int m_sprite_id; int m_hover_id; bool m_dragging; - std::array m_base_color; - std::array m_drag_color; - std::array m_highlight_color; + ColorRGBA m_base_color; + ColorRGBA m_drag_color; + ColorRGBA m_highlight_color; mutable std::vector m_grabbers; ImGuiWrapper* m_imgui; bool m_first_input_window_render; @@ -169,7 +170,7 @@ class GLGizmoBase int get_hover_id() const { return m_hover_id; } void set_hover_id(int id); - void set_highlight_color(const std::array& color); + void set_highlight_color(const ColorRGBA& color) { m_highlight_color = color; } void enable_grabber(unsigned int id); void disable_grabber(unsigned int id); @@ -219,7 +220,7 @@ class GLGizmoBase void GizmoImguiSetNextWIndowPos(float &x, float y, int flag, float pivot_x = 0.0f, float pivot_y = 0.0f); // Returns the picking color for the given id, based on the BASE_ID constant // No check is made for clashing with other picking color (i.e. GLVolumes) - std::array picking_color_component(unsigned int id) const; + ColorRGBA picking_color_component(unsigned int id) const; void render_grabbers(const BoundingBoxf3& box) const; void render_grabbers(float size) const; void render_grabbers_for_picking(const BoundingBoxf3& box) const; @@ -235,11 +236,6 @@ class GLGizmoBase int count = 0; }; - -// 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 GUI } // namespace Slic3r diff --git a/src/slic3r/GUI/Gizmos/GLGizmoCut.cpp b/src/slic3r/GUI/Gizmos/GLGizmoCut.cpp index d5008725e4d..0e5d1c73087 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoCut.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoCut.cpp @@ -23,7 +23,8 @@ namespace GUI { const double GLGizmoCut::Offset = 10.0; const double GLGizmoCut::Margin = 20.0; -const std::array GLGizmoCut::GrabberColor = { 1.0, 0.5, 0.0, 1.0 }; +static const ColorRGBA GRABBER_COLOR = ColorRGBA::ORANGE(); +static const ColorRGBA PLANE_COLOR = { 0.8f, 0.8f, 0.8f, 0.5f }; GLGizmoCut::GLGizmoCut(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id) : GLGizmoBase(parent, icon_filename, sprite_id) @@ -103,7 +104,7 @@ void GLGizmoCut::on_render() // Draw the cutting plane ::glBegin(GL_QUADS); - ::glColor4f(0.8f, 0.8f, 0.8f, 0.5f); + ::glColor4fv(PLANE_COLOR.data()); ::glVertex3f(min_x, min_y, plane_center.z()); ::glVertex3f(max_x, min_y, plane_center.z()); ::glVertex3f(max_x, max_y, plane_center.z()); @@ -134,7 +135,7 @@ void GLGizmoCut::on_render() shader->start_using(); shader->set_uniform("emission_factor", 0.1f); - m_grabbers[0].color = GrabberColor; + m_grabbers[0].color = GRABBER_COLOR; m_grabbers[0].render(m_hover_id == 0, (float)((box.size().x() + box.size().y() + box.size().z()) / 3.0)); shader->stop_using(); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoCut.hpp b/src/slic3r/GUI/Gizmos/GLGizmoCut.hpp index 0d745fe3cb2..cf7c7ac0425 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoCut.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoCut.hpp @@ -13,7 +13,6 @@ class GLGizmoCut : public GLGizmoBase { static const double Offset; static const double Margin; - static const std::array GrabberColor; double m_cut_z{ 0.0 }; double m_max_z{ 0.0 }; diff --git a/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp b/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp index c095c0915e0..49622d84c53 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp @@ -640,7 +640,7 @@ void GLGizmoFdmSupports::update_from_model_object(bool first_update) m_volume_timestamps.clear(); int volume_id = -1; - std::vector> ebt_colors; + std::vector ebt_colors; ebt_colors.push_back(GLVolume::NEUTRAL_COLOR); ebt_colors.push_back(TriangleSelectorGUI::enforcers_color); ebt_colors.push_back(TriangleSelectorGUI::blockers_color); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp b/src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp index 39bc98d7fbb..8f73379e71c 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp @@ -114,7 +114,7 @@ void GLGizmoHollow::render_points(const Selection& selection, bool picking) cons glsafe(::glTranslated(0.0, 0.0, m_c->selection_info()->get_sla_shift())); glsafe(::glMultMatrixd(instance_matrix.data())); - std::array render_color; + ColorRGBA render_color; const sla::DrainHoles& drain_holes = m_c->selection_info()->model_object()->sla_drain_holes; size_t cache_size = drain_holes.size(); @@ -127,8 +127,7 @@ void GLGizmoHollow::render_points(const Selection& selection, bool picking) cons // First decide about the color of the point. if (picking) { - std::array color = picking_color_component(i); - render_color = color; + render_color = picking_color_component(i); } else { if (size_t(m_hover_id) == i) { @@ -140,11 +139,7 @@ void GLGizmoHollow::render_points(const Selection& selection, bool picking) cons render_color = {1.f, 0.f, 0.f, .5f}; } else { // neigher hover nor picking - - render_color[0] = point_selected ? 1.0f : 1.f; - render_color[1] = point_selected ? 0.3f : 1.f; - render_color[2] = point_selected ? 0.3f : 1.f; - render_color[3] = 0.5f; + render_color = point_selected ? ColorRGBA(1.0f, 0.3f, 0.3f, 0.5f) : ColorRGBA(1.0f, 1.0f, 1.0f, 0.5f); } } @@ -544,14 +539,11 @@ void GLGizmoHollow::on_render_input_window(float x, float y, float bottom_limit) } m_imgui->disabled_begin(! m_enable_hollowing); - float max_tooltip_width = ImGui::GetFontSize() * 20.0f; ImGui::AlignTextToFramePadding(); m_imgui->text(m_desc.at("offset")); ImGui::SameLine(settings_sliders_left, m_imgui->get_item_spacing().x); ImGui::PushItemWidth(window_width - settings_sliders_left); - m_imgui->slider_float("##offset", &offset, offset_min, offset_max, "%.1f mm"); - if (m_imgui->get_last_slider_status().hovered) - m_imgui->tooltip((_utf8(opts[0].second->tooltip)).c_str(), max_tooltip_width); + m_imgui->slider_float("##offset", &offset, offset_min, offset_max, "%.1f mm", 1.0f, true, _L(opts[0].second->tooltip)); bool slider_clicked = m_imgui->get_last_slider_status().clicked; // someone clicked the slider bool slider_edited =m_imgui->get_last_slider_status().edited; // someone is dragging the slider @@ -561,9 +553,7 @@ void GLGizmoHollow::on_render_input_window(float x, float y, float bottom_limit) ImGui::AlignTextToFramePadding(); m_imgui->text(m_desc.at("quality")); ImGui::SameLine(settings_sliders_left, m_imgui->get_item_spacing().x); - m_imgui->slider_float("##quality", &quality, quality_min, quality_max, "%.1f"); - if (m_imgui->get_last_slider_status().hovered) - m_imgui->tooltip((_utf8(opts[1].second->tooltip)).c_str(), max_tooltip_width); + m_imgui->slider_float("##quality", &quality, quality_min, quality_max, "%.1f", 1.0f, true, _L(opts[1].second->tooltip)); slider_clicked |= m_imgui->get_last_slider_status().clicked; slider_edited |= m_imgui->get_last_slider_status().edited; @@ -574,9 +564,7 @@ void GLGizmoHollow::on_render_input_window(float x, float y, float bottom_limit) ImGui::AlignTextToFramePadding(); m_imgui->text(m_desc.at("closing_distance")); ImGui::SameLine(settings_sliders_left, m_imgui->get_item_spacing().x); - m_imgui->slider_float("##closing_distance", &closing_d, closing_d_min, closing_d_max, "%.1f mm"); - if (m_imgui->get_last_slider_status().hovered) - m_imgui->tooltip((_utf8(opts[2].second->tooltip)).c_str(), max_tooltip_width); + m_imgui->slider_float("##closing_distance", &closing_d, closing_d_min, closing_d_max, "%.1f mm", 1.0f, true, _L(opts[2].second->tooltip)); slider_clicked |= m_imgui->get_last_slider_status().clicked; slider_edited |= m_imgui->get_last_slider_status().edited; diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp index 517e880d936..3dbb020fe6a 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp @@ -58,11 +58,11 @@ bool GLGizmoMmuSegmentation::on_is_activable() const } //BBS: use the global one in 3DScene.cpp -/*static std::vector> get_extruders_colors() +/*static std::vector get_extruders_colors() { unsigned char rgb_color[3] = {}; std::vector colors = Slic3r::GUI::wxGetApp().plater()->get_extruder_colors_from_plater_config(); - std::vector> colors_out(colors.size()); + std::vector colors_out(colors.size()); for (const std::string &color : colors) { Slic3r::GUI::BitmapCache::parse_color(color, rgb_color); size_t color_idx = &color - &colors.front(); @@ -276,18 +276,14 @@ bool GLGizmoMmuSegmentation::on_key_down_select_tool_type(int keyCode) { return true; } -static void render_extruders_combo(const std::string &label, - const std::vector &extruders, - const std::vector> &extruders_colors, - size_t &selection_idx) +static void render_extruders_combo(const std::string& label, + const std::vector& extruders, + const std::vector& extruders_colors, + size_t& selection_idx) { assert(!extruders_colors.empty()); assert(extruders_colors.size() == extruders_colors.size()); - auto convert_to_imu32 = [](const std::array &color) -> ImU32 { - return IM_COL32(uint8_t(color[0] * 255.f), uint8_t(color[1] * 255.f), uint8_t(color[2] * 255.f), uint8_t(color[3] * 255.f)); - }; - size_t selection_out = selection_idx; // It is necessary to use BeginGroup(). Otherwise, when using SameLine() is called, then other items will be drawn inside the combobox. ImGui::BeginGroup(); @@ -303,7 +299,7 @@ static void render_extruders_combo(const std::string &labe ImGui::SameLine(); ImGuiStyle &style = ImGui::GetStyle(); float height = ImGui::GetTextLineHeight(); - ImGui::GetWindowDrawList()->AddRectFilled(start_position, ImVec2(start_position.x + height + height / 2, start_position.y + height), convert_to_imu32(extruders_colors[extruder_idx])); + ImGui::GetWindowDrawList()->AddRectFilled(start_position, ImVec2(start_position.x + height + height / 2, start_position.y + height), ImGuiWrapper::to_ImU32(extruders_colors[extruder_idx])); ImGui::GetWindowDrawList()->AddRect(start_position, ImVec2(start_position.x + height + height / 2, start_position.y + height), IM_COL32_BLACK); ImGui::SetCursorScreenPos(ImVec2(start_position.x + height + height / 2 + style.FramePadding.x, start_position.y)); @@ -321,7 +317,7 @@ static void render_extruders_combo(const std::string &labe ImVec2 p = ImGui::GetCursorScreenPos(); float height = ImGui::GetTextLineHeight(); - ImGui::GetWindowDrawList()->AddRectFilled(p, ImVec2(p.x + height + height / 2, p.y + height), convert_to_imu32(extruders_colors[selection_idx])); + ImGui::GetWindowDrawList()->AddRectFilled(p, ImVec2(p.x + height + height / 2, p.y + height), ImGuiWrapper::to_ImU32(extruders_colors[selection_idx])); ImGui::GetWindowDrawList()->AddRect(p, ImVec2(p.x + height + height / 2, p.y + height), IM_COL32_BLACK); ImGui::SetCursorScreenPos(ImVec2(p.x + height + height / 2 + style.FramePadding.x, p.y)); @@ -448,8 +444,8 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott const float item_spacing = m_imgui->scaled(0.8f); size_t n_extruder_colors = std::min((size_t)EnforcerBlockerType::ExtruderMax, m_extruders_colors.size()); for (int extruder_idx = 0; extruder_idx < n_extruder_colors; extruder_idx++) { - const std::array &extruder_color = m_extruders_colors[extruder_idx]; - ImVec4 color_vec(extruder_color[0], extruder_color[1], extruder_color[2], extruder_color[3]); + const ColorRGBA &extruder_color = m_extruders_colors[extruder_idx]; + ImVec4 color_vec = ImGuiWrapper::to_ImVec4(extruder_color); std::string color_label = std::string("##extruder color ") + std::to_string(extruder_idx); std::string item_text = std::to_string(extruder_idx + 1); const ImVec2 label_size = ImGui::CalcTextSize(item_text.c_str(), NULL, true); @@ -486,7 +482,7 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott if (extruder_idx < 9 && ImGui::IsItemHovered()) m_imgui->tooltip(_L("Shortcut Key ") + std::to_string(extruder_idx + 1), max_tooltip_width); // draw filament id - float gray = 0.299 * extruder_color[0] + 0.587 * extruder_color[1] + 0.114 * extruder_color[2]; + float gray = 0.299 * extruder_color.r() + 0.587 * extruder_color.g() + 0.114 * extruder_color.b(); ImGui::SameLine(button_offset + (button_size.x - label_size.x) / 2.f); ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, {10.0,15.0}); if (gray * 255.f < 80.f) @@ -811,7 +807,7 @@ void GLGizmoMmuSegmentation::init_model_triangle_selectors() continue; int extruder_idx = (mv->extruder_id() > 0) ? mv->extruder_id() - 1 : 0; - std::vector> ebt_colors; + std::vector ebt_colors; ebt_colors.push_back(m_extruders_colors[size_t(extruder_idx)]); ebt_colors.insert(ebt_colors.end(), m_extruders_colors.begin(), m_extruders_colors.end()); @@ -833,7 +829,7 @@ void GLGizmoMmuSegmentation::update_triangle_selectors_colors() TriangleSelectorPatch* selector = dynamic_cast(m_triangle_selectors[i].get()); int extruder_idx = m_volumes_extruder_idxs[i]; int extruder_color_idx = std::max(0, extruder_idx - 1); - std::vector> ebt_colors; + std::vector ebt_colors; ebt_colors.push_back(m_extruders_colors[extruder_color_idx]); ebt_colors.insert(ebt_colors.end(), m_extruders_colors.begin(), m_extruders_colors.end()); selector->set_ebt_colors(ebt_colors); @@ -871,7 +867,7 @@ PainterGizmoType GLGizmoMmuSegmentation::get_painter_type() const } // BBS -std::array GLGizmoMmuSegmentation::get_cursor_hover_color() const +ColorRGBA GLGizmoMmuSegmentation::get_cursor_hover_color() const { if (m_selected_extruder_idx < m_extruders_colors.size()) return m_extruders_colors[m_selected_extruder_idx]; diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.hpp b/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.hpp index 6b5cde25c73..e7ec8d7bc28 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.hpp @@ -87,7 +87,7 @@ class GLGizmoMmuSegmentation : public GLGizmoPainterBase protected: // BBS - std::array get_cursor_hover_color() const override; + ColorRGBA get_cursor_hover_color() const override; void on_set_state() override; EnforcerBlockerType get_left_button_state_type() const override { return EnforcerBlockerType(m_selected_extruder_idx + 1); } @@ -107,7 +107,7 @@ class GLGizmoMmuSegmentation : public GLGizmoPainterBase // BBS size_t m_selected_extruder_idx = 0; - std::vector> m_extruders_colors; + std::vector m_extruders_colors; std::vector m_volumes_extruder_idxs; // BBS diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMove.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMove.cpp index 747d8ec89e2..62fc1dc6ffb 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMove.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMove.cpp @@ -170,7 +170,7 @@ void GLGizmoMove3D::on_render_for_picking() //get picking colors only for (unsigned int i = 0; i < (unsigned int) m_grabbers.size(); ++i) { if (m_grabbers[i].enabled) { - std::array color = picking_color_component(i); + ColorRGBA color = picking_color_component(i); m_grabbers[i].color = color; } } @@ -224,7 +224,7 @@ void GLGizmoMove3D::render_grabber_extension(Axis axis, const BoundingBoxf3& box double size = 0.75 * GLGizmoBase::Grabber::FixedGrabberSize * GLGizmoBase::INV_ZOOM; - std::array color = m_grabbers[axis].color; + ColorRGBA color = m_grabbers[axis].color; if (!picking && m_hover_id != -1) { if (m_hover_id == axis) { color = m_grabbers[axis].hover_color; diff --git a/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp b/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp index f682d249ec2..7e68b73730d 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp @@ -177,7 +177,7 @@ void GLGizmoPainterBase::render_cursor_circle() const glsafe(::glLineWidth(1.5f)); // BBS - std::array render_color = this->get_cursor_hover_color(); + ColorRGBA render_color = this->get_cursor_hover_color(); if (m_button_down == Button::Left) render_color = this->get_cursor_sphere_left_button_color(); else if (m_button_down == Button::Right) @@ -225,7 +225,7 @@ void GLGizmoPainterBase::render_cursor_sphere(const Transform3d& trafo) const glFrontFace(GL_CW); // BBS - std::array render_color = this->get_cursor_hover_color(); + ColorRGBA render_color = this->get_cursor_hover_color(); if (m_button_down == Button::Left) render_color = this->get_cursor_sphere_left_button_color(); else if (m_button_down == Button::Right) @@ -1002,13 +1002,16 @@ TriangleSelector::ClippingPlane GLGizmoPainterBase::get_clipping_plane_in_volume return TriangleSelector::ClippingPlane({float(normal_transformed.x()), float(normal_transformed.y()), float(normal_transformed.z()), offset_transformed}); } -std::array TriangleSelectorGUI::get_seed_fill_color(const std::array &base_color) +ColorRGBA TriangleSelectorGUI::enforcers_color = {0.5f, 1.f, 0.5f, 1.f}; +ColorRGBA TriangleSelectorGUI::blockers_color = {1.f, 0.5f, 0.5f, 1.f}; + +ColorRGBA TriangleSelectorGUI::get_seed_fill_color(const ColorRGBA& base_color) { // BBS return { - base_color[0] * 1.25f < 1.f ? base_color[0] * 1.25f : 1.f, - base_color[1] * 1.25f < 1.f ? base_color[1] * 1.25f : 1.f, - base_color[2] * 1.25f < 1.f ? base_color[2] * 1.25f : 1.f, + base_color.r() * 1.25f < 1.f ? base_color.r() * 1.25f : 1.f, + base_color.g() * 1.25f < 1.f ? base_color.g() * 1.25f : 1.f, + base_color.b() * 1.25f < 1.f ? base_color.b() * 1.25f : 1.f, 1.f}; } @@ -1036,7 +1039,7 @@ void TriangleSelectorGUI::render(ImGuiWrapper* imgui) for (auto &iva : m_iva_seed_fills) if (iva.has_VBOs()) { size_t color_idx = &iva - &m_iva_seed_fills.front(); - const std::array &color = TriangleSelectorGUI::get_seed_fill_color(color_idx == 1 ? enforcers_color : + const ColorRGBA& color = TriangleSelectorGUI::get_seed_fill_color(color_idx == 1 ? enforcers_color : color_idx == 2 ? blockers_color : GLVolume::NEUTRAL_COLOR); shader->set_uniform("uniform_color", color); @@ -1166,18 +1169,18 @@ void TriangleSelectorPatch::render(ImGuiWrapper* imgui) for (size_t buffer_idx = 0; buffer_idx < m_triangle_patches.size(); ++buffer_idx) { if (this->has_VBOs(buffer_idx)) { const TrianglePatch& patch = m_triangle_patches[buffer_idx]; - std::array color; + ColorRGBA color; if (patch.is_fragment() && !patch.neighbor_types.empty()) { size_t color_idx = (size_t)*patch.neighbor_types.begin(); color = m_ebt_colors[color_idx]; - color[3] = 0.85; + color.a(0.85); } else { size_t color_idx = (size_t)patch.type; color = m_ebt_colors[color_idx]; } //to make black not too hard too see - std::array new_color = adjust_color_for_rendering(color); + ColorRGBA new_color = adjust_color_for_rendering(color); shader->set_uniform("uniform_color", new_color); //shader->set_uniform("uniform_color", color); //BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(", buffer_idx %1%: new_color[%2%, %3%, %4%, %5%]")%buffer_idx%new_color[0]%new_color[1]%new_color[2]%new_color[3]; diff --git a/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.hpp b/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.hpp index d2f69ad2ae6..de92a426c68 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.hpp @@ -84,8 +84,8 @@ class TriangleSelectorGUI : public TriangleSelector { }; // BBS - static constexpr std::array enforcers_color{ 0.5f, 1.f, 0.5f, 1.f }; - static constexpr std::array blockers_color{ 1.f, 0.5f, 0.5f, 1.f }; + static ColorRGBA enforcers_color; + static ColorRGBA blockers_color; #ifdef PRUSASLICER_TRIANGLE_SELECTOR_DEBUG void render_debug(ImGuiWrapper* imgui); @@ -98,7 +98,7 @@ class TriangleSelectorGUI : public TriangleSelector { // BBS bool m_paint_changed = true; - static std::array get_seed_fill_color(const std::array &base_color); + static ColorRGBA get_seed_fill_color(const ColorRGBA &base_color); private: void update_render_data(); @@ -128,7 +128,7 @@ struct TrianglePatch { class TriangleSelectorPatch : public TriangleSelectorGUI { public: - explicit TriangleSelectorPatch(const TriangleMesh& mesh, const std::vector> ebt_colors, float edge_limit = 0.6f) + explicit TriangleSelectorPatch(const TriangleMesh& mesh, const std::vector ebt_colors, float edge_limit = 0.6f) : TriangleSelectorGUI(mesh, edge_limit), m_ebt_colors(ebt_colors) {} virtual ~TriangleSelectorPatch() = default; @@ -141,7 +141,7 @@ class TriangleSelectorPatch : public TriangleSelectorGUI { void update_selector_triangles(); void update_triangles_per_patch(); - void set_ebt_colors(const std::vector> ebt_colors) { m_ebt_colors = ebt_colors; } + void set_ebt_colors(const std::vector ebt_colors) { m_ebt_colors = ebt_colors; } void set_filter_state(bool is_filter_state); constexpr static float GapAreaMin = 0.f; @@ -195,7 +195,7 @@ class TriangleSelectorPatch : public TriangleSelectorGUI { std::vector m_vertices_VBO_ids; std::vector m_triangle_indices_VBO_ids; - std::vector> m_ebt_colors; + std::vector m_ebt_colors; bool m_filter_state = false; @@ -247,10 +247,10 @@ class GLGizmoPainterBase : public GLGizmoBase virtual void update_model_object() = 0; virtual void update_from_model_object(bool first_update) = 0; - virtual std::array get_cursor_sphere_left_button_color() const { return {0.f, 0.f, 1.f, 0.25f}; } - virtual std::array get_cursor_sphere_right_button_color() const { return {1.f, 0.f, 0.f, 0.25f}; } + virtual ColorRGBA get_cursor_sphere_left_button_color() const { return {0.f, 0.f, 1.f, 0.25f}; } + virtual ColorRGBA get_cursor_sphere_right_button_color() const { return {1.f, 0.f, 0.f, 0.25f}; } // BBS - virtual std::array get_cursor_hover_color() const { return { 0.f, 0.f, 0.f, 0.25f }; } + virtual ColorRGBA get_cursor_hover_color() const { return { 0.f, 0.f, 0.f, 0.25f }; } virtual EnforcerBlockerType get_left_button_state_type() const { return EnforcerBlockerType::ENFORCER; } virtual EnforcerBlockerType get_right_button_state_type() const { return EnforcerBlockerType::BLOCKER; } diff --git a/src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp b/src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp index 65479b064e9..124e370a362 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp @@ -331,7 +331,7 @@ void GLGizmoRotate::render_grabber_extension(const BoundingBoxf3& box, bool pick //float mean_size = (float)((box.size()(0) + box.size()(1) + box.size()(2)) / 3.0); //double size = m_dragging ? (double)m_grabbers[0].get_dragging_half_size(mean_size) : (double)m_grabbers[0].get_half_size(mean_size); - std::array color = m_grabbers[0].color; + ColorRGBA color = m_grabbers[0].color; if (!picking && m_hover_id != -1) { color = m_grabbers[0].hover_color; //color[0] = 1.0f - color[0]; diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSeam.cpp b/src/slic3r/GUI/Gizmos/GLGizmoSeam.cpp index d0fae7c0339..9de9d2c9034 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSeam.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSeam.cpp @@ -388,7 +388,7 @@ void GLGizmoSeam::update_from_model_object(bool first_update) m_triangle_selectors.clear(); int volume_id = -1; - std::vector> ebt_colors; + std::vector ebt_colors; ebt_colors.push_back(GLVolume::NEUTRAL_COLOR); ebt_colors.push_back(TriangleSelectorGUI::enforcers_color); ebt_colors.push_back(TriangleSelectorGUI::blockers_color); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp index 73ed826fc6a..94175aef9de 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp @@ -137,7 +137,7 @@ void GLGizmoSlaSupports::render_points(const Selection& selection, bool picking) glsafe(::glTranslated(0.0, 0.0, z_shift)); glsafe(::glMultMatrixd(instance_matrix.data())); - std::array render_color; + ColorRGBA render_color; for (size_t i = 0; i < cache_size; ++i) { const sla::SupportPoint& support_point = m_editing_mode ? m_editing_cache[i].support_point : m_normal_cache[i]; const bool& point_selected = m_editing_mode ? m_editing_cache[i].selected : false; @@ -219,10 +219,7 @@ void GLGizmoSlaSupports::render_points(const Selection& selection, bool picking) // Now render the drain holes: if (has_holes && ! picking) { - render_color[0] = 0.7f; - render_color[1] = 0.7f; - render_color[2] = 0.7f; - render_color[3] = 0.7f; + render_color = { 0.7f, 0.7f, 0.7f, 0.7f }; const_cast(&m_cylinder)->set_color(-1, render_color); if (shader) shader->set_uniform("emission_factor", 0.5f); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoText.cpp b/src/slic3r/GUI/Gizmos/GLGizmoText.cpp index 553b477b329..c50c80ea369 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoText.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoText.cpp @@ -445,7 +445,7 @@ void GLGizmoText::on_render() m_grabbers[0].center = m_mouse_position_world; m_grabbers[0].enabled = true; - std::array color = picking_color_component(0); + ColorRGBA color = picking_color_component(0); m_grabbers[0].color = color; m_grabbers[0].render_for_picking(mean_size); } @@ -490,7 +490,7 @@ void GLGizmoText::on_render_for_picking() float mean_size = (float) (GLGizmoBase::Grabber::FixedGrabberSize); m_grabbers[0].center = m_mouse_position_world; m_grabbers[0].enabled = true; - std::array color = picking_color_component(0); + ColorRGBA color = picking_color_component(0); m_grabbers[0].color = color; m_grabbers[0].render_for_picking(mean_size); } diff --git a/src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp b/src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp index 4e29d10afba..fc6decbaa8e 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp @@ -221,8 +221,8 @@ void InstancesHider::render_cut() const if (mv->is_model_part()) glsafe(::glColor3f(0.8f, 0.3f, 0.0f)); else { - const std::array& c = color_from_model_volume(*mv); - glsafe(::glColor4f(c[0], c[1], c[2], c[3])); + const ColorRGBA color = color_from_model_volume(*mv); + glsafe(::glColor4fv(color.data())); } glsafe(::glPushAttrib(GL_DEPTH_TEST)); glsafe(::glDisable(GL_DEPTH_TEST)); diff --git a/src/slic3r/GUI/IMSlider.cpp b/src/slic3r/GUI/IMSlider.cpp index 7987ea78629..c0293aefa29 100644 --- a/src/slic3r/GUI/IMSlider.cpp +++ b/src/slic3r/GUI/IMSlider.cpp @@ -586,8 +586,8 @@ void IMSlider::draw_colored_band(const ImRect& groove, const ImRect& slideable_r }; //draw main colored band const int default_color_idx = m_mode == MultiAsSingle ? std::max(m_only_extruder - 1, 0) : 0; - std::arrayrgba = decode_color_to_float_array(m_extruder_colors[default_color_idx]); - ImU32 band_clr = IM_COL32(rgba[0] * 255.0f, rgba[1] * 255.0f, rgba[2] * 255.0f, rgba[3] * 255.0f); + ColorRGBA rgba = decode_color_to_float_array(m_extruder_colors[default_color_idx]); + ImU32 band_clr = ImGuiWrapper::to_ImU32(rgba); draw_main_band(band_clr); static float tick_pos; @@ -605,8 +605,8 @@ void IMSlider::draw_colored_band(const ImRect& groove, const ImRect& slideable_r const std::string clr_str = m_mode == SingleExtruder ? tick_it->color : get_color_for_tool_change_tick(tick_it); if (!clr_str.empty()) { - std::arrayrgba = decode_color_to_float_array(clr_str); - ImU32 band_clr = IM_COL32(rgba[0] * 255.0f, rgba[1] * 255.0f, rgba[2] * 255.0f, rgba[3] * 255.0f); + ColorRGBA rgba = decode_color_to_float_array(clr_str); + ImU32 band_clr = ImGuiWrapper::to_ImU32(rgba); if (tick_it->tick == 0) draw_main_band(band_clr); else @@ -1323,9 +1323,9 @@ void IMSlider::render_add_menu() } else if (begin_menu(_u8L("Change Filament").c_str())) { for (int i = 0; i < extruder_num; i++) { - std::array rgba = decode_color_to_float_array(m_extruder_colors[i]); - ImU32 icon_clr = IM_COL32(rgba[0] * 255.0f, rgba[1] * 255.0f, rgba[2] * 255.0f, rgba[3] * 255.0f); - if (rgba[3] == 0) + ColorRGBA rgba = decode_color_to_float_array(m_extruder_colors[i]); + ImU32 icon_clr = ImGuiWrapper::to_ImU32(rgba); + if (rgba.a() == 0) icon_clr = 0; if (menu_item_with_icon((_u8L("Filament ") + std::to_string(i + 1)).c_str(), "", ImVec2(14, 14) * m_scale, icon_clr, false, true, &hovered)) add_code_as_tick(ToolChange, i + 1); if (hovered) { show_tooltip(_u8L("Change filament at the beginning of this layer.")); } @@ -1373,8 +1373,8 @@ void IMSlider::render_edit_menu(const TickCode& tick) } else if (begin_menu(_u8L("Change Filament").c_str())) { for (int i = 0; i < extruder_num; i++) { - std::array rgba = decode_color_to_float_array(m_extruder_colors[i]); - ImU32 icon_clr = IM_COL32(rgba[0] * 255.0f, rgba[1] * 255.0f, rgba[2] * 255.0f, rgba[3] * 255.0f); + ColorRGBA rgba = decode_color_to_float_array(m_extruder_colors[i]); + ImU32 icon_clr = ImGuiWrapper::to_ImU32(rgba); if (menu_item_with_icon((_u8L("Filament ") + std::to_string(i + 1)).c_str(), "", ImVec2(14, 14) * m_scale, icon_clr)) add_code_as_tick(ToolChange, i + 1); } end_menu(); diff --git a/src/slic3r/GUI/IMSlider_Utils.hpp b/src/slic3r/GUI/IMSlider_Utils.hpp index bfe5545a3bb..e69de29bb2d 100644 --- a/src/slic3r/GUI/IMSlider_Utils.hpp +++ b/src/slic3r/GUI/IMSlider_Utils.hpp @@ -1,198 +0,0 @@ -#ifndef slic3r_IMSlider_Utils_hpp_ -#define slic3r_IMSlider_Utils_hpp_ - -#include -#include - -#include "wx/colour.h" - -//double epsilon() { return 0.0011; } - -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; - } -}; - -#endif \ No newline at end of file diff --git a/src/slic3r/GUI/ImGuiWrapper.cpp b/src/slic3r/GUI/ImGuiWrapper.cpp index 05ef3a4c950..f061cd79703 100644 --- a/src/slic3r/GUI/ImGuiWrapper.cpp +++ b/src/slic3r/GUI/ImGuiWrapper.cpp @@ -27,6 +27,7 @@ #include "libslic3r/libslic3r.h" #include "libslic3r/Utils.hpp" +#include "libslic3r/Color.hpp" #include "libslic3r/Shape/TextShape.hpp" #include "3DScene.hpp" #include "GUI.hpp" @@ -127,11 +128,11 @@ static const std::map font_icons_extra_large = { const ImVec4 ImGuiWrapper::COL_GREY_DARK = { 0.333f, 0.333f, 0.333f, 1.0f }; const ImVec4 ImGuiWrapper::COL_GREY_LIGHT = { 0.4f, 0.4f, 0.4f, 1.0f }; const ImVec4 ImGuiWrapper::COL_ORANGE_DARK = { 0.757f, 0.404f, 0.216f, 1.0f }; -const ImVec4 ImGuiWrapper::COL_ORANGE_LIGHT = { 1.0f, 0.49f, 0.216f, 1.0f }; +const ImVec4 ImGuiWrapper::COL_ORANGE_LIGHT = to_ImVec4(ColorRGBA::ORANGE()); const ImVec4 ImGuiWrapper::COL_WINDOW_BACKGROUND = { 0.1f, 0.1f, 0.1f, 0.8f }; const ImVec4 ImGuiWrapper::COL_BUTTON_BACKGROUND = COL_ORANGE_DARK; const ImVec4 ImGuiWrapper::COL_BUTTON_HOVERED = COL_ORANGE_LIGHT; -const ImVec4 ImGuiWrapper::COL_BUTTON_ACTIVE = ImGuiWrapper::COL_BUTTON_HOVERED; +const ImVec4 ImGuiWrapper::COL_BUTTON_ACTIVE = COL_BUTTON_HOVERED; //BBS @@ -1776,6 +1777,26 @@ bool ImGuiWrapper::want_any_input() const return io.WantCaptureMouse || io.WantCaptureKeyboard || io.WantTextInput; } +ImU32 ImGuiWrapper::to_ImU32(const ColorRGBA& color) +{ + return ImGui::GetColorU32({ color.r(), color.g(), color.b(), color.a() }); +} + +ImVec4 ImGuiWrapper::to_ImVec4(const ColorRGBA& color) +{ + return { color.r(), color.g(), color.b(), color.a() }; +} + +ColorRGBA ImGuiWrapper::from_ImU32(const ImU32& color) +{ + return from_ImVec4(ImGui::ColorConvertU32ToFloat4(color)); +} + +ColorRGBA ImGuiWrapper::from_ImVec4(const ImVec4& color) +{ + return { color.x, color.y, color.z, color.w }; +} + #ifdef __APPLE__ static const ImWchar ranges_keyboard_shortcuts[] = { diff --git a/src/slic3r/GUI/ImGuiWrapper.hpp b/src/slic3r/GUI/ImGuiWrapper.hpp index 052ea00e5ef..5f37c16eb7f 100644 --- a/src/slic3r/GUI/ImGuiWrapper.hpp +++ b/src/slic3r/GUI/ImGuiWrapper.hpp @@ -11,9 +11,12 @@ #include "libslic3r/Point.hpp" #include "libslic3r/GCode/ThumbnailData.hpp" -namespace Slic3r {namespace Search { +namespace Slic3r { +class ColorRGBA; +namespace Search { struct OptionViewParameters; -}} +} // namespace Search +} // namespace Slic3r class wxString; class wxMouseEvent; @@ -181,6 +184,11 @@ class ImGuiWrapper void reset_requires_extra_frame() { m_requires_extra_frame = false; } #endif // ENABLE_ENHANCED_IMGUI_SLIDER_FLOAT + static ImU32 to_ImU32(const ColorRGBA& color); + static ImVec4 to_ImVec4(const ColorRGBA& color); + static ColorRGBA from_ImU32(const ImU32& color); + static ColorRGBA from_ImVec4(const ImVec4& color); + static const ImVec4 COL_GREY_DARK; static const ImVec4 COL_GREY_LIGHT; static const ImVec4 COL_ORANGE_DARK; diff --git a/src/slic3r/GUI/MsgDialog.cpp b/src/slic3r/GUI/MsgDialog.cpp index cceb1b5d885..8a91b80b8f9 100644 --- a/src/slic3r/GUI/MsgDialog.cpp +++ b/src/slic3r/GUI/MsgDialog.cpp @@ -14,6 +14,7 @@ #include "libslic3r/libslic3r.h" #include "libslic3r/Utils.hpp" +#include "libslic3r/Color.hpp" #include "GUI.hpp" #include "I18N.hpp" //#include "ConfigWizard.hpp" @@ -264,9 +265,9 @@ static void add_msg_content(wxWindow* parent, wxBoxSizer* content_sizer, wxStrin wxFont font = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT); wxFont monospace = wxGetApp().code_font(); wxColour text_clr = wxGetApp().get_label_clr_default(); - wxColour bgr_clr = parent->GetBackgroundColour(); //wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW); - 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()); + wxColour bgr_clr = parent->GetBackgroundColour(); + auto text_clr_str = encode_color(ColorRGB(text_clr.Red(), text_clr.Green(), text_clr.Blue())); + auto bgr_clr_str = encode_color(ColorRGB(bgr_clr.Red(), bgr_clr.Green(), bgr_clr.Blue())); const int font_size = font.GetPointSize(); int size[] = { font_size, font_size, font_size, font_size, font_size, font_size, font_size }; html->SetFonts(font.GetFaceName(), monospace.GetFaceName(), size); diff --git a/src/slic3r/GUI/PartPlate.cpp b/src/slic3r/GUI/PartPlate.cpp index bd86ceaa3db..546fd65546b 100644 --- a/src/slic3r/GUI/PartPlate.cpp +++ b/src/slic3r/GUI/PartPlate.cpp @@ -64,17 +64,17 @@ namespace GUI { class Bed3D; -std::array PartPlate::SELECT_COLOR = { 0.2666f, 0.2784f, 0.2784f, 1.0f }; //{ 0.4196f, 0.4235f, 0.4235f, 1.0f }; -std::array PartPlate::UNSELECT_COLOR = { 0.82f, 0.82f, 0.82f, 1.0f }; -std::array PartPlate::UNSELECT_DARK_COLOR = { 0.384f, 0.384f, 0.412f, 1.0f }; -std::array PartPlate::DEFAULT_COLOR = { 0.5f, 0.5f, 0.5f, 1.0f }; -std::array PartPlate::LINE_TOP_COLOR = { 0.89f, 0.89f, 0.89f, 1.0f }; -std::array PartPlate::LINE_TOP_DARK_COLOR = { 0.431f, 0.431f, 0.463f, 1.0f }; -std::array PartPlate::LINE_TOP_SEL_COLOR = { 0.5294f, 0.5451, 0.5333f, 1.0f}; -std::array PartPlate::LINE_TOP_SEL_DARK_COLOR = { 0.298f, 0.298f, 0.3333f, 1.0f}; -std::array PartPlate::LINE_BOTTOM_COLOR = { 0.8f, 0.8f, 0.8f, 0.4f }; -std::array PartPlate::HEIGHT_LIMIT_TOP_COLOR = { 0.6f, 0.6f, 1.0f, 1.0f }; -std::array PartPlate::HEIGHT_LIMIT_BOTTOM_COLOR = { 0.4f, 0.4f, 1.0f, 1.0f }; +ColorRGBA PartPlate::SELECT_COLOR = { 0.2666f, 0.2784f, 0.2784f, 1.0f }; //{ 0.4196f, 0.4235f, 0.4235f, 1.0f }; +ColorRGBA PartPlate::UNSELECT_COLOR = { 0.82f, 0.82f, 0.82f, 1.0f }; +ColorRGBA PartPlate::UNSELECT_DARK_COLOR = { 0.384f, 0.384f, 0.412f, 1.0f }; +ColorRGBA PartPlate::DEFAULT_COLOR = { 0.5f, 0.5f, 0.5f, 1.0f }; +ColorRGBA PartPlate::LINE_TOP_COLOR = { 0.89f, 0.89f, 0.89f, 1.0f }; +ColorRGBA PartPlate::LINE_TOP_DARK_COLOR = { 0.431f, 0.431f, 0.463f, 1.0f }; +ColorRGBA PartPlate::LINE_TOP_SEL_COLOR = { 0.5294f, 0.5451, 0.5333f, 1.0f}; +ColorRGBA PartPlate::LINE_TOP_SEL_DARK_COLOR = { 0.298f, 0.298f, 0.3333f, 1.0f}; +ColorRGBA PartPlate::LINE_BOTTOM_COLOR = { 0.8f, 0.8f, 0.8f, 0.4f }; +ColorRGBA PartPlate::HEIGHT_LIMIT_TOP_COLOR = { 0.6f, 0.6f, 1.0f, 1.0f }; +ColorRGBA PartPlate::HEIGHT_LIMIT_BOTTOM_COLOR = { 0.4f, 0.4f, 1.0f, 1.0f }; // get text extent with wxMemoryDC void get_text_extent(const wxString &msg, wxCoord &w, wxCoord &h, wxFont *font) @@ -116,20 +116,20 @@ wxFont* find_font(const std::string& text_str, int max_size = 32) } void PartPlate::update_render_colors() { - PartPlate::SELECT_COLOR = GLColor(RenderColor::colors[RenderCol_Plate_Selected]); - PartPlate::UNSELECT_COLOR = GLColor(RenderColor::colors[RenderCol_Plate_Unselected]); - PartPlate::DEFAULT_COLOR = GLColor(RenderColor::colors[RenderCol_Plate_Default]); - PartPlate::LINE_TOP_COLOR = GLColor(RenderColor::colors[RenderCol_Plate_Line_Top]); - PartPlate::LINE_BOTTOM_COLOR = GLColor(RenderColor::colors[RenderCol_Plate_Line_Bottom]); + PartPlate::SELECT_COLOR = ImGuiWrapper::from_ImVec4(RenderColor::colors[RenderCol_Plate_Selected]); + PartPlate::UNSELECT_COLOR = ImGuiWrapper::from_ImVec4(RenderColor::colors[RenderCol_Plate_Unselected]); + PartPlate::DEFAULT_COLOR = ImGuiWrapper::from_ImVec4(RenderColor::colors[RenderCol_Plate_Default]); + PartPlate::LINE_TOP_COLOR = ImGuiWrapper::from_ImVec4(RenderColor::colors[RenderCol_Plate_Line_Top]); + PartPlate::LINE_BOTTOM_COLOR = ImGuiWrapper::from_ImVec4(RenderColor::colors[RenderCol_Plate_Line_Bottom]); } void PartPlate::load_render_colors() { - RenderColor::colors[RenderCol_Plate_Selected] = IMColor(SELECT_COLOR); - RenderColor::colors[RenderCol_Plate_Unselected] = IMColor(UNSELECT_COLOR); - RenderColor::colors[RenderCol_Plate_Default] = IMColor(DEFAULT_COLOR); - RenderColor::colors[RenderCol_Plate_Line_Top] = IMColor(LINE_TOP_COLOR); - RenderColor::colors[RenderCol_Plate_Line_Bottom] = IMColor(LINE_BOTTOM_COLOR); + RenderColor::colors[RenderCol_Plate_Selected] = ImGuiWrapper::to_ImVec4(SELECT_COLOR); + RenderColor::colors[RenderCol_Plate_Unselected] = ImGuiWrapper::to_ImVec4(UNSELECT_COLOR); + RenderColor::colors[RenderCol_Plate_Default] = ImGuiWrapper::to_ImVec4(DEFAULT_COLOR); + RenderColor::colors[RenderCol_Plate_Line_Top] = ImGuiWrapper::to_ImVec4(LINE_TOP_COLOR); + RenderColor::colors[RenderCol_Plate_Line_Bottom] = ImGuiWrapper::to_ImVec4(LINE_BOTTOM_COLOR); } @@ -708,9 +708,9 @@ void PartPlate::render_exclude_area(bool force_default_color) const { return; unsigned int triangles_vcount = m_exclude_triangles.get_vertices_count(); - std::array select_color{ 0.765f, 0.7686f, 0.7686f, 1.0f }; - std::array unselect_color{ 0.9f, 0.9f, 0.9f, 1.0f }; - std::array default_color{ 0.9f, 0.9f, 0.9f, 1.0f }; + ColorRGBA select_color{ 0.765f, 0.7686f, 0.7686f, 1.0f }; + ColorRGBA unselect_color{ 0.9f, 0.9f, 0.9f, 1.0f }; + ColorRGBA default_color{ 0.9f, 0.9f, 0.9f, 1.0f }; // draw exclude area glsafe(::glDepthMask(GL_FALSE)); @@ -729,7 +729,7 @@ void PartPlate::render_exclude_area(bool force_default_color) const { } -/*void PartPlate::render_background_for_picking(const float* render_color) const +/*void PartPlate::render_background_for_picking(const ColorRGBA render_color) const { unsigned int triangles_vcount = m_triangles.get_vertices_count(); @@ -1000,13 +1000,13 @@ void PartPlate::render_only_numbers(bool bottom) const } } -void PartPlate::render_rectangle_for_picking(const GeometryBuffer &buffer, const float* render_color) const +void PartPlate::render_rectangle_for_picking(const GeometryBuffer &buffer, const ColorRGBA render_color) const { unsigned int triangles_vcount = buffer.get_vertices_count(); //glsafe(::glDepthMask(GL_FALSE)); glsafe(::glEnableClientState(GL_VERTEX_ARRAY)); - glsafe(::glColor4fv(render_color)); + glsafe(::glColor4fv(render_color.data())); glsafe(::glNormal3d(0.0f, 0.0f, 1.0f)); glsafe(::glVertexPointer(3, GL_FLOAT, buffer.get_vertex_data_size(), (GLvoid*)buffer.get_vertices_data())); glsafe(::glDrawArrays(GL_TRIANGLES, 0, (GLsizei)triangles_vcount)); @@ -1058,14 +1058,14 @@ void PartPlate::render_label(GLCanvas3D& canvas) const { } -void PartPlate::render_grabber(const float* render_color, bool use_lighting) const +void PartPlate::render_grabber(const ColorRGBA render_color, bool use_lighting) const { BoundingBoxf3* bounding_box = const_cast(&m_bounding_box); const Vec3d& center = m_grabber_box.center(); if (use_lighting) glsafe(::glEnable(GL_LIGHTING)); - glsafe(::glColor4fv(render_color)); + glsafe(::glColor4fv(render_color.data())); glsafe(::glPushMatrix()); glsafe(::glTranslated(center(0), center(1), center(2))); @@ -1138,7 +1138,7 @@ void PartPlate::render_face(float x_size, float y_size) const glsafe(::glEnd()); } -void PartPlate::render_arrows(const float* render_color, bool use_lighting) const +void PartPlate::render_arrows(const ColorRGBA render_color, bool use_lighting) const { #if 0 if (m_quadric == nullptr) @@ -1176,7 +1176,7 @@ void PartPlate::render_arrows(const float* render_color, bool use_lighting) cons #endif } -void PartPlate::render_left_arrow(const float* render_color, bool use_lighting) const +void PartPlate::render_left_arrow(const ColorRGBA render_color, bool use_lighting) const { #if 0 if (m_quadric == nullptr) @@ -1203,7 +1203,7 @@ void PartPlate::render_left_arrow(const float* render_color, bool use_lighting) glsafe(::glDisable(GL_LIGHTING)); #endif } -void PartPlate::render_right_arrow(const float* render_color, bool use_lighting) const +void PartPlate::render_right_arrow(const ColorRGBA render_color, bool use_lighting) const { #if 0 if (m_quadric == nullptr) @@ -1233,58 +1233,40 @@ void PartPlate::render_right_arrow(const float* render_color, bool use_lighting) void PartPlate::on_render_for_picking() const { //glsafe(::glDisable(GL_DEPTH_TEST)); int hover_id = 0; - std::array color = picking_color_component(hover_id); - m_grabber_color[0] = color[0]; - m_grabber_color[1] = color[1]; - m_grabber_color[2] = color[2]; - m_grabber_color[3] = color[3]; + ColorRGBA color = picking_color_component(hover_id); + m_grabber_color = color; //render_grabber(m_grabber_color, false); render_rectangle_for_picking(m_triangles, m_grabber_color); hover_id = 1; - color = picking_color_component(hover_id); - m_grabber_color[0] = color[0]; - m_grabber_color[1] = color[1]; - m_grabber_color[2] = color[2]; - m_grabber_color[3] = color[3]; + color = picking_color_component(hover_id); + m_grabber_color = color; //render_left_arrow(m_grabber_color, false); render_rectangle_for_picking(m_del_icon, m_grabber_color); hover_id = 2; - color = picking_color_component(hover_id); - m_grabber_color[0] = color[0]; - m_grabber_color[1] = color[1]; - m_grabber_color[2] = color[2]; - m_grabber_color[3] = color[3]; + color = picking_color_component(hover_id); + m_grabber_color = color; render_rectangle_for_picking(m_orient_icon, m_grabber_color); hover_id = 3; - color = picking_color_component(hover_id); - m_grabber_color[0] = color[0]; - m_grabber_color[1] = color[1]; - m_grabber_color[2] = color[2]; - m_grabber_color[3] = color[3]; + color = picking_color_component(hover_id); + m_grabber_color = color; render_rectangle_for_picking(m_arrange_icon, m_grabber_color); hover_id = 4; - color = picking_color_component(hover_id); - m_grabber_color[0] = color[0]; - m_grabber_color[1] = color[1]; - m_grabber_color[2] = color[2]; - m_grabber_color[3] = color[3]; + color = picking_color_component(hover_id); + m_grabber_color = color; //render_right_arrow(m_grabber_color, false); render_rectangle_for_picking(m_lock_icon, m_grabber_color); hover_id = 5; - color = picking_color_component(hover_id); - m_grabber_color[0] = color[0]; - m_grabber_color[1] = color[1]; - m_grabber_color[2] = color[2]; - m_grabber_color[3] = color[3]; + color = picking_color_component(hover_id); + m_grabber_color = color; if (m_partplate_list->render_plate_settings) render_rectangle_for_picking(m_plate_settings_icon, m_grabber_color); } -std::array PartPlate::picking_color_component(int idx) const +ColorRGBA PartPlate::picking_color_component(int idx) const { static const float INV_255 = 1.0f / 255.0f; unsigned int id = PLATE_BASE_ID - this->m_plate_index * GRABBER_COUNT - idx; - return std::array { + return ColorRGBA { float((id >> 0) & 0xff)* INV_255, // red float((id >> 8) & 0xff)* INV_255, // greeen float((id >> 16) & 0xff)* INV_255, // blue diff --git a/src/slic3r/GUI/PartPlate.hpp b/src/slic3r/GUI/PartPlate.hpp index e2b2a3bf1d0..fc3da753151 100644 --- a/src/slic3r/GUI/PartPlate.hpp +++ b/src/slic3r/GUI/PartPlate.hpp @@ -139,7 +139,7 @@ class PartPlate : public ObjectBase mutable unsigned int m_plate_idx_vbo_id{ 0 }; GLTexture m_texture; - mutable float m_grabber_color[4]; + mutable ColorRGBA m_grabber_color; float m_scale_factor{ 1.0f }; GLUquadricObject* m_quadric; int m_hover_id; @@ -175,23 +175,23 @@ class PartPlate : public ObjectBase void render_logo(bool bottom, bool render_cali = true) const; void render_logo_texture(GLTexture& logo_texture, const GeometryBuffer& logo_buffer, bool bottom, unsigned int vbo_id) const; void render_exclude_area(bool force_default_color) const; - //void render_background_for_picking(const float* render_color) const; + //void render_background_for_picking(const ColorRGBA render_color) const; void render_grid(bool bottom) const; void render_height_limit(PartPlate::HeightLimitMode mode = HEIGHT_LIMIT_BOTH) const; void render_label(GLCanvas3D& canvas) const; - void render_grabber(const float* render_color, bool use_lighting) const; + void render_grabber(const ColorRGBA render_color, bool use_lighting) const; void render_face(float x_size, float y_size) const; - void render_arrows(const float* render_color, bool use_lighting) const; - void render_left_arrow(const float* render_color, bool use_lighting) const; - void render_right_arrow(const float* render_color, bool use_lighting) const; + void render_arrows(const ColorRGBA render_color, bool use_lighting) const; + void render_left_arrow(const ColorRGBA render_color, bool use_lighting) const; + void render_right_arrow(const ColorRGBA render_color, bool use_lighting) const; void render_icon_texture(int position_id, int tex_coords_id, const GeometryBuffer &buffer, GLTexture &texture, unsigned int &vbo_id) const; void show_tooltip(const std::string tooltip); void render_icons(bool bottom, bool only_name = false, int hover_id = -1); void render_only_numbers(bool bottom) const; void render_plate_name_texture(int position_id, int tex_coords_id); - void render_rectangle_for_picking(const GeometryBuffer &buffer, const float* render_color) const; + void render_rectangle_for_picking(const GeometryBuffer &buffer, const ColorRGBA render_color) const; void on_render_for_picking() const; - std::array picking_color_component(int idx) const; + ColorRGBA picking_color_component(int idx) const; void release_opengl_resource(); public: @@ -199,17 +199,17 @@ class PartPlate : public ObjectBase static const unsigned int PLATE_NAME_HOVER_ID = 6; static const unsigned int GRABBER_COUNT = 7; - static std::array SELECT_COLOR; - static std::array UNSELECT_COLOR; - static std::array UNSELECT_DARK_COLOR; - static std::array DEFAULT_COLOR; - static std::array LINE_BOTTOM_COLOR; - static std::array LINE_TOP_COLOR; - static std::array LINE_TOP_DARK_COLOR; - static std::array LINE_TOP_SEL_COLOR; - static std::array LINE_TOP_SEL_DARK_COLOR; - static std::array HEIGHT_LIMIT_BOTTOM_COLOR; - static std::array HEIGHT_LIMIT_TOP_COLOR; + static ColorRGBA SELECT_COLOR; + static ColorRGBA UNSELECT_COLOR; + static ColorRGBA UNSELECT_DARK_COLOR; + static ColorRGBA DEFAULT_COLOR; + static ColorRGBA LINE_BOTTOM_COLOR; + static ColorRGBA LINE_TOP_COLOR; + static ColorRGBA LINE_TOP_DARK_COLOR; + static ColorRGBA LINE_TOP_SEL_COLOR; + static ColorRGBA LINE_TOP_SEL_DARK_COLOR; + static ColorRGBA HEIGHT_LIMIT_BOTTOM_COLOR; + static ColorRGBA HEIGHT_LIMIT_TOP_COLOR; static void update_render_colors(); static void load_render_colors(); diff --git a/src/slic3r/GUI/PresetComboBoxes.cpp b/src/slic3r/GUI/PresetComboBoxes.cpp index f00b5c46128..c58150b12a7 100644 --- a/src/slic3r/GUI/PresetComboBoxes.cpp +++ b/src/slic3r/GUI/PresetComboBoxes.cpp @@ -24,6 +24,7 @@ #include "libslic3r/libslic3r.h" #include "libslic3r/PrintConfig.hpp" #include "libslic3r/PresetBundle.hpp" +#include "libslic3r/Color.hpp" #include "GUI.hpp" #include "GUI_App.hpp" diff --git a/src/slic3r/GUI/SelectMachine.cpp b/src/slic3r/GUI/SelectMachine.cpp index 2119632d385..1d581aef9b9 100644 --- a/src/slic3r/GUI/SelectMachine.cpp +++ b/src/slic3r/GUI/SelectMachine.cpp @@ -3,6 +3,7 @@ #include "libslic3r/Utils.hpp" #include "libslic3r/Thread.hpp" +#include "libslic3r/Color.hpp" #include "GUI.hpp" #include "GUI_App.hpp" #include "GUI_Preview.hpp" @@ -3643,7 +3644,6 @@ void SelectMachineDialog::set_default_normal() //init MaterialItem auto extruders = wxGetApp().plater()->get_partplate_list().get_curr_plate()->get_used_extruders(); - BitmapCache bmcache; MaterialHash::iterator iter = m_materialList.begin(); while (iter != m_materialList.end()) { @@ -3661,10 +3661,10 @@ void SelectMachineDialog::set_default_normal() for (auto i = 0; i < extruders.size(); i++) { auto extruder = extruders[i] - 1; auto colour = wxGetApp().preset_bundle->project_config.opt_string("filament_colour", (unsigned int) extruder); - unsigned char rgb[4]; - bmcache.parse_color4(colour, rgb); + ColorRGBA rgb; + decode_color(colour, rgb); - auto colour_rgb = wxColour((int) rgb[0], (int) rgb[1], (int) rgb[2], (int) rgb[3]); + auto colour_rgb = wxColour((int) rgb.r_uchar(), (int) rgb.g_uchar(), (int) rgb.b_uchar(), (int) rgb.a_uchar()); if (extruder >= materials.size() || extruder < 0 || extruder >= display_materials.size()) continue; diff --git a/src/slic3r/GUI/Selection.cpp b/src/slic3r/GUI/Selection.cpp index c9e8fb9b4c1..8628fdd5e14 100644 --- a/src/slic3r/GUI/Selection.cpp +++ b/src/slic3r/GUI/Selection.cpp @@ -23,7 +23,9 @@ #include #include -static const std::array UNIFORM_SCALE_COLOR = { 0.923f, 0.504f, 0.264f, 1.0f }; +static const Slic3r::ColorRGBA UNIFORM_SCALE_COLOR = Slic3r::ColorRGBA::ORANGE(); +static const Slic3r::ColorRGBA SOLID_PLANE_COLOR = {0.0f, 174.0f / 255.0f, 66.0f / 255.0f, 1.0f}; +static const Slic3r::ColorRGBA TRANSPARENT_PLANE_COLOR = { 0.8f, 0.8f, 0.8f, 0.5f }; namespace Slic3r { namespace GUI { @@ -572,11 +574,11 @@ void Selection::clear() for (unsigned int i : m_list) { GLVolume& volume = *(*m_volumes)[i]; volume.selected = false; - bool transparent = volume.color[3] < 1.0f; - if (transparent) + bool is_transparent = volume.color.is_transparent(); + if (is_transparent) volume.force_transparent = true; volume.set_render_color(); - if (transparent) + if (is_transparent) volume.force_transparent = false; } #else @@ -2212,12 +2214,9 @@ void Selection::render_bounding_box(const BoundingBoxf3& box, float* color) cons glsafe(::glEnd()); } -static std::array get_color(Axis axis) +static ColorRGBA get_color(Axis axis) { - return { GLGizmoBase::AXES_COLOR[axis][0], - GLGizmoBase::AXES_COLOR[axis][1], - GLGizmoBase::AXES_COLOR[axis][2], - GLGizmoBase::AXES_COLOR[axis][3] }; + return GLGizmoBase::AXES_COLOR[axis]; }; void Selection::render_sidebar_position_hints(const std::string& sidebar_field) const @@ -2351,10 +2350,8 @@ void Selection::render_sidebar_layers_hints(const std::string& sidebar_field) co glsafe(::glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)); ::glBegin(GL_QUADS); - if ((camera_on_top && type == 1) || (!camera_on_top && type == 2)) - ::glColor4f(0.0f, 174.0f / 255.0f, 66.0f / 255.0f, 1.0f); - else - ::glColor4f(0.8f, 0.8f, 0.8f, 0.5f); + ::glColor4fv((camera_on_top && type == 1) || (!camera_on_top && type == 2) ? + SOLID_PLANE_COLOR.data() : TRANSPARENT_PLANE_COLOR.data()); ::glVertex3f(min_x, min_y, z1); ::glVertex3f(max_x, min_y, z1); ::glVertex3f(max_x, max_y, z1); @@ -2362,10 +2359,8 @@ void Selection::render_sidebar_layers_hints(const std::string& sidebar_field) co glsafe(::glEnd()); ::glBegin(GL_QUADS); - if ((camera_on_top && type == 2) || (!camera_on_top && type == 1)) - ::glColor4f(0.0f, 174.0f / 255.0f, 66.0f / 255.0f, 1.0f); - else - ::glColor4f(0.8f, 0.8f, 0.8f, 0.5f); + ::glColor4fv((camera_on_top && type == 2) || (!camera_on_top && type == 1) ? + SOLID_PLANE_COLOR.data() : TRANSPARENT_PLANE_COLOR.data()); ::glVertex3f(min_x, min_y, z2); ::glVertex3f(max_x, min_y, z2); ::glVertex3f(max_x, max_y, z2); diff --git a/src/slic3r/GUI/SendSystemInfoDialog.cpp b/src/slic3r/GUI/SendSystemInfoDialog.cpp index 5f192f36359..b93c00f767a 100644 --- a/src/slic3r/GUI/SendSystemInfoDialog.cpp +++ b/src/slic3r/GUI/SendSystemInfoDialog.cpp @@ -8,6 +8,7 @@ #include "libslic3r/BlacklistedLibraryCheck.hpp" #include "libslic3r/Platform.hpp" #include "libslic3r/Utils.hpp" +#include "libslic3r/Color.hpp" #include "slic3r/GUI/format.hpp" #include "slic3r/Utils/Http.hpp" @@ -591,9 +592,8 @@ SendSystemInfoDialog::SendSystemInfoDialog(wxWindow* parent) wxColour bgr_clr = wxGetApp().get_window_default_clr(); SetBackgroundColour(bgr_clr); 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()); - + auto text_clr_str = encode_color(ColorRGB(text_clr.Red(), text_clr.Green(), text_clr.Blue())); + auto bgr_clr_str = encode_color(ColorRGB(bgr_clr.Red(), bgr_clr.Green(), bgr_clr.Blue())); auto *topSizer = new wxBoxSizer(wxVERTICAL); auto *vsizer = new wxBoxSizer(wxVERTICAL); diff --git a/src/slic3r/GUI/SysInfoDialog.cpp b/src/slic3r/GUI/SysInfoDialog.cpp index ce7f01f1408..c3ff06873db 100644 --- a/src/slic3r/GUI/SysInfoDialog.cpp +++ b/src/slic3r/GUI/SysInfoDialog.cpp @@ -15,6 +15,7 @@ #include "MainFrame.hpp" #include "wxExtensions.hpp" #include "../libslic3r/BlacklistedLibraryCheck.hpp" +#include "../libslic3r/Color.hpp" #include "format.hpp" #ifdef _WIN32 @@ -114,8 +115,8 @@ SysInfoDialog::SysInfoDialog() // main_info_text wxFont font = get_default_font(this); const auto text_clr = wxGetApp().get_label_clr_default();//wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT); - 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()); + auto text_clr_str = encode_color(ColorRGB(text_clr.Red(), text_clr.Green(), text_clr.Blue())); + auto bgr_clr_str = encode_color(ColorRGB(bgr_clr.Red(), bgr_clr.Green(), bgr_clr.Blue())); const int fs = font.GetPointSize() - 1; int size[] = { static_cast(fs*1.5), static_cast(fs*1.4), static_cast(fs*1.3), fs, fs, fs, fs }; diff --git a/src/slic3r/GUI/TickCode.cpp b/src/slic3r/GUI/TickCode.cpp index 158afe7a1fb..267752c544f 100644 --- a/src/slic3r/GUI/TickCode.cpp +++ b/src/slic3r/GUI/TickCode.cpp @@ -4,28 +4,39 @@ namespace Slic3r { namespace GUI { 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]); + if (ticks.empty()) 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()) { 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]); + if (before_tick_it->type == ColorChange) return opposite_one_color(before_tick_it->color); + return opposite_one_color((*m_colors)[0]); } 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); + if (before_tick_it->type == ColorChange) 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); + if (next_tick_it->type == ColorChange) 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 = ""; @@ -44,12 +55,12 @@ std::string TickCodeInfo::get_color_for_tick(TickCode tick, Type type, const int if (--before_tick_it; before_tick_it->type == ColorChange) break; 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); + if (frst_color.empty()) 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); + if (frst_color.empty()) 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()) return colors[0]; diff --git a/src/slic3r/GUI/TickCode.hpp b/src/slic3r/GUI/TickCode.hpp index 8616d7565ac..14785dee55f 100644 --- a/src/slic3r/GUI/TickCode.hpp +++ b/src/slic3r/GUI/TickCode.hpp @@ -2,7 +2,7 @@ #define slic3r_GUI_TickCode_hpp_ #include "libslic3r/CustomGCode.hpp" -#include "IMSlider_Utils.hpp" +#include "libslic3r/Color.hpp" #include namespace Slic3r { @@ -29,7 +29,6 @@ class TickCodeInfo bool m_use_default_colors = false; std::vector* m_colors{ nullptr };// reference to IMSlider::m_extruder_colors - ColorGenerator color_generator; std::string get_color_for_tick(TickCode tick, Type type, const int extruder); diff --git a/src/slic3r/GUI/UnsavedChangesDialog.cpp b/src/slic3r/GUI/UnsavedChangesDialog.cpp index a5868b377bb..a04152f004e 100644 --- a/src/slic3r/GUI/UnsavedChangesDialog.cpp +++ b/src/slic3r/GUI/UnsavedChangesDialog.cpp @@ -11,6 +11,7 @@ #include "libslic3r/PrintConfig.hpp" #include "libslic3r/PresetBundle.hpp" +#include "libslic3r/Color.hpp" #include "format.hpp" #include "GUI_App.hpp" #include "Plater.hpp" @@ -60,8 +61,7 @@ static std::string get_icon_name(Preset::Type type, PrinterTechnology pt) { static std::string def_text_color() { wxColour def_colour = wxGetApp().get_label_clr_default();//wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT); - auto clr_str = wxString::Format(wxT("#%02X%02X%02X"), def_colour.Red(), def_colour.Green(), def_colour.Blue()); - return clr_str.ToStdString(); + return encode_color(ColorRGB(def_colour.Red(), def_colour.Green(), def_colour.Blue())); } static std::string grey = "#808080"; static std::string orange = "#ed6b21"; @@ -126,8 +126,8 @@ wxBitmap ModelNode::get_bitmap(const wxString& color) const int icon_height = lround(1.6 * em); BitmapCache bmp_cache; - unsigned char rgb[3]; - BitmapCache::parse_color(into_u8(color), rgb); + ColorRGB rgb; + decode_color(into_u8(color), rgb); // there is no need to scale created solid bitmap #ifndef __linux__ return bmp_cache.mksolid(icon_width, icon_height, rgb, true); diff --git a/src/slic3r/GUI/WipeTowerDialog.cpp b/src/slic3r/GUI/WipeTowerDialog.cpp index 4646afc8974..55d47c1b84c 100644 --- a/src/slic3r/GUI/WipeTowerDialog.cpp +++ b/src/slic3r/GUI/WipeTowerDialog.cpp @@ -7,6 +7,7 @@ #include "I18N.hpp" #include "GUI_App.hpp" #include "MsgDialog.hpp" +#include "libslic3r/Color.hpp" #include "Widgets/Button.hpp" #include "slic3r/Utils/ColorSpaceConvert.hpp" #include "MainFrame.hpp" @@ -407,9 +408,9 @@ WipingPanel::WipingPanel(wxWindow* parent, const std::vector& matrix, con m_number_of_extruders = (int)(sqrt(matrix.size())+0.001); for (const std::string& color : extruder_colours) { - //unsigned char rgb[3]; - //Slic3r::GUI::BitmapCache::parse_color(color, rgb); - m_colours.push_back(wxColor(color)); + Slic3r::ColorRGB rgb; + Slic3r::decode_color(color, rgb); + m_colours.push_back(wxColor(rgb.r_uchar(), rgb.g_uchar(), rgb.b_uchar())); } // Create two switched panels with their own sizers diff --git a/src/slic3r/Utils/CalibUtils.cpp b/src/slic3r/Utils/CalibUtils.cpp index 6561bedfe72..62ad2a36f80 100644 --- a/src/slic3r/Utils/CalibUtils.cpp +++ b/src/slic3r/Utils/CalibUtils.cpp @@ -909,9 +909,9 @@ void CalibUtils::process_and_store_3mf(Model *model, const DynamicPrintConfig &f //draw thumbnails { GLVolumeCollection glvolume_collection; - std::vector> colors_out(1); + std::vector colors_out(1); unsigned char rgb_color[4] = {255, 255, 255, 255}; - std::array new_color {1.0f, 1.0f, 1.0f, 1.0f}; + ColorRGBA new_color {1.0f, 1.0f, 1.0f, 1.0f}; colors_out.push_back(new_color); ThumbnailData* thumbnail_data = &plate_data_list[0]->plate_thumbnail; @@ -927,7 +927,7 @@ void CalibUtils::process_and_store_3mf(Model *model, const DynamicPrintConfig &f for (int instance_idx = 0; instance_idx < (int)model_object.instances.size(); ++ instance_idx) { const ModelInstance &model_instance = *model_object.instances[instance_idx]; glvolume_collection.load_object_volume(&model_object, obj_idx, volume_idx, instance_idx, "volume", true, false, true); - glvolume_collection.volumes.back()->set_render_color( new_color[0], new_color[1], new_color[2], new_color[3]); + glvolume_collection.volumes.back()->set_render_color(new_color); glvolume_collection.volumes.back()->set_color(new_color); //glvolume_collection.volumes.back()->printable = model_instance.printable; } From 7f0c09544684ae58b7784aeb472098fcc26eccec Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Fri, 20 Oct 2023 20:28:27 +0800 Subject: [PATCH 02/99] Tech ENABLE_GLBEGIN_GLEND_REMOVAL - 1st installment - Selection bounding box (cherry picked from commit prusa3d/PrusaSlicer@22f38235ea2601fd538a0f7e6a2b9a522b5e7dcf) --- resources/shaders/flat.fs | 8 + resources/shaders/flat.vs | 6 + src/slic3r/GUI/GLCanvas3D.cpp | 4 +- src/slic3r/GUI/GLCanvas3D.hpp | 4 +- src/slic3r/GUI/GLShadersManager.cpp | 2 + src/slic3r/GUI/Gizmos/GLGizmoMeshBoolean.cpp | 4 +- src/slic3r/GUI/Selection.cpp | 185 ++++++++++++------- src/slic3r/GUI/Selection.hpp | 12 +- 8 files changed, 147 insertions(+), 78 deletions(-) create mode 100644 resources/shaders/flat.fs create mode 100644 resources/shaders/flat.vs diff --git a/resources/shaders/flat.fs b/resources/shaders/flat.fs new file mode 100644 index 00000000000..ab656998df7 --- /dev/null +++ b/resources/shaders/flat.fs @@ -0,0 +1,8 @@ +#version 110 + +uniform vec4 uniform_color; + +void main() +{ + gl_FragColor = uniform_color; +} diff --git a/resources/shaders/flat.vs b/resources/shaders/flat.vs new file mode 100644 index 00000000000..d0d3ee42a9a --- /dev/null +++ b/resources/shaders/flat.vs @@ -0,0 +1,6 @@ +#version 110 + +void main() +{ + gl_Position = ftransform(); +} diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 15c343d585b..02b4831de6d 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -6935,7 +6935,7 @@ void GLCanvas3D::_render_gcode(int canvas_width, int canvas_height) } } -void GLCanvas3D::_render_selection() const +void GLCanvas3D::_render_selection() { float scale_factor = 1.0; #if ENABLE_RETINA_GL @@ -6966,7 +6966,7 @@ void GLCanvas3D::_render_sequential_clearance() } #if ENABLE_RENDER_SELECTION_CENTER -void GLCanvas3D::_render_selection_center() const +void GLCanvas3D::_render_selection_center() { m_selection.render_center(m_gizmos.is_dragging()); } diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp index 7f03f00f3c5..013f0ee4dd3 100644 --- a/src/slic3r/GUI/GLCanvas3D.hpp +++ b/src/slic3r/GUI/GLCanvas3D.hpp @@ -1115,10 +1115,10 @@ class GLCanvas3D void _render_gcode(int canvas_width, int canvas_height); //BBS: render a plane for assemble void _render_plane() const; - void _render_selection() const; + void _render_selection(); void _render_sequential_clearance(); #if ENABLE_RENDER_SELECTION_CENTER - void _render_selection_center() const; + void _render_selection_center(); #endif // ENABLE_RENDER_SELECTION_CENTER void _check_and_update_toolbar_icon_scale(); void _render_overlays(); diff --git a/src/slic3r/GUI/GLShadersManager.cpp b/src/slic3r/GUI/GLShadersManager.cpp index 107fcb5627f..c5c3558ebb9 100644 --- a/src/slic3r/GUI/GLShadersManager.cpp +++ b/src/slic3r/GUI/GLShadersManager.cpp @@ -33,6 +33,8 @@ std::pair GLShadersManager::init() bool valid = true; + // basic shader, used to render selection bbox + valid &= append_shader("flat", { "flat.vs", "flat.fs" }); // used to render bed axes and model, selection hints, gcode sequential view marker model, preview shells, options in gcode preview valid &= append_shader("gouraud_light", { "gouraud_light.vs", "gouraud_light.fs" }); //used to render thumbnail diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeshBoolean.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeshBoolean.cpp index 20107305b77..dcff45494e0 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeshBoolean.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeshBoolean.cpp @@ -131,8 +131,8 @@ void GLGizmoMeshBoolean::on_render() } } - float src_color[3] = { 1.0f, 1.0f, 1.0f }; - float tool_color[3] = { 0.0f, 150.0f / 255.0f, 136.0f / 255.0f }; + ColorRGB src_color = { 1.0f, 1.0f, 1.0f }; + ColorRGB tool_color = {0.0f, 150.0f / 255.0f, 136.0f / 255.0f}; m_parent.get_selection().render_bounding_box(src_bb, src_color, m_parent.get_scale()); m_parent.get_selection().render_bounding_box(tool_bb, tool_color, m_parent.get_scale()); } diff --git a/src/slic3r/GUI/Selection.cpp b/src/slic3r/GUI/Selection.cpp index 8628fdd5e14..2fbce1bb05d 100644 --- a/src/slic3r/GUI/Selection.cpp +++ b/src/slic3r/GUI/Selection.cpp @@ -134,9 +134,8 @@ bool Selection::init() { m_arrow.init_from(straight_arrow(10.0f, 5.0f, 5.0f, 10.0f, 1.0f)); m_curved_arrow.init_from(circular_arrow(16, 10.0f, 5.0f, 10.0f, 5.0f, 1.0f)); - #if ENABLE_RENDER_SELECTION_CENTER - m_vbo_sphere.init_from(make_sphere(0.75, 2*PI/24)); + m_vbo_sphere.init_from(its_make_sphere(0.75, PI / 12.0)); #endif // ENABLE_RENDER_SELECTION_CENTER return true; @@ -1554,20 +1553,18 @@ void Selection::erase() } } -void Selection::render(float scale_factor) const +void Selection::render(float scale_factor) { if (!m_valid || is_empty()) return; - *const_cast(&m_scale_factor) = scale_factor; - - // render cumulative bounding box of selected volumes - render_selected_volumes(); + m_scale_factor = scale_factor; + render_bounding_box(get_bounding_box(), ColorRGB::WHITE()); render_synchronized_volumes(); } #if ENABLE_RENDER_SELECTION_CENTER -void Selection::render_center(bool gizmo_is_dragging) const +void Selection::render_center(bool gizmo_is_dragging) { if (!m_valid || is_empty()) return; @@ -1576,10 +1573,17 @@ void Selection::render_center(bool gizmo_is_dragging) const glsafe(::glDisable(GL_DEPTH_TEST)); - glsafe(::glColor3f(1.0f, 1.0f, 1.0f)); glsafe(::glPushMatrix()); - glsafe(::glTranslated(center(0), center(1), center(2))); + glsafe(::glTranslated(center.x(), center.y(), center.z())); + + GLShaderProgram* shader = wxGetApp().get_shader("flat"); + if (shader == nullptr) + return; + + shader->start_using(); + m_vbo_sphere.set_color(-1, ColorRGBA::WHITE()); m_vbo_sphere.render(); + shader->stop_using(); glsafe(::glPopMatrix()); } #endif // ENABLE_RENDER_SELECTION_CENTER @@ -2133,91 +2137,140 @@ void Selection::do_remove_object(unsigned int object_idx) } } -void Selection::render_selected_volumes() const -{ - float color[3] = { 1.0f, 1.0f, 1.0f }; - render_bounding_box(get_bounding_box(), color); -} - -void Selection::render_synchronized_volumes() const +void Selection::render_synchronized_volumes() { if (m_mode == Instance) return; - float color[3] = { 1.0f, 1.0f, 0.0f }; - for (unsigned int i : m_list) { - const GLVolume* volume = (*m_volumes)[i]; - int object_idx = volume->object_idx(); - int volume_idx = volume->volume_idx(); + const GLVolume& volume = *(*m_volumes)[i]; + int object_idx = volume.object_idx(); + int volume_idx = volume.volume_idx(); for (unsigned int j = 0; j < (unsigned int)m_volumes->size(); ++j) { if (i == j) continue; - const GLVolume* v = (*m_volumes)[j]; - if (v->object_idx() != object_idx || v->volume_idx() != volume_idx) + const GLVolume& v = *(*m_volumes)[j]; + if (v.object_idx() != object_idx || v.volume_idx() != volume_idx) continue; - render_bounding_box(v->transformed_convex_hull_bounding_box(), color); + render_bounding_box(v.transformed_convex_hull_bounding_box(), ColorRGB::YELLOW()); } } } -void Selection::render_bounding_box(const BoundingBoxf3& box, float* color) const +void Selection::render_bounding_box(const BoundingBoxf3& box, const ColorRGB& color) { - if (color == nullptr) - return; - - Vec3f b_min = box.min.cast(); - Vec3f b_max = box.max.cast(); - Vec3f size = 0.2f * box.size().cast(); - - glsafe(::glEnable(GL_DEPTH_TEST)); - - glsafe(::glColor3fv(color)); - glsafe(::glLineWidth(2.0f * m_scale_factor)); - - ::glBegin(GL_LINES); - ::glVertex3f(b_min(0), b_min(1), b_min(2)); ::glVertex3f(b_min(0) + size(0), b_min(1), b_min(2)); - ::glVertex3f(b_min(0), b_min(1), b_min(2)); ::glVertex3f(b_min(0), b_min(1) + size(1), b_min(2)); - ::glVertex3f(b_min(0), b_min(1), b_min(2)); ::glVertex3f(b_min(0), b_min(1), b_min(2) + size(2)); - - ::glVertex3f(b_max(0), b_min(1), b_min(2)); ::glVertex3f(b_max(0) - size(0), b_min(1), b_min(2)); - ::glVertex3f(b_max(0), b_min(1), b_min(2)); ::glVertex3f(b_max(0), b_min(1) + size(1), b_min(2)); - ::glVertex3f(b_max(0), b_min(1), b_min(2)); ::glVertex3f(b_max(0), b_min(1), b_min(2) + size(2)); + auto is_approx = [](const Vec3d& v1, const Vec3d& v2) { + for (int i = 0; i < 3; ++i) { + if (std::abs(v1[i] - v2[i]) > EPSILON) + return false; + } + return true; + }; - ::glVertex3f(b_max(0), b_max(1), b_min(2)); ::glVertex3f(b_max(0) - size(0), b_max(1), b_min(2)); - ::glVertex3f(b_max(0), b_max(1), b_min(2)); ::glVertex3f(b_max(0), b_max(1) - size(1), b_min(2)); - ::glVertex3f(b_max(0), b_max(1), b_min(2)); ::glVertex3f(b_max(0), b_max(1), b_min(2) + size(2)); + const BoundingBoxf3& curr_box = m_box.get_bounding_box(); + if (!m_box.is_initialized() || !is_approx(box.min, curr_box.min) || !is_approx(box.max, curr_box.max)) { + m_box.reset(); + + const Vec3f b_min = box.min.cast(); + const Vec3f b_max = box.max.cast(); + const Vec3f size = 0.2f * box.size().cast(); + + GLModel::InitializationData init_data; + GUI::GLModel::InitializationData::Entity entity; + entity.type = GUI::GLModel::PrimitiveType::Lines; + entity.positions.reserve(48); + + entity.positions.emplace_back(Vec3f(b_min.x(), b_min.y(), b_min.z())); + entity.positions.emplace_back(Vec3f(b_min.x() + size.x(), b_min.y(), b_min.z())); + entity.positions.emplace_back(Vec3f(b_min.x(), b_min.y(), b_min.z())); + entity.positions.emplace_back(Vec3f(b_min.x(), b_min.y() + size.y(), b_min.z())); + entity.positions.emplace_back(Vec3f(b_min.x(), b_min.y(), b_min.z())); + entity.positions.emplace_back(Vec3f(b_min.x(), b_min.y(), b_min.z() + size.z())); + + entity.positions.emplace_back(Vec3f(b_max.x(), b_min.y(), b_min.z())); + entity.positions.emplace_back(Vec3f(b_max.x() - size.x(), b_min.y(), b_min.z())); + entity.positions.emplace_back(Vec3f(b_max.x(), b_min.y(), b_min.z())); + entity.positions.emplace_back(Vec3f(b_max.x(), b_min.y() + size.y(), b_min.z())); + entity.positions.emplace_back(Vec3f(b_max.x(), b_min.y(), b_min.z())); + entity.positions.emplace_back(Vec3f(b_max.x(), b_min.y(), b_min.z() + size.z())); + + entity.positions.emplace_back(Vec3f(b_max.x(), b_max.y(), b_min.z())); + entity.positions.emplace_back(Vec3f(b_max.x() - size.x(), b_max.y(), b_min.z())); + entity.positions.emplace_back(Vec3f(b_max.x(), b_max.y(), b_min.z())); + entity.positions.emplace_back(Vec3f(b_max.x(), b_max.y() - size.y(), b_min.z())); + entity.positions.emplace_back(Vec3f(b_max.x(), b_max.y(), b_min.z())); + entity.positions.emplace_back(Vec3f(b_max.x(), b_max.y(), b_min.z() + size.z())); + + entity.positions.emplace_back(Vec3f(b_min.x(), b_max.y(), b_min.z())); + entity.positions.emplace_back(Vec3f(b_min.x() + size.x(), b_max.y(), b_min.z())); + entity.positions.emplace_back(Vec3f(b_min.x(), b_max.y(), b_min.z())); + entity.positions.emplace_back(Vec3f(b_min.x(), b_max.y() - size.y(), b_min.z())); + entity.positions.emplace_back(Vec3f(b_min.x(), b_max.y(), b_min.z())); + entity.positions.emplace_back(Vec3f(b_min.x(), b_max.y(), b_min.z() + size.z())); + + entity.positions.emplace_back(Vec3f(b_min.x(), b_min.y(), b_max.z())); + entity.positions.emplace_back(Vec3f(b_min.x() + size.x(), b_min.y(), b_max.z())); + entity.positions.emplace_back(Vec3f(b_min.x(), b_min.y(), b_max.z())); + entity.positions.emplace_back(Vec3f(b_min.x(), b_min.y() + size.y(), b_max.z())); + entity.positions.emplace_back(Vec3f(b_min.x(), b_min.y(), b_max.z())); + entity.positions.emplace_back(Vec3f(b_min.x(), b_min.y(), b_max.z() - size.z())); + + entity.positions.emplace_back(Vec3f(b_max.x(), b_min.y(), b_max.z())); + entity.positions.emplace_back(Vec3f(b_max.x() - size.x(), b_min.y(), b_max.z())); + entity.positions.emplace_back(Vec3f(b_max.x(), b_min.y(), b_max.z())); + entity.positions.emplace_back(Vec3f(b_max.x(), b_min.y() + size.y(), b_max.z())); + entity.positions.emplace_back(Vec3f(b_max.x(), b_min.y(), b_max.z())); + entity.positions.emplace_back(Vec3f(b_max.x(), b_min.y(), b_max.z() - size.z())); + + entity.positions.emplace_back(Vec3f(b_max.x(), b_max.y(), b_max.z())); + entity.positions.emplace_back(Vec3f(b_max.x() - size.x(), b_max.y(), b_max.z())); + entity.positions.emplace_back(Vec3f(b_max.x(), b_max.y(), b_max.z())); + entity.positions.emplace_back(Vec3f(b_max.x(), b_max.y() - size.y(), b_max.z())); + entity.positions.emplace_back(Vec3f(b_max.x(), b_max.y(), b_max.z())); + entity.positions.emplace_back(Vec3f(b_max.x(), b_max.y(), b_max.z() - size.z())); + + entity.positions.emplace_back(Vec3f(b_min.x(), b_max.y(), b_max.z())); + entity.positions.emplace_back(Vec3f(b_min.x() + size.x(), b_max.y(), b_max.z())); + entity.positions.emplace_back(Vec3f(b_min.x(), b_max.y(), b_max.z())); + entity.positions.emplace_back(Vec3f(b_min.x(), b_max.y() - size.y(), b_max.z())); + entity.positions.emplace_back(Vec3f(b_min.x(), b_max.y(), b_max.z())); + entity.positions.emplace_back(Vec3f(b_min.x(), b_max.y(), b_max.z() - size.z())); + + entity.normals.reserve(48); + for (size_t i = 0; i < 48; ++i) { + entity.normals.emplace_back(Vec3f::UnitZ()); + } - ::glVertex3f(b_min(0), b_max(1), b_min(2)); ::glVertex3f(b_min(0) + size(0), b_max(1), b_min(2)); - ::glVertex3f(b_min(0), b_max(1), b_min(2)); ::glVertex3f(b_min(0), b_max(1) - size(1), b_min(2)); - ::glVertex3f(b_min(0), b_max(1), b_min(2)); ::glVertex3f(b_min(0), b_max(1), b_min(2) + size(2)); + entity.indices.reserve(48); + for (size_t i = 0; i < 48; ++i) { + entity.indices.emplace_back(i); + } - ::glVertex3f(b_min(0), b_min(1), b_max(2)); ::glVertex3f(b_min(0) + size(0), b_min(1), b_max(2)); - ::glVertex3f(b_min(0), b_min(1), b_max(2)); ::glVertex3f(b_min(0), b_min(1) + size(1), b_max(2)); - ::glVertex3f(b_min(0), b_min(1), b_max(2)); ::glVertex3f(b_min(0), b_min(1), b_max(2) - size(2)); + init_data.entities.emplace_back(entity); + m_box.init_from(init_data); + } - ::glVertex3f(b_max(0), b_min(1), b_max(2)); ::glVertex3f(b_max(0) - size(0), b_min(1), b_max(2)); - ::glVertex3f(b_max(0), b_min(1), b_max(2)); ::glVertex3f(b_max(0), b_min(1) + size(1), b_max(2)); - ::glVertex3f(b_max(0), b_min(1), b_max(2)); ::glVertex3f(b_max(0), b_min(1), b_max(2) - size(2)); + glsafe(::glEnable(GL_DEPTH_TEST)); - ::glVertex3f(b_max(0), b_max(1), b_max(2)); ::glVertex3f(b_max(0) - size(0), b_max(1), b_max(2)); - ::glVertex3f(b_max(0), b_max(1), b_max(2)); ::glVertex3f(b_max(0), b_max(1) - size(1), b_max(2)); - ::glVertex3f(b_max(0), b_max(1), b_max(2)); ::glVertex3f(b_max(0), b_max(1), b_max(2) - size(2)); + glsafe(::glLineWidth(2.0f * m_scale_factor)); - ::glVertex3f(b_min(0), b_max(1), b_max(2)); ::glVertex3f(b_min(0) + size(0), b_max(1), b_max(2)); - ::glVertex3f(b_min(0), b_max(1), b_max(2)); ::glVertex3f(b_min(0), b_max(1) - size(1), b_max(2)); - ::glVertex3f(b_min(0), b_max(1), b_max(2)); ::glVertex3f(b_min(0), b_max(1), b_max(2) - size(2)); + GLShaderProgram* shader = wxGetApp().get_shader("flat"); + if (shader == nullptr) + return; - glsafe(::glEnd()); + shader->start_using(); + m_box.set_color(-1, to_rgba(color)); + m_box.render(); + shader->stop_using(); } static ColorRGBA get_color(Axis axis) { return GLGizmoBase::AXES_COLOR[axis]; -}; +} void Selection::render_sidebar_position_hints(const std::string& sidebar_field) const { diff --git a/src/slic3r/GUI/Selection.hpp b/src/slic3r/GUI/Selection.hpp index bfee49bd2ba..944333a9a56 100644 --- a/src/slic3r/GUI/Selection.hpp +++ b/src/slic3r/GUI/Selection.hpp @@ -220,6 +220,7 @@ class Selection GLModel m_arrow; GLModel m_curved_arrow; + GLModel m_box; float m_scale_factor; bool m_dragging; @@ -353,16 +354,16 @@ class Selection void erase(); - void render(float scale_factor = 1.0) const; + void render(float scale_factor = 1.0); #if ENABLE_RENDER_SELECTION_CENTER - void render_center(bool gizmo_is_dragging) const; + void render_center(bool gizmo_is_dragging); #endif // ENABLE_RENDER_SELECTION_CENTER //BBS: GUI refactor: add uniform scale from gizmo void render_sidebar_hints(const std::string& sidebar_field, bool uniform_scale) const; bool requires_local_axes() const; - void render_bounding_box(const BoundingBoxf3& box, float* color, float scale) { + void render_bounding_box(const BoundingBoxf3& box, const ColorRGB& color, float scale) { m_scale_factor = scale; render_bounding_box(box, color); } @@ -399,9 +400,8 @@ class Selection void do_remove_instance(unsigned int object_idx, unsigned int instance_idx); void do_remove_object(unsigned int object_idx); void set_bounding_boxes_dirty() { m_bounding_box.reset(); m_unscaled_instance_bounding_box.reset(); m_scaled_instance_bounding_box.reset(); } - void render_selected_volumes() const; - void render_synchronized_volumes() const; - void render_bounding_box(const BoundingBoxf3& box, float* color) const; + void render_synchronized_volumes(); + void render_bounding_box(const BoundingBoxf3& box, const ColorRGB& color); void render_sidebar_position_hints(const std::string& sidebar_field) const; void render_sidebar_rotation_hints(const std::string& sidebar_field) const; //BBS: GUI refactor: add uniform_scale from gizmo From 356405adf60b824da1aa26296940e600fedd3f64 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Fri, 20 Oct 2023 20:51:00 +0800 Subject: [PATCH 03/99] Tech ENABLE_GLBEGIN_GLEND_REMOVAL - Selection layers hints (cherry picked from commit prusa3d/PrusaSlicer@bebb5505a375de9b17678f2be57883f860f24ee7) --- src/slic3r/GUI/GLCanvas3D.cpp | 2 +- src/slic3r/GUI/GLCanvas3D.hpp | 2 +- src/slic3r/GUI/Selection.cpp | 145 ++++++++++++++++++++++------------ src/slic3r/GUI/Selection.hpp | 18 +++-- 4 files changed, 109 insertions(+), 58 deletions(-) diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 02b4831de6d..14056885211 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -8213,7 +8213,7 @@ void GLCanvas3D::_render_sla_slices() } } -void GLCanvas3D::_render_selection_sidebar_hints() const +void GLCanvas3D::_render_selection_sidebar_hints() { m_selection.render_sidebar_hints(m_sidebar_field, m_gizmos.get_uniform_scaling()); } diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp index 013f0ee4dd3..a7d40179735 100644 --- a/src/slic3r/GUI/GLCanvas3D.hpp +++ b/src/slic3r/GUI/GLCanvas3D.hpp @@ -1142,7 +1142,7 @@ class GLCanvas3D void _render_camera_target() const; #endif // ENABLE_SHOW_CAMERA_TARGET void _render_sla_slices(); - void _render_selection_sidebar_hints() const; + void _render_selection_sidebar_hints(); //BBS: GUI refactor: adjust main toolbar position bool _render_orient_menu(float left, float right, float bottom, float top); bool _render_arrange_menu(float left, float right, float bottom, float top); diff --git a/src/slic3r/GUI/Selection.cpp b/src/slic3r/GUI/Selection.cpp index 2fbce1bb05d..68702303da2 100644 --- a/src/slic3r/GUI/Selection.cpp +++ b/src/slic3r/GUI/Selection.cpp @@ -1589,8 +1589,8 @@ void Selection::render_center(bool gizmo_is_dragging) #endif // ENABLE_RENDER_SELECTION_CENTER //BBS: GUI refactor, add uniform scale from gizmo -void Selection::render_sidebar_hints(const std::string& sidebar_field, bool uniform_scale) const -//void Selection::render_sidebar_hints(const std::string& sidebar_field) const +void Selection::render_sidebar_hints(const std::string& sidebar_field, bool uniform_scale) +//void Selection::render_sidebar_hints(const std::string& sidebar_field) { if (sidebar_field.empty()) return; @@ -1615,7 +1615,7 @@ void Selection::render_sidebar_hints(const std::string& sidebar_field, bool unif // BBS if (is_single_full_instance()/* && !wxGetApp().obj_manipul()->get_world_coordinates()*/) { - glsafe(::glTranslated(center(0), center(1), center(2))); + glsafe(::glTranslated(center.x(), center.y(), center.z())); if (!boost::starts_with(sidebar_field, "position")) { Transform3d orient_matrix = Transform3d::Identity(); if (boost::starts_with(sidebar_field, "scale")) @@ -1635,7 +1635,7 @@ void Selection::render_sidebar_hints(const std::string& sidebar_field, bool unif glsafe(::glMultMatrixd(orient_matrix.data())); } } else if (is_single_volume() || is_single_modifier()) { - glsafe(::glTranslated(center(0), center(1), center(2))); + glsafe(::glTranslated(center.x(), center.y(), center.z())); Transform3d orient_matrix = (*m_volumes)[*m_list.begin()]->get_instance_transformation().get_matrix(true, false, true, true); if (!boost::starts_with(sidebar_field, "position")) orient_matrix = orient_matrix * (*m_volumes)[*m_list.begin()]->get_volume_transformation().get_matrix(true, false, true, true); @@ -2159,17 +2159,17 @@ void Selection::render_synchronized_volumes() } } -void Selection::render_bounding_box(const BoundingBoxf3& box, const ColorRGB& color) +static bool is_approx(const Vec3d& v1, const Vec3d& v2) { + for (int i = 0; i < 3; ++i) { + if (std::abs(v1[i] - v2[i]) > EPSILON) + return false; + } + return true; +} - auto is_approx = [](const Vec3d& v1, const Vec3d& v2) { - for (int i = 0; i < 3; ++i) { - if (std::abs(v1[i] - v2[i]) > EPSILON) - return false; - } - return true; - }; - +void Selection::render_bounding_box(const BoundingBoxf3& box, const ColorRGB& color) +{ const BoundingBoxf3& curr_box = m_box.get_bounding_box(); if (!m_box.is_initialized() || !is_approx(box.min, curr_box.min) || !is_approx(box.max, curr_box.max)) { m_box.reset(); @@ -2272,25 +2272,25 @@ static ColorRGBA get_color(Axis axis) return GLGizmoBase::AXES_COLOR[axis]; } -void Selection::render_sidebar_position_hints(const std::string& sidebar_field) const +void Selection::render_sidebar_position_hints(const std::string& sidebar_field) { if (boost::ends_with(sidebar_field, "x")) { glsafe(::glRotated(-90.0, 0.0, 0.0, 1.0)); - const_cast(&m_arrow)->set_color(-1, get_color(X)); + m_arrow.set_color(-1, get_color(X)); m_arrow.render(); } else if (boost::ends_with(sidebar_field, "y")) { - const_cast(&m_arrow)->set_color(-1, get_color(Y)); + m_arrow.set_color(-1, get_color(Y)); m_arrow.render(); } else if (boost::ends_with(sidebar_field, "z")) { glsafe(::glRotated(90.0, 1.0, 0.0, 0.0)); - const_cast(&m_arrow)->set_color(-1, get_color(Z)); + m_arrow.set_color(-1, get_color(Z)); m_arrow.render(); } } -void Selection::render_sidebar_rotation_hints(const std::string& sidebar_field) const +void Selection::render_sidebar_rotation_hints(const std::string& sidebar_field) { auto render_sidebar_rotation_hint = [this]() { m_curved_arrow.render(); @@ -2300,29 +2300,29 @@ void Selection::render_sidebar_rotation_hints(const std::string& sidebar_field) if (boost::ends_with(sidebar_field, "x")) { glsafe(::glRotated(90.0, 0.0, 1.0, 0.0)); - const_cast(&m_curved_arrow)->set_color(-1, get_color(X)); + m_curved_arrow.set_color(-1, get_color(X)); render_sidebar_rotation_hint(); } else if (boost::ends_with(sidebar_field, "y")) { glsafe(::glRotated(-90.0, 1.0, 0.0, 0.0)); - const_cast(&m_curved_arrow)->set_color(-1, get_color(Y)); + m_curved_arrow.set_color(-1, get_color(Y)); render_sidebar_rotation_hint(); } else if (boost::ends_with(sidebar_field, "z")) { - const_cast(&m_curved_arrow)->set_color(-1, get_color(Z)); + m_curved_arrow.set_color(-1, get_color(Z)); render_sidebar_rotation_hint(); } } //BBS: GUI refactor: add gizmo uniform_scale -void Selection::render_sidebar_scale_hints(const std::string& sidebar_field, bool gizmo_uniform_scale) const +void Selection::render_sidebar_scale_hints(const std::string& sidebar_field, bool gizmo_uniform_scale) { // BBS //bool uniform_scale = requires_uniform_scale() || wxGetApp().obj_manipul()->get_uniform_scaling(); bool uniform_scale = requires_uniform_scale() || gizmo_uniform_scale; auto render_sidebar_scale_hint = [this, uniform_scale](Axis axis) { - const_cast(&m_arrow)->set_color(-1, uniform_scale ? UNIFORM_SCALE_COLOR : get_color(axis)); + m_arrow.set_color(-1, uniform_scale ? UNIFORM_SCALE_COLOR : get_color(axis)); GLShaderProgram* shader = wxGetApp().get_current_shader(); if (shader != nullptr) shader->set_uniform("emission_factor", 0.0f); @@ -2356,9 +2356,9 @@ void Selection::render_sidebar_scale_hints(const std::string& sidebar_field, boo } } -void Selection::render_sidebar_layers_hints(const std::string& sidebar_field) const +void Selection::render_sidebar_layers_hints(const std::string& sidebar_field) { - static const double Margin = 10.0; + static const float Margin = 10.0f; std::string field = sidebar_field; @@ -2367,7 +2367,7 @@ void Selection::render_sidebar_layers_hints(const std::string& sidebar_field) co if (pos == std::string::npos) return; - double max_z = string_to_double_decimal_point(field.substr(pos + 1)); + const float max_z = float(string_to_double_decimal_point(field.substr(pos + 1))); // extract min_z field = field.substr(0, pos); @@ -2375,7 +2375,7 @@ void Selection::render_sidebar_layers_hints(const std::string& sidebar_field) co if (pos == std::string::npos) return; - const double min_z = string_to_double_decimal_point(field.substr(pos + 1)); + const float min_z = float(string_to_double_decimal_point(field.substr(pos + 1))); // extract type field = field.substr(0, pos); @@ -2387,38 +2387,83 @@ void Selection::render_sidebar_layers_hints(const std::string& sidebar_field) co const BoundingBoxf3& box = get_bounding_box(); - const float min_x = box.min(0) - Margin; - const float max_x = box.max(0) + Margin; - const float min_y = box.min(1) - Margin; - const float max_y = box.max(1) + Margin; - // view dependend order of rendering to keep correct transparency - bool camera_on_top = wxGetApp().plater()->get_camera().is_looking_downward(); + const bool camera_on_top = wxGetApp().plater()->get_camera().is_looking_downward(); const float z1 = camera_on_top ? min_z : max_z; const float z2 = camera_on_top ? max_z : min_z; + const Vec3f p1 = { float(box.min.x()) - Margin, float(box.min.y()) - Margin, z1 }; + const Vec3f p2 = { float(box.max.x()) + Margin, float(box.max.y()) + Margin, z2 }; + glsafe(::glEnable(GL_DEPTH_TEST)); glsafe(::glDisable(GL_CULL_FACE)); glsafe(::glEnable(GL_BLEND)); glsafe(::glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)); - ::glBegin(GL_QUADS); - ::glColor4fv((camera_on_top && type == 1) || (!camera_on_top && type == 2) ? - SOLID_PLANE_COLOR.data() : TRANSPARENT_PLANE_COLOR.data()); - ::glVertex3f(min_x, min_y, z1); - ::glVertex3f(max_x, min_y, z1); - ::glVertex3f(max_x, max_y, z1); - ::glVertex3f(min_x, max_y, z1); - glsafe(::glEnd()); - - ::glBegin(GL_QUADS); - ::glColor4fv((camera_on_top && type == 2) || (!camera_on_top && type == 1) ? - SOLID_PLANE_COLOR.data() : TRANSPARENT_PLANE_COLOR.data()); - ::glVertex3f(min_x, min_y, z2); - ::glVertex3f(max_x, min_y, z2); - ::glVertex3f(max_x, max_y, z2); - ::glVertex3f(min_x, max_y, z2); - glsafe(::glEnd()); + if (!m_planes.models[0].is_initialized() || !is_approx(m_planes.check_points[0].cast(), p1.cast())) { + m_planes.check_points[0] = p1; + m_planes.models[0].reset(); + + GLModel::InitializationData init_data; + GUI::GLModel::InitializationData::Entity entity; + entity.type = GUI::GLModel::PrimitiveType::Triangles; + entity.positions.reserve(4); + entity.positions.emplace_back(Vec3f(p1.x(), p1.y(), z1)); + entity.positions.emplace_back(Vec3f(p2.x(), p1.y(), z1)); + entity.positions.emplace_back(Vec3f(p2.x(), p2.y(), z1)); + entity.positions.emplace_back(Vec3f(p1.x(), p2.y(), z1)); + + entity.normals.reserve(4); + for (size_t i = 0; i < 4; ++i) { + entity.normals.emplace_back(Vec3f::UnitZ()); + } + + entity.indices.reserve(6); + entity.indices.emplace_back(0); + entity.indices.emplace_back(1); + entity.indices.emplace_back(2); + entity.indices.emplace_back(2); + entity.indices.emplace_back(3); + entity.indices.emplace_back(0); + + init_data.entities.emplace_back(entity); + m_planes.models[0].init_from(init_data); + } + + if (!m_planes.models[1].is_initialized() || !is_approx(m_planes.check_points[1].cast(), p2.cast())) { + m_planes.check_points[1] = p2; + m_planes.models[1].reset(); + + GLModel::InitializationData init_data; + GUI::GLModel::InitializationData::Entity entity; + entity.type = GUI::GLModel::PrimitiveType::Triangles; + entity.positions.reserve(4); + entity.positions.emplace_back(Vec3f(p1.x(), p1.y(), z2)); + entity.positions.emplace_back(Vec3f(p2.x(), p1.y(), z2)); + entity.positions.emplace_back(Vec3f(p2.x(), p2.y(), z2)); + entity.positions.emplace_back(Vec3f(p1.x(), p2.y(), z2)); + + entity.normals.reserve(4); + for (size_t i = 0; i < 4; ++i) { + entity.normals.emplace_back(Vec3f::UnitZ()); + } + + entity.indices.reserve(6); + entity.indices.emplace_back(0); + entity.indices.emplace_back(1); + entity.indices.emplace_back(2); + entity.indices.emplace_back(2); + entity.indices.emplace_back(3); + entity.indices.emplace_back(0); + + init_data.entities.emplace_back(entity); + m_planes.models[1].init_from(init_data); + } + + m_planes.models[0].set_color(-1, (camera_on_top && type == 1) || (!camera_on_top && type == 2) ? SOLID_PLANE_COLOR : TRANSPARENT_PLANE_COLOR); + m_planes.models[0].render(); + m_planes.models[1].set_color(-1, (camera_on_top && type == 2) || (!camera_on_top && type == 1) ? SOLID_PLANE_COLOR : TRANSPARENT_PLANE_COLOR); + m_planes.models[1].render(); glsafe(::glEnable(GL_CULL_FACE)); glsafe(::glDisable(GL_BLEND)); diff --git a/src/slic3r/GUI/Selection.hpp b/src/slic3r/GUI/Selection.hpp index 944333a9a56..254f82a3cf7 100644 --- a/src/slic3r/GUI/Selection.hpp +++ b/src/slic3r/GUI/Selection.hpp @@ -221,6 +221,12 @@ class Selection GLModel m_arrow; GLModel m_curved_arrow; GLModel m_box; + struct Planes + { + std::array check_points{ Vec3f::Zero(), Vec3f::Zero() }; + std::array models; + }; + Planes m_planes; float m_scale_factor; bool m_dragging; @@ -355,11 +361,11 @@ class Selection void erase(); void render(float scale_factor = 1.0); + //BBS: GUI refactor: add uniform scale from gizmo + void render_sidebar_hints(const std::string& sidebar_field, bool uniform_scale); #if ENABLE_RENDER_SELECTION_CENTER void render_center(bool gizmo_is_dragging); #endif // ENABLE_RENDER_SELECTION_CENTER - //BBS: GUI refactor: add uniform scale from gizmo - void render_sidebar_hints(const std::string& sidebar_field, bool uniform_scale) const; bool requires_local_axes() const; @@ -402,11 +408,11 @@ class Selection void set_bounding_boxes_dirty() { m_bounding_box.reset(); m_unscaled_instance_bounding_box.reset(); m_scaled_instance_bounding_box.reset(); } void render_synchronized_volumes(); void render_bounding_box(const BoundingBoxf3& box, const ColorRGB& color); - void render_sidebar_position_hints(const std::string& sidebar_field) const; - void render_sidebar_rotation_hints(const std::string& sidebar_field) const; + void render_sidebar_position_hints(const std::string& sidebar_field); + void render_sidebar_rotation_hints(const std::string& sidebar_field); //BBS: GUI refactor: add uniform_scale from gizmo - void render_sidebar_scale_hints(const std::string& sidebar_field, bool gizmo_uniform_scale) const; - void render_sidebar_layers_hints(const std::string& sidebar_field) const; + void render_sidebar_scale_hints(const std::string& sidebar_field, bool gizmo_uniform_scale); + void render_sidebar_layers_hints(const std::string& sidebar_field); public: enum SyncRotationType { From f6a3421e2a77f61b3867b2474dce55b9cc3aa4b6 Mon Sep 17 00:00:00 2001 From: Filip Sykala Date: Thu, 19 Oct 2023 19:52:25 +0800 Subject: [PATCH 04/99] =?UTF-8?q?=EF=BB=BFremove=20GLModel=20from=20base?= =?UTF-8?q?=20class=20-=20only=202=20gizmo=20use=20cone?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit (cherry picked from commit prusa3d/PrusaSlicer@3c7390e34e903514d6a15fb3a910d37287ed9855) (cherry picked from commit 4647fc49ef5b925432e087252f32a6601d0410da) --- src/slic3r/GUI/Gizmos/GLGizmoBase.cpp | 3 --- src/slic3r/GUI/Gizmos/GLGizmoBase.hpp | 3 --- src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp | 1 + src/slic3r/GUI/Gizmos/GLGizmoRotate.hpp | 2 ++ src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp | 8 +++++--- src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp | 4 ++++ 6 files changed, 12 insertions(+), 9 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoBase.cpp b/src/slic3r/GUI/Gizmos/GLGizmoBase.cpp index 75efc8902b5..588e8ce58b8 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoBase.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoBase.cpp @@ -161,9 +161,6 @@ GLGizmoBase::GLGizmoBase(GLCanvas3D& parent, const std::string& icon_filename, u m_base_color = DEFAULT_BASE_COLOR; m_drag_color = DEFAULT_DRAG_COLOR; m_highlight_color = DEFAULT_HIGHLIGHT_COLOR; - m_cone.init_from(its_make_cone(1., 1., 2 * PI / 24)); - m_sphere.init_from(its_make_sphere(1., (2 * M_PI) / 24.)); - m_cylinder.init_from(its_make_cylinder(1., 1., 2 * PI / 24.)); } void GLGizmoBase::set_icon_filename(const std::string &filename) { diff --git a/src/slic3r/GUI/Gizmos/GLGizmoBase.hpp b/src/slic3r/GUI/Gizmos/GLGizmoBase.hpp index 1dea8f08d46..a858954b471 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoBase.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoBase.hpp @@ -123,9 +123,6 @@ class GLGizmoBase bool m_first_input_window_render; mutable std::string m_tooltip; CommonGizmosDataPool* m_c; - GLModel m_cone; - GLModel m_cylinder; - GLModel m_sphere; bool m_is_dark_mode = false; diff --git a/src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp b/src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp index 124e370a362..4a142ba9262 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp @@ -76,6 +76,7 @@ std::string GLGizmoRotate::get_tooltip() const bool GLGizmoRotate::on_init() { + m_cone.init_from(its_make_cone(1., 1., 2 * PI / 24)); m_grabbers.push_back(Grabber()); return true; } diff --git a/src/slic3r/GUI/Gizmos/GLGizmoRotate.hpp b/src/slic3r/GUI/Gizmos/GLGizmoRotate.hpp index 9862ec29014..0f426f26f4e 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoRotate.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoRotate.hpp @@ -43,6 +43,8 @@ class GLGizmoRotate : public GLGizmoBase mutable float m_snap_fine_in_radius; mutable float m_snap_fine_out_radius; + GLModel m_cone; + public: GLGizmoRotate(GLCanvas3D& parent, Axis axis); GLGizmoRotate(const GLGizmoRotate& other); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp index 94175aef9de..8cef43e5955 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp @@ -28,9 +28,7 @@ namespace GUI { GLGizmoSlaSupports::GLGizmoSlaSupports(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id) : GLGizmoBase(parent, icon_filename, sprite_id) -{ -} - +{} bool GLGizmoSlaSupports::on_init() { @@ -48,6 +46,10 @@ bool GLGizmoSlaSupports::on_init() m_desc["manual_editing"] = _L("Manual editing"); m_desc["clipping_of_view"] = _L("Clipping of view")+ ": "; m_desc["reset_direction"] = _L("Reset direction"); + + m_cone.init_from(its_make_cone(1., 1., 2 * PI / 24)); + m_cylinder.init_from(its_make_cylinder(1., 1., 2 * PI / 24.)); + m_sphere.init_from(its_make_sphere(1., (2 * M_PI) / 24.)); return true; } diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp index 8dd76336a35..08d4874bdb0 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp @@ -80,6 +80,10 @@ class GLGizmoSlaSupports : public GLGizmoBase void render_points(const Selection& selection, bool picking = false) const; bool unsaved_changes() const; + GLModel m_cone; + GLModel m_cylinder; + GLModel m_sphere; + bool m_lock_unique_islands = false; bool m_editing_mode = false; // Is editing mode active? float m_new_point_head_diameter; // Size of a new point. From 7e04448b7a42a752cd354600ab67dd30c0e9b79f Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Sat, 21 Oct 2023 12:06:59 +0800 Subject: [PATCH 05/99] Tech ENABLE_GLBEGIN_GLEND_REMOVAL - Various Gizmos updates and fixes prusa3d/PrusaSlicer@35dd03e8cbe9c99b5a0dcdc2a1bc96d84dd89966 prusa3d/PrusaSlicer@bcaa0d38bd1a8533cb489da497b4077e206efc2e prusa3d/PrusaSlicer@267399447196eed637cee8abcfd8d985f1083fe7 prusa3d/PrusaSlicer@0e3a3aa52226c808e50d79c98baeb292bb1c3e9f prusa3d/PrusaSlicer@08a27110342826973d8d018fdbb78d5cc8ae012d prusa3d/PrusaSlicer@f6f95808cc3afdb9ffbfcad62d545ae9bc6e35c6 prusa3d/PrusaSlicer@81edc7d75295ce6c2f652dfc6b6d1ed5db401f41 prusa3d/PrusaSlicer@0b6e2b4aec4d6b4cb64e578474df22139042d147 prusa3d/PrusaSlicer@71f08841f9bff6e2b050ea472ff65241ee20a127 --- src/libslic3r/Geometry.cpp | 131 +++---- src/libslic3r/Geometry.hpp | 24 +- src/slic3r/GUI/GLCanvas3D.cpp | 132 +++++-- src/slic3r/GUI/GLCanvas3D.hpp | 19 +- src/slic3r/GUI/GLSelectionRectangle.cpp | 53 ++- src/slic3r/GUI/GLSelectionRectangle.hpp | 12 +- src/slic3r/GUI/GLShadersManager.cpp | 3 +- src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp | 2 +- src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.hpp | 2 +- .../GUI/Gizmos/GLGizmoMmuSegmentation.cpp | 2 +- .../GUI/Gizmos/GLGizmoMmuSegmentation.hpp | 2 +- src/slic3r/GUI/Gizmos/GLGizmoMove.cpp | 65 +++- src/slic3r/GUI/Gizmos/GLGizmoMove.hpp | 18 +- src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp | 68 ++-- src/slic3r/GUI/Gizmos/GLGizmoPainterBase.hpp | 9 +- src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp | 356 +++++++++++------- src/slic3r/GUI/Gizmos/GLGizmoRotate.hpp | 71 ++-- src/slic3r/GUI/Gizmos/GLGizmoScale.cpp | 169 +++++---- src/slic3r/GUI/Gizmos/GLGizmoScale.hpp | 17 +- src/slic3r/GUI/Gizmos/GLGizmoSeam.cpp | 2 +- src/slic3r/GUI/Gizmos/GLGizmoSeam.hpp | 2 +- src/slic3r/GUI/Gizmos/GLGizmosManager.cpp | 2 +- src/slic3r/GUI/Gizmos/GLGizmosManager.hpp | 22 +- 23 files changed, 738 insertions(+), 445 deletions(-) diff --git a/src/libslic3r/Geometry.cpp b/src/libslic3r/Geometry.cpp index a2c59ec17d5..d1c1a03e0d5 100644 --- a/src/libslic3r/Geometry.cpp +++ b/src/libslic3r/Geometry.cpp @@ -326,40 +326,36 @@ Vec3d extract_euler_angles(const Eigen::Matrix& Vec3d angles1 = Vec3d::Zero(); Vec3d angles2 = Vec3d::Zero(); // BBS: rotation_matrix(2, 0) may be slighterly larger than 1 due to numerical accuracy - if (std::abs(std::abs(rotation_matrix(2, 0)) - 1.0) < 1e-5 || std::abs(rotation_matrix(2, 0))>1) - { - angles1(2) = 0.0; - if (rotation_matrix(2, 0) < 0.0) // == -1.0 - { - angles1(1) = 0.5 * (double)PI; - angles1(0) = angles1(2) + ::atan2(rotation_matrix(0, 1), rotation_matrix(0, 2)); + if (std::abs(std::abs(rotation_matrix(2, 0)) - 1.0) < 1e-5 || std::abs(rotation_matrix(2, 0))>1) { + angles1.z() = 0.0; + if (rotation_matrix(2, 0) < 0.0) { // == -1.0 + angles1.y() = 0.5 * double(PI); + angles1.x() = angles1.z() + ::atan2(rotation_matrix(0, 1), rotation_matrix(0, 2)); } - else // == 1.0 - { - angles1(1) = - 0.5 * (double)PI; - angles1(0) = - angles1(2) + ::atan2(- rotation_matrix(0, 1), - rotation_matrix(0, 2)); + else { // == 1.0 + angles1.y() = - 0.5 * double(PI); + angles1.x() = - angles1.y() + ::atan2(- rotation_matrix(0, 1), - rotation_matrix(0, 2)); } angles2 = angles1; } - else - { - angles1(1) = -::asin(rotation_matrix(2, 0)); - double inv_cos1 = 1.0 / ::cos(angles1(1)); - angles1(0) = ::atan2(rotation_matrix(2, 1) * inv_cos1, rotation_matrix(2, 2) * inv_cos1); - angles1(2) = ::atan2(rotation_matrix(1, 0) * inv_cos1, rotation_matrix(0, 0) * inv_cos1); - - angles2(1) = (double)PI - angles1(1); - double inv_cos2 = 1.0 / ::cos(angles2(1)); - angles2(0) = ::atan2(rotation_matrix(2, 1) * inv_cos2, rotation_matrix(2, 2) * inv_cos2); - angles2(2) = ::atan2(rotation_matrix(1, 0) * inv_cos2, rotation_matrix(0, 0) * inv_cos2); + else { + angles1.y() = -::asin(rotation_matrix(2, 0)); + const double inv_cos1 = 1.0 / ::cos(angles1.y()); + angles1.x() = ::atan2(rotation_matrix(2, 1) * inv_cos1, rotation_matrix(2, 2) * inv_cos1); + angles1.z() = ::atan2(rotation_matrix(1, 0) * inv_cos1, rotation_matrix(0, 0) * inv_cos1); + + angles2.y() = double(PI) - angles1.y(); + const double inv_cos2 = 1.0 / ::cos(angles2.y()); + angles2.x() = ::atan2(rotation_matrix(2, 1) * inv_cos2, rotation_matrix(2, 2) * inv_cos2); + angles2.z() = ::atan2(rotation_matrix(1, 0) * inv_cos2, rotation_matrix(0, 0) * inv_cos2); } // The following euristic is the best found up to now (in the sense that it works fine with the greatest number of edge use-cases) // but there are other use-cases were it does not // We need to improve it - double min_1 = angles1.cwiseAbs().minCoeff(); - double min_2 = angles2.cwiseAbs().minCoeff(); - bool use_1 = (min_1 < min_2) || (is_approx(min_1, min_2) && (angles1.norm() <= angles2.norm())); + const double min_1 = angles1.cwiseAbs().minCoeff(); + const double min_2 = angles2.cwiseAbs().minCoeff(); + const bool use_1 = (min_1 < min_2) || (is_approx(min_1, min_2) && (angles1.norm() <= angles2.norm())); return use_1 ? angles1 : angles2; } @@ -423,14 +419,6 @@ Transform3d rotation_transform(const Vec3d& rotation) return transform; } -Transformation::Flags::Flags() - : dont_translate(true) - , dont_rotate(true) - , dont_scale(true) - , dont_mirror(true) -{ -} - bool Transformation::Flags::needs_update(bool dont_translate, bool dont_rotate, bool dont_scale, bool dont_mirror) const { return (this->dont_translate != dont_translate) || (this->dont_rotate != dont_rotate) || (this->dont_scale != dont_scale) || (this->dont_mirror != dont_mirror); @@ -456,15 +444,14 @@ Transformation::Transformation(const Transform3d& transform) void Transformation::set_offset(const Vec3d& offset) { - set_offset(X, offset(0)); - set_offset(Y, offset(1)); - set_offset(Z, offset(2)); + set_offset(X, offset.x()); + set_offset(Y, offset.y()); + set_offset(Z, offset.z()); } void Transformation::set_offset(Axis axis, double offset) { - if (m_offset(axis) != offset) - { + if (m_offset(axis) != offset) { m_offset(axis) = offset; m_dirty = true; } @@ -472,19 +459,18 @@ void Transformation::set_offset(Axis axis, double offset) void Transformation::set_rotation(const Vec3d& rotation) { - set_rotation(X, rotation(0)); - set_rotation(Y, rotation(1)); - set_rotation(Z, rotation(2)); + set_rotation(X, rotation.x()); + set_rotation(Y, rotation.y()); + set_rotation(Z, rotation.z()); } void Transformation::set_rotation(Axis axis, double rotation) { rotation = angle_to_0_2PI(rotation); - if (is_approx(std::abs(rotation), 2.0 * (double)PI)) + if (is_approx(std::abs(rotation), 2.0 * double(PI))) rotation = 0.0; - if (m_rotation(axis) != rotation) - { + if (m_rotation(axis) != rotation) { m_rotation(axis) = rotation; m_dirty = true; } @@ -492,15 +478,14 @@ void Transformation::set_rotation(Axis axis, double rotation) void Transformation::set_scaling_factor(const Vec3d& scaling_factor) { - set_scaling_factor(X, scaling_factor(0)); - set_scaling_factor(Y, scaling_factor(1)); - set_scaling_factor(Z, scaling_factor(2)); + set_scaling_factor(X, scaling_factor.x()); + set_scaling_factor(Y, scaling_factor.y()); + set_scaling_factor(Z, scaling_factor.z()); } void Transformation::set_scaling_factor(Axis axis, double scaling_factor) { - if (m_scaling_factor(axis) != std::abs(scaling_factor)) - { + if (m_scaling_factor(axis) != std::abs(scaling_factor)) { m_scaling_factor(axis) = std::abs(scaling_factor); m_dirty = true; } @@ -508,9 +493,9 @@ void Transformation::set_scaling_factor(Axis axis, double scaling_factor) void Transformation::set_mirror(const Vec3d& mirror) { - set_mirror(X, mirror(0)); - set_mirror(Y, mirror(1)); - set_mirror(Z, mirror(2)); + set_mirror(X, mirror.x()); + set_mirror(Y, mirror.y()); + set_mirror(Z, mirror.z()); } void Transformation::set_mirror(Axis axis, double mirror) @@ -521,8 +506,7 @@ void Transformation::set_mirror(Axis axis, double mirror) else if (abs_mirror != 1.0) mirror /= abs_mirror; - if (m_mirror(axis) != mirror) - { + if (m_mirror(axis) != mirror) { m_mirror(axis) = mirror; m_dirty = true; } @@ -540,9 +524,8 @@ void Transformation::set_from_transform(const Transform3d& transform) // we can only detect if the matrix contains a left handed reference system // in which case we reorient it back to right handed by mirroring the x axis Vec3d mirror = Vec3d::Ones(); - if (m3x3.col(0).dot(m3x3.col(1).cross(m3x3.col(2))) < 0.0) - { - mirror(0) = -1.0; + if (m3x3.col(0).dot(m3x3.col(1).cross(m3x3.col(2))) < 0.0) { + mirror.x() = -1.0; // remove mirror m3x3.col(0) *= -1.0; } @@ -579,8 +562,7 @@ void Transformation::reset() const Transform3d& Transformation::get_matrix(bool dont_translate, bool dont_rotate, bool dont_scale, bool dont_mirror) const { - if (m_dirty || m_flags.needs_update(dont_translate, dont_rotate, dont_scale, dont_mirror)) - { + if (m_dirty || m_flags.needs_update(dont_translate, dont_rotate, dont_scale, dont_mirror)) { m_matrix = Geometry::assemble_transform( dont_translate ? Vec3d::Zero() : m_offset, dont_rotate ? Vec3d::Zero() : m_rotation, @@ -609,8 +591,7 @@ Transformation Transformation::volume_to_bed_transformation(const Transformation // Just set the inverse. out.set_from_transform(instance_transformation.get_matrix(true).inverse()); } - else if (is_rotation_ninety_degrees(instance_transformation.get_rotation())) - { + else if (is_rotation_ninety_degrees(instance_transformation.get_rotation())) { // Anisotropic scaling, rotation by multiples of ninety degrees. Eigen::Matrix3d instance_rotation_trafo = (Eigen::AngleAxisd(instance_transformation.get_rotation().z(), Vec3d::UnitZ()) * @@ -643,8 +624,8 @@ Transformation Transformation::volume_to_bed_transformation(const Transformation scale(i) = pts.col(i).dot(qs.col(i)) / pts.col(i).dot(pts.col(i)); out.set_rotation(Geometry::extract_euler_angles(volume_rotation_trafo)); - out.set_scaling_factor(Vec3d(std::abs(scale(0)), std::abs(scale(1)), std::abs(scale(2)))); - out.set_mirror(Vec3d(scale(0) > 0 ? 1. : -1, scale(1) > 0 ? 1. : -1, scale(2) > 0 ? 1. : -1)); + out.set_scaling_factor(Vec3d(std::abs(scale.x()), std::abs(scale.y()), std::abs(scale.z()))); + out.set_mirror(Vec3d(scale.x() > 0 ? 1. : -1, scale.y() > 0 ? 1. : -1, scale.z() > 0 ? 1. : -1)); } else { @@ -663,19 +644,15 @@ Transform3d transform3d_from_string(const std::string& transform_str) assert(is_decimal_separator_point()); // for atof Transform3d transform = Transform3d::Identity(); - if (!transform_str.empty()) - { + if (!transform_str.empty()) { std::vector mat_elements_str; boost::split(mat_elements_str, transform_str, boost::is_any_of(" "), boost::token_compress_on); - unsigned int size = (unsigned int)mat_elements_str.size(); - if (size == 16) - { + const unsigned int size = (unsigned int)mat_elements_str.size(); + if (size == 16) { unsigned int i = 0; - for (unsigned int r = 0; r < 4; ++r) - { - for (unsigned int c = 0; c < 4; ++c) - { + for (unsigned int r = 0; r < 4; ++r) { + for (unsigned int c = 0; c < 4; ++c) { transform(r, c) = ::atof(mat_elements_str[i++].c_str()); } } @@ -689,17 +666,17 @@ Eigen::Quaterniond rotation_xyz_diff(const Vec3d &rot_xyz_from, const Vec3d &rot { return // From the current coordinate system to world. - Eigen::AngleAxisd(rot_xyz_to(2), Vec3d::UnitZ()) * Eigen::AngleAxisd(rot_xyz_to(1), Vec3d::UnitY()) * Eigen::AngleAxisd(rot_xyz_to(0), Vec3d::UnitX()) * + Eigen::AngleAxisd(rot_xyz_to.z(), Vec3d::UnitZ()) * Eigen::AngleAxisd(rot_xyz_to.y(), Vec3d::UnitY()) * Eigen::AngleAxisd(rot_xyz_to.x(), Vec3d::UnitX()) * // From world to the initial coordinate system. - Eigen::AngleAxisd(-rot_xyz_from(0), Vec3d::UnitX()) * Eigen::AngleAxisd(-rot_xyz_from(1), Vec3d::UnitY()) * Eigen::AngleAxisd(-rot_xyz_from(2), Vec3d::UnitZ()); + Eigen::AngleAxisd(-rot_xyz_from.x(), Vec3d::UnitX()) * Eigen::AngleAxisd(-rot_xyz_from.y(), Vec3d::UnitY()) * Eigen::AngleAxisd(-rot_xyz_from.z(), Vec3d::UnitZ()); } // This should only be called if it is known, that the two rotations only differ in rotation around the Z axis. double rotation_diff_z(const Vec3d &rot_xyz_from, const Vec3d &rot_xyz_to) { - Eigen::AngleAxisd angle_axis(rotation_xyz_diff(rot_xyz_from, rot_xyz_to)); - Vec3d axis = angle_axis.axis(); - double angle = angle_axis.angle(); + const Eigen::AngleAxisd angle_axis(rotation_xyz_diff(rot_xyz_from, rot_xyz_to)); + const Vec3d axis = angle_axis.axis(); + const double angle = angle_axis.angle(); #ifndef NDEBUG if (std::abs(angle) > 1e-8) { assert(std::abs(axis.x()) < 1e-8); diff --git a/src/libslic3r/Geometry.hpp b/src/libslic3r/Geometry.hpp index 8eb6195a107..cbb5df6a81b 100644 --- a/src/libslic3r/Geometry.hpp +++ b/src/libslic3r/Geometry.hpp @@ -361,25 +361,23 @@ class Transformation { struct Flags { - bool dont_translate; - bool dont_rotate; - bool dont_scale; - bool dont_mirror; - - Flags(); + bool dont_translate{ true }; + bool dont_rotate{ true }; + bool dont_scale{ true }; + bool dont_mirror{ true }; bool needs_update(bool dont_translate, bool dont_rotate, bool dont_scale, bool dont_mirror) const; void set(bool dont_translate, bool dont_rotate, bool dont_scale, bool dont_mirror); }; - Vec3d m_offset; // In unscaled coordinates - Vec3d m_rotation; // Rotation around the three axes, in radians around mesh center point - Vec3d m_scaling_factor; // Scaling factors along the three axes - Vec3d m_mirror; // Mirroring along the three axes + Vec3d m_offset{ Vec3d::Zero() }; // In unscaled coordinates + Vec3d m_rotation{ Vec3d::Zero() }; // Rotation around the three axes, in radians around mesh center point + Vec3d m_scaling_factor{ Vec3d::Ones() }; // Scaling factors along the three axes + Vec3d m_mirror{ Vec3d::Ones() }; // Mirroring along the three axes - mutable Transform3d m_matrix; + mutable Transform3d m_matrix{ Transform3d::Identity() }; mutable Flags m_flags; - mutable bool m_dirty; + mutable bool m_dirty{ false }; public: Transformation(); @@ -457,7 +455,7 @@ extern double rotation_diff_z(const Vec3d &rot_xyz_from, const Vec3d &rot_xyz_to // Is the angle close to a multiple of 90 degrees? inline bool is_rotation_ninety_degrees(double a) { - a = fmod(std::abs(a), 0.5 * M_PI); + a = fmod(std::abs(a), 0.5 * PI); if (a > 0.25 * PI) a = 0.5 * PI - a; return a < 0.001; diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 14056885211..54846f168d6 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -462,19 +462,62 @@ void GLCanvas3D::LayersEditing::render_curve(const Rect & bar_rect) const float scale_y = bar_rect.get_height() / m_object_max_z; const float x = bar_rect.get_left() + float(m_slicing_parameters->layer_height) * scale_x; + bool bar_rect_changed = m_profile.old_bar_rect != bar_rect; + m_profile.old_bar_rect = bar_rect; + // Baseline - glsafe(::glColor3f(0.0f, 0.0f, 0.0f)); - ::glBegin(GL_LINE_STRIP); - ::glVertex2f(x, bar_rect.get_bottom()); - ::glVertex2f(x, bar_rect.get_top()); - glsafe(::glEnd()); + if (!m_profile.baseline.is_initialized() || bar_rect_changed) { + m_profile.old_bar_rect = bar_rect; - // Curve - glsafe(::glColor3f(0.0f, 0.0f, 1.0f)); - ::glBegin(GL_LINE_STRIP); - for (unsigned int i = 0; i < m_layer_height_profile.size(); i += 2) - ::glVertex2f(bar_rect.get_left() + (float)m_layer_height_profile[i + 1] * scale_x, bar_rect.get_bottom() + (float)m_layer_height_profile[i] * scale_y); - glsafe(::glEnd()); + GLModel::InitializationData init_data; + GLModel::InitializationData::Entity entity; + entity.type = GLModel::PrimitiveType::Lines; + entity.positions.reserve(2); + entity.positions.emplace_back(x, bar_rect.get_bottom(), 0.0f); + entity.positions.emplace_back(x, bar_rect.get_top(), 0.0f); + + entity.normals.reserve(2); + for (size_t j = 0; j < 2; ++j) { + entity.normals.emplace_back(Vec3f::UnitZ()); + } + + entity.indices.reserve(2); + entity.indices.emplace_back(0); + entity.indices.emplace_back(1); + + init_data.entities.emplace_back(entity); + m_profile.baseline.init_from(init_data); + m_profile.baseline.set_color(-1, ColorRGBA::BLACK()); + } + + if (!m_profile.profile.is_initialized() || bar_rect_changed || m_profile.old_layer_height_profile != m_layer_height_profile) { + m_profile.old_layer_height_profile = m_layer_height_profile; + m_profile.profile.reset(); + + GLModel::InitializationData init_data; + GLModel::InitializationData::Entity entity; + entity.type = GLModel::PrimitiveType::LineStrip; + entity.positions.reserve(m_layer_height_profile.size()); + entity.normals.reserve(m_layer_height_profile.size()); + entity.indices.reserve(m_layer_height_profile.size()); + for (unsigned int i = 0; i < unsigned int(m_layer_height_profile.size()); i += 2) { + entity.positions.emplace_back(bar_rect.get_left() + float(m_layer_height_profile[i + 1]) * scale_x, bar_rect.get_bottom() + float(m_layer_height_profile[i]) * scale_y, 0.0f); + entity.normals.emplace_back(Vec3f::UnitZ()); + entity.indices.emplace_back(i / 2); + } + + init_data.entities.emplace_back(entity); + m_profile.profile.init_from(init_data); + m_profile.profile.set_color(-1, ColorRGBA::BLUE()); + } + + GLShaderProgram* shader = wxGetApp().get_shader("flat"); + if (shader != nullptr) { + shader->start_using(); + m_profile.baseline.render(); + m_profile.profile.render(); + shader->stop_using(); + } } void GLCanvas3D::LayersEditing::render_volumes(const GLCanvas3D & canvas, const GLVolumeCollection & volumes)//render volume and layer height texture (has mapping relation with each other) @@ -6822,7 +6865,7 @@ void GLCanvas3D::_render_objects(GLVolumeCollection::ERenderType type, bool with default: case GLVolumeCollection::ERenderType::Opaque: { - const GLGizmosManager& gm = get_gizmos_manager(); + GLGizmosManager& gm = get_gizmos_manager(); if (dynamic_cast(gm.get_current()) == nullptr) { if (m_picking_enabled && m_layers_editing.is_enabled() && (m_layers_editing.last_object_id != -1) && (m_layers_editing.object_max_z() > 0.0f)) { @@ -8070,28 +8113,59 @@ void GLCanvas3D::_render_assemble_info() const } #if ENABLE_SHOW_CAMERA_TARGET -void GLCanvas3D::_render_camera_target() const +void GLCanvas3D::_render_camera_target() { - double half_length = 5.0; + static const double half_length = 5.0; glsafe(::glDisable(GL_DEPTH_TEST)); - glsafe(::glLineWidth(2.0f)); - ::glBegin(GL_LINES); const Vec3d& target = wxGetApp().plater()->get_camera().get_target(); - // draw line for x axis - ::glColor3f(1.0f, 0.0f, 0.0f); - ::glVertex3d(target(0) - half_length, target(1), target(2)); - ::glVertex3d(target(0) + half_length, target(1), target(2)); - // draw line for y axis - ::glColor3f(0.0f, 1.0f, 0.0f); - ::glVertex3d(target(0), target(1) - half_length, target(2)); - ::glVertex3d(target(0), target(1) + half_length, target(2)); - // draw line for z axis - ::glColor3f(0.0f, 0.0f, 1.0f); - ::glVertex3d(target(0), target(1), target(2) - half_length); - ::glVertex3d(target(0), target(1), target(2) + half_length); - glsafe(::glEnd()); + bool target_changed = !m_camera_target.target.isApprox(target); + m_camera_target.target = target; + + for (int i = 0; i < 3; ++i) { + if (!m_camera_target.axis[i].is_initialized() || target_changed) { + m_camera_target.axis[i].reset(); + + GLModel::InitializationData init_data; + GLModel::InitializationData::Entity entity; + entity.type = GLModel::PrimitiveType::Lines; + entity.positions.reserve(2); + if (i == X) { + entity.positions.emplace_back(target.x() - half_length, target.y(), target.z()); + entity.positions.emplace_back(target.x() + half_length, target.y(), target.z()); + } + else if (i == Y) { + entity.positions.emplace_back(target.x(), target.y() - half_length, target.z()); + entity.positions.emplace_back(target.x(), target.y() + half_length, target.z()); + } + else { + entity.positions.emplace_back(target.x(), target.y(), target.z() - half_length); + entity.positions.emplace_back(target.x(), target.y(), target.z() + half_length); + } + entity.normals.reserve(2); + for (size_t j = 0; j < 2; ++j) { + entity.normals.emplace_back(Vec3f::UnitZ()); + } + + entity.indices.reserve(2); + entity.indices.emplace_back(0); + entity.indices.emplace_back(1); + + init_data.entities.emplace_back(entity); + m_camera_target.axis[i].init_from(init_data); + m_camera_target.axis[i].set_color(-1, (i == X) ? ColorRGBA::X() : (i == Y) ? ColorRGBA::Y() : ColorRGBA::Z()); + } + } + + GLShaderProgram* shader = wxGetApp().get_shader("flat"); + if (shader != nullptr) { + shader->start_using(); + for (int i = 0; i < 3; ++i) { + m_camera_target.axis[i].render(); + } + shader->stop_using(); + } } #endif // ENABLE_SHOW_CAMERA_TARGET diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp index a7d40179735..ceb9eacc76a 100644 --- a/src/slic3r/GUI/GLCanvas3D.hpp +++ b/src/slic3r/GUI/GLCanvas3D.hpp @@ -257,6 +257,14 @@ class GLCanvas3D int last_object_id{ -1 }; float last_z{ 0.0f }; LayerHeightEditActionType last_action{ LAYER_HEIGHT_EDIT_ACTION_INCREASE }; + struct Profile + { + GLModel baseline; + GLModel profile; + Rect old_bar_rect; + std::vector old_layer_height_profile; + }; + Profile m_profile; LayersEditing() = default; ~LayersEditing(); @@ -698,6 +706,15 @@ class GLCanvas3D } m_gizmo_highlighter; +#if ENABLE_SHOW_CAMERA_TARGET + struct CameraTarget + { + std::array axis; + Vec3d target{ Vec3d::Zero() }; + }; + + CameraTarget m_camera_target; +#endif // ENABLE_SHOW_CAMERA_TARGET public: explicit GLCanvas3D(wxGLCanvas* canvas, Bed3D &bed); ~GLCanvas3D(); @@ -1139,7 +1156,7 @@ class GLCanvas3D void _render_assemble_control() const; void _render_assemble_info() const; #if ENABLE_SHOW_CAMERA_TARGET - void _render_camera_target() const; + void _render_camera_target(); #endif // ENABLE_SHOW_CAMERA_TARGET void _render_sla_slices(); void _render_selection_sidebar_hints(); diff --git a/src/slic3r/GUI/GLSelectionRectangle.cpp b/src/slic3r/GUI/GLSelectionRectangle.cpp index f6dfbe10f72..30b7888c537 100644 --- a/src/slic3r/GUI/GLSelectionRectangle.cpp +++ b/src/slic3r/GUI/GLSelectionRectangle.cpp @@ -69,7 +69,7 @@ namespace GUI { m_state = Off; } - void GLSelectionRectangle::render(const GLCanvas3D& canvas) const + void GLSelectionRectangle::render(const GLCanvas3D& canvas) { if (!is_dragging()) return; @@ -92,11 +92,6 @@ namespace GUI { float bottom = (float)std::min(start(1), end(1)) * inv_zoom; glsafe(::glLineWidth(1.5f)); - float color[3]; - color[0] = 0.00f; - color[1] = 1.00f; - color[2] = 0.38f; - glsafe(::glColor3fv(color)); glsafe(::glDisable(GL_DEPTH_TEST)); @@ -112,12 +107,46 @@ namespace GUI { glsafe(::glLineStipple(4, 0xAAAA)); glsafe(::glEnable(GL_LINE_STIPPLE)); - ::glBegin(GL_LINE_LOOP); - ::glVertex2f((GLfloat)left, (GLfloat)bottom); - ::glVertex2f((GLfloat)right, (GLfloat)bottom); - ::glVertex2f((GLfloat)right, (GLfloat)top); - ::glVertex2f((GLfloat)left, (GLfloat)top); - glsafe(::glEnd()); + GLShaderProgram* shader = wxGetApp().get_shader("flat"); + if (shader != nullptr) { + shader->start_using(); + + if (!m_rectangle.is_initialized() || !m_old_start_corner.isApprox(m_start_corner) || !m_old_end_corner.isApprox(m_end_corner)) { + m_old_start_corner = m_start_corner; + m_old_end_corner = m_end_corner; + m_rectangle.reset(); + + GLModel::InitializationData init_data; + GLModel::InitializationData::Entity entity; + entity.type = GLModel::PrimitiveType::LineLoop; + entity.positions.reserve(4); + entity.positions.emplace_back(left, bottom, 0.0f); + entity.positions.emplace_back(right, bottom, 0.0f); + entity.positions.emplace_back(right, top, 0.0f); + entity.positions.emplace_back(left, top, 0.0f); + + entity.normals.reserve(4); + for (size_t j = 0; j < 5; ++j) { + entity.normals.emplace_back(Vec3f::UnitZ()); + } + + entity.indices.reserve(6); + entity.indices.emplace_back(0); + entity.indices.emplace_back(1); + entity.indices.emplace_back(2); + entity.indices.emplace_back(2); + entity.indices.emplace_back(3); + entity.indices.emplace_back(0); + + init_data.entities.emplace_back(entity); + m_rectangle.init_from(init_data); + } + + ColorRGBA color(0.0f, 1.0f, 0.38f, 1.0f); + m_rectangle.set_color(-1, color); + m_rectangle.render(); + shader->stop_using(); + } glsafe(::glPopAttrib()); diff --git a/src/slic3r/GUI/GLSelectionRectangle.hpp b/src/slic3r/GUI/GLSelectionRectangle.hpp index d9869771ef9..ad0360e0ccb 100644 --- a/src/slic3r/GUI/GLSelectionRectangle.hpp +++ b/src/slic3r/GUI/GLSelectionRectangle.hpp @@ -2,6 +2,7 @@ #define slic3r_GLSelectionRectangle_hpp_ #include "libslic3r/Point.hpp" +#include "GLModel.hpp" namespace Slic3r { namespace GUI { @@ -30,7 +31,7 @@ class GLSelectionRectangle { // Disables the rectangle. void stop_dragging(); - void render(const GLCanvas3D& canvas) const; + void render(const GLCanvas3D& canvas); bool is_dragging() const { return m_state != Off; } EState get_state() const { return m_state; } @@ -43,9 +44,12 @@ class GLSelectionRectangle { float get_bottom() const { return std::min(m_start_corner(1), m_end_corner(1)); } private: - EState m_state = Off; - Vec2d m_start_corner; - Vec2d m_end_corner; + EState m_state{ Off }; + Vec2d m_start_corner{ Vec2d::Zero() }; + Vec2d m_end_corner{ Vec2d::Zero() }; + GLModel m_rectangle; + Vec2d m_old_start_corner{ Vec2d::Zero() }; + Vec2d m_old_end_corner{ Vec2d::Zero() }; }; diff --git a/src/slic3r/GUI/GLShadersManager.cpp b/src/slic3r/GUI/GLShadersManager.cpp index c5c3558ebb9..6b39c44f58f 100644 --- a/src/slic3r/GUI/GLShadersManager.cpp +++ b/src/slic3r/GUI/GLShadersManager.cpp @@ -33,7 +33,8 @@ std::pair GLShadersManager::init() bool valid = true; - // basic shader, used to render selection bbox + // basic shader, used to render selection bbox, gizmo cut plane and grabbers connections, + // gizmo move grabbers connections, gizmo scale grabbers connections valid &= append_shader("flat", { "flat.vs", "flat.fs" }); // used to render bed axes and model, selection hints, gcode sequential view marker model, preview shells, options in gcode preview valid &= append_shader("gouraud_light", { "gouraud_light.vs", "gouraud_light.fs" }); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp b/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp index 49622d84c53..b9dc5770d4a 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp @@ -105,7 +105,7 @@ bool GLGizmoFdmSupports::on_init() return true; } -void GLGizmoFdmSupports::render_painter_gizmo() const +void GLGizmoFdmSupports::render_painter_gizmo() { const Selection& selection = m_parent.get_selection(); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.hpp b/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.hpp index 6960a81dc62..23e782fa1ce 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.hpp @@ -15,7 +15,7 @@ class GLGizmoFdmSupports : public GLGizmoPainterBase public: GLGizmoFdmSupports(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id); - void render_painter_gizmo() const override; + void render_painter_gizmo() override; //BBS: add edit state enum EditState { diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp index 3dbb020fe6a..30bc71f8e61 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp @@ -146,7 +146,7 @@ GLGizmoMmuSegmentation::GLGizmoMmuSegmentation(GLCanvas3D& parent, const std::st { } -void GLGizmoMmuSegmentation::render_painter_gizmo() const +void GLGizmoMmuSegmentation::render_painter_gizmo() { const Selection& selection = m_parent.get_selection(); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.hpp b/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.hpp index e7ec8d7bc28..7457d971014 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.hpp @@ -67,7 +67,7 @@ class GLGizmoMmuSegmentation : public GLGizmoPainterBase GLGizmoMmuSegmentation(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id); ~GLGizmoMmuSegmentation() override = default; - void render_painter_gizmo() const override; + void render_painter_gizmo() override; void set_painter_gizmo_data(const Selection& selection) override; diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMove.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMove.cpp index 62fc1dc6ffb..483c833d742 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMove.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMove.cpp @@ -23,11 +23,6 @@ const double GLGizmoMove3D::Offset = 10.0; //BBS: GUI refactor: add obj manipulation GLGizmoMove3D::GLGizmoMove3D(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id, GizmoObjectManipulation* obj_manipulation) : GLGizmoBase(parent, icon_filename, sprite_id) - , m_displacement(Vec3d::Zero()) - , m_snap_step(1.0) - , m_starting_drag_position(Vec3d::Zero()) - , m_starting_box_center(Vec3d::Zero()) - , m_starting_box_bottom_center(Vec3d::Zero()) //BBS: GUI refactor: add obj manipulation , m_object_manipulation(obj_manipulation) { @@ -137,25 +132,57 @@ void GLGizmoMove3D::on_render() glsafe(::glLineWidth((m_hover_id != -1) ? 2.0f : 1.5f)); - // draw grabbers - for (unsigned int i = 0; i < 3; ++i) { - if (m_grabbers[i].enabled) render_grabber_extension((Axis) i, box, false); - } + auto render_grabber_connection = [this, ¢er](unsigned int id) { + if (m_grabbers[id].enabled) { + if (!m_grabber_connections[id].model.is_initialized() || !m_grabber_connections[id].old_center.isApprox(center)) { + m_grabber_connections[id].old_center = center; + m_grabber_connections[id].model.reset(); + + GLModel::InitializationData init_data; + GUI::GLModel::InitializationData::Entity entity; + entity.type = GUI::GLModel::PrimitiveType::Lines; + entity.positions.reserve(2); + entity.positions.emplace_back(center.cast()); + entity.positions.emplace_back(m_grabbers[id].center.cast()); + + entity.normals.reserve(2); + for (size_t j = 0; j < 2; ++j) { + entity.normals.emplace_back(Vec3f::UnitZ()); + } + + entity.indices.reserve(2); + entity.indices.emplace_back(0); + entity.indices.emplace_back(1); + + init_data.entities.emplace_back(entity); + m_grabber_connections[id].model.init_from(init_data); + m_grabber_connections[id].model.set_color(-1, AXES_COLOR[id]); + } - // draw axes line - // draw axes - for (unsigned int i = 0; i < 3; ++i) { - if (m_grabbers[i].enabled) { - glsafe(::glColor4fv(AXES_COLOR[i].data())); glLineStipple(1, 0x0FFF); glEnable(GL_LINE_STIPPLE); - ::glBegin(GL_LINES); - ::glVertex3dv(center.data()); - // use extension center - ::glVertex3dv(m_grabbers[i].center.data()); - glsafe(::glEnd()); + m_grabber_connections[id].model.render(); glDisable(GL_LINE_STIPPLE); } + }; + + GLShaderProgram* shader = wxGetApp().get_shader("flat"); + if (shader != nullptr) { + shader->start_using(); + + // draw axes line + // draw axes + for (unsigned int i = 0; i < 3; ++i) { + render_grabber_connection(i); + } + + shader->stop_using(); + } + + // draw grabbers + for (unsigned int i = 0; i < 3; ++i) { + if (m_grabbers[i].enabled) + render_grabber_extension((Axis) i, box, false); } } diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMove.hpp b/src/slic3r/GUI/Gizmos/GLGizmoMove.hpp index 21d19b4465a..70ae525f78c 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMove.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMove.hpp @@ -15,15 +15,19 @@ class GLGizmoMove3D : public GLGizmoBase { static const double Offset; - Vec3d m_displacement; - - double m_snap_step; - - Vec3d m_starting_drag_position; - Vec3d m_starting_box_center; - Vec3d m_starting_box_bottom_center; + Vec3d m_displacement{ Vec3d::Zero() }; + double m_snap_step{ 1.0 }; + Vec3d m_starting_drag_position{ Vec3d::Zero() }; + Vec3d m_starting_box_center{ Vec3d::Zero() }; + Vec3d m_starting_box_bottom_center{ Vec3d::Zero() }; GLModel m_vbo_cone; + struct GrabberConnection + { + GLModel model; + Vec3d old_center{ Vec3d::Zero() }; + }; + std::array m_grabber_connections; //BBS: add size adjust related GizmoObjectManipulation* m_object_manipulation; diff --git a/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp b/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp index 7e68b73730d..53fc03edcba 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp @@ -119,7 +119,7 @@ void GLGizmoPainterBase::render_triangles(const Selection& selection) const } -void GLGizmoPainterBase::render_cursor() const +void GLGizmoPainterBase::render_cursor() { // First check that the mouse pointer is on an object. const ModelObject* mo = m_c->selection_info()->model_object(); @@ -159,31 +159,22 @@ void GLGizmoPainterBase::render_cursor() const -void GLGizmoPainterBase::render_cursor_circle() const +void GLGizmoPainterBase::render_cursor_circle() { const Camera &camera = wxGetApp().plater()->get_camera(); - auto zoom = (float) camera.get_zoom(); - float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f; + const float zoom = float(camera.get_zoom()); + const float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f; - Size cnv_size = m_parent.get_canvas_size(); - float cnv_half_width = 0.5f * (float) cnv_size.get_width(); - float cnv_half_height = 0.5f * (float) cnv_size.get_height(); - if ((cnv_half_width == 0.0f) || (cnv_half_height == 0.0f)) + const Size cnv_size = m_parent.get_canvas_size(); + const float cnv_half_width = 0.5f * float(cnv_size.get_width()); + const float cnv_half_height = 0.5f * float(cnv_size.get_height()); + if (cnv_half_width == 0.0f || cnv_half_height == 0.0f) return; - Vec2d mouse_pos(m_parent.get_local_mouse_position()(0), m_parent.get_local_mouse_position()(1)); - Vec2d center(mouse_pos(0) - cnv_half_width, cnv_half_height - mouse_pos(1)); + const Vec2d mouse_pos(m_parent.get_local_mouse_position().x(), m_parent.get_local_mouse_position().y()); + Vec2d center(mouse_pos.x() - cnv_half_width, cnv_half_height - mouse_pos.y()); center = center * inv_zoom; glsafe(::glLineWidth(1.5f)); - - // BBS - ColorRGBA render_color = this->get_cursor_hover_color(); - if (m_button_down == Button::Left) - render_color = this->get_cursor_sphere_left_button_color(); - else if (m_button_down == Button::Right) - render_color = this->get_cursor_sphere_right_button_color(); - glsafe(::glColor4fv(render_color.data())); - glsafe(::glDisable(GL_DEPTH_TEST)); glsafe(::glPushMatrix()); @@ -191,17 +182,46 @@ void GLGizmoPainterBase::render_cursor_circle() const // ensure that the circle is renderered inside the frustrum glsafe(::glTranslated(0.0, 0.0, -(camera.get_near_z() + 0.5))); // ensure that the overlay fits the frustrum near z plane - double gui_scale = camera.get_gui_scale(); + const double gui_scale = camera.get_gui_scale(); glsafe(::glScaled(gui_scale, gui_scale, 1.0)); glsafe(::glPushAttrib(GL_ENABLE_BIT)); glsafe(::glLineStipple(4, 0xAAAA)); glsafe(::glEnable(GL_LINE_STIPPLE)); - ::glBegin(GL_LINE_LOOP); - for (double angle=0; angle<2*M_PI; angle+=M_PI/20.) - ::glVertex2f(GLfloat(center.x()+m_cursor_radius*cos(angle)), GLfloat(center.y()+m_cursor_radius*sin(angle))); - glsafe(::glEnd()); + if (!m_circle.is_initialized() || !m_old_center.isApprox(center) || std::abs(m_old_cursor_radius - m_cursor_radius) > EPSILON) { + m_old_center = center; + m_old_cursor_radius = m_cursor_radius; + m_circle.reset(); + + GLModel::InitializationData init_data; + GLModel::InitializationData::Entity entity; + entity.type = GLModel::PrimitiveType::LineLoop; + static const unsigned int StepsCount = 32; + static const float StepSize = 2.0f * float(PI) / float(StepsCount); + entity.positions.reserve(StepsCount); + entity.normals.reserve(StepsCount); + entity.indices.reserve(StepsCount); + for (unsigned int i = 0; i < StepsCount; ++i) { + const float angle = float(i * StepSize); + entity.positions.emplace_back(center.x() + ::cos(angle) * m_cursor_radius, center.y() + ::sin(angle) * m_cursor_radius, 0.0f); + entity.normals.emplace_back(Vec3f::UnitZ()); + entity.indices.emplace_back(i); + } + + init_data.entities.emplace_back(entity); + m_circle.init_from(init_data); + } + + // BBS + ColorRGBA render_color = this->get_cursor_hover_color(); + if (m_button_down == Button::Left) + render_color = this->get_cursor_sphere_left_button_color(); + else if (m_button_down == Button::Right) + render_color = this->get_cursor_sphere_right_button_color(); + + m_circle.set_color(-1, render_color); + m_circle.render(); glsafe(::glPopAttrib()); glsafe(::glPopMatrix()); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.hpp b/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.hpp index de92a426c68..d953c5653ca 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.hpp @@ -225,7 +225,7 @@ class GLGizmoPainterBase : public GLGizmoBase // from usual on_render method allows to render them before transparent // objects, so they can be seen inside them. The usual on_render is called // after all volumes (including transparent ones) are rendered. - virtual void render_painter_gizmo() const = 0; + virtual void render_painter_gizmo() = 0; virtual const float get_cursor_radius_min() const { return CursorRadiusMin; } virtual const float get_cursor_radius_max() const { return CursorRadiusMax; } @@ -238,8 +238,8 @@ class GLGizmoPainterBase : public GLGizmoBase protected: virtual void render_triangles(const Selection& selection) const; - void render_cursor() const; - void render_cursor_circle() const; + void render_cursor(); + void render_cursor_circle(); void render_cursor_sphere(const Transform3d& trafo) const; // BBS void render_cursor_height_range(const Transform3d& trafo) const; @@ -300,6 +300,9 @@ class GLGizmoPainterBase : public GLGizmoBase bool m_paint_on_overhangs_only = false; float m_highlight_by_angle_threshold_deg = 0.f; + GLModel m_circle; + Vec2d m_old_center{ Vec2d::Zero() }; + float m_old_cursor_radius{ 0.0f }; static constexpr float SmartFillAngleMin = 0.0f; static constexpr float SmartFillAngleMax = 90.f; static constexpr float SmartFillAngleStep = 1.f; diff --git a/src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp b/src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp index 4a142ba9262..534070f6440 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp @@ -17,10 +17,9 @@ namespace GUI { const float GLGizmoRotate::Offset = 5.0f; -const unsigned int GLGizmoRotate::CircleResolution = 64; const unsigned int GLGizmoRotate::AngleResolution = 64; const unsigned int GLGizmoRotate::ScaleStepsCount = 72; -const float GLGizmoRotate::ScaleStepRad = 2.0f * (float)PI / GLGizmoRotate::ScaleStepsCount; +const float GLGizmoRotate::ScaleStepRad = 2.0f * float(PI) / GLGizmoRotate::ScaleStepsCount; const unsigned int GLGizmoRotate::ScaleLongEvery = 2; const float GLGizmoRotate::ScaleLongTooth = 0.1f; // in percent of radius const unsigned int GLGizmoRotate::SnapRegionsCount = 8; @@ -30,15 +29,7 @@ const float GLGizmoRotate::GrabberOffset = 0.15f; // in percent of radius GLGizmoRotate::GLGizmoRotate(GLCanvas3D& parent, GLGizmoRotate::Axis axis) : GLGizmoBase(parent, "", -1) , m_axis(axis) - , m_angle(0.0) - , m_center(0.0, 0.0, 0.0) - , m_radius(0.0f) - , m_snap_coarse_in_radius(0.0f) - , m_snap_coarse_out_radius(0.0f) - , m_snap_fine_in_radius(0.0f) - , m_snap_fine_out_radius(0.0f) -{ -} +{} GLGizmoRotate::GLGizmoRotate(const GLGizmoRotate& other) : GLGizmoBase(other.m_parent, other.m_icon_filename, other.m_sprite_id) @@ -56,7 +47,7 @@ GLGizmoRotate::GLGizmoRotate(const GLGizmoRotate& other) void GLGizmoRotate::set_angle(double angle) { - if (std::abs(angle - 2.0 * (double)PI) < EPSILON) + if (std::abs(angle - 2.0 * double(PI)) < EPSILON) angle = 0.0; m_angle = angle; @@ -71,7 +62,7 @@ std::string GLGizmoRotate::get_tooltip() const case Y: { axis = "Y"; break; } case Z: { axis = "Z"; break; } } - return (m_hover_id == 0 || m_grabbers[0].dragging) ? axis + ": " + format((float)Geometry::rad2deg(m_angle), 2) : ""; + return (m_hover_id == 0 || m_grabbers.front().dragging) ? axis + ": " + format(float(Geometry::rad2deg(m_angle)), 2) : ""; } bool GLGizmoRotate::on_init() @@ -94,34 +85,31 @@ void GLGizmoRotate::on_start_dragging() void GLGizmoRotate::on_update(const UpdateData& data) { - Vec2d mouse_pos = to_2d(mouse_position_in_local_plane(data.mouse_ray, m_parent.get_selection())); + const Vec2d mouse_pos = to_2d(mouse_position_in_local_plane(data.mouse_ray, m_parent.get_selection())); - Vec2d orig_dir = Vec2d::UnitX(); - Vec2d new_dir = mouse_pos.normalized(); + const Vec2d orig_dir = Vec2d::UnitX(); + const Vec2d new_dir = mouse_pos.normalized(); double theta = ::acos(std::clamp(new_dir.dot(orig_dir), -1.0, 1.0)); if (cross2(orig_dir, new_dir) < 0.0) theta = 2.0 * (double)PI - theta; - double len = mouse_pos.norm(); + const double len = mouse_pos.norm(); // snap to coarse snap region - if ((m_snap_coarse_in_radius <= len) && (len <= m_snap_coarse_out_radius)) - { - double step = 2.0 * (double)PI / (double)SnapRegionsCount; - theta = step * (double)std::round(theta / step); + if (m_snap_coarse_in_radius <= len && len <= m_snap_coarse_out_radius) { + const double step = 2.0 * double(PI) / double(SnapRegionsCount); + theta = step * std::round(theta / step); } - else - { + else { // snap to fine snap region (scale) - if ((m_snap_fine_in_radius <= len) && (len <= m_snap_fine_out_radius)) - { - double step = 2.0 * (double)PI / (double)ScaleStepsCount; - theta = step * (double)std::round(theta / step); + if (m_snap_fine_in_radius <= len && len <= m_snap_fine_out_radius) { + const double step = 2.0 * double(PI) / double(ScaleStepsCount); + theta = step * std::round(theta / step); } } - if (theta == 2.0 * (double)PI) + if (theta == 2.0 * double(PI)) theta = 0.0; m_angle = theta; @@ -129,13 +117,13 @@ void GLGizmoRotate::on_update(const UpdateData& data) void GLGizmoRotate::on_render() { - if (!m_grabbers[0].enabled) + if (!m_grabbers.front().enabled) return; const Selection& selection = m_parent.get_selection(); const BoundingBoxf3& box = selection.get_bounding_box(); - if (m_hover_id != 0 && !m_grabbers[0].dragging) { + if (m_hover_id != 0 && !m_grabbers.front().dragging) { m_center = m_custom_center == Vec3d::Zero() ? box.center() : m_custom_center; m_radius = Offset + box.radius(); m_snap_coarse_in_radius = m_radius / 3.0f; @@ -144,26 +132,41 @@ void GLGizmoRotate::on_render() m_snap_fine_out_radius = m_radius * (1.0f + ScaleLongTooth); } + const double grabber_radius = (double)m_radius * (1.0 + (double)GrabberOffset); + m_grabbers.front().center = Vec3d(::cos(m_angle) * grabber_radius, ::sin(m_angle) * grabber_radius, 0.0); + m_grabbers.front().angles.z() = m_angle; + m_grabbers.front().color = AXES_COLOR[m_axis]; + m_grabbers.front().hover_color = AXES_HOVER_COLOR[m_axis]; + glsafe(::glEnable(GL_DEPTH_TEST)); glsafe(::glPushMatrix()); transform_to_local(selection); glsafe(::glLineWidth((m_hover_id != -1) ? 2.0f : 1.5f)); - glsafe(::glColor4fv((m_hover_id != -1) ? m_drag_color.data() : m_highlight_color.data())); + GLShaderProgram* shader = wxGetApp().get_shader("flat"); + if (shader != nullptr) { + shader->start_using(); - render_circle(); + const float radius = Offset + m_parent.get_selection().get_bounding_box().radius(); + const bool radius_changed = std::abs(m_old_radius - radius) > EPSILON; + m_old_radius = radius; - if (m_hover_id != -1) { - render_scale(); - render_snap_radii(); - render_reference_radius(); - } + ColorRGBA color((m_hover_id != -1) ? m_drag_color : m_highlight_color); + render_circle(color, radius_changed); + if (m_hover_id != -1) { + const bool hover_radius_changed = std::abs(m_old_hover_radius - radius) > EPSILON; + m_old_hover_radius = radius; - glsafe(::glColor4fv(m_highlight_color.data())); + render_scale(color, hover_radius_changed); + render_snap_radii(color, hover_radius_changed); + render_reference_radius(color, hover_radius_changed); + render_angle_arc(m_highlight_color, hover_radius_changed); + } - if (m_hover_id != -1) - render_angle(); + render_grabber_connection(color, radius_changed); + shader->stop_using(); + } render_grabber(box); render_grabber_extension(box, false); @@ -220,138 +223,223 @@ void GLGizmoRotate3D::load_rotoptimize_state() } } -void GLGizmoRotate::render_circle() const +void GLGizmoRotate::render_circle(const ColorRGBA& color, bool radius_changed) { - ::glBegin(GL_LINE_LOOP); - for (unsigned int i = 0; i < ScaleStepsCount; ++i) - { - float angle = (float)i * ScaleStepRad; - float x = ::cos(angle) * m_radius; - float y = ::sin(angle) * m_radius; - float z = 0.0f; - ::glVertex3f((GLfloat)x, (GLfloat)y, (GLfloat)z); + if (!m_circle.is_initialized() || radius_changed) { + m_circle.reset(); + + GLModel::InitializationData init_data; + GLModel::InitializationData::Entity entity; + entity.type = GLModel::PrimitiveType::LineLoop; + entity.positions.reserve(ScaleStepsCount); + entity.normals.reserve(ScaleStepsCount); + entity.indices.reserve(ScaleStepsCount); + for (unsigned int i = 0; i < ScaleStepsCount; ++i) { + const float angle = float(i * ScaleStepRad); + entity.positions.emplace_back(::cos(angle) * m_radius, ::sin(angle) * m_radius, 0.0f); + entity.normals.emplace_back(Vec3f::UnitZ()); + entity.indices.emplace_back(i); + } + + init_data.entities.emplace_back(entity); + m_circle.init_from(init_data); } - glsafe(::glEnd()); + + m_circle.set_color(-1, color); + m_circle.render(); } -void GLGizmoRotate::render_scale() const +void GLGizmoRotate::render_scale(const ColorRGBA& color, bool radius_changed) { - float out_radius_long = m_snap_fine_out_radius; - float out_radius_short = m_radius * (1.0f + 0.5f * ScaleLongTooth); + const float out_radius_long = m_snap_fine_out_radius; + const float out_radius_short = m_radius * (1.0f + 0.5f * ScaleLongTooth); + + if (!m_scale.is_initialized() || radius_changed) { + m_scale.reset(); + + GLModel::InitializationData init_data; + GLModel::InitializationData::Entity entity; + entity.type = GLModel::PrimitiveType::Lines; + entity.positions.reserve(2 * ScaleStepsCount); + entity.normals.reserve(2 * ScaleStepsCount); + entity.indices.reserve(2 * ScaleStepsCount); + for (unsigned int i = 0; i < ScaleStepsCount; ++i) { + const float angle = float(i * ScaleStepRad); + const float cosa = ::cos(angle); + const float sina = ::sin(angle); + const float in_x = cosa * m_radius; + const float in_y = sina * m_radius; + const float out_x = (i % ScaleLongEvery == 0) ? cosa * out_radius_long : cosa * out_radius_short; + const float out_y = (i % ScaleLongEvery == 0) ? sina * out_radius_long : sina * out_radius_short; + + entity.positions.emplace_back(in_x, in_y, 0.0f); + entity.positions.emplace_back(out_x, out_y, 0.0f); + entity.normals.emplace_back(Vec3f::UnitZ()); + entity.normals.emplace_back(Vec3f::UnitZ()); + entity.indices.emplace_back(i * 2 + 0); + entity.indices.emplace_back(i * 2 + 1); + } - ::glBegin(GL_LINES); - for (unsigned int i = 0; i < ScaleStepsCount; ++i) - { - float angle = (float)i * ScaleStepRad; - float cosa = ::cos(angle); - float sina = ::sin(angle); - float in_x = cosa * m_radius; - float in_y = sina * m_radius; - float in_z = 0.0f; - float out_x = (i % ScaleLongEvery == 0) ? cosa * out_radius_long : cosa * out_radius_short; - float out_y = (i % ScaleLongEvery == 0) ? sina * out_radius_long : sina * out_radius_short; - float out_z = 0.0f; - ::glVertex3f((GLfloat)in_x, (GLfloat)in_y, (GLfloat)in_z); - ::glVertex3f((GLfloat)out_x, (GLfloat)out_y, (GLfloat)out_z); - } - glsafe(::glEnd()); + init_data.entities.emplace_back(entity); + m_scale.init_from(init_data); } -void GLGizmoRotate::render_snap_radii() const -{ - float step = 2.0f * (float)PI / (float)SnapRegionsCount; + m_scale.set_color(-1, color); + m_scale.render(); +} - float in_radius = m_radius / 3.0f; - float out_radius = 2.0f * in_radius; +void GLGizmoRotate::render_snap_radii(const ColorRGBA& color, bool radius_changed) +{ + const float step = 2.0f * float(PI) / float(SnapRegionsCount); + const float in_radius = m_radius / 3.0f; + const float out_radius = 2.0f * in_radius; + + if (!m_snap_radii.is_initialized() || radius_changed) { + m_snap_radii.reset(); + + GLModel::InitializationData init_data; + GLModel::InitializationData::Entity entity; + entity.type = GLModel::PrimitiveType::Lines; + entity.positions.reserve(2 * ScaleStepsCount); + entity.normals.reserve(2 * ScaleStepsCount); + entity.indices.reserve(2 * ScaleStepsCount); + for (unsigned int i = 0; i < ScaleStepsCount; ++i) { + const float angle = float(i * step); + const float cosa = ::cos(angle); + const float sina = ::sin(angle); + const float in_x = cosa * in_radius; + const float in_y = sina * in_radius; + const float out_x = cosa * out_radius; + const float out_y = sina * out_radius; + + entity.positions.emplace_back(in_x, in_y, 0.0f); + entity.positions.emplace_back(out_x, out_y, 0.0f); + entity.normals.emplace_back(Vec3f::UnitZ()); + entity.normals.emplace_back(Vec3f::UnitZ()); + entity.indices.emplace_back(i * 2 + 0); + entity.indices.emplace_back(i * 2 + 1); + } - ::glBegin(GL_LINES); - for (unsigned int i = 0; i < SnapRegionsCount; ++i) - { - float angle = (float)i * step; - float cosa = ::cos(angle); - float sina = ::sin(angle); - float in_x = cosa * in_radius; - float in_y = sina * in_radius; - float in_z = 0.0f; - float out_x = cosa * out_radius; - float out_y = sina * out_radius; - float out_z = 0.0f; - ::glVertex3f((GLfloat)in_x, (GLfloat)in_y, (GLfloat)in_z); - ::glVertex3f((GLfloat)out_x, (GLfloat)out_y, (GLfloat)out_z); + init_data.entities.emplace_back(entity); + m_snap_radii.init_from(init_data); } - glsafe(::glEnd()); + + m_snap_radii.set_color(-1, color); + m_snap_radii.render(); } -void GLGizmoRotate::render_reference_radius() const +void GLGizmoRotate::render_reference_radius(const ColorRGBA& color, bool radius_changed) { - ::glBegin(GL_LINES); - ::glVertex3f(0.0f, 0.0f, 0.0f); - ::glVertex3f((GLfloat)(m_radius * (1.0f + GrabberOffset)), 0.0f, 0.0f); - glsafe(::glEnd()); + if (!m_reference_radius.is_initialized() || radius_changed) { + m_reference_radius.reset(); + + GLModel::InitializationData init_data; + GLModel::InitializationData::Entity entity; + entity.type = GLModel::PrimitiveType::Lines; + entity.positions.reserve(2); + entity.positions.emplace_back(0.0f, 0.0f, 0.0f); + entity.positions.emplace_back(m_radius * (1.0f + GrabberOffset), 0.0f, 0.0f); + entity.normals.reserve(2); + entity.normals.emplace_back(Vec3f::UnitZ()); + entity.normals.emplace_back(Vec3f::UnitZ()); + entity.indices.reserve(2); + entity.indices.emplace_back(0); + entity.indices.emplace_back(1); + + init_data.entities.emplace_back(entity); + m_reference_radius.init_from(init_data); + } + + m_reference_radius.set_color(-1, color); + m_reference_radius.render(); } -void GLGizmoRotate::render_angle() const +void GLGizmoRotate::render_angle_arc(const ColorRGBA& color, bool radius_changed) { - float step_angle = (float)m_angle / AngleResolution; - float ex_radius = m_radius * (1.0f + GrabberOffset); + const float step_angle = float(m_angle) / float(AngleResolution); + const float ex_radius = m_radius * (1.0f + GrabberOffset); + + if (!m_angle_arc.is_initialized() || radius_changed) { + m_angle_arc.reset(); + + GLModel::InitializationData init_data; + GLModel::InitializationData::Entity entity; + entity.type = GLModel::PrimitiveType::LineStrip; + entity.positions.reserve(1 + AngleResolution); + entity.normals.reserve(1 + AngleResolution); + entity.indices.reserve(1 + AngleResolution); + for (unsigned int i = 0; i <= AngleResolution; ++i) { + const float angle = float(i) * step_angle; + entity.positions.emplace_back(::cos(angle) * ex_radius, ::sin(angle) * ex_radius, 0.0f); + entity.normals.emplace_back(Vec3f::UnitZ()); + entity.indices.emplace_back(i); + } - ::glBegin(GL_LINE_STRIP); - for (unsigned int i = 0; i <= AngleResolution; ++i) - { - float angle = (float)i * step_angle; - float x = ::cos(angle) * ex_radius; - float y = ::sin(angle) * ex_radius; - float z = 0.0f; - ::glVertex3f((GLfloat)x, (GLfloat)y, (GLfloat)z); + init_data.entities.emplace_back(entity); + m_angle_arc.init_from(init_data); } - glsafe(::glEnd()); + + m_angle_arc.set_color(-1, color); + m_angle_arc.render(); } -void GLGizmoRotate::render_grabber(const BoundingBoxf3& box) const +void GLGizmoRotate::render_grabber_connection(const ColorRGBA& color, bool radius_changed) { - double grabber_radius = (double)m_radius * (1.0 + (double)GrabberOffset); - m_grabbers[0].center = Vec3d(::cos(m_angle) * grabber_radius, ::sin(m_angle) * grabber_radius, 0.0); - m_grabbers[0].angles(2) = m_angle; - m_grabbers[0].color = AXES_COLOR[m_axis]; - m_grabbers[0].hover_color = AXES_HOVER_COLOR[m_axis]; - - glsafe(::glColor4fv((m_hover_id != -1) ? m_drag_color.data() : m_highlight_color.data())); + if (!m_grabber_connection.model.is_initialized() || radius_changed || !m_grabber_connection.old_center.isApprox(m_grabbers.front().center)) { + m_grabber_connection.model.reset(); + m_grabber_connection.old_center = m_grabbers.front().center; + + GLModel::InitializationData init_data; + GLModel::InitializationData::Entity entity; + entity.type = GLModel::PrimitiveType::Lines; + entity.positions.reserve(2); + entity.positions.emplace_back(0.0f, 0.0f, 0.0f); + entity.positions.emplace_back(m_grabbers.front().center.cast()); + entity.normals.reserve(2); + entity.normals.emplace_back(Vec3f::UnitZ()); + entity.normals.emplace_back(Vec3f::UnitZ()); + entity.indices.reserve(2); + entity.indices.emplace_back(0); + entity.indices.emplace_back(1); + + init_data.entities.emplace_back(entity); + m_grabber_connection.model.init_from(init_data); + } - ::glBegin(GL_LINES); - ::glVertex3f(0.0f, 0.0f, 0.0f); - ::glVertex3dv(m_grabbers[0].center.data()); - glsafe(::glEnd()); + m_grabber_connection.model.set_color(-1, color); + m_grabber_connection.model.render(); +} - m_grabbers[0].color = m_highlight_color; +void GLGizmoRotate::render_grabber(const BoundingBoxf3& box) const +{ + m_grabbers.front().color = m_highlight_color; render_grabbers(box); } -void GLGizmoRotate::render_grabber_extension(const BoundingBoxf3& box, bool picking) const +void GLGizmoRotate::render_grabber_extension(const BoundingBoxf3& box, bool picking) { double size = 0.75 * GLGizmoBase::Grabber::FixedGrabberSize * GLGizmoBase::INV_ZOOM; //float mean_size = (float)((box.size()(0) + box.size()(1) + box.size()(2)) / 3.0); //double size = m_dragging ? (double)m_grabbers[0].get_dragging_half_size(mean_size) : (double)m_grabbers[0].get_half_size(mean_size); - ColorRGBA color = m_grabbers[0].color; - if (!picking && m_hover_id != -1) { - color = m_grabbers[0].hover_color; - //color[0] = 1.0f - color[0]; - //color[1] = 1.0f - color[1]; - //color[2] = 1.0f - color[2]; - } + ColorRGBA color = m_grabbers.front().color; + if (!picking && m_hover_id != -1) + color = m_grabbers.front().hover_color; GLShaderProgram* shader = wxGetApp().get_shader("gouraud_light"); if (shader == nullptr) return; - const_cast(&m_cone)->set_color(-1, color); + m_cone.set_color(-1, color); if (!picking) { shader->start_using(); shader->set_uniform("emission_factor", 0.1f); } + const Vec3d& center = m_grabbers.front().center; + glsafe(::glPushMatrix()); - glsafe(::glTranslated(m_grabbers[0].center.x(), m_grabbers[0].center.y(), m_grabbers[0].center.z())); + glsafe(::glTranslated(center.x(), center.y(), center.z())); glsafe(::glRotated(Geometry::rad2deg(m_angle), 0.0, 0.0, 1.0)); glsafe(::glRotated(90.0, 1.0, 0.0, 0.0)); glsafe(::glTranslated(0.0, 0.0, 1.5 * size)); @@ -359,7 +447,7 @@ void GLGizmoRotate::render_grabber_extension(const BoundingBoxf3& box, bool pick m_cone.render(); glsafe(::glPopMatrix()); glsafe(::glPushMatrix()); - glsafe(::glTranslated(m_grabbers[0].center.x(), m_grabbers[0].center.y(), m_grabbers[0].center.z())); + glsafe(::glTranslated(center.x(), center.y(), center.z())); glsafe(::glRotated(Geometry::rad2deg(m_angle), 0.0, 0.0, 1.0)); glsafe(::glRotated(-90.0, 1.0, 0.0, 0.0)); glsafe(::glTranslated(0.0, 0.0, 1.5 * size)); @@ -376,7 +464,7 @@ void GLGizmoRotate::transform_to_local(const Selection& selection) const glsafe(::glTranslated(m_center(0), m_center(1), m_center(2))); if (selection.is_single_volume() || selection.is_single_modifier() || selection.requires_local_axes()) { - Transform3d orient_matrix = selection.get_volume(*selection.get_volume_idxs().begin())->get_instance_transformation().get_matrix(true, false, true, true); + const Transform3d orient_matrix = selection.get_volume(*selection.get_volume_idxs().begin())->get_instance_transformation().get_matrix(true, false, true, true); glsafe(::glMultMatrixd(orient_matrix.data())); } @@ -405,7 +493,7 @@ void GLGizmoRotate::transform_to_local(const Selection& selection) const Vec3d GLGizmoRotate::mouse_position_in_local_plane(const Linef3& mouse_ray, const Selection& selection) const { - double half_pi = 0.5 * (double)PI; + double half_pi = 0.5 * double(PI); Transform3d m = Transform3d::Identity(); @@ -486,13 +574,13 @@ bool GLGizmoRotate3D::on_is_activable() const void GLGizmoRotate3D::on_start_dragging() { - if ((0 <= m_hover_id) && (m_hover_id < 3)) + if (0 <= m_hover_id && m_hover_id < 3) m_gizmos[m_hover_id].start_dragging(); } void GLGizmoRotate3D::on_stop_dragging() { - if ((0 <= m_hover_id) && (m_hover_id < 3)) + if (0 <= m_hover_id && m_hover_id < 3) m_gizmos[m_hover_id].stop_dragging(); } diff --git a/src/slic3r/GUI/Gizmos/GLGizmoRotate.hpp b/src/slic3r/GUI/Gizmos/GLGizmoRotate.hpp index 0f426f26f4e..bc546a89567 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoRotate.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoRotate.hpp @@ -13,7 +13,6 @@ namespace GUI { class GLGizmoRotate : public GLGizmoBase { static const float Offset; - static const unsigned int CircleResolution; static const unsigned int AngleResolution; static const unsigned int ScaleStepsCount; static const float ScaleStepRad; @@ -32,18 +31,29 @@ class GLGizmoRotate : public GLGizmoBase private: Axis m_axis; - double m_angle; - - mutable Vec3d m_custom_center{Vec3d::Zero()}; - mutable Vec3d m_center; - mutable float m_radius; - - mutable float m_snap_coarse_in_radius; - mutable float m_snap_coarse_out_radius; - mutable float m_snap_fine_in_radius; - mutable float m_snap_fine_out_radius; + double m_angle{ 0.0 }; + Vec3d m_custom_center{Vec3d::Zero()}; + Vec3d m_center{ Vec3d::Zero() }; + float m_radius{ 0.0f }; + float m_snap_coarse_in_radius{ 0.0f }; + float m_snap_coarse_out_radius{ 0.0f }; + float m_snap_fine_in_radius{ 0.0f }; + float m_snap_fine_out_radius{ 0.0f }; GLModel m_cone; + GLModel m_circle; + GLModel m_scale; + GLModel m_snap_radii; + GLModel m_reference_radius; + GLModel m_angle_arc; + struct GrabberConnection + { + GLModel model; + Vec3d old_center{ Vec3d::Zero() }; + }; + GrabberConnection m_grabber_connection; + float m_old_radius{ 0.0f }; + float m_old_hover_radius{ 0.0f }; public: GLGizmoRotate(GLCanvas3D& parent, Axis axis); @@ -66,13 +76,14 @@ class GLGizmoRotate : public GLGizmoBase void on_render_for_picking() override; private: - void render_circle() const; - void render_scale() const; - void render_snap_radii() const; - void render_reference_radius() const; - void render_angle() const; + void render_circle(const ColorRGBA& color, bool radius_changed); + void render_scale(const ColorRGBA& color, bool radius_changed); + void render_snap_radii(const ColorRGBA& color, bool radius_changed); + void render_reference_radius(const ColorRGBA& color, bool radius_changed); + void render_angle_arc(const ColorRGBA& color, bool radius_changed); + void render_grabber_connection(const ColorRGBA& color, bool radius_changed); void render_grabber(const BoundingBoxf3& box) const; - void render_grabber_extension(const BoundingBoxf3& box, bool picking) const; + void render_grabber_extension(const BoundingBoxf3& box, bool picking); void transform_to_local(const Selection& selection) const; // returns the intersection of the mouse ray with the plane perpendicular to the gizmo axis, in local coordinate @@ -96,8 +107,7 @@ class GLGizmoRotate3D : public GLGizmoBase Vec3d get_rotation() const { return Vec3d(m_gizmos[X].get_angle(), m_gizmos[Y].get_angle(), m_gizmos[Z].get_angle()); } void set_rotation(const Vec3d& rotation) { m_gizmos[X].set_angle(rotation(0)); m_gizmos[Y].set_angle(rotation(1)); m_gizmos[Z].set_angle(rotation(2)); } - std::string get_tooltip() const override - { + std::string get_tooltip() const override { std::string tooltip = m_gizmos[X].get_tooltip(); if (tooltip.empty()) tooltip = m_gizmos[Y].get_tooltip(); @@ -116,38 +126,32 @@ class GLGizmoRotate3D : public GLGizmoBase protected: bool on_init() override; std::string on_get_name() const override; - void on_set_state() override - { + void on_set_state() override { for (GLGizmoRotate& g : m_gizmos) g.set_state(m_state); } - void on_set_hover_id() override - { + void on_set_hover_id() override { for (int i = 0; i < 3; ++i) m_gizmos[i].set_hover_id((m_hover_id == i) ? 0 : -1); } - void on_enable_grabber(unsigned int id) override - { + void on_enable_grabber(unsigned int id) override { if (id < 3) m_gizmos[id].enable_grabber(0); } - void on_disable_grabber(unsigned int id) override - { + void on_disable_grabber(unsigned int id) override { if (id < 3) m_gizmos[id].disable_grabber(0); } bool on_is_activable() const override; void on_start_dragging() override; void on_stop_dragging() override; - void on_update(const UpdateData& data) override - { + void on_update(const UpdateData& data) override { for (GLGizmoRotate& g : m_gizmos) { g.update(data); } } void on_render() override; - void on_render_for_picking() override - { + void on_render_for_picking() override { for (GLGizmoRotate& g : m_gizmos) { g.render_for_picking(); } @@ -157,10 +161,11 @@ class GLGizmoRotate3D : public GLGizmoBase private: - class RotoptimzeWindow { + class RotoptimzeWindow + { ImGuiWrapper *m_imgui = nullptr; - public: + public: struct State { float accuracy = 1.f; int method_id = 0; diff --git a/src/slic3r/GUI/Gizmos/GLGizmoScale.cpp b/src/slic3r/GUI/Gizmos/GLGizmoScale.cpp index 0f98c5dd358..c89af3f0ee8 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoScale.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoScale.cpp @@ -24,12 +24,16 @@ Vec3d GetIntersectionOfRayAndPlane(Vec3d ray_position, Vec3d ray_dir, Vec3d plan //BBS: GUI refactor: add obj manipulation GLGizmoScale3D::GLGizmoScale3D(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id, GizmoObjectManipulation* obj_manipulation) : GLGizmoBase(parent, icon_filename, sprite_id) - , m_scale(Vec3d::Ones()) - , m_offset(Vec3d::Zero()) - , m_snap_step(0.05) //BBS: GUI refactor: add obj manipulation , m_object_manipulation(obj_manipulation) { + m_grabber_connections[0].grabber_indices = { 0, 1 }; + m_grabber_connections[1].grabber_indices = { 2, 3 }; + m_grabber_connections[2].grabber_indices = { 4, 5 }; + m_grabber_connections[3].grabber_indices = { 6, 7 }; + m_grabber_connections[4].grabber_indices = { 7, 8 }; + m_grabber_connections[5].grabber_indices = { 8, 9 }; + m_grabber_connections[6].grabber_indices = { 9, 6 }; } std::string GLGizmoScale3D::get_tooltip() const @@ -46,17 +50,17 @@ std::string GLGizmoScale3D::get_tooltip() const scale = 100.0f * selection.get_volume(*selection.get_volume_idxs().begin())->get_volume_scaling_factor().cast(); if (m_hover_id == 0 || m_hover_id == 1 || m_grabbers[0].dragging || m_grabbers[1].dragging) - return "X: " + format(scale(0), 4) + "%"; + return "X: " + format(scale.x(), 4) + "%"; else if (m_hover_id == 2 || m_hover_id == 3 || m_grabbers[2].dragging || m_grabbers[3].dragging) - return "Y: " + format(scale(1), 4) + "%"; + return "Y: " + format(scale.y(), 4) + "%"; else if (m_hover_id == 4 || m_hover_id == 5 || m_grabbers[4].dragging || m_grabbers[5].dragging) - return "Z: " + format(scale(2), 4) + "%"; + return "Z: " + format(scale.z(), 4) + "%"; else if (m_hover_id == 6 || m_hover_id == 7 || m_hover_id == 8 || m_hover_id == 9 || m_grabbers[6].dragging || m_grabbers[7].dragging || m_grabbers[8].dragging || m_grabbers[9].dragging) { - std::string tooltip = "X: " + format(scale(0), 2) + "%\n"; - tooltip += "Y: " + format(scale(1), 2) + "%\n"; - tooltip += "Z: " + format(scale(2), 2) + "%"; + std::string tooltip = "X: " + format(scale.x(), 2) + "%\n"; + tooltip += "Y: " + format(scale.y(), 2) + "%\n"; + tooltip += "Z: " + format(scale.z(), 2) + "%"; return tooltip; } else @@ -71,8 +75,7 @@ void GLGizmoScale3D::enable_ununiversal_scale(bool enable) bool GLGizmoScale3D::on_init() { - for (int i = 0; i < 10; ++i) - { + for (int i = 0; i < 10; ++i) { m_grabbers.push_back(Grabber()); } @@ -106,8 +109,7 @@ bool GLGizmoScale3D::on_is_activable() const void GLGizmoScale3D::on_start_dragging() { - if (m_hover_id != -1) - { + if (m_hover_id != -1) { m_starting.drag_position = m_grabbers[m_hover_id].center; m_starting.plane_center = m_grabbers[4].center; m_starting.plane_nromal = m_grabbers[5].center - m_grabbers[4].center; @@ -115,22 +117,22 @@ void GLGizmoScale3D::on_start_dragging() m_starting.box = (m_starting.ctrl_down && (m_hover_id < 6)) ? m_box : m_parent.get_selection().get_bounding_box(); const Vec3d& center = m_starting.box.center(); - m_starting.pivots[0] = m_transform * Vec3d(m_starting.box.max(0), center(1), center(2)); - m_starting.pivots[1] = m_transform * Vec3d(m_starting.box.min(0), center(1), center(2)); - m_starting.pivots[2] = m_transform * Vec3d(center(0), m_starting.box.max(1), center(2)); - m_starting.pivots[3] = m_transform * Vec3d(center(0), m_starting.box.min(1), center(2)); - m_starting.pivots[4] = m_transform * Vec3d(center(0), center(1), m_starting.box.max(2)); - m_starting.pivots[5] = m_transform * Vec3d(center(0), center(1), m_starting.box.min(2)); + m_starting.pivots[0] = m_transform * Vec3d(m_starting.box.max.x(), center.y(), center.z()); + m_starting.pivots[1] = m_transform * Vec3d(m_starting.box.min.x(), center.y(), center.z()); + m_starting.pivots[2] = m_transform * Vec3d(center.x(), m_starting.box.max.y(), center.z()); + m_starting.pivots[3] = m_transform * Vec3d(center.x(), m_starting.box.min.y(), center.z()); + m_starting.pivots[4] = m_transform * Vec3d(center.x(), center.y(), m_starting.box.max.z()); + m_starting.pivots[5] = m_transform * Vec3d(center.x(), center.y(), m_starting.box.min.z()); } } void GLGizmoScale3D::on_update(const UpdateData& data) { - if ((m_hover_id == 0) || (m_hover_id == 1)) + if (m_hover_id == 0 || m_hover_id == 1) do_scale_along_axis(X, data); - else if ((m_hover_id == 2) || (m_hover_id == 3)) + else if (m_hover_id == 2 || m_hover_id == 3) do_scale_along_axis(Y, data); - else if ((m_hover_id == 4) || (m_hover_id == 5)) + else if (m_hover_id == 4 || m_hover_id == 5) do_scale_along_axis(Z, data); else if (m_hover_id >= 6) do_scale_uniform(data); @@ -190,24 +192,24 @@ void GLGizmoScale3D::on_render() bool ctrl_down = (m_dragging && m_starting.ctrl_down) || (!m_dragging && wxGetKeyState(WXK_CONTROL)); // x axis - m_grabbers[0].center = m_transform * Vec3d(m_box.min(0), center(1), m_box.min(2)); - m_grabbers[1].center = m_transform * Vec3d(m_box.max(0), center(1), m_box.min(2)); + m_grabbers[0].center = m_transform * Vec3d(m_box.min.x(), center.y(), m_box.min.z()); + m_grabbers[1].center = m_transform * Vec3d(m_box.max.x(), center.y(), m_box.min.z()); // y axis - m_grabbers[2].center = m_transform * Vec3d(center(0), m_box.min(1), m_box.min(2)); - m_grabbers[3].center = m_transform * Vec3d(center(0), m_box.max(1), m_box.min(2)); + m_grabbers[2].center = m_transform * Vec3d(center.x(), m_box.min.y(), m_box.min.z()); + m_grabbers[3].center = m_transform * Vec3d(center.x(), m_box.max.y(), m_box.min.z()); // z axis do not show 4 - m_grabbers[4].center = m_transform * Vec3d(center(0), center(1), m_box.min(2)); + m_grabbers[4].center = m_transform * Vec3d(center.x(), center.y(), m_box.min.z()); m_grabbers[4].enabled = false; - m_grabbers[5].center = m_transform * Vec3d(center(0), center(1), m_box.max(2)); + m_grabbers[5].center = m_transform * Vec3d(center.x(), center.y(), m_box.max.z()); // uniform - m_grabbers[6].center = m_transform * Vec3d(m_box.min(0), m_box.min(1), m_box.min(2)); - m_grabbers[7].center = m_transform * Vec3d(m_box.max(0), m_box.min(1), m_box.min(2)); - m_grabbers[8].center = m_transform * Vec3d(m_box.max(0), m_box.max(1), m_box.min(2)); - m_grabbers[9].center = m_transform * Vec3d(m_box.min(0), m_box.max(1), m_box.min(2)); + m_grabbers[6].center = m_transform * Vec3d(m_box.min.x(), m_box.min.y(), m_box.min.z()); + m_grabbers[7].center = m_transform * Vec3d(m_box.max.x(), m_box.min.y(), m_box.min.z()); + m_grabbers[8].center = m_transform * Vec3d(m_box.max.x(), m_box.max.y(), m_box.min.z()); + m_grabbers[9].center = m_transform * Vec3d(m_box.min.x(), m_box.max.y(), m_box.min.z()); for (int i = 0; i < 6; ++i) { m_grabbers[i].color = AXES_COLOR[i/2]; @@ -228,26 +230,23 @@ void GLGizmoScale3D::on_render() const BoundingBoxf3& selection_box = selection.get_bounding_box(); - float grabber_mean_size = (float)((selection_box.size()(0) + selection_box.size()(1) + selection_box.size()(2)) / 3.0); - - //draw connections - - // BBS: when select multiple objects, uniform scale can be deselected, display the connection(4,5) - //if (single_instance || single_volume) { - - if (m_grabbers[4].enabled && m_grabbers[5].enabled) { - glsafe(::glColor4fv(m_grabbers[4].color.data())); - render_grabbers_connection(4, 5); + float grabber_mean_size = (float)((selection_box.size().x() + selection_box.size().y() + selection_box.size().z()) / 3.0); + + //draw connections + GLShaderProgram* shader = wxGetApp().get_shader("flat"); + if (shader != nullptr) { + shader->start_using(); + // BBS: when select multiple objects, uniform scale can be deselected, display the connection(4,5) + //if (single_instance || single_volume) { + if (m_grabbers[4].enabled && m_grabbers[5].enabled) + render_grabbers_connection(4, 5, m_grabbers[4].color); + render_grabbers_connection(6, 7, m_grabbers[2].color); + render_grabbers_connection(7, 8, m_grabbers[2].color); + render_grabbers_connection(8, 9, m_grabbers[0].color); + render_grabbers_connection(9, 6, m_grabbers[0].color); + shader->stop_using(); } - glsafe(::glColor4fv(m_grabbers[2].color.data())); - render_grabbers_connection(6, 7); - render_grabbers_connection(8, 9); - - glsafe(::glColor4fv(m_grabbers[0].color.data())); - render_grabbers_connection(7, 8); - render_grabbers_connection(9, 6); - // draw grabbers render_grabbers(grabber_mean_size); } @@ -258,19 +257,52 @@ void GLGizmoScale3D::on_render_for_picking() render_grabbers_for_picking(m_parent.get_selection().get_bounding_box()); } -void GLGizmoScale3D::render_grabbers_connection(unsigned int id_1, unsigned int id_2) const +void GLGizmoScale3D::render_grabbers_connection(unsigned int id_1, unsigned int id_2, const ColorRGBA& color) { - unsigned int grabbers_count = (unsigned int)m_grabbers.size(); - if ((id_1 < grabbers_count) && (id_2 < grabbers_count)) - { - glLineStipple(1, 0x0FFF); - glEnable(GL_LINE_STIPPLE); - ::glBegin(GL_LINES); - ::glVertex3dv(m_grabbers[id_1].center.data()); - ::glVertex3dv(m_grabbers[id_2].center.data()); - glsafe(::glEnd()); - glDisable(GL_LINE_STIPPLE); + auto grabber_connection = [this](unsigned int id_1, unsigned int id_2) { + for (int i = 0; i < int(m_grabber_connections.size()); ++i) { + if (m_grabber_connections[i].grabber_indices.first == id_1 && m_grabber_connections[i].grabber_indices.second == id_2) + return i; + } + return -1; + }; + + int id = grabber_connection(id_1, id_2); + if (id == -1) + return; + + if (!m_grabber_connections[id].model.is_initialized() || + !m_grabber_connections[id].old_v1.isApprox(m_grabbers[id_1].center) || + !m_grabber_connections[id].old_v2.isApprox(m_grabbers[id_2].center)) { + m_grabber_connections[id].old_v1 = m_grabbers[id_1].center; + m_grabber_connections[id].old_v2 = m_grabbers[id_2].center; + m_grabber_connections[id].model.reset(); + + GLModel::InitializationData init_data; + GUI::GLModel::InitializationData::Entity entity; + entity.type = GUI::GLModel::PrimitiveType::Lines; + entity.positions.reserve(2); + entity.positions.emplace_back(m_grabbers[id_1].center.cast()); + entity.positions.emplace_back(m_grabbers[id_2].center.cast()); + + entity.normals.reserve(2); + for (size_t j = 0; j < 2; ++j) { + entity.normals.emplace_back(Vec3f::UnitZ()); + } + + entity.indices.reserve(2); + entity.indices.emplace_back(0); + entity.indices.emplace_back(1); + + init_data.entities.emplace_back(entity); + m_grabber_connections[id].model.init_from(init_data); } + + m_grabber_connections[id].model.set_color(-1, color); + glLineStipple(1, 0x0FFF); + glEnable(GL_LINE_STIPPLE); + m_grabber_connections[id].model.render(); + glDisable(GL_LINE_STIPPLE); } //BBS: add input window for move @@ -283,11 +315,9 @@ void GLGizmoScale3D::on_render_input_window(float x, float y, float bottom_limit void GLGizmoScale3D::do_scale_along_axis(Axis axis, const UpdateData& data) { double ratio = calc_ratio(data); - if (ratio > 0.0) - { + if (ratio > 0.0) { m_scale(axis) = m_starting.scale(axis) * ratio; - if (m_starting.ctrl_down) - { + if (m_starting.ctrl_down) { double local_offset = 0.5 * (m_scale(axis) - m_starting.scale(axis)) * m_starting.box.size()(axis); if (m_hover_id == 2 * axis) local_offset *= -1.0; @@ -311,8 +341,7 @@ void GLGizmoScale3D::do_scale_along_axis(Axis axis, const UpdateData& data) void GLGizmoScale3D::do_scale_uniform(const UpdateData& data) { double ratio = calc_ratio(data); - if (ratio > 0.0) - { + if (ratio > 0.0) { m_scale = m_starting.scale * ratio; m_offset = Vec3d::Zero(); } @@ -322,11 +351,11 @@ double GLGizmoScale3D::calc_ratio(const UpdateData& data) const { double ratio = 0.0; - Vec3d pivot = (m_starting.ctrl_down && (m_hover_id < 6)) ? m_starting.pivots[m_hover_id] : m_starting.plane_center; + Vec3d pivot = (m_starting.ctrl_down && m_hover_id < 6) ? m_starting.pivots[m_hover_id] : m_starting.plane_center; + Vec3d starting_vec = m_starting.drag_position - pivot; double len_starting_vec = starting_vec.norm(); - if (len_starting_vec != 0.0) - { + if (len_starting_vec != 0.0) { Vec3d mouse_dir = data.mouse_ray.unit_vector(); Vec3d plane_normal = m_starting.plane_nromal; if (m_hover_id == 5) { diff --git a/src/slic3r/GUI/Gizmos/GLGizmoScale.hpp b/src/slic3r/GUI/Gizmos/GLGizmoScale.hpp index 839c7f6823c..b87625a7c1e 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoScale.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoScale.hpp @@ -32,10 +32,19 @@ class GLGizmoScale3D : public GLGizmoBase mutable Transform3d m_transform; // Transforms grabbers offsets to the proper reference system (world for instances, instance for volumes) mutable Transform3d m_offsets_transform; - Vec3d m_scale; - Vec3d m_offset; - double m_snap_step; + Vec3d m_scale{ Vec3d::Ones() }; + Vec3d m_offset{ Vec3d::Zero() }; + double m_snap_step{ 0.05 }; StartingData m_starting; + + struct GrabberConnection + { + GLModel model; + std::pair grabber_indices; + Vec3d old_v1{ Vec3d::Zero() }; + Vec3d old_v2{ Vec3d::Zero() }; + }; + std::array m_grabber_connections; //BBS: add size adjust related GizmoObjectManipulation* m_object_manipulation; @@ -68,7 +77,7 @@ class GLGizmoScale3D : public GLGizmoBase virtual void on_render_input_window(float x, float y, float bottom_limit); private: - void render_grabbers_connection(unsigned int id_1, unsigned int id_2) const; + void render_grabbers_connection(unsigned int id_1, unsigned int id_2, const ColorRGBA& color); void do_scale_along_axis(Axis axis, const UpdateData& data); void do_scale_uniform(const UpdateData& data); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSeam.cpp b/src/slic3r/GUI/Gizmos/GLGizmoSeam.cpp index 9de9d2c9034..04e32898d6d 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSeam.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSeam.cpp @@ -62,7 +62,7 @@ std::string GLGizmoSeam::on_get_name() const -void GLGizmoSeam::render_painter_gizmo() const +void GLGizmoSeam::render_painter_gizmo() { const Selection& selection = m_parent.get_selection(); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSeam.hpp b/src/slic3r/GUI/Gizmos/GLGizmoSeam.hpp index 94cefa7f072..abfd4c28aaf 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSeam.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSeam.hpp @@ -10,7 +10,7 @@ class GLGizmoSeam : public GLGizmoPainterBase public: GLGizmoSeam(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id); - void render_painter_gizmo() const override; + void render_painter_gizmo() override; //BBS bool on_key_down_select_tool_type(int keyCode); diff --git a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp index 87c9a00c9ea..8f13dc81438 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp @@ -692,7 +692,7 @@ void GLGizmosManager::render_current_gizmo() const m_gizmos[m_current]->render(); } -void GLGizmosManager::render_painter_gizmo() const +void GLGizmosManager::render_painter_gizmo() { // This function shall only be called when current gizmo is // derived from GLGizmoPainterBase. diff --git a/src/slic3r/GUI/Gizmos/GLGizmosManager.hpp b/src/slic3r/GUI/Gizmos/GLGizmosManager.hpp index fefb85b6b9c..6237d4e1933 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosManager.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosManager.hpp @@ -31,16 +31,24 @@ class CommonGizmosDataPool; class GizmoObjectManipulation; class Rect { - float m_left; - float m_top; - float m_right; - float m_bottom; + float m_left{ 0.0f }; + float m_top{ 0.0f }; + float m_right{ 0.0f }; + float m_bottom{ 0.0f }; public: - Rect() : m_left(0.0f) , m_top(0.0f) , m_right(0.0f) , m_bottom(0.0f) {} - + Rect() = default; Rect(float left, float top, float right, float bottom) : m_left(left) , m_top(top) , m_right(right) , m_bottom(bottom) {} + bool operator == (const Rect& other) { + if (std::abs(m_left - other.m_left) > EPSILON) return false; + if (std::abs(m_top - other.m_top) > EPSILON) return false; + if (std::abs(m_right - other.m_right) > EPSILON) return false; + if (std::abs(m_bottom - other.m_bottom) > EPSILON) return false; + return true; + } + bool operator != (const Rect& other) { return !operator==(other); } + float get_left() const { return m_left; } void set_left(float left) { m_left = left; } @@ -287,7 +295,7 @@ class GLGizmosManager : public Slic3r::ObjectBase void on_change_color_mode(bool is_dark); void render_current_gizmo() const; void render_current_gizmo_for_picking_pass() const; - void render_painter_gizmo() const; + void render_painter_gizmo(); void render_painter_assemble_view() const; void render_overlay(); From 354f8e20fb218e5da83551314810328c9e06882f Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Sat, 21 Oct 2023 16:16:21 +0800 Subject: [PATCH 06/99] Tech ENABLE_GLBEGIN_GLEND_REMOVAL - Refactoring of GLModel to: 1) allow for custom vertex data layout 2) allow for custom index data format 3) allow for any OpenGL primitive type (cherry picked from commit prusa3d/PrusaSlicer@afcac6e2ea306fbbb12428e360c0fe70b2a3f12d) --- src/libslic3r/Color.hpp | 4 + src/slic3r/GUI/3DBed.cpp | 44 +- src/slic3r/GUI/3DBed.hpp | 14 +- src/slic3r/GUI/3DScene.cpp | 77 +- src/slic3r/GUI/GCodeViewer.cpp | 50 +- src/slic3r/GUI/GCodeViewer.hpp | 8 +- src/slic3r/GUI/GLCanvas3D.cpp | 149 +-- src/slic3r/GUI/GLModel.cpp | 1201 +++++++++++------- src/slic3r/GUI/GLModel.hpp | 153 ++- src/slic3r/GUI/GLSelectionRectangle.cpp | 60 +- src/slic3r/GUI/Gizmos/GLGizmoAdvancedCut.cpp | 184 +-- src/slic3r/GUI/Gizmos/GLGizmoAdvancedCut.hpp | 2 + src/slic3r/GUI/Gizmos/GLGizmoBase.cpp | 68 +- src/slic3r/GUI/Gizmos/GLGizmoBase.hpp | 25 +- src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp | 41 +- src/slic3r/GUI/Gizmos/GLGizmoHollow.hpp | 5 +- src/slic3r/GUI/Gizmos/GLGizmoMove.cpp | 57 +- src/slic3r/GUI/Gizmos/GLGizmoMove.hpp | 4 +- src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp | 35 +- src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp | 187 ++- src/slic3r/GUI/Gizmos/GLGizmoRotate.hpp | 2 +- src/slic3r/GUI/Gizmos/GLGizmoScale.cpp | 29 +- src/slic3r/GUI/Gizmos/GLGizmoSimplify.cpp | 2 +- src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp | 23 +- src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp | 10 +- src/slic3r/GUI/Gizmos/GLGizmoText.cpp | 20 +- src/slic3r/GUI/Selection.cpp | 260 ++-- 27 files changed, 1517 insertions(+), 1197 deletions(-) diff --git a/src/libslic3r/Color.hpp b/src/libslic3r/Color.hpp index fce0c67e000..183705c4af3 100644 --- a/src/libslic3r/Color.hpp +++ b/src/libslic3r/Color.hpp @@ -48,12 +48,14 @@ class ColorRGB 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 CYAN() { return { 0.0f, 1.0f, 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 MAGENTA() { return { 1.0f, 0.0f, 1.0f }; } 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 }; } @@ -112,12 +114,14 @@ class ColorRGBA 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 CYAN() { return { 0.0f, 1.0f, 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 MAGENTA() { return { 1.0f, 0.0f, 1.0f, 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 }; } diff --git a/src/slic3r/GUI/3DBed.cpp b/src/slic3r/GUI/3DBed.cpp index 0c29cdc195c..786cd401331 100644 --- a/src/slic3r/GUI/3DBed.cpp +++ b/src/slic3r/GUI/3DBed.cpp @@ -157,7 +157,7 @@ void Bed3D::load_render_colors() RenderColor::colors[RenderCol_Axis_Z] = ImGuiWrapper::to_ImVec4(Bed3D::AXIS_Z_COLOR); } -void Bed3D::Axes::render() const +void Bed3D::Axes::render() { auto render_axis = [this](const Transform3f& transform) { glsafe(::glPushMatrix()); @@ -167,7 +167,7 @@ void Bed3D::Axes::render() const }; if (!m_arrow.is_initialized()) - const_cast(&m_arrow)->init_from(stilized_arrow(16, DefaultTipRadius, DefaultTipLength, DefaultStemRadius, m_stem_length)); + m_arrow.init_from(stilized_arrow(16, DefaultTipRadius, DefaultTipLength, DefaultStemRadius, m_stem_length)); GLShaderProgram* shader = wxGetApp().get_shader("gouraud_light"); if (shader == nullptr) @@ -179,15 +179,15 @@ void Bed3D::Axes::render() const shader->set_uniform("emission_factor", 0.0f); // x axis - const_cast(&m_arrow)->set_color(-1, AXIS_X_COLOR); + m_arrow.set_color(AXIS_X_COLOR); 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, AXIS_Y_COLOR); + m_arrow.set_color(AXIS_Y_COLOR); 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, AXIS_Z_COLOR); + m_arrow.set_color(AXIS_Z_COLOR); render_axis(Geometry::assemble_transform(m_origin).cast()); shader->stop_using(); @@ -340,14 +340,14 @@ void Bed3D::render(GLCanvas3D& canvas, bool bottom, float scale_factor, bool sho void Bed3D::render_internal(GLCanvas3D& canvas, bool bottom, float scale_factor, bool show_axes) { - float* factor = const_cast(&m_scale_factor); - *factor = scale_factor; + m_scale_factor = scale_factor; if (show_axes) render_axes(); + glsafe(::glEnable(GL_DEPTH_TEST)); - m_model.set_color(-1, m_is_dark ? DEFAULT_MODEL_COLOR_DARK : DEFAULT_MODEL_COLOR); + m_model.set_color(m_is_dark ? DEFAULT_MODEL_COLOR_DARK : DEFAULT_MODEL_COLOR); switch (m_type) { @@ -456,13 +456,13 @@ std::tuple Bed3D::detect_type(const Point return { Type::Custom, {}, {} }; } -void Bed3D::render_axes() const +void Bed3D::render_axes() { if (m_build_volume.valid()) m_axes.render(); } -void Bed3D::render_system(GLCanvas3D& canvas, bool bottom) const +void Bed3D::render_system(GLCanvas3D& canvas, bool bottom) { if (!bottom) render_model(); @@ -471,7 +471,7 @@ void Bed3D::render_system(GLCanvas3D& canvas, bool bottom) const render_texture(bottom, canvas);*/ } -/*void Bed3D::render_texture(bool bottom, GLCanvas3D& canvas) const +/*void Bed3D::render_texture(bool bottom, GLCanvas3D& canvas) { GLTexture* texture = const_cast(&m_texture); GLTexture* temp_texture = const_cast(&m_temp_texture); @@ -656,34 +656,32 @@ GeometryBuffer Bed3D::update_bed_triangles() const return new_triangles; } -void Bed3D::render_model() const +void Bed3D::render_model() { if (m_model_filename.empty()) return; - GLModel* model = const_cast(&m_model); - - if (model->get_filename() != m_model_filename && model->init_from_file(m_model_filename)) { - model->set_color(-1, m_is_dark ? DEFAULT_MODEL_COLOR_DARK : DEFAULT_MODEL_COLOR); + if (m_model.get_filename() != m_model_filename && m_model.init_from_file(m_model_filename)) { + m_model.set_color(m_is_dark ? DEFAULT_MODEL_COLOR_DARK : DEFAULT_MODEL_COLOR); update_model_offset(); } - if (!model->get_filename().empty()) { + if (!m_model.get_filename().empty()) { GLShaderProgram* shader = wxGetApp().get_shader("gouraud_light"); if (shader != nullptr) { shader->start_using(); shader->set_uniform("emission_factor", 0.0f); glsafe(::glPushMatrix()); glsafe(::glTranslated(m_model_offset.x(), m_model_offset.y(), m_model_offset.z())); - model->render(); + m_model.render(); glsafe(::glPopMatrix()); shader->stop_using(); } } } -void Bed3D::render_custom(GLCanvas3D& canvas, bool bottom) const +void Bed3D::render_custom(GLCanvas3D& canvas, bool bottom) { if (m_model_filename.empty()) { render_default(bottom); @@ -697,15 +695,15 @@ void Bed3D::render_custom(GLCanvas3D& canvas, bool bottom) const render_texture(bottom, canvas);*/ } -void Bed3D::render_default(bool bottom) const +void Bed3D::render_default(bool bottom) { bool picking = false; - const_cast(&m_texture)->reset(); + m_texture.reset(); - unsigned int triangles_vcount = m_triangles.get_vertices_count(); + const unsigned int triangles_vcount = m_triangles.get_vertices_count(); GeometryBuffer default_triangles = update_bed_triangles(); if (triangles_vcount > 0) { - bool has_model = !m_model.get_filename().empty(); + const bool has_model = !m_model.get_filename().empty(); glsafe(::glEnable(GL_DEPTH_TEST)); glsafe(::glEnable(GL_BLEND)); diff --git a/src/slic3r/GUI/3DBed.hpp b/src/slic3r/GUI/3DBed.hpp index d1af27f4255..7bb4ebfb74d 100644 --- a/src/slic3r/GUI/3DBed.hpp +++ b/src/slic3r/GUI/3DBed.hpp @@ -70,7 +70,7 @@ class Bed3D m_arrow.reset(); } float get_total_length() const { return m_stem_length + DefaultTipLength; } - void render() const; + void render(); }; public: @@ -159,12 +159,12 @@ class Bed3D static std::tuple detect_type(const Pointfs& shape); void render_internal(GLCanvas3D& canvas, bool bottom, float scale_factor, bool show_axes); - void render_axes() const; - void render_system(GLCanvas3D& canvas, bool bottom) const; - //void render_texture(bool bottom, GLCanvas3D& canvas) const; - void render_model() const; - void render_custom(GLCanvas3D& canvas, bool bottom) const; - void render_default(bool bottom) const; + void render_axes(); + void render_system(GLCanvas3D& canvas, bool bottom); + //void render_texture(bool bottom, GLCanvas3D& canvas); + void render_model(); + void render_custom(GLCanvas3D& canvas, bool bottom); + void render_default(bool bottom); void release_VBOs(); }; diff --git a/src/slic3r/GUI/3DScene.cpp b/src/slic3r/GUI/3DScene.cpp index f94bba6c4fa..209e77c01b2 100644 --- a/src/slic3r/GUI/3DScene.cpp +++ b/src/slic3r/GUI/3DScene.cpp @@ -332,10 +332,10 @@ void GLVolume::SinkingContours::render() void GLVolume::SinkingContours::update() { - int object_idx = m_parent.object_idx(); - Model& model = GUI::wxGetApp().plater()->model(); + const int object_idx = m_parent.object_idx(); + const Model& model = GUI::wxGetApp().plater()->model(); - if (0 <= object_idx && object_idx < (int)model.objects.size() && m_parent.is_sinking() && !m_parent.is_below_printbed()) { + if (0 <= object_idx && object_idx < int(model.objects.size()) && m_parent.is_sinking() && !m_parent.is_below_printbed()) { const BoundingBoxf3& box = m_parent.transformed_convex_hull_bounding_box(); if (!m_old_box.size().isApprox(box.size()) || m_old_box.min.z() != box.min.z()) { m_old_box = box; @@ -344,28 +344,25 @@ void GLVolume::SinkingContours::update() const TriangleMesh& mesh = model.objects[object_idx]->volumes[m_parent.volume_idx()]->mesh(); m_model.reset(); - GUI::GLModel::InitializationData init_data; + GUI::GLModel::Geometry init_data; + init_data.format = { GUI::GLModel::Geometry::EPrimitiveType::Triangles, GUI::GLModel::Geometry::EVertexLayout::P3, GUI::GLModel::Geometry::EIndexType::UINT }; + init_data.color = ColorRGBA::WHITE(); + unsigned int vertices_counter = 0; MeshSlicingParams slicing_params; slicing_params.trafo = m_parent.world_matrix(); - Polygons polygons = union_(slice_mesh(mesh.its, 0.0f, slicing_params)); - for (ExPolygon &expoly : diff_ex(expand(polygons, float(scale_(HalfWidth))), shrink(polygons, float(scale_(HalfWidth))))) { - GUI::GLModel::InitializationData::Entity entity; - entity.type = GUI::GLModel::PrimitiveType::Triangles; + const Polygons polygons = union_(slice_mesh(mesh.its, 0.0f, slicing_params)); + for (const ExPolygon& expoly : diff_ex(expand(polygons, float(scale_(HalfWidth))), shrink(polygons, float(scale_(HalfWidth))))) { const std::vector triangulation = triangulate_expolygon_3d(expoly); + init_data.vertices.reserve(init_data.vertices.size() + triangulation.size() * GUI::GLModel::Geometry::vertex_stride_floats(init_data.format)); + init_data.indices.reserve(init_data.indices.size() + triangulation.size() * GUI::GLModel::Geometry::index_stride_bytes(init_data.format)); for (const Vec3d& v : triangulation) { - entity.positions.emplace_back(v.cast() + Vec3f(0.0f, 0.0f, 0.015f)); // add a small positive z to avoid z-fighting - entity.normals.emplace_back(Vec3f::UnitZ()); - const size_t positions_count = entity.positions.size(); - if (positions_count % 3 == 0) { - entity.indices.emplace_back(positions_count - 3); - entity.indices.emplace_back(positions_count - 2); - entity.indices.emplace_back(positions_count - 1); - } + init_data.add_vertex((Vec3f)(v.cast() + 0.015f * Vec3f::UnitZ())); // add a small positive z to avoid z-fighting + ++vertices_counter; + if (vertices_counter % 3 == 0) + init_data.add_uint_triangle(vertices_counter - 3, vertices_counter - 2, vertices_counter - 1); } - init_data.entities.emplace_back(entity); } - - m_model.init_from(init_data); + m_model.init_from(std::move(init_data)); } else m_shift = box.center() - m_old_box.center(); @@ -1247,6 +1244,9 @@ void GLVolumeCollection::render( if (shader == nullptr) return; + GLShaderProgram* sink_shader = GUI::wxGetApp().get_shader("flat"); + GLShaderProgram* edges_shader = GUI::wxGetApp().get_shader("flat"); + if (type == ERenderType::Transparent) { glsafe(::glEnable(GL_BLEND)); glsafe(::glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)); @@ -1272,13 +1272,18 @@ void GLVolumeCollection::render( #endif // ENABLE_MODIFIERS_ALWAYS_TRANSPARENT // render sinking contours of non-hovered volumes - if (m_show_sinking_contours) - if (volume.first->is_sinking() && !volume.first->is_below_printbed() && - volume.first->hover == GLVolume::HS_None && !volume.first->force_sinking_contours) { - shader->stop_using(); - volume.first->render_sinking_contours(); - shader->start_using(); + shader->stop_using(); + if (sink_shader != nullptr) { + sink_shader->start_using(); + if (m_show_sinking_contours) { + if (volume.first->is_sinking() && !volume.first->is_below_printbed() && + volume.first->hover == GLVolume::HS_None && !volume.first->force_sinking_contours) { + volume.first->render_sinking_contours(); + } } + sink_shader->stop_using(); + } + shader->start_using(); glsafe(::glEnableClientState(GL_VERTEX_ARRAY)); glsafe(::glEnableClientState(GL_NORMAL_ARRAY)); @@ -1341,17 +1346,21 @@ void GLVolumeCollection::render( } if (m_show_sinking_contours) { - for (GLVolumeWithIdAndZ& volume : to_render) { - // render sinking contours of hovered/displaced volumes - if (volume.first->is_sinking() && !volume.first->is_below_printbed() && - (volume.first->hover != GLVolume::HS_None || volume.first->force_sinking_contours)) { - shader->stop_using(); - glsafe(::glDepthFunc(GL_ALWAYS)); - volume.first->render_sinking_contours(); - glsafe(::glDepthFunc(GL_LESS)); - shader->start_using(); + shader->stop_using(); + if (sink_shader != nullptr) { + sink_shader->start_using(); + for (GLVolumeWithIdAndZ& volume : to_render) { + // render sinking contours of hovered/displaced volumes + if (volume.first->is_sinking() && !volume.first->is_below_printbed() && + (volume.first->hover != GLVolume::HS_None || volume.first->force_sinking_contours)) { + glsafe(::glDepthFunc(GL_ALWAYS)); + volume.first->render_sinking_contours(); + glsafe(::glDepthFunc(GL_LESS)); + } } + sink_shader->start_using(); } + shader->start_using(); } if (disable_cullface) diff --git a/src/slic3r/GUI/GCodeViewer.cpp b/src/slic3r/GUI/GCodeViewer.cpp index 082e7b84dfa..36e27b26359 100644 --- a/src/slic3r/GUI/GCodeViewer.cpp +++ b/src/slic3r/GUI/GCodeViewer.cpp @@ -288,7 +288,7 @@ void GCodeViewer::SequentialView::Marker::init(std::string filename) } else { m_model.init_from_file(filename); } - m_model.set_color(-1, {1.0f, 1.0f, 1.0f, 0.5f}); + m_model.set_color({ 1.0f, 1.0f, 1.0f, 0.5f }); } void GCodeViewer::SequentialView::Marker::set_world_position(const Vec3f& position) @@ -302,7 +302,7 @@ void GCodeViewer::SequentialView::Marker::update_curr_move(const GCodeProcessorR } //BBS: GUI refactor: add canvas size from parameters -void GCodeViewer::SequentialView::Marker::render(int canvas_width, int canvas_height, const EViewType& view_type) const +void GCodeViewer::SequentialView::Marker::render(int canvas_width, int canvas_height, const EViewType& view_type) { if (!m_visible) return; @@ -670,7 +670,7 @@ void GCodeViewer::SequentialView::GCodeWindow::stop_mapping_file() BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ": finished mapping file " << m_filename; } } -void GCodeViewer::SequentialView::render(const bool has_render_path, float legend_height, int canvas_width, int canvas_height, int right_margin, const EViewType& view_type) const +void GCodeViewer::SequentialView::render(const bool has_render_path, float legend_height, int canvas_width, int canvas_height, int right_margin, const EViewType& view_type) { if (has_render_path) marker.render(canvas_width, canvas_height, view_type); @@ -1346,7 +1346,7 @@ void GCodeViewer::_render_calibration_thumbnail_internal(ThumbnailData& thumbnai } if (range.vbo > 0) { - buffer.model.model.set_color(-1, range.color); + buffer.model.model.set_color(range.color); buffer.model.model.render_instanced(range.vbo, range.count); #if ENABLE_GCODE_VIEWER_STATISTICS ++m_statistics.gl_instanced_models_calls_count; @@ -2291,28 +2291,27 @@ void GCodeViewer::load_toolpaths(const GCodeProcessorResult& gcode_result, const }; // format data into the buffers to be rendered as batched model - auto add_vertices_as_model_batch = [](const GCodeProcessorResult::MoveVertex& curr, const GLModel::InitializationData& data, VertexBuffer& vertices, InstanceBuffer& instances, InstanceIdBuffer& instances_ids, size_t move_id) { + auto add_vertices_as_model_batch = [](const GCodeProcessorResult::MoveVertex& curr, const GLModel::Geometry& data, VertexBuffer& vertices, InstanceBuffer& instances, InstanceIdBuffer& instances_ids, size_t move_id) { const double width = static_cast(1.5f * curr.width); const double height = static_cast(1.5f * curr.height); const Transform3d trafo = Geometry::assemble_transform((curr.position - 0.5f * curr.height * Vec3f::UnitZ()).cast(), Vec3d::Zero(), { width, width, height }); const Eigen::Matrix normal_matrix = trafo.matrix().template block<3, 3>(0, 0).inverse().transpose(); - for (const auto& entity : data.entities) { - // append vertices - for (size_t i = 0; i < entity.positions.size(); ++i) { - // append position - const Vec3d position = trafo * entity.positions[i].cast(); - vertices.push_back(static_cast(position.x())); - vertices.push_back(static_cast(position.y())); - vertices.push_back(static_cast(position.z())); - - // append normal - const Vec3d normal = normal_matrix * entity.normals[i].cast(); - vertices.push_back(static_cast(normal.x())); - vertices.push_back(static_cast(normal.y())); - vertices.push_back(static_cast(normal.z())); - } + // append vertices + const size_t vertices_count = data.vertices_count(); + for (size_t i = 0; i < vertices_count; ++i) { + // append position + const Vec3d position = trafo * data.extract_position_3(i).cast(); + vertices.push_back(float(position.x())); + vertices.push_back(float(position.y())); + vertices.push_back(float(position.z())); + + // append normal + const Vec3d normal = normal_matrix * data.extract_normal_3(i).cast(); + vertices.push_back(float(normal.x())); + vertices.push_back(float(normal.y())); + vertices.push_back(float(normal.z())); } // append instance position @@ -2323,11 +2322,10 @@ void GCodeViewer::load_toolpaths(const GCodeProcessorResult& gcode_result, const instances_ids.push_back(move_id); }; - auto add_indices_as_model_batch = [](const GLModel::InitializationData& data, IndexBuffer& indices, IBufferType base_index) { - for (const auto& entity : data.entities) { - for (size_t i = 0; i < entity.indices.size(); ++i) { - indices.push_back(static_cast(entity.indices[i] + base_index)); - } + auto add_indices_as_model_batch = [](const GLModel::Geometry& data, IndexBuffer& indices, IBufferType base_index) { + const size_t indices_count = data.indices_count(); + for (size_t i = 0; i < indices_count; ++i) { + indices.push_back(static_cast(data.extract_ushort_index(i) + base_index)); } }; @@ -3868,7 +3866,7 @@ void GCodeViewer::render_toolpaths() } if (range.vbo > 0) { - buffer.model.model.set_color(-1, range.color); + buffer.model.model.set_color(range.color); buffer.model.model.render_instanced(range.vbo, range.count); #if ENABLE_GCODE_VIEWER_STATISTICS ++m_statistics.gl_instanced_models_calls_count; diff --git a/src/slic3r/GUI/GCodeViewer.hpp b/src/slic3r/GUI/GCodeViewer.hpp index 4c0f0809749..2bb2542f24f 100644 --- a/src/slic3r/GUI/GCodeViewer.hpp +++ b/src/slic3r/GUI/GCodeViewer.hpp @@ -311,7 +311,7 @@ class GCodeViewer GLModel model; ColorRGBA color; InstanceVBuffer instances; - GLModel::InitializationData data; + GLModel::Geometry data; void reset(); }; @@ -374,7 +374,7 @@ class GCodeViewer } case ERenderPrimitiveType::InstancedModel: { return model.model.is_initialized() && !model.instances.buffer.empty(); } case ERenderPrimitiveType::BatchedModel: { - return model.data.vertices_count() > 0 && model.data.indices_count() && + return !model.data.vertices.empty() && !model.data.indices.empty() && !vertices.vbos.empty() && vertices.vbos.front() != 0 && !indices.empty() && indices.front().ibo != 0; } default: { return false; } @@ -642,7 +642,7 @@ Range layer_duration_log; bool is_visible() const { return m_visible; } void set_visible(bool visible) { m_visible = visible; } - void render(int canvas_width, int canvas_height, const EViewType& view_type) const; + void render(int canvas_width, int canvas_height, const EViewType& view_type); void on_change_color_mode(bool is_dark) { m_is_dark = is_dark; } void update_curr_move(const GCodeProcessorResult::MoveVertex move); @@ -709,7 +709,7 @@ Range layer_duration_log; std::vector gcode_ids; float m_scale = 1.0; bool m_show_gcode_window = false; - void render(const bool has_render_path, float legend_height, int canvas_width, int canvas_height, int right_margin, const EViewType& view_type) const; + void render(const bool has_render_path, float legend_height, int canvas_width, int canvas_height, int right_margin, const EViewType& view_type); }; struct ETools diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 54846f168d6..83e4502e642 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -462,53 +462,48 @@ void GLCanvas3D::LayersEditing::render_curve(const Rect & bar_rect) const float scale_y = bar_rect.get_height() / m_object_max_z; const float x = bar_rect.get_left() + float(m_slicing_parameters->layer_height) * scale_x; - bool bar_rect_changed = m_profile.old_bar_rect != bar_rect; + const bool bar_rect_changed = m_profile.old_bar_rect != bar_rect; m_profile.old_bar_rect = bar_rect; // Baseline if (!m_profile.baseline.is_initialized() || bar_rect_changed) { m_profile.old_bar_rect = bar_rect; - GLModel::InitializationData init_data; - GLModel::InitializationData::Entity entity; - entity.type = GLModel::PrimitiveType::Lines; - entity.positions.reserve(2); - entity.positions.emplace_back(x, bar_rect.get_bottom(), 0.0f); - entity.positions.emplace_back(x, bar_rect.get_top(), 0.0f); + GLModel::Geometry init_data; + init_data.format = { GLModel::Geometry::EPrimitiveType::Lines, GLModel::Geometry::EVertexLayout::P3, GLModel::Geometry::EIndexType::USHORT }; + init_data.color = ColorRGBA::BLACK(); + init_data.vertices.reserve(2 * GLModel::Geometry::vertex_stride_floats(init_data.format)); + init_data.indices.reserve(2 * GLModel::Geometry::index_stride_bytes(init_data.format)); - entity.normals.reserve(2); - for (size_t j = 0; j < 2; ++j) { - entity.normals.emplace_back(Vec3f::UnitZ()); - } + // vertices + init_data.add_vertex(Vec3f(x, bar_rect.get_bottom(), 0.0f)); + init_data.add_vertex(Vec3f(x, bar_rect.get_top(), 0.0f)); - entity.indices.reserve(2); - entity.indices.emplace_back(0); - entity.indices.emplace_back(1); + // indices + init_data.add_ushort_line(0, 1); - init_data.entities.emplace_back(entity); - m_profile.baseline.init_from(init_data); - m_profile.baseline.set_color(-1, ColorRGBA::BLACK()); + m_profile.baseline.init_from(std::move(init_data)); } if (!m_profile.profile.is_initialized() || bar_rect_changed || m_profile.old_layer_height_profile != m_layer_height_profile) { m_profile.old_layer_height_profile = m_layer_height_profile; m_profile.profile.reset(); - GLModel::InitializationData init_data; - GLModel::InitializationData::Entity entity; - entity.type = GLModel::PrimitiveType::LineStrip; - entity.positions.reserve(m_layer_height_profile.size()); - entity.normals.reserve(m_layer_height_profile.size()); - entity.indices.reserve(m_layer_height_profile.size()); - for (unsigned int i = 0; i < unsigned int(m_layer_height_profile.size()); i += 2) { - entity.positions.emplace_back(bar_rect.get_left() + float(m_layer_height_profile[i + 1]) * scale_x, bar_rect.get_bottom() + float(m_layer_height_profile[i]) * scale_y, 0.0f); - entity.normals.emplace_back(Vec3f::UnitZ()); - entity.indices.emplace_back(i / 2); + GLModel::Geometry init_data; + init_data.format = { GLModel::Geometry::EPrimitiveType::LineStrip, GLModel::Geometry::EVertexLayout::P3, GLModel::Geometry::EIndexType::UINT }; + init_data.color = ColorRGBA::BLUE(); + init_data.vertices.reserve(m_layer_height_profile.size() * GLModel::Geometry::vertex_stride_floats(init_data.format)); + init_data.indices.reserve(m_layer_height_profile.size() * GLModel::Geometry::index_stride_bytes(init_data.format)); + + // vertices + indices + for (unsigned int i = 0; i < (unsigned int)m_layer_height_profile.size(); i += 2) { + init_data.add_vertex(Vec3f(bar_rect.get_left() + float(m_layer_height_profile[i + 1]) * scale_x, + bar_rect.get_bottom() + float(m_layer_height_profile[i]) * scale_y, + 0.0f)); + init_data.add_uint_index(i / 2); } - init_data.entities.emplace_back(entity); - m_profile.profile.init_from(init_data); - m_profile.profile.set_color(-1, ColorRGBA::BLUE()); + m_profile.profile.init_from(std::move(init_data)); } GLShaderProgram* shader = wxGetApp().get_shader("flat"); @@ -924,89 +919,51 @@ void GLCanvas3D::SequentialPrintClearance::set_polygons(const Polygons& polygons m_perimeter.reset(); m_fill.reset(); if (!polygons.empty()) { - size_t triangles_count = 0; - for (const Polygon &poly : polygons) { triangles_count += poly.points.size() - 2; } - const size_t vertices_count = 3 * triangles_count; - if (m_render_fill) { - GLModel::InitializationData fill_data; - GLModel::InitializationData::Entity entity; - entity.type = GLModel::PrimitiveType::Triangles; - entity.color = {0.8f, 0.8f, 1.0f, 0.5f}; - entity.positions.reserve(vertices_count); - entity.normals.reserve(vertices_count); - entity.indices.reserve(vertices_count); + GLModel::Geometry fill_data; + fill_data.format = { GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3, GLModel::Geometry::EIndexType::UINT }; + fill_data.color = { 0.8f, 0.8f, 1.0f, 0.5f }; + // vertices + indices const ExPolygons polygons_union = union_ex(polygons); - for (const ExPolygon &poly : polygons_union) { - const std::vector triangulation = triangulate_expolygon_3d(poly); - for (const Vec3d &v : triangulation) { - entity.positions.emplace_back(v.cast() + Vec3f(0.0f, 0.0f, 0.0125f)); // add a small positive z to avoid z-fighting - entity.normals.emplace_back(Vec3f::UnitZ()); - const size_t positions_count = entity.positions.size(); - if (positions_count % 3 == 0) { - entity.indices.emplace_back(positions_count - 3); - entity.indices.emplace_back(positions_count - 2); - entity.indices.emplace_back(positions_count - 1); - } + unsigned int vertices_counter = 0; + for (const ExPolygon& poly : polygons_union) { + const std::vector triangulation = triangulate_expolygon_3d(poly); + for (const Vec3d& v : triangulation) { + fill_data.add_vertex((Vec3f)(v.cast() + 0.0125f * Vec3f::UnitZ())); // add a small positive z to avoid z-fighting + ++vertices_counter; + if (vertices_counter % 3 == 0) + fill_data.add_uint_triangle(vertices_counter - 3, vertices_counter - 2, vertices_counter - 1); } } - fill_data.entities.emplace_back(entity); - m_fill.init_from(fill_data); - } - - GLModel::InitializationData perimeter_data; - for (const Polygon &poly : polygons) { - GLModel::InitializationData::Entity ent; - ent.type = GLModel::PrimitiveType::LineLoop; - ent.positions.reserve(poly.points.size()); - ent.indices.reserve(poly.points.size()); - unsigned int id_count = 0; - for (const Point &p : poly.points) { - ent.positions.emplace_back(unscale(p.x()), unscale(p.y()), 0.025f); // add a small positive z to avoid z-fighting - ent.normals.emplace_back(Vec3f::UnitZ()); - ent.indices.emplace_back(id_count++); - } - - perimeter_data.entities.emplace_back(ent); + m_fill.init_from(std::move(fill_data)); } - m_perimeter.init_from(perimeter_data); + m_perimeter.init_from(polygons, 0.025f); // add a small positive z to avoid z-fighting } //BBS: add the height limit compute logic if (!height_polygons.empty()) { - size_t height_triangles_count = 0; - for (const auto &poly : height_polygons) { height_triangles_count += poly.first.points.size() - 2; } - const size_t height_vertices_count = 3 * height_triangles_count; - - GLModel::InitializationData height_fill_data; - GLModel::InitializationData::Entity height_entity; - height_entity.type = GLModel::PrimitiveType::Triangles; - height_entity.color = {0.8f, 0.8f, 1.0f, 0.5f}; - height_entity.positions.reserve(height_vertices_count); - height_entity.normals.reserve(height_vertices_count); - height_entity.indices.reserve(height_vertices_count); + GLModel::Geometry height_fill_data; + height_fill_data.format = { GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3, GLModel::Geometry::EIndexType::UINT }; + height_fill_data.color = {0.8f, 0.8f, 1.0f, 0.5f}; + // vertices + indices + unsigned int vertices_counter = 0; for (const auto &poly : height_polygons) { ExPolygon ex_poly(poly.first); const std::vector height_triangulation = triangulate_expolygon_3d(ex_poly); for (const Vec3d &v : height_triangulation) { - Vec3d point{v.x(), v.y(), poly.second}; - height_entity.positions.emplace_back(point.cast()); - height_entity.normals.emplace_back(Vec3f::UnitZ()); - const size_t height_positions_count = height_entity.positions.size(); - if (height_positions_count % 3 == 0) { - height_entity.indices.emplace_back(height_positions_count - 3); - height_entity.indices.emplace_back(height_positions_count - 2); - height_entity.indices.emplace_back(height_positions_count - 1); - } + Vec3f point{(float) v.x(), (float) v.y(), poly.second}; + height_fill_data.add_vertex(point); + ++vertices_counter; + if (vertices_counter % 3 == 0) + height_fill_data.add_uint_triangle(vertices_counter - 3, vertices_counter - 2, vertices_counter - 1); } } - height_fill_data.entities.emplace_back(height_entity); - m_height_limit.init_from(height_fill_data); + m_height_limit.init_from(std::move(height_fill_data)); } } @@ -1015,7 +972,7 @@ void GLCanvas3D::SequentialPrintClearance::render() const ColorRGBA FILL_COLOR = { 0.7f, 0.7f, 1.0f, 0.5f }; const ColorRGBA NO_FILL_COLOR = { 0.75f, 0.75f, 0.75f, 0.75f }; - GLShaderProgram* shader = wxGetApp().get_shader("gouraud_light"); + GLShaderProgram* shader = wxGetApp().get_shader("flat"); if (shader == nullptr) return; @@ -1026,11 +983,11 @@ void GLCanvas3D::SequentialPrintClearance::render() glsafe(::glEnable(GL_BLEND)); glsafe(::glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)); - m_perimeter.set_color(-1, m_render_fill ? FILL_COLOR : NO_FILL_COLOR); + m_perimeter.set_color(m_render_fill ? FILL_COLOR : NO_FILL_COLOR); m_perimeter.render(); m_fill.render(); //BBS: add height limit - m_height_limit.set_color(-1, m_render_fill ? FILL_COLOR : NO_FILL_COLOR); + m_height_limit.set_color(m_render_fill ? FILL_COLOR : NO_FILL_COLOR); m_height_limit.render(); glsafe(::glDisable(GL_BLEND)); diff --git a/src/slic3r/GUI/GLModel.cpp b/src/slic3r/GUI/GLModel.cpp index fa804efc2f3..affd4cc8616 100644 --- a/src/slic3r/GUI/GLModel.cpp +++ b/src/slic3r/GUI/GLModel.cpp @@ -17,126 +17,414 @@ namespace Slic3r { namespace GUI { -size_t GLModel::InitializationData::vertices_count() const +void GLModel::Geometry::add_vertex(const Vec2f& position) { - size_t ret = 0; - for (const Entity& entity : entities) { - ret += entity.positions.size(); + assert(format.vertex_layout == EVertexLayout::P2); + vertices.emplace_back(position.x()); + vertices.emplace_back(position.y()); +} + +void GLModel::Geometry::add_vertex(const Vec3f& position) +{ + assert(format.vertex_layout == EVertexLayout::P3); + vertices.emplace_back(position.x()); + vertices.emplace_back(position.y()); + vertices.emplace_back(position.z()); +} + +void GLModel::Geometry::add_vertex(const Vec3f& position, const Vec3f& normal) +{ + assert(format.vertex_layout == EVertexLayout::P3N3); + vertices.emplace_back(position.x()); + vertices.emplace_back(position.y()); + vertices.emplace_back(position.z()); + vertices.emplace_back(normal.x()); + vertices.emplace_back(normal.y()); + vertices.emplace_back(normal.z()); +} + +void GLModel::Geometry::add_ushort_index(unsigned short id) +{ + if (format.index_type != EIndexType::USHORT) { + assert(false); + return; } - return ret; + indices.resize(indices.size() + sizeof(unsigned short)); + ::memcpy(indices.data() + indices.size() - sizeof(unsigned short), &id, sizeof(unsigned short)); } -size_t GLModel::InitializationData::indices_count() const +void GLModel::Geometry::add_uint_index(unsigned int id) { - size_t ret = 0; - for (const Entity& entity : entities) { - ret += entity.indices.size(); + if (format.index_type != EIndexType::UINT) { + assert(false); + return; } - return ret; + indices.resize(indices.size() + sizeof(unsigned int)); + ::memcpy(indices.data() + indices.size() - sizeof(unsigned int), &id, sizeof(unsigned int)); } -void GLModel::init_from(const InitializationData& data) +void GLModel::Geometry::add_ushort_line(unsigned short id1, unsigned short id2) { - if (!m_render_data.empty()) // call reset() if you want to reuse this model + if (format.index_type != EIndexType::USHORT) { + assert(false); return; + } + indices.resize(indices.size() + 2 * sizeof(unsigned short)); + ::memcpy(indices.data() + indices.size() - 2 * sizeof(unsigned short), &id1, sizeof(unsigned short)); + ::memcpy(indices.data() + indices.size() - sizeof(unsigned short), &id2, sizeof(unsigned short)); +} - for (const InitializationData::Entity& entity : data.entities) { - if (entity.positions.empty() || entity.indices.empty()) - continue; +void GLModel::Geometry::add_uint_line(unsigned int id1, unsigned int id2) +{ + if (format.index_type != EIndexType::UINT) { + assert(false); + return; + } + indices.resize(indices.size() + 2 * sizeof(unsigned int)); + ::memcpy(indices.data() + indices.size() - 2 * sizeof(unsigned int), &id1, sizeof(unsigned int)); + ::memcpy(indices.data() + indices.size() - sizeof(unsigned int), &id2, sizeof(unsigned int)); +} - assert(entity.normals.empty() || entity.normals.size() == entity.positions.size()); +void GLModel::Geometry::add_ushort_triangle(unsigned short id1, unsigned short id2, unsigned short id3) +{ + if (format.index_type != EIndexType::USHORT) { + assert(false); + return; + } + indices.resize(indices.size() + 3 * sizeof(unsigned short)); + ::memcpy(indices.data() + indices.size() - 3 * sizeof(unsigned short), &id1, sizeof(unsigned short)); + ::memcpy(indices.data() + indices.size() - 2 * sizeof(unsigned short), &id2, sizeof(unsigned short)); + ::memcpy(indices.data() + indices.size() - sizeof(unsigned short), &id3, sizeof(unsigned short)); +} - RenderData rdata; - rdata.type = entity.type; - rdata.color = entity.color; +void GLModel::Geometry::add_uint_triangle(unsigned int id1, unsigned int id2, unsigned int id3) +{ + if (format.index_type != EIndexType::UINT) { + assert(false); + return; + } + indices.resize(indices.size() + 3 * sizeof(unsigned int)); + ::memcpy(indices.data() + indices.size() - 3 * sizeof(unsigned int), &id1, sizeof(unsigned int)); + ::memcpy(indices.data() + indices.size() - 2 * sizeof(unsigned int), &id2, sizeof(unsigned int)); + ::memcpy(indices.data() + indices.size() - sizeof(unsigned int), &id3, sizeof(unsigned int)); +} - // vertices/normals data - std::vector vertices(6 * entity.positions.size()); - for (size_t i = 0; i < entity.positions.size(); ++i) { - const size_t offset = i * 6; - ::memcpy(static_cast(&vertices[offset]), static_cast(entity.positions[i].data()), 3 * sizeof(float)); - if (!entity.normals.empty()) - ::memcpy(static_cast(&vertices[3 + offset]), static_cast(entity.normals[i].data()), 3 * sizeof(float)); - } +Vec2f GLModel::Geometry::extract_position_2(size_t id) const +{ + const size_t p_stride = position_stride_floats(format); + if (p_stride != 2) { + assert(false); + return { FLT_MAX, FLT_MAX }; + } - // indices data - std::vector indices = entity.indices; + if (vertices_count() <= id) { + assert(false); + return { FLT_MAX, FLT_MAX }; + } - rdata.indices_count = static_cast(indices.size()); + const float* start = &vertices[id * vertex_stride_floats(format) + position_offset_floats(format)]; + return { *(start + 0), *(start + 1) }; +} - // update bounding box - for (size_t i = 0; i < entity.positions.size(); ++i) { - m_bounding_box.merge(entity.positions[i].cast()); - } +Vec3f GLModel::Geometry::extract_position_3(size_t id) const +{ + const size_t p_stride = position_stride_floats(format); + if (p_stride != 3) { + assert(false); + return { FLT_MAX, FLT_MAX, FLT_MAX }; + } - send_to_gpu(rdata, vertices, indices); - m_render_data.emplace_back(rdata); + if (vertices_count() <= id) { + assert(false); + return { FLT_MAX, FLT_MAX, FLT_MAX }; } + + const float* start = &vertices[id * vertex_stride_floats(format) + position_offset_floats(format)]; + return { *(start + 0), *(start + 1), *(start + 2) }; } -void GLModel::init_from(const indexed_triangle_set& its, const BoundingBoxf3 &bbox) +Vec3f GLModel::Geometry::extract_normal_3(size_t id) const { - if (!m_render_data.empty()) // call reset() if you want to reuse this model - return; + const size_t n_stride = normal_stride_floats(format); + if (n_stride != 3) { + assert(false); + return { FLT_MAX, FLT_MAX, FLT_MAX }; + } - RenderData data; - data.type = PrimitiveType::Triangles; + if (vertices_count() <= id) { + assert(false); + return { FLT_MAX, FLT_MAX, FLT_MAX }; + } - std::vector vertices = std::vector(18 * its.indices.size()); - std::vector indices = std::vector(3 * its.indices.size()); + const float* start = &vertices[id * vertex_stride_floats(format) + normal_offset_floats(format)]; + return { *(start + 0), *(start + 1), *(start + 2) }; +} - unsigned int vertices_count = 0; - for (uint32_t i = 0; i < its.indices.size(); ++i) { - stl_triangle_vertex_indices face = its.indices[i]; - stl_vertex vertex[3] = { its.vertices[face[0]], its.vertices[face[1]], its.vertices[face[2]] }; - stl_vertex n = face_normal_normalized(vertex); - for (size_t j = 0; j < 3; ++ j) { - size_t offset = i * 18 + j * 6; - ::memcpy(static_cast(&vertices[offset]), static_cast(vertex[j].data()), 3 * sizeof(float)); - ::memcpy(static_cast(&vertices[3 + offset]), static_cast(n.data()), 3 * sizeof(float)); - } - for (size_t j = 0; j < 3; ++j) - indices[i * 3 + j] = vertices_count + j; - vertices_count += 3; +Vec2f GLModel::Geometry::extract_tex_coord_2(size_t id) const +{ + const size_t t_stride = tex_coord_stride_floats(format); + if (t_stride != 2) { + assert(false); + return { FLT_MAX, FLT_MAX }; + } + + if (vertices_count() <= id) { + assert(false); + return { FLT_MAX, FLT_MAX }; + } + + const float* start = &vertices[id * vertex_stride_floats(format) + tex_coord_offset_floats(format)]; + return { *(start + 0), *(start + 1) }; +} + +unsigned int GLModel::Geometry::extract_uint_index(size_t id) const +{ + if (format.index_type != EIndexType::UINT) { + assert(false); + return -1; + } + + if (indices_count() <= id) { + assert(false); + return -1; + } + + unsigned int ret = -1; + ::memcpy(&ret, indices.data() + id * index_stride_bytes(format), sizeof(unsigned int)); + return ret; +} + +unsigned short GLModel::Geometry::extract_ushort_index(size_t id) const +{ + if (format.index_type != EIndexType::USHORT) { + assert(false); + return -1; + } + + if (indices_count() <= id) { + assert(false); + return -1; + } + + unsigned short ret = -1; + ::memcpy(&ret, indices.data() + id * index_stride_bytes(format), sizeof(unsigned short)); + return ret; +} + +size_t GLModel::Geometry::vertex_stride_floats(const Format& format) +{ + switch (format.vertex_layout) + { + case EVertexLayout::P2: { return 2; } + case EVertexLayout::P2T2: { return 4; } + case EVertexLayout::P3: { return 3; } + case EVertexLayout::P3N3: { return 6; } + default: { assert(false); return 0; } + }; +} + +size_t GLModel::Geometry::position_stride_floats(const Format& format) +{ + switch (format.vertex_layout) + { + case EVertexLayout::P2: + case EVertexLayout::P2T2: { return 2; } + case EVertexLayout::P3: + case EVertexLayout::P3N3: { return 3; } + default: { assert(false); return 0; } + }; +} + +size_t GLModel::Geometry::position_offset_floats(const Format& format) +{ + switch (format.vertex_layout) + { + case EVertexLayout::P2: + case EVertexLayout::P2T2: + case EVertexLayout::P3: + case EVertexLayout::P3N3: { return 0; } + default: { assert(false); return 0; } + }; +} + +size_t GLModel::Geometry::normal_stride_floats(const Format& format) +{ + switch (format.vertex_layout) + { + case EVertexLayout::P3N3: { return 3; } + default: { assert(false); return 0; } + }; +} + +size_t GLModel::Geometry::normal_offset_floats(const Format& format) +{ + switch (format.vertex_layout) + { + case EVertexLayout::P3N3: { return 3; } + default: { assert(false); return 0; } + }; +} + +size_t GLModel::Geometry::tex_coord_stride_floats(const Format& format) +{ + switch (format.vertex_layout) + { + case EVertexLayout::P2T2: { return 2; } + default: { assert(false); return 0; } + }; +} + +size_t GLModel::Geometry::tex_coord_offset_floats(const Format& format) +{ + switch (format.vertex_layout) + { + case EVertexLayout::P2T2: { return 2; } + default: { assert(false); return 0; } + }; +} + +size_t GLModel::Geometry::index_stride_bytes(const Format& format) +{ + switch (format.index_type) + { + case EIndexType::UINT: { return sizeof(unsigned int); } + case EIndexType::USHORT: { return sizeof(unsigned short); } + default: { assert(false); return 0; } + }; +} + +bool GLModel::Geometry::has_position(const Format& format) +{ + switch (format.vertex_layout) + { + case EVertexLayout::P2: + case EVertexLayout::P2T2: + case EVertexLayout::P3: + case EVertexLayout::P3N3: { return true; } + default: { assert(false); return false; } + }; +} + +bool GLModel::Geometry::has_normal(const Format& format) +{ + switch (format.vertex_layout) + { + case EVertexLayout::P2: + case EVertexLayout::P2T2: + case EVertexLayout::P3: { return false; } + case EVertexLayout::P3N3: { return true; } + default: { assert(false); return false; } + }; +} + +bool GLModel::Geometry::has_tex_coord(const Format& format) +{ + switch (format.vertex_layout) + { + case EVertexLayout::P2T2: { return true; } + case EVertexLayout::P2: + case EVertexLayout::P3: + case EVertexLayout::P3N3: { return false; } + default: { assert(false); return false; } + }; +} + +void GLModel::init_from(Geometry&& data) +{ + if (is_initialized()) // call reset() if you want to reuse this model + return; + + if (data.vertices.empty() || data.indices.empty()) { + assert(false); + return; } - data.indices_count = static_cast(indices.size()); - m_bounding_box = bbox; + m_render_data.geometry = std::move(data); - send_to_gpu(data, vertices, indices); - m_render_data.emplace_back(data); + // update bounding box + for (size_t i = 0; i < vertices_count(); ++i) { + const size_t position_stride = Geometry::position_stride_floats(data.format); + if (position_stride == 3) + m_bounding_box.merge(m_render_data.geometry.extract_position_3(i).cast()); + else if (position_stride == 2) { + const Vec2f position = m_render_data.geometry.extract_position_2(i); + m_bounding_box.merge(Vec3f(position.x(), position.y(), 0.0f).cast()); + } + } } void GLModel::init_from(const indexed_triangle_set& its) { - this->init_from(its, bounding_box(its)); + if (is_initialized()) // call reset() if you want to reuse this model + return; + + if (its.vertices.empty() || its.indices.empty()){ + assert(false); + return; + } + + Geometry& data = m_render_data.geometry; + data.format = { Geometry::EPrimitiveType::Triangles, Geometry::EVertexLayout::P3N3, Geometry::EIndexType::UINT }; + data.vertices.reserve(3 * its.indices.size() * Geometry::vertex_stride_floats(data.format)); + data.indices.reserve(3 * its.indices.size() * Geometry::index_stride_bytes(data.format)); + + // vertices + indices + unsigned int vertices_counter = 0; + for (uint32_t i = 0; i < its.indices.size(); ++i) { + stl_triangle_vertex_indices face = its.indices[i]; + stl_vertex vertex[3] = { its.vertices[face[0]], its.vertices[face[1]], its.vertices[face[2]] }; + stl_vertex n = face_normal_normalized(vertex); + for (size_t j = 0; j < 3; ++j) { + data.add_vertex(vertex[j], n); + } + vertices_counter += 3; + data.add_uint_triangle(vertices_counter - 3, vertices_counter - 2, vertices_counter - 1); + } + + // update bounding box + for (size_t i = 0; i < vertices_count(); ++i) { + m_bounding_box.merge(m_render_data.geometry.extract_position_3(i).cast()); + } } void GLModel::init_from(const Polygons& polygons, float z) { - auto append_polygon = [](const Polygon& polygon, float z, GUI::GLModel::InitializationData& data) { - if (!polygon.empty()) { - GUI::GLModel::InitializationData::Entity entity; - entity.type = GUI::GLModel::PrimitiveType::LineLoop; - // contour - entity.positions.reserve(polygon.size() + 1); - entity.indices.reserve(polygon.size() + 1); - unsigned int id = 0; - for (const Point& p : polygon) { - Vec3f position = unscale(p.x(), p.y(), 0.0).cast(); - position.z() = z; - entity.positions.emplace_back(position); - entity.indices.emplace_back(id++); - } - data.entities.emplace_back(entity); - } - }; + if (is_initialized()) // call reset() if you want to reuse this model + return; + + if (polygons.empty()) { + assert(false); + return; + } - InitializationData init_data; + Geometry& data = m_render_data.geometry; + data.format = { Geometry::EPrimitiveType::Lines, Geometry::EVertexLayout::P3, Geometry::EIndexType::UINT }; + + size_t segments_count = 0; for (const Polygon& polygon : polygons) { - append_polygon(polygon, z, init_data); + segments_count += polygon.points.size(); + } + + data.vertices.reserve(2 * segments_count * Geometry::vertex_stride_floats(data.format)); + data.indices.reserve(2 * segments_count * Geometry::index_stride_bytes(data.format)); + + // vertices + indices + unsigned int vertices_counter = 0; + for (const Polygon& poly : polygons) { + for (size_t i = 0; i < poly.points.size(); ++i) { + const Point& p0 = poly.points[i]; + const Point& p1 = (i == poly.points.size() - 1) ? poly.points.front() : poly.points[i + 1]; + data.add_vertex(Vec3f(unscale(p0.x()), unscale(p0.y()), z)); + data.add_vertex(Vec3f(unscale(p1.x()), unscale(p1.y()), z)); + vertices_counter += 2; + data.add_uint_line(vertices_counter - 2, vertices_counter - 1); + } + } + + // update bounding box + for (size_t i = 0; i < vertices_count(); ++i) { + m_bounding_box.merge(m_render_data.geometry.extract_position_3(i).cast()); } - init_from(init_data); } bool GLModel::init_from_file(const std::string& filename) @@ -148,206 +436,252 @@ bool GLModel::init_from_file(const std::string& filename) return false; Model model; - try - { + try { model = Model::read_from_file(filename); } - catch (std::exception&) - { + catch (std::exception&) { return false; } - TriangleMesh mesh = model.mesh(); - init_from(mesh.its, mesh.bounding_box()); + const TriangleMesh mesh = model.mesh(); + init_from(mesh.its); m_filename = filename; return true; } -void GLModel::set_color(int entity_id, const ColorRGBA& color) +void GLModel::reset() { - for (size_t i = 0; i < m_render_data.size(); ++i) { - if (entity_id == -1 || static_cast(i) == entity_id) - m_render_data[i].color = color; + // release gpu memory + if (m_render_data.ibo_id > 0) { + glsafe(::glDeleteBuffers(1, &m_render_data.ibo_id)); + m_render_data.ibo_id = 0; } + if (m_render_data.vbo_id > 0) { + glsafe(::glDeleteBuffers(1, &m_render_data.vbo_id)); + m_render_data.vbo_id = 0; + } + + m_render_data.vertices_count = 0; + m_render_data.indices_count = 0; + m_render_data.geometry.vertices = std::vector(); + m_render_data.geometry.indices = std::vector(); + m_bounding_box = BoundingBoxf3(); + m_filename = std::string(); } -void GLModel::reset() +static GLenum get_primitive_mode(const GLModel::Geometry::Format& format) { - for (RenderData& data : m_render_data) { - // release gpu memory - if (data.ibo_id > 0) - glsafe(::glDeleteBuffers(1, &data.ibo_id)); - if (data.vbo_id > 0) - glsafe(::glDeleteBuffers(1, &data.vbo_id)); + switch (format.type) + { + case GLModel::Geometry::EPrimitiveType::Points: { return GL_POINTS; } + default: + case GLModel::Geometry::EPrimitiveType::Triangles: { return GL_TRIANGLES; } + case GLModel::Geometry::EPrimitiveType::TriangleStrip: { return GL_TRIANGLE_STRIP; } + case GLModel::Geometry::EPrimitiveType::TriangleFan: { return GL_TRIANGLE_FAN; } + case GLModel::Geometry::EPrimitiveType::Lines: { return GL_LINES; } + case GLModel::Geometry::EPrimitiveType::LineStrip: { return GL_LINE_STRIP; } + case GLModel::Geometry::EPrimitiveType::LineLoop: { return GL_LINE_LOOP; } } +} - m_render_data.clear(); - m_bounding_box = BoundingBoxf3(); - m_filename = std::string(); +static GLenum get_index_type(const GLModel::Geometry::Format& format) +{ + switch (format.index_type) + { + default: + case GLModel::Geometry::EIndexType::UINT: { return GL_UNSIGNED_INT; } + case GLModel::Geometry::EIndexType::USHORT: { return GL_UNSIGNED_SHORT; } + } } -void GLModel::render() const +void GLModel::render() { GLShaderProgram* shader = wxGetApp().get_current_shader(); - for (const RenderData& data : m_render_data) { - if (data.vbo_id == 0 || data.ibo_id == 0) - continue; - - GLenum mode; - switch (data.type) - { - default: - case PrimitiveType::Triangles: { mode = GL_TRIANGLES; break; } - case PrimitiveType::Lines: { mode = GL_LINES; break; } - case PrimitiveType::LineStrip: { mode = GL_LINE_STRIP; break; } - case PrimitiveType::LineLoop: { mode = GL_LINE_LOOP; break; } - } + if (shader == nullptr) + return; + + // sends data to gpu if not done yet + if (m_render_data.vbo_id == 0 || m_render_data.ibo_id == 0) { + if (m_render_data.geometry.vertices_count() > 0 && m_render_data.geometry.indices_count() > 0 && !send_to_gpu()) + return; + } + + const Geometry& data = m_render_data.geometry; + + GLenum mode = get_primitive_mode(data.format); + GLenum index_type = get_index_type(data.format); - glsafe(::glBindBuffer(GL_ARRAY_BUFFER, data.vbo_id)); - glsafe(::glVertexPointer(3, GL_FLOAT, 6 * sizeof(float), (const void*)0)); - glsafe(::glNormalPointer(GL_FLOAT, 6 * sizeof(float), (const void*)(3 * sizeof(float)))); + const size_t vertex_stride_bytes = Geometry::vertex_stride_bytes(data.format); + const bool position = Geometry::has_position(data.format); + const bool normal = Geometry::has_normal(data.format); + const bool tex_coord = Geometry::has_tex_coord(data.format); + glsafe(::glBindBuffer(GL_ARRAY_BUFFER, m_render_data.vbo_id)); + + if (position) { + glsafe(::glVertexPointer(Geometry::position_stride_floats(data.format), GL_FLOAT, vertex_stride_bytes, (const void*)Geometry::position_offset_bytes(data.format))); glsafe(::glEnableClientState(GL_VERTEX_ARRAY)); + } + if (normal) { + glsafe(::glNormalPointer(GL_FLOAT, vertex_stride_bytes, (const void*)Geometry::normal_offset_bytes(data.format))); glsafe(::glEnableClientState(GL_NORMAL_ARRAY)); + } + if (tex_coord) { + glsafe(::glTexCoordPointer(Geometry::tex_coord_stride_floats(data.format), GL_FLOAT, vertex_stride_bytes, (const void*)Geometry::tex_coord_offset_bytes(data.format))); + glsafe(::glEnableClientState(GL_TEXTURE_COORD_ARRAY)); + } - if (shader != nullptr) - shader->set_uniform("uniform_color", data.color); - else - glsafe(::glColor4fv(data.color.data())); + shader->set_uniform("uniform_color", data.color); - glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, data.ibo_id)); - glsafe(::glDrawElements(mode, static_cast(data.indices_count), GL_UNSIGNED_INT, (const void*)0)); - glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0)); + glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_render_data.ibo_id)); + glsafe(::glDrawElements(mode, indices_count(), index_type, nullptr)); + glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0)); + if (tex_coord) + glsafe(::glDisableClientState(GL_TEXTURE_COORD_ARRAY)); + if (normal) glsafe(::glDisableClientState(GL_NORMAL_ARRAY)); + if (position) glsafe(::glDisableClientState(GL_VERTEX_ARRAY)); - glsafe(::glBindBuffer(GL_ARRAY_BUFFER, 0)); - } + glsafe(::glBindBuffer(GL_ARRAY_BUFFER, 0)); } -void GLModel::render_instanced(unsigned int instances_vbo, unsigned int instances_count) const +void GLModel::render_instanced(unsigned int instances_vbo, unsigned int instances_count) { if (instances_vbo == 0) return; GLShaderProgram* shader = wxGetApp().get_current_shader(); - assert(shader == nullptr || boost::algorithm::iends_with(shader->get_name(), "_instanced")); + if (shader == nullptr || !boost::algorithm::iends_with(shader->get_name(), "_instanced")) + return; // vertex attributes - GLint position_id = (shader != nullptr) ? shader->get_attrib_location("v_position") : -1; - GLint normal_id = (shader != nullptr) ? shader->get_attrib_location("v_normal") : -1; - assert(position_id != -1 && normal_id != -1); + GLint position_id = shader->get_attrib_location("v_position"); + GLint normal_id = shader->get_attrib_location("v_normal"); + if (position_id == -1 || normal_id == -1) + return; // instance attributes - GLint offset_id = (shader != nullptr) ? shader->get_attrib_location("i_offset") : -1; - GLint scales_id = (shader != nullptr) ? shader->get_attrib_location("i_scales") : -1; - assert(offset_id != -1 && scales_id != -1); + GLint offset_id = shader->get_attrib_location("i_offset"); + GLint scales_id = shader->get_attrib_location("i_scales"); + if (offset_id == -1 || scales_id == -1) + return; + + if (m_render_data.vbo_id == 0 || m_render_data.ibo_id == 0) { + if (!send_to_gpu()) + return; + } glsafe(::glBindBuffer(GL_ARRAY_BUFFER, instances_vbo)); - if (offset_id != -1) { - glsafe(::glVertexAttribPointer(offset_id, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (GLvoid*)0)); - glsafe(::glEnableVertexAttribArray(offset_id)); - glsafe(::glVertexAttribDivisor(offset_id, 1)); - } - if (scales_id != -1) { - glsafe(::glVertexAttribPointer(scales_id, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (GLvoid*)(3 * sizeof(float)))); - glsafe(::glEnableVertexAttribArray(scales_id)); - glsafe(::glVertexAttribDivisor(scales_id, 1)); - } - - for (const RenderData& data : m_render_data) { - if (data.vbo_id == 0 || data.ibo_id == 0) - continue; - - GLenum mode; - switch (data.type) - { - default: - case PrimitiveType::Triangles: { mode = GL_TRIANGLES; break; } - case PrimitiveType::Lines: { mode = GL_LINES; break; } - case PrimitiveType::LineStrip: { mode = GL_LINE_STRIP; break; } - case PrimitiveType::LineLoop: { mode = GL_LINE_LOOP; break; } - } + glsafe(::glVertexAttribPointer(offset_id, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (GLvoid*)0)); + glsafe(::glEnableVertexAttribArray(offset_id)); + glsafe(::glVertexAttribDivisor(offset_id, 1)); - if (shader != nullptr) - shader->set_uniform("uniform_color", data.color); - else - glsafe(::glColor4fv(data.color.data())); + glsafe(::glVertexAttribPointer(scales_id, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (GLvoid*)(3 * sizeof(float)))); + glsafe(::glEnableVertexAttribArray(scales_id)); + glsafe(::glVertexAttribDivisor(scales_id, 1)); - glsafe(::glBindBuffer(GL_ARRAY_BUFFER, data.vbo_id)); - if (position_id != -1) { - glsafe(::glVertexAttribPointer(position_id, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (GLvoid*)0)); - glsafe(::glEnableVertexAttribArray(position_id)); - } - if (normal_id != -1) { - glsafe(::glVertexAttribPointer(normal_id, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (GLvoid*)(3 * sizeof(float)))); - glsafe(::glEnableVertexAttribArray(normal_id)); - } + const Geometry& data = m_render_data.geometry; + + GLenum mode = get_primitive_mode(data.format); + GLenum index_type = get_index_type(data.format); + + shader->set_uniform("uniform_color", data.color); + + const size_t vertex_stride_bytes = Geometry::vertex_stride_bytes(data.format); + const bool position = Geometry::has_position(data.format); + const bool normal = Geometry::has_normal(data.format); - glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, data.ibo_id)); - glsafe(::glDrawElementsInstanced(mode, static_cast(data.indices_count), GL_UNSIGNED_INT, (const void*)0, instances_count)); - glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0)); + glsafe(::glBindBuffer(GL_ARRAY_BUFFER, m_render_data.vbo_id)); - if (normal_id != -1) - glsafe(::glDisableVertexAttribArray(normal_id)); - if (position_id != -1) - glsafe(::glDisableVertexAttribArray(position_id)); + if (position) { + glsafe(::glVertexAttribPointer(position_id, Geometry::position_stride_floats(data.format), GL_FLOAT, GL_FALSE, vertex_stride_bytes, (GLvoid*)Geometry::position_offset_bytes(data.format))); + glsafe(::glEnableVertexAttribArray(position_id)); } - if (scales_id != -1) - glsafe(::glDisableVertexAttribArray(scales_id)); - if (offset_id != -1) - glsafe(::glDisableVertexAttribArray(offset_id)); + if (normal) { + glsafe(::glVertexAttribPointer(normal_id, Geometry::normal_stride_floats(data.format), GL_FLOAT, GL_FALSE, vertex_stride_bytes, (GLvoid*)Geometry::normal_offset_bytes(data.format))); + glsafe(::glEnableVertexAttribArray(normal_id)); + } + + glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_render_data.ibo_id)); + glsafe(::glDrawElementsInstanced(mode, indices_count(), index_type, (const void*)0, instances_count)); + glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0)); + + if (normal) + glsafe(::glDisableVertexAttribArray(normal_id)); + if (position) + glsafe(::glDisableVertexAttribArray(position_id)); + + glsafe(::glDisableVertexAttribArray(scales_id)); + glsafe(::glDisableVertexAttribArray(offset_id)); glsafe(::glBindBuffer(GL_ARRAY_BUFFER, 0)); } -void GLModel::send_to_gpu(RenderData& data, const std::vector& vertices, const std::vector& indices) +bool GLModel::send_to_gpu() { - assert(data.vbo_id == 0); - assert(data.ibo_id == 0); + if (m_render_data.vbo_id > 0 || m_render_data.ibo_id > 0) { + assert(false); + return false; + } + + Geometry& data = m_render_data.geometry; + if (data.vertices.empty() || data.indices.empty()) { + assert(false); + return false; + } - // vertex data -> send to gpu - glsafe(::glGenBuffers(1, &data.vbo_id)); - glsafe(::glBindBuffer(GL_ARRAY_BUFFER, data.vbo_id)); - glsafe(::glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(float), vertices.data(), GL_STATIC_DRAW)); + // vertices + glsafe(::glGenBuffers(1, &m_render_data.vbo_id)); + glsafe(::glBindBuffer(GL_ARRAY_BUFFER, m_render_data.vbo_id)); + glsafe(::glBufferData(GL_ARRAY_BUFFER, data.vertices_size_bytes(), data.vertices.data(), GL_STATIC_DRAW)); glsafe(::glBindBuffer(GL_ARRAY_BUFFER, 0)); + m_render_data.vertices_count = vertices_count(); + data.vertices = std::vector(); - // indices data -> send to gpu - glsafe(::glGenBuffers(1, &data.ibo_id)); - glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, data.ibo_id)); - glsafe(::glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size() * sizeof(unsigned int), indices.data(), GL_STATIC_DRAW)); + // indices + glsafe(::glGenBuffers(1, &m_render_data.ibo_id)); + glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_render_data.ibo_id)); + glsafe(::glBufferData(GL_ELEMENT_ARRAY_BUFFER, data.indices_size_bytes(), data.indices.data(), GL_STATIC_DRAW)); glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0)); + m_render_data.indices_count = indices_count(); + data.indices = std::vector(); + + return true; } -GLModel::InitializationData stilized_arrow(int resolution, float tip_radius, float tip_height, float stem_radius, float stem_height) +static void append_vertex(GLModel::Geometry& data, const Vec3f& position, const Vec3f& normal) { - auto append_vertex = [](GLModel::InitializationData::Entity& entity, const Vec3f& position, const Vec3f& normal) { - entity.positions.emplace_back(position); - entity.normals.emplace_back(normal); - }; - auto append_indices = [](GLModel::InitializationData::Entity& entity, unsigned int v1, unsigned int v2, unsigned int v3) { - entity.indices.emplace_back(v1); - entity.indices.emplace_back(v2); - entity.indices.emplace_back(v3); - }; + data.add_vertex(position, normal); +} - resolution = std::max(4, resolution); +static void append_triangle(GLModel::Geometry& data, unsigned short v1, unsigned short v2, unsigned short v3) +{ + data.add_ushort_index(v1); + data.add_ushort_index(v2); + data.add_ushort_index(v3); +} +GLModel::Geometry stilized_arrow(unsigned short resolution, float tip_radius, float tip_height, float stem_radius, float stem_height) +{ + resolution = std::max(4, resolution); + resolution = std::min(10922, resolution); // ensure no unsigned short overflow of indices - GLModel::InitializationData data; - GLModel::InitializationData::Entity entity; - entity.type = GLModel::PrimitiveType::Triangles; + GLModel::Geometry data; + data.format = { GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3N3, GLModel::Geometry::EIndexType::USHORT }; + data.vertices.reserve((6 * resolution + 2) * GLModel::Geometry::vertex_stride_floats(data.format)); + data.indices.reserve((6 * resolution * 3) * GLModel::Geometry::index_stride_bytes(data.format)); - const float angle_step = 2.0f * M_PI / static_cast(resolution); + const float angle_step = 2.0f * float(PI) / float(resolution); std::vector cosines(resolution); std::vector sines(resolution); - for (int i = 0; i < resolution; ++i) { - const float angle = angle_step * static_cast(i); + for (unsigned short i = 0; i < resolution; ++i) { + const float angle = angle_step * float(i); cosines[i] = ::cos(angle); sines[i] = -::sin(angle); } @@ -355,86 +689,76 @@ GLModel::InitializationData stilized_arrow(int resolution, float tip_radius, flo const float total_height = tip_height + stem_height; // tip vertices/normals - append_vertex(entity, { 0.0f, 0.0f, total_height }, Vec3f::UnitZ()); - for (int i = 0; i < resolution; ++i) { - append_vertex(entity, { tip_radius * sines[i], tip_radius * cosines[i], stem_height }, { sines[i], cosines[i], 0.0f }); + append_vertex(data, { 0.0f, 0.0f, total_height }, Vec3f::UnitZ()); + for (unsigned short i = 0; i < resolution; ++i) { + append_vertex(data, { tip_radius * sines[i], tip_radius * cosines[i], stem_height }, { sines[i], cosines[i], 0.0f }); } // tip triangles - for (int i = 0; i < resolution; ++i) { - const int v3 = (i < resolution - 1) ? i + 2 : 1; - append_indices(entity, 0, i + 1, v3); + for (unsigned short i = 0; i < resolution; ++i) { + const unsigned short v3 = (i < resolution - 1) ? i + 2 : 1; + append_triangle(data, 0, i + 1, v3); } // tip cap outer perimeter vertices - for (int i = 0; i < resolution; ++i) { - append_vertex(entity, { tip_radius * sines[i], tip_radius * cosines[i], stem_height }, -Vec3f::UnitZ()); + for (unsigned short i = 0; i < resolution; ++i) { + append_vertex(data, { tip_radius * sines[i], tip_radius * cosines[i], stem_height }, -Vec3f::UnitZ()); } // tip cap inner perimeter vertices - for (int i = 0; i < resolution; ++i) { - append_vertex(entity, { stem_radius * sines[i], stem_radius * cosines[i], stem_height }, -Vec3f::UnitZ()); + for (unsigned short i = 0; i < resolution; ++i) { + append_vertex(data, { stem_radius * sines[i], stem_radius * cosines[i], stem_height }, -Vec3f::UnitZ()); } // tip cap triangles - for (int i = 0; i < resolution; ++i) { - const int v2 = (i < resolution - 1) ? i + resolution + 2 : resolution + 1; - const int v3 = (i < resolution - 1) ? i + 2 * resolution + 2 : 2 * resolution + 1; - append_indices(entity, i + resolution + 1, v3, v2); - append_indices(entity, i + resolution + 1, i + 2 * resolution + 1, v3); + for (unsigned short i = 0; i < resolution; ++i) { + const unsigned short v2 = (i < resolution - 1) ? i + resolution + 2 : resolution + 1; + const unsigned short v3 = (i < resolution - 1) ? i + 2 * resolution + 2 : 2 * resolution + 1; + append_triangle(data, i + resolution + 1, v3, v2); + append_triangle(data, i + resolution + 1, i + 2 * resolution + 1, v3); } // stem bottom vertices - for (int i = 0; i < resolution; ++i) { - append_vertex(entity, { stem_radius * sines[i], stem_radius * cosines[i], stem_height }, { sines[i], cosines[i], 0.0f }); + for (unsigned short i = 0; i < resolution; ++i) { + append_vertex(data, { stem_radius * sines[i], stem_radius * cosines[i], stem_height }, { sines[i], cosines[i], 0.0f }); } // stem top vertices - for (int i = 0; i < resolution; ++i) { - append_vertex(entity, { stem_radius * sines[i], stem_radius * cosines[i], 0.0f }, { sines[i], cosines[i], 0.0f }); + for (unsigned short i = 0; i < resolution; ++i) { + append_vertex(data, { stem_radius * sines[i], stem_radius * cosines[i], 0.0f }, { sines[i], cosines[i], 0.0f }); } // stem triangles - for (int i = 0; i < resolution; ++i) { - const int v2 = (i < resolution - 1) ? i + 3 * resolution + 2 : 3 * resolution + 1; - const int v3 = (i < resolution - 1) ? i + 4 * resolution + 2 : 4 * resolution + 1; - append_indices(entity, i + 3 * resolution + 1, v3, v2); - append_indices(entity, i + 3 * resolution + 1, i + 4 * resolution + 1, v3); + for (unsigned short i = 0; i < resolution; ++i) { + const unsigned short v2 = (i < resolution - 1) ? i + 3 * resolution + 2 : 3 * resolution + 1; + const unsigned short v3 = (i < resolution - 1) ? i + 4 * resolution + 2 : 4 * resolution + 1; + append_triangle(data, i + 3 * resolution + 1, v3, v2); + append_triangle(data, i + 3 * resolution + 1, i + 4 * resolution + 1, v3); } // stem cap vertices - append_vertex(entity, Vec3f::Zero(), -Vec3f::UnitZ()); - for (int i = 0; i < resolution; ++i) { - append_vertex(entity, { stem_radius * sines[i], stem_radius * cosines[i], 0.0f }, -Vec3f::UnitZ()); + append_vertex(data, Vec3f::Zero(), -Vec3f::UnitZ()); + for (unsigned short i = 0; i < resolution; ++i) { + append_vertex(data, { stem_radius * sines[i], stem_radius * cosines[i], 0.0f }, -Vec3f::UnitZ()); } // stem cap triangles - for (int i = 0; i < resolution; ++i) { - const int v3 = (i < resolution - 1) ? i + 5 * resolution + 3 : 5 * resolution + 2; - append_indices(entity, 5 * resolution + 1, v3, i + 5 * resolution + 2); + for (unsigned short i = 0; i < resolution; ++i) { + const unsigned short v3 = (i < resolution - 1) ? i + 5 * resolution + 3 : 5 * resolution + 2; + append_triangle(data, 5 * resolution + 1, v3, i + 5 * resolution + 2); } - - data.entities.emplace_back(entity); return data; } -GLModel::InitializationData circular_arrow(int resolution, float radius, float tip_height, float tip_width, float stem_width, float thickness) +GLModel::Geometry circular_arrow(unsigned short resolution, float radius, float tip_height, float tip_width, float stem_width, float thickness) { - auto append_vertex = [](GLModel::InitializationData::Entity& entity, const Vec3f& position, const Vec3f& normal) { - entity.positions.emplace_back(position); - entity.normals.emplace_back(normal); - }; - auto append_indices = [](GLModel::InitializationData::Entity& entity, unsigned int v1, unsigned int v2, unsigned int v3) { - entity.indices.emplace_back(v1); - entity.indices.emplace_back(v2); - entity.indices.emplace_back(v3); - }; + resolution = std::max(2, resolution); + resolution = std::min(8188, resolution); // ensure no unsigned short overflow of indices - resolution = std::max(2, resolution); - - GLModel::InitializationData data; - GLModel::InitializationData::Entity entity; - entity.type = GLModel::PrimitiveType::Triangles; + GLModel::Geometry data; + data.format = { GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3N3, GLModel::Geometry::EIndexType::USHORT }; + data.vertices.reserve((8 * (resolution + 1) + 30) * GLModel::Geometry::vertex_stride_floats(data.format)); + data.indices.reserve(((8 * resolution + 16) * 3) * GLModel::Geometry::index_stride_bytes(data.format)); const float half_thickness = 0.5f * thickness; const float half_stem_width = 0.5f * stem_width; @@ -442,171 +766,160 @@ GLModel::InitializationData circular_arrow(int resolution, float radius, float t const float outer_radius = radius + half_stem_width; const float inner_radius = radius - half_stem_width; - const float step_angle = 0.5f * PI / static_cast(resolution); + const float step_angle = 0.5f * float(PI) / float(resolution); // tip // top face vertices - append_vertex(entity, { 0.0f, outer_radius, half_thickness }, Vec3f::UnitZ()); - append_vertex(entity, { 0.0f, radius + half_tip_width, half_thickness }, Vec3f::UnitZ()); - append_vertex(entity, { -tip_height, radius, half_thickness }, Vec3f::UnitZ()); - append_vertex(entity, { 0.0f, radius - half_tip_width, half_thickness }, Vec3f::UnitZ()); - append_vertex(entity, { 0.0f, inner_radius, half_thickness }, Vec3f::UnitZ()); + append_vertex(data, { 0.0f, outer_radius, half_thickness }, Vec3f::UnitZ()); + append_vertex(data, { 0.0f, radius + half_tip_width, half_thickness }, Vec3f::UnitZ()); + append_vertex(data, { -tip_height, radius, half_thickness }, Vec3f::UnitZ()); + append_vertex(data, { 0.0f, radius - half_tip_width, half_thickness }, Vec3f::UnitZ()); + append_vertex(data, { 0.0f, inner_radius, half_thickness }, Vec3f::UnitZ()); // top face triangles - append_indices(entity, 0, 1, 2); - append_indices(entity, 0, 2, 4); - append_indices(entity, 4, 2, 3); + append_triangle(data, 0, 1, 2); + append_triangle(data, 0, 2, 4); + append_triangle(data, 4, 2, 3); // bottom face vertices - append_vertex(entity, { 0.0f, outer_radius, -half_thickness }, -Vec3f::UnitZ()); - append_vertex(entity, { 0.0f, radius + half_tip_width, -half_thickness }, -Vec3f::UnitZ()); - append_vertex(entity, { -tip_height, radius, -half_thickness }, -Vec3f::UnitZ()); - append_vertex(entity, { 0.0f, radius - half_tip_width, -half_thickness }, -Vec3f::UnitZ()); - append_vertex(entity, { 0.0f, inner_radius, -half_thickness }, -Vec3f::UnitZ()); + append_vertex(data, { 0.0f, outer_radius, -half_thickness }, -Vec3f::UnitZ()); + append_vertex(data, { 0.0f, radius + half_tip_width, -half_thickness }, -Vec3f::UnitZ()); + append_vertex(data, { -tip_height, radius, -half_thickness }, -Vec3f::UnitZ()); + append_vertex(data, { 0.0f, radius - half_tip_width, -half_thickness }, -Vec3f::UnitZ()); + append_vertex(data, { 0.0f, inner_radius, -half_thickness }, -Vec3f::UnitZ()); // bottom face triangles - append_indices(entity, 5, 7, 6); - append_indices(entity, 5, 9, 7); - append_indices(entity, 9, 8, 7); + append_triangle(data, 5, 7, 6); + append_triangle(data, 5, 9, 7); + append_triangle(data, 9, 8, 7); // side faces vertices - append_vertex(entity, { 0.0f, outer_radius, -half_thickness }, Vec3f::UnitX()); - append_vertex(entity, { 0.0f, radius + half_tip_width, -half_thickness }, Vec3f::UnitX()); - append_vertex(entity, { 0.0f, outer_radius, half_thickness }, Vec3f::UnitX()); - append_vertex(entity, { 0.0f, radius + half_tip_width, half_thickness }, Vec3f::UnitX()); + append_vertex(data, { 0.0f, outer_radius, -half_thickness }, Vec3f::UnitX()); + append_vertex(data, { 0.0f, radius + half_tip_width, -half_thickness }, Vec3f::UnitX()); + append_vertex(data, { 0.0f, outer_radius, half_thickness }, Vec3f::UnitX()); + append_vertex(data, { 0.0f, radius + half_tip_width, half_thickness }, Vec3f::UnitX()); Vec3f normal(-half_tip_width, tip_height, 0.0f); normal.normalize(); - append_vertex(entity, { 0.0f, radius + half_tip_width, -half_thickness }, normal); - append_vertex(entity, { -tip_height, radius, -half_thickness }, normal); - append_vertex(entity, { 0.0f, radius + half_tip_width, half_thickness }, normal); - append_vertex(entity, { -tip_height, radius, half_thickness }, normal); + append_vertex(data, { 0.0f, radius + half_tip_width, -half_thickness }, normal); + append_vertex(data, { -tip_height, radius, -half_thickness }, normal); + append_vertex(data, { 0.0f, radius + half_tip_width, half_thickness }, normal); + append_vertex(data, { -tip_height, radius, half_thickness }, normal); - normal = Vec3f(-half_tip_width, -tip_height, 0.0f); + normal = { -half_tip_width, -tip_height, 0.0f }; normal.normalize(); - append_vertex(entity, { -tip_height, radius, -half_thickness }, normal); - append_vertex(entity, { 0.0f, radius - half_tip_width, -half_thickness }, normal); - append_vertex(entity, { -tip_height, radius, half_thickness }, normal); - append_vertex(entity, { 0.0f, radius - half_tip_width, half_thickness }, normal); + append_vertex(data, { -tip_height, radius, -half_thickness }, normal); + append_vertex(data, { 0.0f, radius - half_tip_width, -half_thickness }, normal); + append_vertex(data, { -tip_height, radius, half_thickness }, normal); + append_vertex(data, { 0.0f, radius - half_tip_width, half_thickness }, normal); - append_vertex(entity, { 0.0f, radius - half_tip_width, -half_thickness }, Vec3f::UnitX()); - append_vertex(entity, { 0.0f, inner_radius, -half_thickness }, Vec3f::UnitX()); - append_vertex(entity, { 0.0f, radius - half_tip_width, half_thickness }, Vec3f::UnitX()); - append_vertex(entity, { 0.0f, inner_radius, half_thickness }, Vec3f::UnitX()); + append_vertex(data, { 0.0f, radius - half_tip_width, -half_thickness }, Vec3f::UnitX()); + append_vertex(data, { 0.0f, inner_radius, -half_thickness }, Vec3f::UnitX()); + append_vertex(data, { 0.0f, radius - half_tip_width, half_thickness }, Vec3f::UnitX()); + append_vertex(data, { 0.0f, inner_radius, half_thickness }, Vec3f::UnitX()); // side face triangles - for (int i = 0; i < 4; ++i) { - const int ii = i * 4; - append_indices(entity, 10 + ii, 11 + ii, 13 + ii); - append_indices(entity, 10 + ii, 13 + ii, 12 + ii); + for (unsigned short i = 0; i < 4; ++i) { + const unsigned short ii = i * 4; + append_triangle(data, 10 + ii, 11 + ii, 13 + ii); + append_triangle(data, 10 + ii, 13 + ii, 12 + ii); } // stem // top face vertices - for (int i = 0; i <= resolution; ++i) { - const float angle = static_cast(i) * step_angle; - append_vertex(entity, { inner_radius * ::sin(angle), inner_radius * ::cos(angle), half_thickness }, Vec3f::UnitZ()); + for (unsigned short i = 0; i <= resolution; ++i) { + const float angle = float(i) * step_angle; + append_vertex(data, { inner_radius * ::sin(angle), inner_radius * ::cos(angle), half_thickness }, Vec3f::UnitZ()); } - for (int i = 0; i <= resolution; ++i) { - const float angle = static_cast(i) * step_angle; - append_vertex(entity, { outer_radius * ::sin(angle), outer_radius * ::cos(angle), half_thickness }, Vec3f::UnitZ()); + for (unsigned short i = 0; i <= resolution; ++i) { + const float angle = float(i) * step_angle; + append_vertex(data, { outer_radius * ::sin(angle), outer_radius * ::cos(angle), half_thickness }, Vec3f::UnitZ()); } // top face triangles - for (int i = 0; i < resolution; ++i) { - append_indices(entity, 26 + i, 27 + i, 27 + resolution + i); - append_indices(entity, 27 + i, 28 + resolution + i, 27 + resolution + i); + for (unsigned short i = 0; i < resolution; ++i) { + append_triangle(data, 26 + i, 27 + i, 27 + resolution + i); + append_triangle(data, 27 + i, 28 + resolution + i, 27 + resolution + i); } // bottom face vertices - for (int i = 0; i <= resolution; ++i) { - const float angle = static_cast(i) * step_angle; - append_vertex(entity, { inner_radius * ::sin(angle), inner_radius * ::cos(angle), -half_thickness }, -Vec3f::UnitZ()); + for (unsigned short i = 0; i <= resolution; ++i) { + const float angle = float(i) * step_angle; + append_vertex(data, { inner_radius * ::sin(angle), inner_radius * ::cos(angle), -half_thickness }, -Vec3f::UnitZ()); } - for (int i = 0; i <= resolution; ++i) { - const float angle = static_cast(i) * step_angle; - append_vertex(entity, { outer_radius * ::sin(angle), outer_radius * ::cos(angle), -half_thickness }, -Vec3f::UnitZ()); + for (unsigned short i = 0; i <= resolution; ++i) { + const float angle = float(i) * step_angle; + append_vertex(data, { outer_radius * ::sin(angle), outer_radius * ::cos(angle), -half_thickness }, -Vec3f::UnitZ()); } // bottom face triangles - for (int i = 0; i < resolution; ++i) { - append_indices(entity, 28 + 2 * resolution + i, 29 + 3 * resolution + i, 29 + 2 * resolution + i); - append_indices(entity, 29 + 2 * resolution + i, 29 + 3 * resolution + i, 30 + 3 * resolution + i); + for (unsigned short i = 0; i < resolution; ++i) { + append_triangle(data, 28 + 2 * resolution + i, 29 + 3 * resolution + i, 29 + 2 * resolution + i); + append_triangle(data, 29 + 2 * resolution + i, 29 + 3 * resolution + i, 30 + 3 * resolution + i); } // side faces vertices and triangles - for (int i = 0; i <= resolution; ++i) { - const float angle = static_cast(i) * step_angle; + for (unsigned short i = 0; i <= resolution; ++i) { + const float angle = float(i) * step_angle; const float c = ::cos(angle); const float s = ::sin(angle); - append_vertex(entity, { inner_radius * s, inner_radius * c, -half_thickness }, { -s, -c, 0.0f }); + append_vertex(data, { inner_radius * s, inner_radius * c, -half_thickness }, { -s, -c, 0.0f }); } - for (int i = 0; i <= resolution; ++i) { - const float angle = static_cast(i) * step_angle; + for (unsigned short i = 0; i <= resolution; ++i) { + const float angle = float(i) * step_angle; const float c = ::cos(angle); const float s = ::sin(angle); - append_vertex(entity, { inner_radius * s, inner_radius * c, half_thickness }, { -s, -c, 0.0f }); + append_vertex(data, { inner_radius * s, inner_radius * c, half_thickness }, { -s, -c, 0.0f }); } - int first_id = 26 + 4 * (resolution + 1); - for (int i = 0; i < resolution; ++i) { - const int ii = first_id + i; - append_indices(entity, ii, ii + 1, ii + resolution + 2); - append_indices(entity, ii, ii + resolution + 2, ii + resolution + 1); + unsigned short first_id = 26 + 4 * (resolution + 1); + for (unsigned short i = 0; i < resolution; ++i) { + const unsigned short ii = first_id + i; + append_triangle(data, ii, ii + 1, ii + resolution + 2); + append_triangle(data, ii, ii + resolution + 2, ii + resolution + 1); } - append_vertex(entity, { inner_radius, 0.0f, -half_thickness }, -Vec3f::UnitY()); - append_vertex(entity, { outer_radius, 0.0f, -half_thickness }, -Vec3f::UnitY()); - append_vertex(entity, { inner_radius, 0.0f, half_thickness }, -Vec3f::UnitY()); - append_vertex(entity, { outer_radius, 0.0f, half_thickness }, -Vec3f::UnitY()); + append_vertex(data, { inner_radius, 0.0f, -half_thickness }, -Vec3f::UnitY()); + append_vertex(data, { outer_radius, 0.0f, -half_thickness }, -Vec3f::UnitY()); + append_vertex(data, { inner_radius, 0.0f, half_thickness }, -Vec3f::UnitY()); + append_vertex(data, { outer_radius, 0.0f, half_thickness }, -Vec3f::UnitY()); first_id = 26 + 6 * (resolution + 1); - append_indices(entity, first_id, first_id + 1, first_id + 3); - append_indices(entity, first_id, first_id + 3, first_id + 2); + append_triangle(data, first_id, first_id + 1, first_id + 3); + append_triangle(data, first_id, first_id + 3, first_id + 2); - for (int i = resolution; i >= 0; --i) { - const float angle = static_cast(i) * step_angle; + for (short i = resolution; i >= 0; --i) { + const float angle = float(i) * step_angle; const float c = ::cos(angle); const float s = ::sin(angle); - append_vertex(entity, { outer_radius * s, outer_radius * c, -half_thickness }, { s, c, 0.0f }); + append_vertex(data, { outer_radius * s, outer_radius * c, -half_thickness }, { s, c, 0.0f }); } - for (int i = resolution; i >= 0; --i) { - const float angle = static_cast(i) * step_angle; + for (short i = resolution; i >= 0; --i) { + const float angle = float(i) * step_angle; const float c = ::cos(angle); const float s = ::sin(angle); - append_vertex(entity, { outer_radius * s, outer_radius * c, +half_thickness }, { s, c, 0.0f }); + append_vertex(data, { outer_radius * s, outer_radius * c, +half_thickness }, { s, c, 0.0f }); } first_id = 30 + 6 * (resolution + 1); - for (int i = 0; i < resolution; ++i) { - const int ii = first_id + i; - append_indices(entity, ii, ii + 1, ii + resolution + 2); - append_indices(entity, ii, ii + resolution + 2, ii + resolution + 1); + for (unsigned short i = 0; i < resolution; ++i) { + const unsigned short ii = first_id + i; + append_triangle(data, ii, ii + 1, ii + resolution + 2); + append_triangle(data, ii, ii + resolution + 2, ii + resolution + 1); } - - data.entities.emplace_back(entity); return data; } -GLModel::InitializationData straight_arrow(float tip_width, float tip_height, float stem_width, float stem_height, float thickness) +GLModel::Geometry straight_arrow(float tip_width, float tip_height, float stem_width, float stem_height, float thickness) { - auto append_vertex = [](GLModel::InitializationData::Entity& entity, const Vec3f& position, const Vec3f& normal) { - entity.positions.emplace_back(position); - entity.normals.emplace_back(normal); - }; - auto append_indices = [](GLModel::InitializationData::Entity& entity, unsigned int v1, unsigned int v2, unsigned int v3) { - entity.indices.emplace_back(v1); - entity.indices.emplace_back(v2); - entity.indices.emplace_back(v3); - }; - - GLModel::InitializationData data; - GLModel::InitializationData::Entity entity; - entity.type = GLModel::PrimitiveType::Triangles; + GLModel::Geometry data; + data.format = { GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3N3, GLModel::Geometry::EIndexType::USHORT }; + data.vertices.reserve(42 * GLModel::Geometry::vertex_stride_floats(data.format)); + data.indices.reserve((24 * 3) * GLModel::Geometry::index_stride_bytes(data.format)); const float half_thickness = 0.5f * thickness; const float half_stem_width = 0.5f * stem_width; @@ -614,133 +927,121 @@ GLModel::InitializationData straight_arrow(float tip_width, float tip_height, fl const float total_height = tip_height + stem_height; // top face vertices - append_vertex(entity, { half_stem_width, 0.0, half_thickness }, Vec3f::UnitZ()); - append_vertex(entity, { half_stem_width, stem_height, half_thickness }, Vec3f::UnitZ()); - append_vertex(entity, { half_tip_width, stem_height, half_thickness }, Vec3f::UnitZ()); - append_vertex(entity, { 0.0, total_height, half_thickness }, Vec3f::UnitZ()); - append_vertex(entity, { -half_tip_width, stem_height, half_thickness }, Vec3f::UnitZ()); - append_vertex(entity, { -half_stem_width, stem_height, half_thickness }, Vec3f::UnitZ()); - append_vertex(entity, { -half_stem_width, 0.0, half_thickness }, Vec3f::UnitZ()); + append_vertex(data, { half_stem_width, 0.0, half_thickness }, Vec3f::UnitZ()); + append_vertex(data, { half_stem_width, stem_height, half_thickness }, Vec3f::UnitZ()); + append_vertex(data, { half_tip_width, stem_height, half_thickness }, Vec3f::UnitZ()); + append_vertex(data, { 0.0, total_height, half_thickness }, Vec3f::UnitZ()); + append_vertex(data, { -half_tip_width, stem_height, half_thickness }, Vec3f::UnitZ()); + append_vertex(data, { -half_stem_width, stem_height, half_thickness }, Vec3f::UnitZ()); + append_vertex(data, { -half_stem_width, 0.0, half_thickness }, Vec3f::UnitZ()); // top face triangles - append_indices(entity, 0, 1, 6); - append_indices(entity, 6, 1, 5); - append_indices(entity, 4, 5, 3); - append_indices(entity, 5, 1, 3); - append_indices(entity, 1, 2, 3); + append_triangle(data, 0, 1, 6); + append_triangle(data, 6, 1, 5); + append_triangle(data, 4, 5, 3); + append_triangle(data, 5, 1, 3); + append_triangle(data, 1, 2, 3); // bottom face vertices - append_vertex(entity, { half_stem_width, 0.0, -half_thickness }, -Vec3f::UnitZ()); - append_vertex(entity, { half_stem_width, stem_height, -half_thickness }, -Vec3f::UnitZ()); - append_vertex(entity, { half_tip_width, stem_height, -half_thickness }, -Vec3f::UnitZ()); - append_vertex(entity, { 0.0, total_height, -half_thickness }, -Vec3f::UnitZ()); - append_vertex(entity, { -half_tip_width, stem_height, -half_thickness }, -Vec3f::UnitZ()); - append_vertex(entity, { -half_stem_width, stem_height, -half_thickness }, -Vec3f::UnitZ()); - append_vertex(entity, { -half_stem_width, 0.0, -half_thickness }, -Vec3f::UnitZ()); + append_vertex(data, { half_stem_width, 0.0, -half_thickness }, -Vec3f::UnitZ()); + append_vertex(data, { half_stem_width, stem_height, -half_thickness }, -Vec3f::UnitZ()); + append_vertex(data, { half_tip_width, stem_height, -half_thickness }, -Vec3f::UnitZ()); + append_vertex(data, { 0.0, total_height, -half_thickness }, -Vec3f::UnitZ()); + append_vertex(data, { -half_tip_width, stem_height, -half_thickness }, -Vec3f::UnitZ()); + append_vertex(data, { -half_stem_width, stem_height, -half_thickness }, -Vec3f::UnitZ()); + append_vertex(data, { -half_stem_width, 0.0, -half_thickness }, -Vec3f::UnitZ()); // bottom face triangles - append_indices(entity, 7, 13, 8); - append_indices(entity, 13, 12, 8); - append_indices(entity, 12, 11, 10); - append_indices(entity, 8, 12, 10); - append_indices(entity, 9, 8, 10); + append_triangle(data, 7, 13, 8); + append_triangle(data, 13, 12, 8); + append_triangle(data, 12, 11, 10); + append_triangle(data, 8, 12, 10); + append_triangle(data, 9, 8, 10); // side faces vertices - append_vertex(entity, { half_stem_width, 0.0, -half_thickness }, Vec3f::UnitX()); - append_vertex(entity, { half_stem_width, stem_height, -half_thickness }, Vec3f::UnitX()); - append_vertex(entity, { half_stem_width, 0.0, half_thickness }, Vec3f::UnitX()); - append_vertex(entity, { half_stem_width, stem_height, half_thickness }, Vec3f::UnitX()); + append_vertex(data, { half_stem_width, 0.0, -half_thickness }, Vec3f::UnitX()); + append_vertex(data, { half_stem_width, stem_height, -half_thickness }, Vec3f::UnitX()); + append_vertex(data, { half_stem_width, 0.0, half_thickness }, Vec3f::UnitX()); + append_vertex(data, { half_stem_width, stem_height, half_thickness }, Vec3f::UnitX()); - append_vertex(entity, { half_stem_width, stem_height, -half_thickness }, -Vec3f::UnitY()); - append_vertex(entity, { half_tip_width, stem_height, -half_thickness }, -Vec3f::UnitY()); - append_vertex(entity, { half_stem_width, stem_height, half_thickness }, -Vec3f::UnitY()); - append_vertex(entity, { half_tip_width, stem_height, half_thickness }, -Vec3f::UnitY()); + append_vertex(data, { half_stem_width, stem_height, -half_thickness }, -Vec3f::UnitY()); + append_vertex(data, { half_tip_width, stem_height, -half_thickness }, -Vec3f::UnitY()); + append_vertex(data, { half_stem_width, stem_height, half_thickness }, -Vec3f::UnitY()); + append_vertex(data, { half_tip_width, stem_height, half_thickness }, -Vec3f::UnitY()); Vec3f normal(tip_height, half_tip_width, 0.0f); normal.normalize(); - append_vertex(entity, { half_tip_width, stem_height, -half_thickness }, normal); - append_vertex(entity, { 0.0, total_height, -half_thickness }, normal); - append_vertex(entity, { half_tip_width, stem_height, half_thickness }, normal); - append_vertex(entity, { 0.0, total_height, half_thickness }, normal); + append_vertex(data, { half_tip_width, stem_height, -half_thickness }, normal); + append_vertex(data, { 0.0, total_height, -half_thickness }, normal); + append_vertex(data, { half_tip_width, stem_height, half_thickness }, normal); + append_vertex(data, { 0.0, total_height, half_thickness }, normal); - normal = Vec3f(-tip_height, half_tip_width, 0.0f); + normal = { -tip_height, half_tip_width, 0.0f }; normal.normalize(); - append_vertex(entity, { 0.0, total_height, -half_thickness }, normal); - append_vertex(entity, { -half_tip_width, stem_height, -half_thickness }, normal); - append_vertex(entity, { 0.0, total_height, half_thickness }, normal); - append_vertex(entity, { -half_tip_width, stem_height, half_thickness }, normal); - - append_vertex(entity, { -half_tip_width, stem_height, -half_thickness }, -Vec3f::UnitY()); - append_vertex(entity, { -half_stem_width, stem_height, -half_thickness }, -Vec3f::UnitY()); - append_vertex(entity, { -half_tip_width, stem_height, half_thickness }, -Vec3f::UnitY()); - append_vertex(entity, { -half_stem_width, stem_height, half_thickness }, -Vec3f::UnitY()); - - append_vertex(entity, { -half_stem_width, stem_height, -half_thickness }, -Vec3f::UnitX()); - append_vertex(entity, { -half_stem_width, 0.0, -half_thickness }, -Vec3f::UnitX()); - append_vertex(entity, { -half_stem_width, stem_height, half_thickness }, -Vec3f::UnitX()); - append_vertex(entity, { -half_stem_width, 0.0, half_thickness }, -Vec3f::UnitX()); - - append_vertex(entity, { -half_stem_width, 0.0, -half_thickness }, -Vec3f::UnitY()); - append_vertex(entity, { half_stem_width, 0.0, -half_thickness }, -Vec3f::UnitY()); - append_vertex(entity, { -half_stem_width, 0.0, half_thickness }, -Vec3f::UnitY()); - append_vertex(entity, { half_stem_width, 0.0, half_thickness }, -Vec3f::UnitY()); + append_vertex(data, { 0.0, total_height, -half_thickness }, normal); + append_vertex(data, { -half_tip_width, stem_height, -half_thickness }, normal); + append_vertex(data, { 0.0, total_height, half_thickness }, normal); + append_vertex(data, { -half_tip_width, stem_height, half_thickness }, normal); + + append_vertex(data, { -half_tip_width, stem_height, -half_thickness }, -Vec3f::UnitY()); + append_vertex(data, { -half_stem_width, stem_height, -half_thickness }, -Vec3f::UnitY()); + append_vertex(data, { -half_tip_width, stem_height, half_thickness }, -Vec3f::UnitY()); + append_vertex(data, { -half_stem_width, stem_height, half_thickness }, -Vec3f::UnitY()); + + append_vertex(data, { -half_stem_width, stem_height, -half_thickness }, -Vec3f::UnitX()); + append_vertex(data, { -half_stem_width, 0.0, -half_thickness }, -Vec3f::UnitX()); + append_vertex(data, { -half_stem_width, stem_height, half_thickness }, -Vec3f::UnitX()); + append_vertex(data, { -half_stem_width, 0.0, half_thickness }, -Vec3f::UnitX()); + + append_vertex(data, { -half_stem_width, 0.0, -half_thickness }, -Vec3f::UnitY()); + append_vertex(data, { half_stem_width, 0.0, -half_thickness }, -Vec3f::UnitY()); + append_vertex(data, { -half_stem_width, 0.0, half_thickness }, -Vec3f::UnitY()); + append_vertex(data, { half_stem_width, 0.0, half_thickness }, -Vec3f::UnitY()); // side face triangles - for (int i = 0; i < 7; ++i) { - const int ii = i * 4; - append_indices(entity, 14 + ii, 15 + ii, 17 + ii); - append_indices(entity, 14 + ii, 17 + ii, 16 + ii); + for (unsigned short i = 0; i < 7; ++i) { + const unsigned short ii = i * 4; + append_triangle(data, 14 + ii, 15 + ii, 17 + ii); + append_triangle(data, 14 + ii, 17 + ii, 16 + ii); } - - data.entities.emplace_back(entity); return data; } -GLModel::InitializationData diamond(int resolution) +GLModel::Geometry diamond(unsigned short resolution) { - resolution = std::max(4, resolution); + resolution = std::max(4, resolution); + resolution = std::min(65534, resolution); // ensure no unsigned short overflow of indices - GLModel::InitializationData data; - GLModel::InitializationData::Entity entity; - entity.type = GLModel::PrimitiveType::Triangles; + GLModel::Geometry data; + data.format = { GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3N3, GLModel::Geometry::EIndexType::USHORT }; + data.vertices.reserve((resolution + 2) * GLModel::Geometry::vertex_stride_floats(data.format)); + data.indices.reserve(((2 * (resolution + 1)) * 3) * GLModel::Geometry::index_stride_bytes(data.format)); const float step = 2.0f * float(PI) / float(resolution); - // positions - for (int i = 0; i < resolution; ++i) { + // vertices + for (unsigned short i = 0; i < resolution; ++i) { float ii = float(i) * step; - entity.positions.emplace_back(0.5f * ::cos(ii), 0.5f * ::sin(ii), 0.0f); - } - entity.positions.emplace_back(0.0f, 0.0f, 0.5f); - entity.positions.emplace_back(0.0f, 0.0f, -0.5f); - - // normals - for (const Vec3f& v : entity.positions) { - entity.normals.emplace_back(v.normalized()); + const Vec3f p = { 0.5f * ::cos(ii), 0.5f * ::sin(ii), 0.0f }; + append_vertex(data, p, p.normalized()); } + Vec3f p = { 0.0f, 0.0f, 0.5f }; + append_vertex(data, p, p.normalized()); + p = { 0.0f, 0.0f, -0.5f }; + append_vertex(data, p, p.normalized()); // triangles // top - for (int i = 0; i < resolution; ++i) { - entity.indices.push_back(i + 0); - entity.indices.push_back(i + 1); - entity.indices.push_back(resolution); + for (unsigned short i = 0; i < resolution; ++i) { + append_triangle(data, i + 0, i + 1, resolution); } - entity.indices.push_back(resolution - 1); - entity.indices.push_back(0); - entity.indices.push_back(resolution); + append_triangle(data, resolution - 1, 0, resolution); // bottom - for (int i = 0; i < resolution; ++i) { - entity.indices.push_back(i + 0); - entity.indices.push_back(resolution + 1); - entity.indices.push_back(i + 1); + for (unsigned short i = 0; i < resolution; ++i) { + append_triangle(data, i + 0, resolution + 1, i + 1); } - entity.indices.push_back(resolution - 1); - entity.indices.push_back(resolution + 1); - entity.indices.push_back(0); - - data.entities.emplace_back(entity); + append_triangle(data, resolution - 1, resolution + 1, 0); return data; } diff --git a/src/slic3r/GUI/GLModel.hpp b/src/slic3r/GUI/GLModel.hpp index 62722b18cf2..3b1d20cea16 100644 --- a/src/slic3r/GUI/GLModel.hpp +++ b/src/slic3r/GUI/GLModel.hpp @@ -20,46 +20,108 @@ namespace GUI { class GLModel { public: - enum class PrimitiveType : unsigned char + struct Geometry { - Triangles, - Lines, - LineStrip, - LineLoop - }; + enum class EPrimitiveType : unsigned char + { + Points, + Triangles, + TriangleStrip, + TriangleFan, + Lines, + LineStrip, + LineLoop + }; - struct RenderData - { - PrimitiveType type; - unsigned int vbo_id{ 0 }; - unsigned int ibo_id{ 0 }; - size_t indices_count{ 0 }; - ColorRGBA color; - }; + enum class EVertexLayout : unsigned char + { + P2, // position 2 floats + P2T2, // position 2 floats + texture coords 2 floats + P3, // position 3 floats + P3N3, // position 3 floats + normal 3 floats + }; - struct InitializationData - { - struct Entity + enum class EIndexType : unsigned char { - PrimitiveType type; - std::vector positions; - std::vector normals; - std::vector indices; - ColorRGBA color; + UINT, // unsigned int + USHORT // unsigned short }; - std::vector entities; + struct Format + { + EPrimitiveType type{ EPrimitiveType::Triangles }; + EVertexLayout vertex_layout{ EVertexLayout::P3N3 }; + EIndexType index_type{ EIndexType::UINT }; + }; + + Format format; + std::vector vertices; + std::vector indices; + ColorRGBA color{ ColorRGBA::BLACK() }; + + void add_vertex(const Vec2f& position); + void add_vertex(const Vec3f& position); + void add_vertex(const Vec3f& position, const Vec3f& normal); + + void add_ushort_index(unsigned short id); + void add_uint_index(unsigned int id); + + void add_ushort_line(unsigned short id1, unsigned short id2); + void add_uint_line(unsigned int id1, unsigned int id2); - size_t vertices_count() const; - size_t vertices_size_floats() const { return vertices_count() * 6; } - size_t vertices_size_bytes() const { return vertices_size_floats() * sizeof(float); } + void add_ushort_triangle(unsigned short id1, unsigned short id2, unsigned short id3); + void add_uint_triangle(unsigned int id1, unsigned int id2, unsigned int id3); - size_t indices_count() const; - size_t indices_size_bytes() const { return indices_count() * sizeof(unsigned int); } + Vec2f extract_position_2(size_t id) const; + Vec3f extract_position_3(size_t id) const; + Vec3f extract_normal_3(size_t id) const; + Vec2f extract_tex_coord_2(size_t id) const; + + unsigned int extract_uint_index(size_t id) const; + unsigned short extract_ushort_index(size_t id) const; + + size_t vertices_count() const { return vertices.size() / vertex_stride_floats(format); } + size_t indices_count() const { return indices.size() / index_stride_bytes(format); } + + size_t vertices_size_floats() const { return vertices.size(); } + size_t vertices_size_bytes() const { return vertices_size_floats() * sizeof(float); } + size_t indices_size_bytes() const { return indices.size(); } + + static size_t vertex_stride_floats(const Format& format); + static size_t vertex_stride_bytes(const Format& format) { return vertex_stride_floats(format) * sizeof(float); } + + static size_t position_stride_floats(const Format& format); + static size_t position_stride_bytes(const Format& format) { return position_stride_floats(format) * sizeof(float); } + static size_t position_offset_floats(const Format& format); + static size_t position_offset_bytes(const Format& format) { return position_offset_floats(format) * sizeof(float); } + + static size_t normal_stride_floats(const Format& format); + static size_t normal_stride_bytes(const Format& format) { return normal_stride_floats(format) * sizeof(float); } + static size_t normal_offset_floats(const Format& format); + static size_t normal_offset_bytes(const Format& format) { return normal_offset_floats(format) * sizeof(float); } + + static size_t tex_coord_stride_floats(const Format& format); + static size_t tex_coord_stride_bytes(const Format& format) { return tex_coord_stride_floats(format) * sizeof(float); } + static size_t tex_coord_offset_floats(const Format& format); + static size_t tex_coord_offset_bytes(const Format& format) { return tex_coord_offset_floats(format) * sizeof(float); } + + static size_t index_stride_bytes(const Format& format); + + static bool has_position(const Format& format); + static bool has_normal(const Format& format); + static bool has_tex_coord(const Format& format); }; + struct RenderData + { + Geometry geometry; + unsigned int vbo_id{ 0 }; + unsigned int ibo_id{ 0 }; + size_t vertices_count{ 0 }; + size_t indices_count{ 0 }; + }; private: - std::vector m_render_data; + RenderData m_render_data; BoundingBoxf3 m_bounding_box; std::string m_filename; @@ -68,50 +130,59 @@ namespace GUI { GLModel() = default; virtual ~GLModel() { reset(); } - void init_from(const InitializationData& data); - void init_from(const indexed_triangle_set& its, const BoundingBoxf3& bbox); + size_t vertices_count() const { return m_render_data.vertices_count > 0 ? + m_render_data.vertices_count : m_render_data.geometry.vertices_count(); } + size_t indices_count() const { return m_render_data.indices_count > 0 ? + m_render_data.indices_count : m_render_data.geometry.indices_count(); } + + size_t vertices_size_floats() const { return vertices_count() * Geometry::vertex_stride_floats(m_render_data.geometry.format); } + size_t vertices_size_bytes() const { return vertices_size_floats() * sizeof(float); } + + size_t indices_size_bytes() const { return indices_count() * Geometry::index_stride_bytes(m_render_data.geometry.format); } + + void init_from(Geometry&& data); void init_from(const indexed_triangle_set& its); void init_from(const Polygons& polygons, float z); bool init_from_file(const std::string& filename); - // if entity_id == -1 set the color of all entities - void set_color(int entity_id, const ColorRGBA& color); + void set_color(const ColorRGBA& color) { m_render_data.geometry.color = color; } + const ColorRGBA& get_color() const { return m_render_data.geometry.color; } void reset(); - void render() const; - void render_instanced(unsigned int instances_vbo, unsigned int instances_count) const; + void render(); + void render_instanced(unsigned int instances_vbo, unsigned int instances_count); - bool is_initialized() const { return !m_render_data.empty(); } + bool is_initialized() const { return vertices_count() > 0 && indices_count() > 0; } const BoundingBoxf3& get_bounding_box() const { return m_bounding_box; } const std::string& get_filename() const { return m_filename; } private: - void send_to_gpu(RenderData& data, const std::vector& vertices, const std::vector& indices); + bool send_to_gpu(); }; // create an arrow with cylindrical stem and conical tip, with the given dimensions and resolution // the origin of the arrow is in the center of the stem cap // the arrow has its axis of symmetry along the Z axis and is pointing upward // used to render bed axes and sequential marker - GLModel::InitializationData stilized_arrow(int resolution, float tip_radius, float tip_height, float stem_radius, float stem_height); + GLModel::Geometry stilized_arrow(unsigned short resolution, float tip_radius, float tip_height, float stem_radius, float stem_height); // create an arrow whose stem is a quarter of circle, with the given dimensions and resolution // the origin of the arrow is in the center of the circle // the arrow is contained in the 1st quadrant of the XY plane and is pointing counterclockwise // used to render sidebar hints for rotations - GLModel::InitializationData circular_arrow(int resolution, float radius, float tip_height, float tip_width, float stem_width, float thickness); + GLModel::Geometry circular_arrow(unsigned short resolution, float radius, float tip_height, float tip_width, float stem_width, float thickness); // create an arrow with the given dimensions // the origin of the arrow is in the center of the stem cap // the arrow is contained in XY plane and has its main axis along the Y axis // used to render sidebar hints for position and scale - GLModel::InitializationData straight_arrow(float tip_width, float tip_height, float stem_width, float stem_height, float thickness); + GLModel::Geometry straight_arrow(float tip_width, float tip_height, float stem_width, float stem_height, float thickness); // create a diamond with the given resolution // the origin of the diamond is in its center // the diamond is contained into a box with size [1, 1, 1] - GLModel::InitializationData diamond(int resolution); + GLModel::Geometry diamond(unsigned short resolution); } // namespace GUI } // namespace Slic3r diff --git a/src/slic3r/GUI/GLSelectionRectangle.cpp b/src/slic3r/GUI/GLSelectionRectangle.cpp index 30b7888c537..9ae15bbe8e1 100644 --- a/src/slic3r/GUI/GLSelectionRectangle.cpp +++ b/src/slic3r/GUI/GLSelectionRectangle.cpp @@ -80,17 +80,17 @@ namespace GUI { Size cnv_size = canvas.get_canvas_size(); float cnv_half_width = 0.5f * (float)cnv_size.get_width(); float cnv_half_height = 0.5f * (float)cnv_size.get_height(); - if ((cnv_half_width == 0.0f) || (cnv_half_height == 0.0f)) + if (cnv_half_width == 0.0f || cnv_half_height == 0.0f) return; Vec2d start(m_start_corner(0) - cnv_half_width, cnv_half_height - m_start_corner(1)); Vec2d end(m_end_corner(0) - cnv_half_width, cnv_half_height - m_end_corner(1)); - float left = (float)std::min(start(0), end(0)) * inv_zoom; - float top = (float)std::max(start(1), end(1)) * inv_zoom; - float right = (float)std::max(start(0), end(0)) * inv_zoom; - float bottom = (float)std::min(start(1), end(1)) * inv_zoom; - + const float left = (float)std::min(start(0), end(0)) * inv_zoom; + const float top = (float)std::max(start(1), end(1)) * inv_zoom; + const float right = (float)std::max(start(0), end(0)) * inv_zoom; + const float bottom = (float)std::min(start(1), end(1)) * inv_zoom; + glsafe(::glLineWidth(1.5f)); glsafe(::glDisable(GL_DEPTH_TEST)); @@ -100,7 +100,7 @@ namespace GUI { // ensure that the rectangle is renderered inside the frustrum glsafe(::glTranslated(0.0, 0.0, -(camera.get_near_z() + 0.5))); // ensure that the overlay fits the frustrum near z plane - double gui_scale = camera.get_gui_scale(); + const double gui_scale = camera.get_gui_scale(); glsafe(::glScaled(gui_scale, gui_scale, 1.0)); glsafe(::glPushAttrib(GL_ENABLE_BIT)); @@ -116,34 +116,28 @@ namespace GUI { m_old_end_corner = m_end_corner; m_rectangle.reset(); - GLModel::InitializationData init_data; - GLModel::InitializationData::Entity entity; - entity.type = GLModel::PrimitiveType::LineLoop; - entity.positions.reserve(4); - entity.positions.emplace_back(left, bottom, 0.0f); - entity.positions.emplace_back(right, bottom, 0.0f); - entity.positions.emplace_back(right, top, 0.0f); - entity.positions.emplace_back(left, top, 0.0f); - - entity.normals.reserve(4); - for (size_t j = 0; j < 5; ++j) { - entity.normals.emplace_back(Vec3f::UnitZ()); - } - - entity.indices.reserve(6); - entity.indices.emplace_back(0); - entity.indices.emplace_back(1); - entity.indices.emplace_back(2); - entity.indices.emplace_back(2); - entity.indices.emplace_back(3); - entity.indices.emplace_back(0); - - init_data.entities.emplace_back(entity); - m_rectangle.init_from(init_data); + GLModel::Geometry init_data; + init_data.format = { GLModel::Geometry::EPrimitiveType::LineLoop, GLModel::Geometry::EVertexLayout::P2, GLModel::Geometry::EIndexType::USHORT }; + init_data.vertices.reserve(4 * GLModel::Geometry::vertex_stride_floats(init_data.format)); + init_data.indices.reserve(4 * GLModel::Geometry::index_stride_bytes(init_data.format)); + + // vertices + init_data.add_vertex(Vec2f(left, bottom)); + init_data.add_vertex(Vec2f(right, bottom)); + init_data.add_vertex(Vec2f(right, top)); + init_data.add_vertex(Vec2f(left, top)); + + // indices + init_data.add_ushort_index(0); + init_data.add_ushort_index(1); + init_data.add_ushort_index(2); + init_data.add_ushort_index(3); + + m_rectangle.init_from(std::move(init_data)); } - ColorRGBA color(0.0f, 1.0f, 0.38f, 1.0f); - m_rectangle.set_color(-1, color); + const ColorRGBA color(0.0f, 1.0f, 0.38f, 1.0f); + m_rectangle.set_color(color); m_rectangle.render(); shader->stop_using(); } diff --git a/src/slic3r/GUI/Gizmos/GLGizmoAdvancedCut.cpp b/src/slic3r/GUI/Gizmos/GLGizmoAdvancedCut.cpp index bc1ff411a15..47b3a55ad38 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoAdvancedCut.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoAdvancedCut.cpp @@ -27,30 +27,12 @@ const int c_connectors_group_id = 4; const float UndefFloat = -999.f; // connector colors - -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 CYAN() { return {0.0f, 1.0f, 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 MAGENTA() { return {1.0f, 0.0f, 1.0f, 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 PLAG_COLOR = YELLOW(); -static const ColorRGBA DOWEL_COLOR = DARK_YELLOW(); -static const ColorRGBA HOVERED_PLAG_COLOR = CYAN(); +static const ColorRGBA PLAG_COLOR = ColorRGBA::YELLOW(); +static const ColorRGBA DOWEL_COLOR = ColorRGBA::DARK_YELLOW(); +static const ColorRGBA HOVERED_PLAG_COLOR = ColorRGBA::CYAN(); static const ColorRGBA HOVERED_DOWEL_COLOR = {0.0f, 0.5f, 0.5f, 1.0f}; -static const ColorRGBA SELECTED_PLAG_COLOR = GRAY(); -static const ColorRGBA SELECTED_DOWEL_COLOR = GRAY(); // DARK_GRAY(); +static const ColorRGBA SELECTED_PLAG_COLOR = ColorRGBA::GRAY(); +static const ColorRGBA SELECTED_DOWEL_COLOR = ColorRGBA::GRAY(); // DARK_GRAY(); static const ColorRGBA CONNECTOR_DEF_COLOR = {1.0f, 1.0f, 1.0f, 0.5f}; static const ColorRGBA CONNECTOR_ERR_COLOR = {1.0f, 0.3f, 0.3f, 0.5f}; static const ColorRGBA HOVERED_ERR_COLOR = {1.0f, 0.3f, 0.3f, 1.0f}; @@ -516,6 +498,8 @@ void GLGizmoAdvancedCut::on_render_for_picking() glsafe(::glDisable(GL_DEPTH_TEST)); + glsafe(::glPushMatrix()); + BoundingBoxf3 box = m_parent.get_selection().get_bounding_box(); #if ENABLE_FIXED_GRABBER float mean_size = (float)(GLGizmoBase::Grabber::FixedGrabberSize); @@ -523,8 +507,17 @@ void GLGizmoAdvancedCut::on_render_for_picking() float mean_size = (float)((box.size().x() + box.size().y() + box.size().z()) / 3.0); #endif - m_move_grabber.color = picking_color_component(0); - m_move_grabber.render_for_picking(mean_size); + m_move_grabber.color = picking_color_component(0); + GLShaderProgram *shader = wxGetApp().get_shader("flat"); + if (shader != nullptr) { + shader->start_using(); + + m_move_grabber.render_for_picking(mean_size); + + shader->stop_using(); + } + + glsafe(::glPopMatrix()); glsafe(::glEnable(GL_DEPTH_TEST)); auto inst_id = m_c->selection_info()->get_active_instance(); @@ -876,67 +869,112 @@ void GLGizmoAdvancedCut::render_cut_plane_and_grabbers() point += object_offset; } - // draw plane glsafe(::glEnable(GL_DEPTH_TEST)); glsafe(::glDisable(GL_CULL_FACE)); glsafe(::glEnable(GL_BLEND)); glsafe(::glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)); + + GLShaderProgram *shader = wxGetApp().get_shader("flat"); + if (shader != nullptr) { + shader->start_using(); - ::glBegin(GL_QUADS); - ::glColor4f(0.8f, 0.8f, 0.8f, 0.5f); - for (const Vec3d& point : plane_points_rot) { - ::glVertex3f(point(0), point(1), point(2)); - } - glsafe(::glEnd()); + // draw plane + { + m_plane.reset(); - glsafe(::glEnable(GL_CULL_FACE)); - glsafe(::glDisable(GL_BLEND)); + GLModel::Geometry init_data; + init_data.format = { GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3, GLModel::Geometry::EIndexType::USHORT }; + init_data.color = { 0.8f, 0.8f, 0.8f, 0.5f }; + init_data.vertices.reserve(4 * GLModel::Geometry::vertex_stride_floats(init_data.format)); + init_data.indices.reserve(6 * GLModel::Geometry::index_stride_bytes(init_data.format)); - // Draw the grabber and the connecting line - Vec3d plane_center_rot = calc_plane_center(plane_points_rot); - m_move_grabber.center = plane_center_rot + plane_normal_rot * Offset; - // m_move_grabber.angles = m_current_base_rotation + m_rotation; + // vertices + for (const Vec3d &point : plane_points_rot) { + init_data.add_vertex((Vec3f)point.cast()); + } - glsafe(::glDisable(GL_DEPTH_TEST)); - glsafe(::glLineWidth(m_hover_id != -1 ? 2.0f : 1.5f)); - glsafe(::glColor3f(1.0, 1.0, 0.0)); - glLineStipple(1, 0x0FFF); - glEnable(GL_LINE_STIPPLE); - ::glBegin(GL_LINES); - ::glVertex3dv(plane_center_rot.data()); - ::glVertex3dv(m_move_grabber.center.data()); - glsafe(::glEnd()); - glDisable(GL_LINE_STIPPLE); + // indices + init_data.add_ushort_triangle(0, 1, 2); + init_data.add_ushort_triangle(2, 3, 0); - // std::copy(std::begin(GrabberColor), std::end(GrabberColor), m_move_grabber.color); - // m_move_grabber.color = GrabberColor; - // m_move_grabber.hover_color = GrabberHoverColor; - // m_move_grabber.render(m_hover_id == get_group_id(), (float)((box.size()(0) + box.size()(1) + box.size()(2)) / 3.0)); - bool hover = (m_hover_id == get_group_id()); - ColorRGBA render_color; - if (hover) { - render_color = GrabberHoverColor; - } - else - render_color = GrabberColor; + m_plane.init_from(std::move(init_data)); + } + m_plane.render(); + + glsafe(::glEnable(GL_CULL_FACE)); + glsafe(::glDisable(GL_BLEND)); + + // Draw the grabber and the connecting line + Vec3d plane_center_rot = calc_plane_center(plane_points_rot); + m_move_grabber.center = plane_center_rot + plane_normal_rot * Offset; + // m_move_grabber.angles = m_current_base_rotation + m_rotation; + + { + m_grabber_connection.reset(); + + GLModel::Geometry init_data; + init_data.format = { GLModel::Geometry::EPrimitiveType::Lines, GLModel::Geometry::EVertexLayout::P3, GLModel::Geometry::EIndexType::USHORT }; + init_data.color = ColorRGBA::YELLOW(); + init_data.vertices.reserve(2 * GLModel::Geometry::vertex_stride_floats(init_data.format)); + init_data.indices.reserve(2 * GLModel::Geometry::index_stride_bytes(init_data.format)); + + // vertices + init_data.add_vertex((Vec3f)plane_center_rot.cast()); + init_data.add_vertex((Vec3f)m_move_grabber.center.cast()); - const GLModel &cube = m_move_grabber.get_cube(); - // BBS set to fixed size grabber - // float fullsize = 2 * (dragging ? get_dragging_half_size(size) : get_half_size(size)); - float fullsize = 8.0f; - if (GLGizmoBase::INV_ZOOM > 0) { - fullsize = m_move_grabber.FixedGrabberSize * GLGizmoBase::INV_ZOOM; + // indices + init_data.add_ushort_line(0, 1); + + m_grabber_connection.init_from(std::move(init_data)); + } + + glsafe(::glDisable(GL_DEPTH_TEST)); + glsafe(::glLineWidth(m_hover_id != -1 ? 2.0f : 1.5f)); + glLineStipple(1, 0x0FFF); + glEnable(GL_LINE_STIPPLE); + m_grabber_connection.render(); + glDisable(GL_LINE_STIPPLE); + + shader->stop_using(); } - const_cast(&cube)->set_color(-1, render_color); + { + GLShaderProgram *shader = wxGetApp().get_shader("gouraud_light"); + if (shader == nullptr) + return; + shader->start_using(); + shader->set_uniform("emission_factor", 0.1f); + // std::copy(std::begin(GrabberColor), std::end(GrabberColor), m_move_grabber.color); + // m_move_grabber.color = GrabberColor; + // m_move_grabber.hover_color = GrabberHoverColor; + // m_move_grabber.render(m_hover_id == get_group_id(), (float)((box.size()(0) + box.size()(1) + box.size()(2)) / 3.0)); + bool hover = (m_hover_id == get_group_id()); + ColorRGBA render_color; + if (hover) { + render_color = GrabberHoverColor; + } + else + render_color = GrabberColor; + + GLModel &cube = m_move_grabber.get_cube(); + // BBS set to fixed size grabber + // float fullsize = 2 * (dragging ? get_dragging_half_size(size) : get_half_size(size)); + float fullsize = 8.0f; + if (GLGizmoBase::INV_ZOOM > 0) { + fullsize = m_move_grabber.FixedGrabberSize * GLGizmoBase::INV_ZOOM; + } - glsafe(::glPushMatrix()); - glsafe(::glTranslated(m_move_grabber.center.x(), m_move_grabber.center.y(), m_move_grabber.center.z())); - glsafe(::glMultMatrixd(m_rotate_matrix.data())); + cube.set_color(render_color); - glsafe(::glScaled(fullsize, fullsize, fullsize)); - cube.render(); - glsafe(::glPopMatrix()); + glsafe(::glPushMatrix()); + glsafe(::glTranslated(m_move_grabber.center.x(), m_move_grabber.center.y(), m_move_grabber.center.z())); + glsafe(::glMultMatrixd(m_rotate_matrix.data())); + + glsafe(::glScaled(fullsize, fullsize, fullsize)); + cube.render(); + glsafe(::glPopMatrix()); + shader->stop_using(); + } // Should be placed at last, because GLGizmoRotate3D clears depth buffer set_center(m_cut_plane_center); @@ -1043,7 +1081,7 @@ void GLGizmoAdvancedCut::render_connector_model(GLModel &model, const ColorRGBA glsafe(::glMultMatrixd(view_model_matrix.data())); - model.set_color(-1, color); + model.set_color(color); model.render(); shader->stop_using(); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoAdvancedCut.hpp b/src/slic3r/GUI/Gizmos/GLGizmoAdvancedCut.hpp index 38abb30c3fe..c381dffff02 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoAdvancedCut.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoAdvancedCut.hpp @@ -53,6 +53,8 @@ struct Rotate_data { bool m_place_on_cut_lower{false}; bool m_rotate_upper{false}; bool m_rotate_lower{false}; + GLModel m_plane; + GLModel m_grabber_connection; bool m_do_segment; double m_segment_smoothing_alpha; diff --git a/src/slic3r/GUI/Gizmos/GLGizmoBase.cpp b/src/slic3r/GUI/Gizmos/GLGizmoBase.cpp index 588e8ce58b8..32308233cac 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoBase.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoBase.cpp @@ -68,26 +68,9 @@ void GLGizmoBase::load_render_colors() RenderColor::colors[RenderCol_Flatten_Plane_Hover] = ImGuiWrapper::to_ImVec4(GLGizmoBase::FLATTEN_HOVER_COLOR); } -GLGizmoBase::Grabber::Grabber() - : center(Vec3d::Zero()) - , angles(Vec3d::Zero()) - , dragging(false) - , enabled(true) +void GLGizmoBase::Grabber::render(bool hover, float size) { - color = GRABBER_NORMAL_COL; - hover_color = GRABBER_HOVER_COL; -} - -void GLGizmoBase::Grabber::render(bool hover, float size) const -{ - ColorRGBA render_color; - if (hover) { - render_color = hover_color; - } - else - render_color = color; - - render(size, render_color, false); + render(size, hover ? hover_color : color, false); } float GLGizmoBase::Grabber::get_half_size(float size) const @@ -100,28 +83,26 @@ float GLGizmoBase::Grabber::get_dragging_half_size(float size) const return get_half_size(size) * DraggingScaleFactor; } -const GLModel& GLGizmoBase::Grabber::get_cube() const +GLModel& GLGizmoBase::Grabber::get_cube() { - if (! cube_initialized) { + if (!m_cube.is_initialized()) { // This cannot be done in constructor, OpenGL is not yet // initialized at that point (on Linux at least). - indexed_triangle_set mesh = its_make_cube(1., 1., 1.); - its_translate(mesh, Vec3f(-0.5, -0.5, -0.5)); - const_cast(cube).init_from(mesh, BoundingBoxf3{ { -0.5, -0.5, -0.5 }, { 0.5, 0.5, 0.5 } }); - const_cast(cube_initialized) = true; + indexed_triangle_set its = its_make_cube(1., 1., 1.); + its_translate(its, Vec3f(-0.5, -0.5, -0.5)); + m_cube.init_from(its); } - return cube; + return m_cube; } -void GLGizmoBase::Grabber::render(float size, const ColorRGBA& render_color, bool picking) const +void GLGizmoBase::Grabber::render(float size, const ColorRGBA& render_color, bool picking) { - if (! cube_initialized) { + if (!m_cube.is_initialized()) { // This cannot be done in constructor, OpenGL is not yet // initialized at that point (on Linux at least). - indexed_triangle_set mesh = its_make_cube(1., 1., 1.); - its_translate(mesh, Vec3f(-0.5, -0.5, -0.5)); - const_cast(cube).init_from(mesh, BoundingBoxf3{ { -0.5, -0.5, -0.5 }, { 0.5, 0.5, 0.5 } }); - const_cast(cube_initialized) = true; + indexed_triangle_set its = its_make_cube(1., 1., 1.); + its_translate(its, Vec3f(-0.5, -0.5, -0.5)); + m_cube.init_from(its); } //BBS set to fixed size grabber @@ -132,7 +113,7 @@ void GLGizmoBase::Grabber::render(float size, const ColorRGBA& render_color, boo } - const_cast(&cube)->set_color(-1, render_color); + m_cube.set_color(render_color); glsafe(::glPushMatrix()); glsafe(::glTranslated(center.x(), center.y(), center.z())); @@ -140,11 +121,10 @@ void GLGizmoBase::Grabber::render(float size, const ColorRGBA& render_color, boo glsafe(::glRotated(Geometry::rad2deg(angles.y()), 0.0, 1.0, 0.0)); glsafe(::glRotated(Geometry::rad2deg(angles.x()), 1.0, 0.0, 0.0)); glsafe(::glScaled(fullsize, fullsize, fullsize)); - cube.render(); + m_cube.render(); glsafe(::glPopMatrix()); } - GLGizmoBase::GLGizmoBase(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id) : m_parent(parent) , m_group_id(-1) @@ -292,17 +272,23 @@ void GLGizmoBase::render_grabbers(float size) const void GLGizmoBase::render_grabbers_for_picking(const BoundingBoxf3& box) const { + GLShaderProgram* shader = wxGetApp().get_shader("flat"); + if (shader != nullptr) { + shader->start_using(); + #if ENABLE_FIXED_GRABBER - float mean_size = (float)(GLGizmoBase::Grabber::FixedGrabberSize); + const float mean_size = (float)(GLGizmoBase::Grabber::FixedGrabberSize); #else - float mean_size = (float)((box.size().x() + box.size().y() + box.size().z()) / 3.0); + const float mean_size = (float)((box.size().x() + box.size().y() + box.size().z()) / 3.0); #endif - for (unsigned int i = 0; i < (unsigned int)m_grabbers.size(); ++i) { - if (m_grabbers[i].enabled) { - m_grabbers[i].color = picking_color_component(i); - m_grabbers[i].render_for_picking(mean_size); + for (unsigned int i = 0; i < (unsigned int)m_grabbers.size(); ++i) { + if (m_grabbers[i].enabled) { + m_grabbers[i].color = picking_color_component(i); + m_grabbers[i].render_for_picking(mean_size); + } } + shader->stop_using(); } } diff --git a/src/slic3r/GUI/Gizmos/GLGizmoBase.hpp b/src/slic3r/GUI/Gizmos/GLGizmoBase.hpp index a858954b471..b2b8c4626e8 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoBase.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoBase.hpp @@ -64,27 +64,26 @@ class GLGizmoBase static const float FixedGrabberSize; static const float FixedRadiusSize; - Vec3d center; - Vec3d angles; - ColorRGBA color; - ColorRGBA hover_color; - bool enabled; - bool dragging; + bool enabled{ true }; + bool dragging{ false }; + Vec3d center{ Vec3d::Zero() }; + Vec3d angles{ Vec3d::Zero() }; + ColorRGBA color{GRABBER_NORMAL_COL}; + ColorRGBA hover_color{GRABBER_HOVER_COL}; - Grabber(); + Grabber() = default; - void render(bool hover, float size) const; - void render_for_picking(float size) const { render(size, color, true); } + void render(bool hover, float size); + void render_for_picking(float size) { render(size, color, true); } float get_half_size(float size) const; float get_dragging_half_size(float size) const; - const GLModel& get_cube() const; + GLModel& get_cube(); private: - void render(float size, const ColorRGBA& render_color, bool picking) const; + void render(float size, const ColorRGBA& render_color, bool picking); - GLModel cube; - bool cube_initialized = false; + GLModel m_cube; }; public: diff --git a/src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp b/src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp index 8f73379e71c..c8514ed103c 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp @@ -20,7 +20,6 @@ namespace GUI { GLGizmoHollow::GLGizmoHollow(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id) : GLGizmoBase(parent, icon_filename, sprite_id) { - m_vbo_cylinder.init_from(its_make_cylinder(1., 1.)); } @@ -63,6 +62,9 @@ void GLGizmoHollow::set_sla_support_data(ModelObject*, const Selection&) void GLGizmoHollow::on_render() { + if (!m_cylinder.is_initialized()) + m_cylinder.init_from(its_make_cylinder(1.0, 1.0)); + const Selection& selection = m_parent.get_selection(); const CommonGizmosDataObjects::SelectionInfo* sel_info = m_c->selection_info(); @@ -99,12 +101,14 @@ void GLGizmoHollow::on_render_for_picking() render_points(selection, true); } -void GLGizmoHollow::render_points(const Selection& selection, bool picking) const +void GLGizmoHollow::render_points(const Selection& selection, bool picking) { - GLShaderProgram* shader = picking ? nullptr : wxGetApp().get_shader("gouraud_light"); - if (shader) - shader->start_using(); - ScopeGuard guard([shader]() { if (shader) shader->stop_using(); }); + GLShaderProgram* shader = picking ? wxGetApp().get_shader("flat") : wxGetApp().get_shader("gouraud_light"); + if (shader == nullptr) + return; + + shader->start_using(); + ScopeGuard guard([shader]() { shader->stop_using(); }); const GLVolume* vol = selection.get_volume(*selection.get_volume_idxs().begin()); const Transform3d& instance_scaling_matrix_inverse = vol->get_instance_transformation().get_matrix(true, true, false, true).inverse(); @@ -126,28 +130,25 @@ void GLGizmoHollow::render_points(const Selection& selection, bool picking) cons continue; // First decide about the color of the point. - if (picking) { + if (picking) render_color = picking_color_component(i); - } else { - if (size_t(m_hover_id) == i) { - render_color = {0.f, 1.f, 1.f, 1.f}; - } + if (size_t(m_hover_id) == i) + render_color = ColorRGBA::CYAN(); else if (m_c->hollowed_mesh() && i < m_c->hollowed_mesh()->get_drainholes().size() && m_c->hollowed_mesh()->get_drainholes()[i].failed) { - render_color = {1.f, 0.f, 0.f, .5f}; + render_color = { 1.0f, 0.0f, 0.0f, 0.5f }; } - else { // neigher hover nor picking + else // neither hover nor picking render_color = point_selected ? ColorRGBA(1.0f, 0.3f, 0.3f, 0.5f) : ColorRGBA(1.0f, 1.0f, 1.0f, 0.5f); - } } - const_cast(&m_vbo_cylinder)->set_color(-1, render_color); + m_cylinder.set_color(render_color); // Inverse matrix of the instance scaling is applied so that the mark does not scale with the object. glsafe(::glPushMatrix()); - glsafe(::glTranslatef(drain_hole.pos(0), drain_hole.pos(1), drain_hole.pos(2))); + glsafe(::glTranslatef(drain_hole.pos.x(), drain_hole.pos.y(), drain_hole.pos.z())); glsafe(::glMultMatrixd(instance_scaling_matrix_inverse.data())); if (vol->is_left_handed()) @@ -155,13 +156,13 @@ void GLGizmoHollow::render_points(const Selection& selection, bool picking) cons // Matrices set, we can render the point mark now. Eigen::Quaterniond q; - q.setFromTwoVectors(Vec3d{0., 0., 1.}, instance_scaling_matrix_inverse * (-drain_hole.normal).cast()); + q.setFromTwoVectors(Vec3d::UnitZ(), instance_scaling_matrix_inverse * (-drain_hole.normal).cast()); Eigen::AngleAxisd aa(q); - glsafe(::glRotated(aa.angle() * (180. / M_PI), aa.axis()(0), aa.axis()(1), aa.axis()(2))); + glsafe(::glRotated(aa.angle() * (180. / M_PI), aa.axis().x(), aa.axis().y(), aa.axis().z())); glsafe(::glPushMatrix()); glsafe(::glTranslated(0., 0., -drain_hole.height)); glsafe(::glScaled(drain_hole.radius, drain_hole.radius, drain_hole.height + sla::HoleStickOutLength)); - m_vbo_cylinder.render(); + m_cylinder.render(); glsafe(::glPopMatrix()); if (vol->is_left_handed()) @@ -172,8 +173,6 @@ void GLGizmoHollow::render_points(const Selection& selection, bool picking) cons glsafe(::glPopMatrix()); } - - bool GLGizmoHollow::is_mesh_point_clipped(const Vec3d& point) const { if (m_c->object_clipper()->get_position() == 0.) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoHollow.hpp b/src/slic3r/GUI/Gizmos/GLGizmoHollow.hpp index 2cf08de2a0a..fa89e0febc2 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoHollow.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoHollow.hpp @@ -42,13 +42,14 @@ class GLGizmoHollow : public GLGizmoBase void on_render() override; void on_render_for_picking() override; - void render_points(const Selection& selection, bool picking = false) const; + void render_points(const Selection& selection, bool picking = false); void hollow_mesh(bool postpone_error_messages = false); bool unsaved_changes() const; ObjectID m_old_mo_id = -1; - GLModel m_vbo_cylinder; + GLModel m_cylinder; + float m_new_hole_radius = 2.f; // Size of a new hole. float m_new_hole_height = 6.f; mutable std::vector m_selected; // which holes are currently selected diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMove.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMove.cpp index 483c833d742..e7c861cb02d 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMove.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMove.cpp @@ -25,9 +25,7 @@ GLGizmoMove3D::GLGizmoMove3D(GLCanvas3D& parent, const std::string& icon_filenam : GLGizmoBase(parent, icon_filename, sprite_id) //BBS: GUI refactor: add obj manipulation , m_object_manipulation(obj_manipulation) -{ - m_vbo_cone.init_from(its_make_cone(1., 1., 2*PI/36)); -} +{} std::string GLGizmoMove3D::get_tooltip() const { @@ -95,6 +93,9 @@ void GLGizmoMove3D::on_update(const UpdateData& data) void GLGizmoMove3D::on_render() { + if (!m_cone.is_initialized()) + m_cone.init_from(its_make_cone(1.0, 1.0, double(PI) / 18.0)); + const Selection& selection = m_parent.get_selection(); glsafe(::glClear(GL_DEPTH_BUFFER_BIT)); @@ -138,25 +139,20 @@ void GLGizmoMove3D::on_render() m_grabber_connections[id].old_center = center; m_grabber_connections[id].model.reset(); - GLModel::InitializationData init_data; - GUI::GLModel::InitializationData::Entity entity; - entity.type = GUI::GLModel::PrimitiveType::Lines; - entity.positions.reserve(2); - entity.positions.emplace_back(center.cast()); - entity.positions.emplace_back(m_grabbers[id].center.cast()); - - entity.normals.reserve(2); - for (size_t j = 0; j < 2; ++j) { - entity.normals.emplace_back(Vec3f::UnitZ()); - } - - entity.indices.reserve(2); - entity.indices.emplace_back(0); - entity.indices.emplace_back(1); - - init_data.entities.emplace_back(entity); - m_grabber_connections[id].model.init_from(init_data); - m_grabber_connections[id].model.set_color(-1, AXES_COLOR[id]); + GLModel::Geometry init_data; + init_data.format = { GLModel::Geometry::EPrimitiveType::Lines, GLModel::Geometry::EVertexLayout::P3, GLModel::Geometry::EIndexType::USHORT }; + init_data.color = AXES_COLOR[id]; + init_data.vertices.reserve(2 * GLModel::Geometry::vertex_stride_floats(init_data.format)); + init_data.indices.reserve(2 * GLModel::Geometry::index_stride_bytes(init_data.format)); + + // vertices + init_data.add_vertex((Vec3f)center.cast()); + init_data.add_vertex((Vec3f)m_grabbers[id].center.cast()); + + // indices + init_data.add_ushort_line(0, 1); + + m_grabber_connections[id].model.init_from(std::move(init_data)); } glLineStipple(1, 0x0FFF); @@ -241,7 +237,7 @@ double GLGizmoMove3D::calc_projection(const UpdateData& data) const return projection; } -void GLGizmoMove3D::render_grabber_extension(Axis axis, const BoundingBoxf3& box, bool picking) const +void GLGizmoMove3D::render_grabber_extension(Axis axis, const BoundingBoxf3& box, bool picking) { #if ENABLE_FIXED_GRABBER float mean_size = (float)(GLGizmoBase::Grabber::FixedGrabberSize); @@ -258,15 +254,13 @@ void GLGizmoMove3D::render_grabber_extension(Axis axis, const BoundingBoxf3& box } } - GLShaderProgram* shader = wxGetApp().get_shader("gouraud_light"); + GLShaderProgram* shader = wxGetApp().get_shader(picking ? "flat" : "gouraud_light"); if (shader == nullptr) return; - const_cast(&m_vbo_cone)->set_color(-1, color); - if (!picking) { - shader->start_using(); - shader->set_uniform("emission_factor", 0.1f); - } + m_cone.set_color(color); + shader->start_using(); + shader->set_uniform("emission_factor", 0.1f); glsafe(::glPushMatrix()); glsafe(::glTranslated(m_grabbers[axis].center.x(), m_grabbers[axis].center.y(), m_grabbers[axis].center.z())); @@ -277,11 +271,10 @@ void GLGizmoMove3D::render_grabber_extension(Axis axis, const BoundingBoxf3& box //glsafe(::glTranslated(0.0, 0.0, 2.0 * size)); glsafe(::glScaled(0.75 * size, 0.75 * size, 2.0 * size)); - m_vbo_cone.render(); + m_cone.render(); glsafe(::glPopMatrix()); - if (! picking) - shader->stop_using(); + shader->stop_using(); } diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMove.hpp b/src/slic3r/GUI/Gizmos/GLGizmoMove.hpp index 70ae525f78c..f4cc4f6c74c 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMove.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMove.hpp @@ -21,7 +21,7 @@ class GLGizmoMove3D : public GLGizmoBase Vec3d m_starting_box_center{ Vec3d::Zero() }; Vec3d m_starting_box_bottom_center{ Vec3d::Zero() }; - GLModel m_vbo_cone; + GLModel m_cone; struct GrabberConnection { GLModel model; @@ -59,7 +59,7 @@ class GLGizmoMove3D : public GLGizmoBase private: double calc_projection(const UpdateData& data) const; - void render_grabber_extension(Axis axis, const BoundingBoxf3& box, bool picking) const; + void render_grabber_extension(Axis axis, const BoundingBoxf3& box, bool picking); }; diff --git a/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp b/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp index 53fc03edcba..ab7f242ce51 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp @@ -194,23 +194,22 @@ void GLGizmoPainterBase::render_cursor_circle() m_old_cursor_radius = m_cursor_radius; m_circle.reset(); - GLModel::InitializationData init_data; - GLModel::InitializationData::Entity entity; - entity.type = GLModel::PrimitiveType::LineLoop; + GLModel::Geometry init_data; static const unsigned int StepsCount = 32; static const float StepSize = 2.0f * float(PI) / float(StepsCount); - entity.positions.reserve(StepsCount); - entity.normals.reserve(StepsCount); - entity.indices.reserve(StepsCount); - for (unsigned int i = 0; i < StepsCount; ++i) { + init_data.format = { GLModel::Geometry::EPrimitiveType::LineLoop, GLModel::Geometry::EVertexLayout::P3, GLModel::Geometry::EIndexType::USHORT }; + init_data.color = { 0.0f, 1.0f, 0.3f, 1.0f }; + init_data.vertices.reserve(StepsCount * GLModel::Geometry::vertex_stride_floats(init_data.format)); + init_data.indices.reserve(StepsCount * GLModel::Geometry::index_stride_bytes(init_data.format)); + + // vertices + indices + for (unsigned short i = 0; i < StepsCount; ++i) { const float angle = float(i * StepSize); - entity.positions.emplace_back(center.x() + ::cos(angle) * m_cursor_radius, center.y() + ::sin(angle) * m_cursor_radius, 0.0f); - entity.normals.emplace_back(Vec3f::UnitZ()); - entity.indices.emplace_back(i); + init_data.add_vertex(Vec3f(center.x() + ::cos(angle) * m_cursor_radius, center.y() + ::sin(angle) * m_cursor_radius, 0.0f)); + init_data.add_ushort_index(i); } - init_data.entities.emplace_back(entity); - m_circle.init_from(init_data); + m_circle.init_from(std::move(init_data)); } // BBS @@ -220,8 +219,14 @@ void GLGizmoPainterBase::render_cursor_circle() else if (m_button_down == Button::Right) render_color = this->get_cursor_sphere_right_button_color(); - m_circle.set_color(-1, render_color); - m_circle.render(); + m_circle.set_color(render_color); + + GLShaderProgram* shader = GUI::wxGetApp().get_shader("flat"); + if (shader != nullptr) { + shader->start_using(); + m_circle.render(); + shader->stop_using(); + } glsafe(::glPopAttrib()); glsafe(::glPopMatrix()); @@ -337,7 +342,7 @@ void GLGizmoPainterBase::update_contours(const TriangleMesh& vol_mesh, float cur const Polygons polys = slice_mesh(m_cut_contours.mesh.its, cursor_z, slicing_params); if (!polys.empty()) { m_cut_contours.contours.init_from(polys, static_cast(cursor_z)); - m_cut_contours.contours.set_color(-1, { 1.0f, 1.0f, 1.0f, 1.0f }); + m_cut_contours.contours.set_color({ 1.0f, 1.0f, 1.0f, 1.0f }); } } else if (box.center() != m_cut_contours.position) { diff --git a/src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp b/src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp index 534070f6440..b58ec86688d 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp @@ -228,24 +228,22 @@ void GLGizmoRotate::render_circle(const ColorRGBA& color, bool radius_changed) if (!m_circle.is_initialized() || radius_changed) { m_circle.reset(); - GLModel::InitializationData init_data; - GLModel::InitializationData::Entity entity; - entity.type = GLModel::PrimitiveType::LineLoop; - entity.positions.reserve(ScaleStepsCount); - entity.normals.reserve(ScaleStepsCount); - entity.indices.reserve(ScaleStepsCount); - for (unsigned int i = 0; i < ScaleStepsCount; ++i) { + GLModel::Geometry init_data; + init_data.format = { GLModel::Geometry::EPrimitiveType::LineLoop, GLModel::Geometry::EVertexLayout::P3, GLModel::Geometry::EIndexType::USHORT }; + init_data.vertices.reserve(ScaleStepsCount * GLModel::Geometry::vertex_stride_floats(init_data.format)); + init_data.indices.reserve(ScaleStepsCount * GLModel::Geometry::index_stride_bytes(init_data.format)); + + // vertices + indices + for (unsigned short i = 0; i < ScaleStepsCount; ++i) { const float angle = float(i * ScaleStepRad); - entity.positions.emplace_back(::cos(angle) * m_radius, ::sin(angle) * m_radius, 0.0f); - entity.normals.emplace_back(Vec3f::UnitZ()); - entity.indices.emplace_back(i); + init_data.add_vertex(Vec3f(::cos(angle) * m_radius, ::sin(angle) * m_radius, 0.0f)); + init_data.add_ushort_index(i); } - init_data.entities.emplace_back(entity); - m_circle.init_from(init_data); + m_circle.init_from(std::move(init_data)); } - m_circle.set_color(-1, color); + m_circle.set_color(color); m_circle.render(); } @@ -257,13 +255,13 @@ void GLGizmoRotate::render_scale(const ColorRGBA& color, bool radius_changed) if (!m_scale.is_initialized() || radius_changed) { m_scale.reset(); - GLModel::InitializationData init_data; - GLModel::InitializationData::Entity entity; - entity.type = GLModel::PrimitiveType::Lines; - entity.positions.reserve(2 * ScaleStepsCount); - entity.normals.reserve(2 * ScaleStepsCount); - entity.indices.reserve(2 * ScaleStepsCount); - for (unsigned int i = 0; i < ScaleStepsCount; ++i) { + GLModel::Geometry init_data; + init_data.format = { GLModel::Geometry::EPrimitiveType::Lines, GLModel::Geometry::EVertexLayout::P3, GLModel::Geometry::EIndexType::USHORT }; + init_data.vertices.reserve(2 * ScaleStepsCount * GLModel::Geometry::vertex_stride_floats(init_data.format)); + init_data.indices.reserve(2 * ScaleStepsCount * GLModel::Geometry::index_stride_bytes(init_data.format)); + + // vertices + indices + for (unsigned short i = 0; i < ScaleStepsCount; ++i) { const float angle = float(i * ScaleStepRad); const float cosa = ::cos(angle); const float sina = ::sin(angle); @@ -272,19 +270,16 @@ void GLGizmoRotate::render_scale(const ColorRGBA& color, bool radius_changed) const float out_x = (i % ScaleLongEvery == 0) ? cosa * out_radius_long : cosa * out_radius_short; const float out_y = (i % ScaleLongEvery == 0) ? sina * out_radius_long : sina * out_radius_short; - entity.positions.emplace_back(in_x, in_y, 0.0f); - entity.positions.emplace_back(out_x, out_y, 0.0f); - entity.normals.emplace_back(Vec3f::UnitZ()); - entity.normals.emplace_back(Vec3f::UnitZ()); - entity.indices.emplace_back(i * 2 + 0); - entity.indices.emplace_back(i * 2 + 1); + init_data.add_vertex(Vec3f(in_x, in_y, 0.0f)); + init_data.add_vertex(Vec3f(out_x, out_y, 0.0f)); + init_data.add_ushort_index(i * 2); + init_data.add_ushort_index(i * 2 + 1); } - init_data.entities.emplace_back(entity); - m_scale.init_from(init_data); -} + m_scale.init_from(std::move(init_data)); + } - m_scale.set_color(-1, color); + m_scale.set_color(color); m_scale.render(); } @@ -297,13 +292,13 @@ void GLGizmoRotate::render_snap_radii(const ColorRGBA& color, bool radius_change if (!m_snap_radii.is_initialized() || radius_changed) { m_snap_radii.reset(); - GLModel::InitializationData init_data; - GLModel::InitializationData::Entity entity; - entity.type = GLModel::PrimitiveType::Lines; - entity.positions.reserve(2 * ScaleStepsCount); - entity.normals.reserve(2 * ScaleStepsCount); - entity.indices.reserve(2 * ScaleStepsCount); - for (unsigned int i = 0; i < ScaleStepsCount; ++i) { + GLModel::Geometry init_data; + init_data.format = { GLModel::Geometry::EPrimitiveType::Lines, GLModel::Geometry::EVertexLayout::P3, GLModel::Geometry::EIndexType::USHORT }; + init_data.vertices.reserve(2 * ScaleStepsCount * GLModel::Geometry::vertex_stride_floats(init_data.format)); + init_data.indices.reserve(2 * ScaleStepsCount * GLModel::Geometry::index_stride_bytes(init_data.format)); + + // vertices + indices + for (unsigned short i = 0; i < ScaleStepsCount; ++i) { const float angle = float(i * step); const float cosa = ::cos(angle); const float sina = ::sin(angle); @@ -312,19 +307,16 @@ void GLGizmoRotate::render_snap_radii(const ColorRGBA& color, bool radius_change const float out_x = cosa * out_radius; const float out_y = sina * out_radius; - entity.positions.emplace_back(in_x, in_y, 0.0f); - entity.positions.emplace_back(out_x, out_y, 0.0f); - entity.normals.emplace_back(Vec3f::UnitZ()); - entity.normals.emplace_back(Vec3f::UnitZ()); - entity.indices.emplace_back(i * 2 + 0); - entity.indices.emplace_back(i * 2 + 1); + init_data.add_vertex(Vec3f(in_x, in_y, 0.0f)); + init_data.add_vertex(Vec3f(out_x, out_y, 0.0f)); + init_data.add_ushort_index(i * 2); + init_data.add_ushort_index(i * 2 + 1); } - init_data.entities.emplace_back(entity); - m_snap_radii.init_from(init_data); + m_snap_radii.init_from(std::move(init_data)); } - m_snap_radii.set_color(-1, color); + m_snap_radii.set_color(color); m_snap_radii.render(); } @@ -333,24 +325,22 @@ void GLGizmoRotate::render_reference_radius(const ColorRGBA& color, bool radius_ if (!m_reference_radius.is_initialized() || radius_changed) { m_reference_radius.reset(); - GLModel::InitializationData init_data; - GLModel::InitializationData::Entity entity; - entity.type = GLModel::PrimitiveType::Lines; - entity.positions.reserve(2); - entity.positions.emplace_back(0.0f, 0.0f, 0.0f); - entity.positions.emplace_back(m_radius * (1.0f + GrabberOffset), 0.0f, 0.0f); - entity.normals.reserve(2); - entity.normals.emplace_back(Vec3f::UnitZ()); - entity.normals.emplace_back(Vec3f::UnitZ()); - entity.indices.reserve(2); - entity.indices.emplace_back(0); - entity.indices.emplace_back(1); - - init_data.entities.emplace_back(entity); - m_reference_radius.init_from(init_data); + GLModel::Geometry init_data; + init_data.format = { GLModel::Geometry::EPrimitiveType::Lines, GLModel::Geometry::EVertexLayout::P3, GLModel::Geometry::EIndexType::USHORT }; + init_data.vertices.reserve(2 * GLModel::Geometry::vertex_stride_floats(init_data.format)); + init_data.indices.reserve(2 * GLModel::Geometry::index_stride_bytes(init_data.format)); + + // vertices + init_data.add_vertex(Vec3f(0.0f, 0.0f, 0.0f)); + init_data.add_vertex(Vec3f(m_radius * (1.0f + GrabberOffset), 0.0f, 0.0f)); + + // indices + init_data.add_ushort_line(0, 1); + + m_reference_radius.init_from(std::move(init_data)); } - m_reference_radius.set_color(-1, color); + m_reference_radius.set_color(color); m_reference_radius.render(); } @@ -362,24 +352,22 @@ void GLGizmoRotate::render_angle_arc(const ColorRGBA& color, bool radius_changed if (!m_angle_arc.is_initialized() || radius_changed) { m_angle_arc.reset(); - GLModel::InitializationData init_data; - GLModel::InitializationData::Entity entity; - entity.type = GLModel::PrimitiveType::LineStrip; - entity.positions.reserve(1 + AngleResolution); - entity.normals.reserve(1 + AngleResolution); - entity.indices.reserve(1 + AngleResolution); - for (unsigned int i = 0; i <= AngleResolution; ++i) { + GLModel::Geometry init_data; + init_data.format = { GLModel::Geometry::EPrimitiveType::LineStrip, GLModel::Geometry::EVertexLayout::P3, GLModel::Geometry::EIndexType::USHORT }; + init_data.vertices.reserve((1 + AngleResolution) * GLModel::Geometry::vertex_stride_floats(init_data.format)); + init_data.indices.reserve((1 + AngleResolution) * GLModel::Geometry::index_stride_bytes(init_data.format)); + + // vertices + indices + for (unsigned short i = 0; i <= AngleResolution; ++i) { const float angle = float(i) * step_angle; - entity.positions.emplace_back(::cos(angle) * ex_radius, ::sin(angle) * ex_radius, 0.0f); - entity.normals.emplace_back(Vec3f::UnitZ()); - entity.indices.emplace_back(i); + init_data.add_vertex(Vec3f(::cos(angle) * ex_radius, ::sin(angle) * ex_radius, 0.0f)); + init_data.add_ushort_index(i); } - init_data.entities.emplace_back(entity); - m_angle_arc.init_from(init_data); + m_angle_arc.init_from(std::move(init_data)); } - m_angle_arc.set_color(-1, color); + m_angle_arc.set_color(color); m_angle_arc.render(); } @@ -389,28 +377,26 @@ void GLGizmoRotate::render_grabber_connection(const ColorRGBA& color, bool radiu m_grabber_connection.model.reset(); m_grabber_connection.old_center = m_grabbers.front().center; - GLModel::InitializationData init_data; - GLModel::InitializationData::Entity entity; - entity.type = GLModel::PrimitiveType::Lines; - entity.positions.reserve(2); - entity.positions.emplace_back(0.0f, 0.0f, 0.0f); - entity.positions.emplace_back(m_grabbers.front().center.cast()); - entity.normals.reserve(2); - entity.normals.emplace_back(Vec3f::UnitZ()); - entity.normals.emplace_back(Vec3f::UnitZ()); - entity.indices.reserve(2); - entity.indices.emplace_back(0); - entity.indices.emplace_back(1); - - init_data.entities.emplace_back(entity); - m_grabber_connection.model.init_from(init_data); + GLModel::Geometry init_data; + init_data.format = { GLModel::Geometry::EPrimitiveType::Lines, GLModel::Geometry::EVertexLayout::P3, GLModel::Geometry::EIndexType::USHORT }; + init_data.vertices.reserve(2 * GLModel::Geometry::vertex_stride_floats(init_data.format)); + init_data.indices.reserve(2 * GLModel::Geometry::index_stride_bytes(init_data.format)); + + // vertices + init_data.add_vertex(Vec3f(0.0f, 0.0f, 0.0f)); + init_data.add_vertex((Vec3f)m_grabbers.front().center.cast()); + + // indices + init_data.add_ushort_line(0, 1); + + m_grabber_connection.model.init_from(std::move(init_data)); } - m_grabber_connection.model.set_color(-1, color); + m_grabber_connection.model.set_color(color); m_grabber_connection.model.render(); } -void GLGizmoRotate::render_grabber(const BoundingBoxf3& box) const +void GLGizmoRotate::render_grabber(const BoundingBoxf3& box) { m_grabbers.front().color = m_highlight_color; render_grabbers(box); @@ -418,7 +404,7 @@ void GLGizmoRotate::render_grabber(const BoundingBoxf3& box) const void GLGizmoRotate::render_grabber_extension(const BoundingBoxf3& box, bool picking) { - double size = 0.75 * GLGizmoBase::Grabber::FixedGrabberSize * GLGizmoBase::INV_ZOOM; + const double size = 0.75 * GLGizmoBase::Grabber::FixedGrabberSize * GLGizmoBase::INV_ZOOM; //float mean_size = (float)((box.size()(0) + box.size()(1) + box.size()(2)) / 3.0); //double size = m_dragging ? (double)m_grabbers[0].get_dragging_half_size(mean_size) : (double)m_grabbers[0].get_half_size(mean_size); @@ -426,15 +412,13 @@ void GLGizmoRotate::render_grabber_extension(const BoundingBoxf3& box, bool pick if (!picking && m_hover_id != -1) color = m_grabbers.front().hover_color; - GLShaderProgram* shader = wxGetApp().get_shader("gouraud_light"); + GLShaderProgram* shader = wxGetApp().get_shader(picking ? "flat" : "gouraud_light"); if (shader == nullptr) return; - m_cone.set_color(-1, color); - if (!picking) { - shader->start_using(); - shader->set_uniform("emission_factor", 0.1f); - } + m_cone.set_color(color); + shader->start_using(); + shader->set_uniform("emission_factor", 0.1f); const Vec3d& center = m_grabbers.front().center; @@ -455,13 +439,12 @@ void GLGizmoRotate::render_grabber_extension(const BoundingBoxf3& box, bool pick m_cone.render(); glsafe(::glPopMatrix()); - if (! picking) - shader->stop_using(); + shader->stop_using(); } void GLGizmoRotate::transform_to_local(const Selection& selection) const { - glsafe(::glTranslated(m_center(0), m_center(1), m_center(2))); + glsafe(::glTranslated(m_center.x(), m_center.y(), m_center.z())); if (selection.is_single_volume() || selection.is_single_modifier() || selection.requires_local_axes()) { const Transform3d orient_matrix = selection.get_volume(*selection.get_volume_idxs().begin())->get_instance_transformation().get_matrix(true, false, true, true); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoRotate.hpp b/src/slic3r/GUI/Gizmos/GLGizmoRotate.hpp index bc546a89567..61ff0e20a0a 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoRotate.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoRotate.hpp @@ -82,7 +82,7 @@ class GLGizmoRotate : public GLGizmoBase void render_reference_radius(const ColorRGBA& color, bool radius_changed); void render_angle_arc(const ColorRGBA& color, bool radius_changed); void render_grabber_connection(const ColorRGBA& color, bool radius_changed); - void render_grabber(const BoundingBoxf3& box) const; + void render_grabber(const BoundingBoxf3& box); void render_grabber_extension(const BoundingBoxf3& box, bool picking); void transform_to_local(const Selection& selection) const; diff --git a/src/slic3r/GUI/Gizmos/GLGizmoScale.cpp b/src/slic3r/GUI/Gizmos/GLGizmoScale.cpp index c89af3f0ee8..40478f6311b 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoScale.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoScale.cpp @@ -267,7 +267,7 @@ void GLGizmoScale3D::render_grabbers_connection(unsigned int id_1, unsigned int return -1; }; - int id = grabber_connection(id_1, id_2); + const int id = grabber_connection(id_1, id_2); if (id == -1) return; @@ -278,27 +278,22 @@ void GLGizmoScale3D::render_grabbers_connection(unsigned int id_1, unsigned int m_grabber_connections[id].old_v2 = m_grabbers[id_2].center; m_grabber_connections[id].model.reset(); - GLModel::InitializationData init_data; - GUI::GLModel::InitializationData::Entity entity; - entity.type = GUI::GLModel::PrimitiveType::Lines; - entity.positions.reserve(2); - entity.positions.emplace_back(m_grabbers[id_1].center.cast()); - entity.positions.emplace_back(m_grabbers[id_2].center.cast()); + GLModel::Geometry init_data; + init_data.format = { GLModel::Geometry::EPrimitiveType::Lines, GLModel::Geometry::EVertexLayout::P3, GLModel::Geometry::EIndexType::USHORT }; + init_data.vertices.reserve(2 * GLModel::Geometry::vertex_stride_floats(init_data.format)); + init_data.indices.reserve(2 * GLModel::Geometry::index_stride_bytes(init_data.format)); - entity.normals.reserve(2); - for (size_t j = 0; j < 2; ++j) { - entity.normals.emplace_back(Vec3f::UnitZ()); - } + // vertices + init_data.add_vertex((Vec3f)m_grabbers[id_1].center.cast()); + init_data.add_vertex((Vec3f)m_grabbers[id_2].center.cast()); - entity.indices.reserve(2); - entity.indices.emplace_back(0); - entity.indices.emplace_back(1); + // indices + init_data.add_ushort_line(0, 1); - init_data.entities.emplace_back(entity); - m_grabber_connections[id].model.init_from(init_data); + m_grabber_connections[id].model.init_from(std::move(init_data)); } - m_grabber_connections[id].model.set_color(-1, color); + m_grabber_connections[id].model.set_color(color); glLineStipple(1, 0x0FFF); glEnable(GL_LINE_STIPPLE); m_grabber_connections[id].model.render(); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSimplify.cpp b/src/slic3r/GUI/Gizmos/GLGizmoSimplify.cpp index 7b7cc2065de..aca431750d0 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSimplify.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSimplify.cpp @@ -622,7 +622,7 @@ void GLGizmoSimplify::init_model(const indexed_triangle_set& its) m_c->selection_info()->get_active_instance(), m_volume); if (const Selection&sel = m_parent.get_selection(); sel.get_volume_idxs().size() == 1) - m_glmodel.set_color(-1, sel.get_volume(*sel.get_volume_idxs().begin())->color); + m_glmodel.set_color(sel.get_volume(*sel.get_volume_idxs().begin())->color); m_triangle_count = its.indices.size(); } diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp index 8cef43e5955..8745274f4b2 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp @@ -28,7 +28,9 @@ namespace GUI { GLGizmoSlaSupports::GLGizmoSlaSupports(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id) : GLGizmoBase(parent, icon_filename, sprite_id) -{} +{ +} + bool GLGizmoSlaSupports::on_init() { @@ -46,10 +48,6 @@ bool GLGizmoSlaSupports::on_init() m_desc["manual_editing"] = _L("Manual editing"); m_desc["clipping_of_view"] = _L("Clipping of view")+ ": "; m_desc["reset_direction"] = _L("Reset direction"); - - m_cone.init_from(its_make_cone(1., 1., 2 * PI / 24)); - m_cylinder.init_from(its_make_cylinder(1., 1., 2 * PI / 24.)); - m_sphere.init_from(its_make_sphere(1., (2 * M_PI) / 24.)); return true; } @@ -79,6 +77,13 @@ void GLGizmoSlaSupports::set_sla_support_data(ModelObject* model_object, const S void GLGizmoSlaSupports::on_render() { + if (!m_cone.is_initialized()) + m_cone.init_from(its_make_cone(1.0, 1.0, double(PI) / 12.0)); + if (!m_sphere.is_initialized()) + m_sphere.init_from(its_make_sphere(1.0, double(PI) / 12.0)); + if (!m_cylinder.is_initialized()) + m_cylinder.init_from(its_make_cylinder(1.0, 1.0, double(PI) / 12.0)); + ModelObject* mo = m_c->selection_info()->model_object(); const Selection& selection = m_parent.get_selection(); @@ -111,7 +116,7 @@ void GLGizmoSlaSupports::on_render_for_picking() render_points(selection, true); } -void GLGizmoSlaSupports::render_points(const Selection& selection, bool picking) const +void GLGizmoSlaSupports::render_points(const Selection& selection, bool picking) { size_t cache_size = m_editing_mode ? m_editing_cache.size() : m_normal_cache.size(); @@ -169,8 +174,8 @@ void GLGizmoSlaSupports::render_points(const Selection& selection, bool picking) } } - const_cast(&m_cone)->set_color(-1, render_color); - const_cast(&m_sphere)->set_color(-1, render_color); + m_cone.set_color(render_color); + m_sphere.set_color(render_color); if (shader && !picking) shader->set_uniform("emission_factor", 0.5f); @@ -222,7 +227,7 @@ void GLGizmoSlaSupports::render_points(const Selection& selection, bool picking) // Now render the drain holes: if (has_holes && ! picking) { render_color = { 0.7f, 0.7f, 0.7f, 0.7f }; - const_cast(&m_cylinder)->set_color(-1, render_color); + m_cylinder.set_color(render_color); if (shader) shader->set_uniform("emission_factor", 0.5f); for (const sla::DrainHole& drain_hole : m_c->selection_info()->model_object()->sla_drain_holes) { diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp index 08d4874bdb0..985b9aeb563 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp @@ -77,13 +77,9 @@ class GLGizmoSlaSupports : public GLGizmoBase void on_render() override; void on_render_for_picking() override; - void render_points(const Selection& selection, bool picking = false) const; + void render_points(const Selection& selection, bool picking = false); bool unsaved_changes() const; - GLModel m_cone; - GLModel m_cylinder; - GLModel m_sphere; - bool m_lock_unique_islands = false; bool m_editing_mode = false; // Is editing mode active? float m_new_point_head_diameter; // Size of a new point. @@ -95,6 +91,10 @@ class GLGizmoSlaSupports : public GLGizmoBase std::vector m_normal_cache; // to restore after discarding changes or undo/redo ObjectID m_old_mo_id; + GLModel m_cone; + GLModel m_cylinder; + GLModel m_sphere; + // This map holds all translated description texts, so they can be easily referenced during layout calculations // etc. When language changes, GUI is recreated and this class constructed again, so the change takes effect. std::map m_desc; diff --git a/src/slic3r/GUI/Gizmos/GLGizmoText.cpp b/src/slic3r/GUI/Gizmos/GLGizmoText.cpp index c50c80ea369..facfa464ede 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoText.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoText.cpp @@ -447,7 +447,14 @@ void GLGizmoText::on_render() m_grabbers[0].enabled = true; ColorRGBA color = picking_color_component(0); m_grabbers[0].color = color; - m_grabbers[0].render_for_picking(mean_size); + + GLShaderProgram *shader = wxGetApp().get_shader("gouraud_light"); + if (shader != nullptr) { + shader->start_using(); + m_grabbers[0].render_for_picking(mean_size); + + shader->stop_using(); + } } delete_temp_preview_text_volume(); @@ -492,7 +499,16 @@ void GLGizmoText::on_render_for_picking() m_grabbers[0].enabled = true; ColorRGBA color = picking_color_component(0); m_grabbers[0].color = color; - m_grabbers[0].render_for_picking(mean_size); + + GLShaderProgram *shader = wxGetApp().get_shader("flat"); + if (shader != nullptr) { + glsafe(::glPushMatrix()); + shader->start_using(); + m_grabbers[0].render_for_picking(mean_size); + + shader->stop_using(); + glsafe(::glPopMatrix()); + } } } } diff --git a/src/slic3r/GUI/Selection.cpp b/src/slic3r/GUI/Selection.cpp index 68702303da2..21096a01116 100644 --- a/src/slic3r/GUI/Selection.cpp +++ b/src/slic3r/GUI/Selection.cpp @@ -1595,16 +1595,11 @@ void Selection::render_sidebar_hints(const std::string& sidebar_field, bool unif if (sidebar_field.empty()) return; - GLShaderProgram* shader = nullptr; - - if (!boost::starts_with(sidebar_field, "layer")) { - shader = wxGetApp().get_shader("gouraud_light"); - if (shader == nullptr) - return; + GLShaderProgram* shader = wxGetApp().get_shader(boost::starts_with(sidebar_field, "layer") ? "flat" : "gouraud_light"); + if (shader == nullptr) + return; - shader->start_using(); - glsafe(::glClear(GL_DEPTH_BUFFER_BIT)); - } + shader->start_using(); glsafe(::glEnable(GL_DEPTH_TEST)); @@ -1650,6 +1645,8 @@ void Selection::render_sidebar_hints(const std::string& sidebar_field, bool unif } } + if (!boost::starts_with(sidebar_field, "layer")) + glsafe(::glClear(GL_DEPTH_BUFFER_BIT)); if (boost::starts_with(sidebar_field, "position")) render_sidebar_position_hints(sidebar_field); else if (boost::starts_with(sidebar_field, "rotation")) @@ -1662,8 +1659,7 @@ void Selection::render_sidebar_hints(const std::string& sidebar_field, bool unif glsafe(::glPopMatrix()); - if (!boost::starts_with(sidebar_field, "layer")) - shader->stop_using(); + shader->stop_using(); } bool Selection::requires_local_axes() const @@ -2159,15 +2155,6 @@ void Selection::render_synchronized_volumes() } } -static bool is_approx(const Vec3d& v1, const Vec3d& v2) -{ - for (int i = 0; i < 3; ++i) { - if (std::abs(v1[i] - v2[i]) > EPSILON) - return false; - } - return true; -} - void Selection::render_bounding_box(const BoundingBoxf3& box, const ColorRGB& color) { const BoundingBoxf3& curr_box = m_box.get_bounding_box(); @@ -2178,79 +2165,74 @@ void Selection::render_bounding_box(const BoundingBoxf3& box, const ColorRGB& co const Vec3f b_max = box.max.cast(); const Vec3f size = 0.2f * box.size().cast(); - GLModel::InitializationData init_data; - GUI::GLModel::InitializationData::Entity entity; - entity.type = GUI::GLModel::PrimitiveType::Lines; - entity.positions.reserve(48); - - entity.positions.emplace_back(Vec3f(b_min.x(), b_min.y(), b_min.z())); - entity.positions.emplace_back(Vec3f(b_min.x() + size.x(), b_min.y(), b_min.z())); - entity.positions.emplace_back(Vec3f(b_min.x(), b_min.y(), b_min.z())); - entity.positions.emplace_back(Vec3f(b_min.x(), b_min.y() + size.y(), b_min.z())); - entity.positions.emplace_back(Vec3f(b_min.x(), b_min.y(), b_min.z())); - entity.positions.emplace_back(Vec3f(b_min.x(), b_min.y(), b_min.z() + size.z())); - - entity.positions.emplace_back(Vec3f(b_max.x(), b_min.y(), b_min.z())); - entity.positions.emplace_back(Vec3f(b_max.x() - size.x(), b_min.y(), b_min.z())); - entity.positions.emplace_back(Vec3f(b_max.x(), b_min.y(), b_min.z())); - entity.positions.emplace_back(Vec3f(b_max.x(), b_min.y() + size.y(), b_min.z())); - entity.positions.emplace_back(Vec3f(b_max.x(), b_min.y(), b_min.z())); - entity.positions.emplace_back(Vec3f(b_max.x(), b_min.y(), b_min.z() + size.z())); - - entity.positions.emplace_back(Vec3f(b_max.x(), b_max.y(), b_min.z())); - entity.positions.emplace_back(Vec3f(b_max.x() - size.x(), b_max.y(), b_min.z())); - entity.positions.emplace_back(Vec3f(b_max.x(), b_max.y(), b_min.z())); - entity.positions.emplace_back(Vec3f(b_max.x(), b_max.y() - size.y(), b_min.z())); - entity.positions.emplace_back(Vec3f(b_max.x(), b_max.y(), b_min.z())); - entity.positions.emplace_back(Vec3f(b_max.x(), b_max.y(), b_min.z() + size.z())); - - entity.positions.emplace_back(Vec3f(b_min.x(), b_max.y(), b_min.z())); - entity.positions.emplace_back(Vec3f(b_min.x() + size.x(), b_max.y(), b_min.z())); - entity.positions.emplace_back(Vec3f(b_min.x(), b_max.y(), b_min.z())); - entity.positions.emplace_back(Vec3f(b_min.x(), b_max.y() - size.y(), b_min.z())); - entity.positions.emplace_back(Vec3f(b_min.x(), b_max.y(), b_min.z())); - entity.positions.emplace_back(Vec3f(b_min.x(), b_max.y(), b_min.z() + size.z())); - - entity.positions.emplace_back(Vec3f(b_min.x(), b_min.y(), b_max.z())); - entity.positions.emplace_back(Vec3f(b_min.x() + size.x(), b_min.y(), b_max.z())); - entity.positions.emplace_back(Vec3f(b_min.x(), b_min.y(), b_max.z())); - entity.positions.emplace_back(Vec3f(b_min.x(), b_min.y() + size.y(), b_max.z())); - entity.positions.emplace_back(Vec3f(b_min.x(), b_min.y(), b_max.z())); - entity.positions.emplace_back(Vec3f(b_min.x(), b_min.y(), b_max.z() - size.z())); - - entity.positions.emplace_back(Vec3f(b_max.x(), b_min.y(), b_max.z())); - entity.positions.emplace_back(Vec3f(b_max.x() - size.x(), b_min.y(), b_max.z())); - entity.positions.emplace_back(Vec3f(b_max.x(), b_min.y(), b_max.z())); - entity.positions.emplace_back(Vec3f(b_max.x(), b_min.y() + size.y(), b_max.z())); - entity.positions.emplace_back(Vec3f(b_max.x(), b_min.y(), b_max.z())); - entity.positions.emplace_back(Vec3f(b_max.x(), b_min.y(), b_max.z() - size.z())); - - entity.positions.emplace_back(Vec3f(b_max.x(), b_max.y(), b_max.z())); - entity.positions.emplace_back(Vec3f(b_max.x() - size.x(), b_max.y(), b_max.z())); - entity.positions.emplace_back(Vec3f(b_max.x(), b_max.y(), b_max.z())); - entity.positions.emplace_back(Vec3f(b_max.x(), b_max.y() - size.y(), b_max.z())); - entity.positions.emplace_back(Vec3f(b_max.x(), b_max.y(), b_max.z())); - entity.positions.emplace_back(Vec3f(b_max.x(), b_max.y(), b_max.z() - size.z())); - - entity.positions.emplace_back(Vec3f(b_min.x(), b_max.y(), b_max.z())); - entity.positions.emplace_back(Vec3f(b_min.x() + size.x(), b_max.y(), b_max.z())); - entity.positions.emplace_back(Vec3f(b_min.x(), b_max.y(), b_max.z())); - entity.positions.emplace_back(Vec3f(b_min.x(), b_max.y() - size.y(), b_max.z())); - entity.positions.emplace_back(Vec3f(b_min.x(), b_max.y(), b_max.z())); - entity.positions.emplace_back(Vec3f(b_min.x(), b_max.y(), b_max.z() - size.z())); - - entity.normals.reserve(48); - for (size_t i = 0; i < 48; ++i) { - entity.normals.emplace_back(Vec3f::UnitZ()); + GLModel::Geometry init_data; + init_data.format = { GLModel::Geometry::EPrimitiveType::Lines, GLModel::Geometry::EVertexLayout::P3, GLModel::Geometry::EIndexType::USHORT }; + init_data.vertices.reserve(48 * GLModel::Geometry::vertex_stride_floats(init_data.format)); + init_data.indices.reserve(48 * GLModel::Geometry::index_stride_bytes(init_data.format)); + + // vertices + init_data.add_vertex(Vec3f(b_min.x(), b_min.y(), b_min.z())); + init_data.add_vertex(Vec3f(b_min.x() + size.x(), b_min.y(), b_min.z())); + init_data.add_vertex(Vec3f(b_min.x(), b_min.y(), b_min.z())); + init_data.add_vertex(Vec3f(b_min.x(), b_min.y() + size.y(), b_min.z())); + init_data.add_vertex(Vec3f(b_min.x(), b_min.y(), b_min.z())); + init_data.add_vertex(Vec3f(b_min.x(), b_min.y(), b_min.z() + size.z())); + + init_data.add_vertex(Vec3f(b_max.x(), b_min.y(), b_min.z())); + init_data.add_vertex(Vec3f(b_max.x() - size.x(), b_min.y(), b_min.z())); + init_data.add_vertex(Vec3f(b_max.x(), b_min.y(), b_min.z())); + init_data.add_vertex(Vec3f(b_max.x(), b_min.y() + size.y(), b_min.z())); + init_data.add_vertex(Vec3f(b_max.x(), b_min.y(), b_min.z())); + init_data.add_vertex(Vec3f(b_max.x(), b_min.y(), b_min.z() + size.z())); + + init_data.add_vertex(Vec3f(b_max.x(), b_max.y(), b_min.z())); + init_data.add_vertex(Vec3f(b_max.x() - size.x(), b_max.y(), b_min.z())); + init_data.add_vertex(Vec3f(b_max.x(), b_max.y(), b_min.z())); + init_data.add_vertex(Vec3f(b_max.x(), b_max.y() - size.y(), b_min.z())); + init_data.add_vertex(Vec3f(b_max.x(), b_max.y(), b_min.z())); + init_data.add_vertex(Vec3f(b_max.x(), b_max.y(), b_min.z() + size.z())); + + init_data.add_vertex(Vec3f(b_min.x(), b_max.y(), b_min.z())); + init_data.add_vertex(Vec3f(b_min.x() + size.x(), b_max.y(), b_min.z())); + init_data.add_vertex(Vec3f(b_min.x(), b_max.y(), b_min.z())); + init_data.add_vertex(Vec3f(b_min.x(), b_max.y() - size.y(), b_min.z())); + init_data.add_vertex(Vec3f(b_min.x(), b_max.y(), b_min.z())); + init_data.add_vertex(Vec3f(b_min.x(), b_max.y(), b_min.z() + size.z())); + + init_data.add_vertex(Vec3f(b_min.x(), b_min.y(), b_max.z())); + init_data.add_vertex(Vec3f(b_min.x() + size.x(), b_min.y(), b_max.z())); + init_data.add_vertex(Vec3f(b_min.x(), b_min.y(), b_max.z())); + init_data.add_vertex(Vec3f(b_min.x(), b_min.y() + size.y(), b_max.z())); + init_data.add_vertex(Vec3f(b_min.x(), b_min.y(), b_max.z())); + init_data.add_vertex(Vec3f(b_min.x(), b_min.y(), b_max.z() - size.z())); + + init_data.add_vertex(Vec3f(b_max.x(), b_min.y(), b_max.z())); + init_data.add_vertex(Vec3f(b_max.x() - size.x(), b_min.y(), b_max.z())); + init_data.add_vertex(Vec3f(b_max.x(), b_min.y(), b_max.z())); + init_data.add_vertex(Vec3f(b_max.x(), b_min.y() + size.y(), b_max.z())); + init_data.add_vertex(Vec3f(b_max.x(), b_min.y(), b_max.z())); + init_data.add_vertex(Vec3f(b_max.x(), b_min.y(), b_max.z() - size.z())); + + init_data.add_vertex(Vec3f(b_max.x(), b_max.y(), b_max.z())); + init_data.add_vertex(Vec3f(b_max.x() - size.x(), b_max.y(), b_max.z())); + init_data.add_vertex(Vec3f(b_max.x(), b_max.y(), b_max.z())); + init_data.add_vertex(Vec3f(b_max.x(), b_max.y() - size.y(), b_max.z())); + init_data.add_vertex(Vec3f(b_max.x(), b_max.y(), b_max.z())); + init_data.add_vertex(Vec3f(b_max.x(), b_max.y(), b_max.z() - size.z())); + + init_data.add_vertex(Vec3f(b_min.x(), b_max.y(), b_max.z())); + init_data.add_vertex(Vec3f(b_min.x() + size.x(), b_max.y(), b_max.z())); + init_data.add_vertex(Vec3f(b_min.x(), b_max.y(), b_max.z())); + init_data.add_vertex(Vec3f(b_min.x(), b_max.y() - size.y(), b_max.z())); + init_data.add_vertex(Vec3f(b_min.x(), b_max.y(), b_max.z())); + init_data.add_vertex(Vec3f(b_min.x(), b_max.y(), b_max.z() - size.z())); + + // indices + for (unsigned short i = 0; i < 48; ++i) { + init_data.add_ushort_index(i); } - entity.indices.reserve(48); - for (size_t i = 0; i < 48; ++i) { - entity.indices.emplace_back(i); - } - - init_data.entities.emplace_back(entity); - m_box.init_from(init_data); + m_box.init_from(std::move(init_data)); } glsafe(::glEnable(GL_DEPTH_TEST)); @@ -2262,7 +2244,7 @@ void Selection::render_bounding_box(const BoundingBoxf3& box, const ColorRGB& co return; shader->start_using(); - m_box.set_color(-1, to_rgba(color)); + m_box.set_color(to_rgba(color)); m_box.render(); shader->stop_using(); } @@ -2276,16 +2258,16 @@ void Selection::render_sidebar_position_hints(const std::string& sidebar_field) { if (boost::ends_with(sidebar_field, "x")) { glsafe(::glRotated(-90.0, 0.0, 0.0, 1.0)); - m_arrow.set_color(-1, get_color(X)); + m_arrow.set_color(get_color(X)); m_arrow.render(); } else if (boost::ends_with(sidebar_field, "y")) { - m_arrow.set_color(-1, get_color(Y)); + m_arrow.set_color(get_color(Y)); m_arrow.render(); } else if (boost::ends_with(sidebar_field, "z")) { glsafe(::glRotated(90.0, 1.0, 0.0, 0.0)); - m_arrow.set_color(-1, get_color(Z)); + m_arrow.set_color(get_color(Z)); m_arrow.render(); } } @@ -2300,16 +2282,16 @@ void Selection::render_sidebar_rotation_hints(const std::string& sidebar_field) if (boost::ends_with(sidebar_field, "x")) { glsafe(::glRotated(90.0, 0.0, 1.0, 0.0)); - m_curved_arrow.set_color(-1, get_color(X)); + m_curved_arrow.set_color(get_color(X)); render_sidebar_rotation_hint(); } else if (boost::ends_with(sidebar_field, "y")) { glsafe(::glRotated(-90.0, 1.0, 0.0, 0.0)); - m_curved_arrow.set_color(-1, get_color(Y)); + m_curved_arrow.set_color(get_color(Y)); render_sidebar_rotation_hint(); } else if (boost::ends_with(sidebar_field, "z")) { - m_curved_arrow.set_color(-1, get_color(Z)); + m_curved_arrow.set_color(get_color(Z)); render_sidebar_rotation_hint(); } } @@ -2322,7 +2304,7 @@ void Selection::render_sidebar_scale_hints(const std::string& sidebar_field, boo bool uniform_scale = requires_uniform_scale() || gizmo_uniform_scale; auto render_sidebar_scale_hint = [this, uniform_scale](Axis axis) { - m_arrow.set_color(-1, uniform_scale ? UNIFORM_SCALE_COLOR : get_color(axis)); + m_arrow.set_color(uniform_scale ? UNIFORM_SCALE_COLOR : get_color(axis)); GLShaderProgram* shader = wxGetApp().get_current_shader(); if (shader != nullptr) shader->set_uniform("emission_factor", 0.0f); @@ -2400,69 +2382,53 @@ void Selection::render_sidebar_layers_hints(const std::string& sidebar_field) glsafe(::glEnable(GL_BLEND)); glsafe(::glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)); - if (!m_planes.models[0].is_initialized() || !is_approx(m_planes.check_points[0].cast(), p1.cast())) { + if (!m_planes.models[0].is_initialized() || !is_approx(m_planes.check_points[0], p1)) { m_planes.check_points[0] = p1; m_planes.models[0].reset(); - GLModel::InitializationData init_data; - GUI::GLModel::InitializationData::Entity entity; - entity.type = GUI::GLModel::PrimitiveType::Triangles; - entity.positions.reserve(4); - entity.positions.emplace_back(Vec3f(p1.x(), p1.y(), z1)); - entity.positions.emplace_back(Vec3f(p2.x(), p1.y(), z1)); - entity.positions.emplace_back(Vec3f(p2.x(), p2.y(), z1)); - entity.positions.emplace_back(Vec3f(p1.x(), p2.y(), z1)); - - entity.normals.reserve(4); - for (size_t i = 0; i < 4; ++i) { - entity.normals.emplace_back(Vec3f::UnitZ()); - } + GLModel::Geometry init_data; + init_data.format = { GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3, GLModel::Geometry::EIndexType::USHORT }; + init_data.vertices.reserve(4 * GLModel::Geometry::vertex_stride_floats(init_data.format)); + init_data.indices.reserve(6 * GLModel::Geometry::index_stride_bytes(init_data.format)); - entity.indices.reserve(6); - entity.indices.emplace_back(0); - entity.indices.emplace_back(1); - entity.indices.emplace_back(2); - entity.indices.emplace_back(2); - entity.indices.emplace_back(3); - entity.indices.emplace_back(0); + // vertices + init_data.add_vertex(Vec3f(p1.x(), p1.y(), z1)); + init_data.add_vertex(Vec3f(p2.x(), p1.y(), z1)); + init_data.add_vertex(Vec3f(p2.x(), p2.y(), z1)); + init_data.add_vertex(Vec3f(p1.x(), p2.y(), z1)); - init_data.entities.emplace_back(entity); - m_planes.models[0].init_from(init_data); + // indices + init_data.add_ushort_triangle(0, 1, 2); + init_data.add_ushort_triangle(2, 3, 0); + + m_planes.models[0].init_from(std::move(init_data)); } - if (!m_planes.models[1].is_initialized() || !is_approx(m_planes.check_points[1].cast(), p2.cast())) { + if (!m_planes.models[1].is_initialized() || !is_approx(m_planes.check_points[1], p2)) { m_planes.check_points[1] = p2; m_planes.models[1].reset(); - GLModel::InitializationData init_data; - GUI::GLModel::InitializationData::Entity entity; - entity.type = GUI::GLModel::PrimitiveType::Triangles; - entity.positions.reserve(4); - entity.positions.emplace_back(Vec3f(p1.x(), p1.y(), z2)); - entity.positions.emplace_back(Vec3f(p2.x(), p1.y(), z2)); - entity.positions.emplace_back(Vec3f(p2.x(), p2.y(), z2)); - entity.positions.emplace_back(Vec3f(p1.x(), p2.y(), z2)); - - entity.normals.reserve(4); - for (size_t i = 0; i < 4; ++i) { - entity.normals.emplace_back(Vec3f::UnitZ()); - } + GLModel::Geometry init_data; + init_data.format = { GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3, GLModel::Geometry::EIndexType::USHORT }; + init_data.vertices.reserve(4 * GLModel::Geometry::vertex_stride_floats(init_data.format)); + init_data.indices.reserve(6 * GLModel::Geometry::index_stride_bytes(init_data.format)); + + // vertices + init_data.add_vertex(Vec3f(p1.x(), p1.y(), z2)); + init_data.add_vertex(Vec3f(p2.x(), p1.y(), z2)); + init_data.add_vertex(Vec3f(p2.x(), p2.y(), z2)); + init_data.add_vertex(Vec3f(p1.x(), p2.y(), z2)); - entity.indices.reserve(6); - entity.indices.emplace_back(0); - entity.indices.emplace_back(1); - entity.indices.emplace_back(2); - entity.indices.emplace_back(2); - entity.indices.emplace_back(3); - entity.indices.emplace_back(0); + // indices + init_data.add_ushort_triangle(0, 1, 2); + init_data.add_ushort_triangle(2, 3, 0); - init_data.entities.emplace_back(entity); - m_planes.models[1].init_from(init_data); + m_planes.models[1].init_from(std::move(init_data)); } - m_planes.models[0].set_color(-1, (camera_on_top && type == 1) || (!camera_on_top && type == 2) ? SOLID_PLANE_COLOR : TRANSPARENT_PLANE_COLOR); + m_planes.models[0].set_color((camera_on_top && type == 1) || (!camera_on_top && type == 2) ? SOLID_PLANE_COLOR : TRANSPARENT_PLANE_COLOR); m_planes.models[0].render(); - m_planes.models[1].set_color(-1, (camera_on_top && type == 2) || (!camera_on_top && type == 1) ? SOLID_PLANE_COLOR : TRANSPARENT_PLANE_COLOR); + m_planes.models[1].set_color((camera_on_top && type == 2) || (!camera_on_top && type == 1) ? SOLID_PLANE_COLOR : TRANSPARENT_PLANE_COLOR); m_planes.models[1].render(); glsafe(::glEnable(GL_CULL_FACE)); From 35899b96ba9101e1f3e3c03aa92739d2360edf20 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Sat, 21 Oct 2023 17:05:16 +0800 Subject: [PATCH 07/99] Tech ENABLE_GLBEGIN_GLEND_REMOVAL - Layers editing profile's background texture rendering Tech ENABLE_GLBEGIN_GLEND_REMOVAL - A few fixes in layers editing profile rendering (cherry picked from commit prusa3d/PrusaSlicer@a939d8e4c0626de5c988f77a43d7080a9ffe92f1) (cherry picked from commit prusa3d/PrusaSlicer@8c807dbcc4272a1e1c37bc8be84105038defa04d) --- src/slic3r/GUI/GLCanvas3D.cpp | 114 ++++++++-------------- src/slic3r/GUI/GLCanvas3D.hpp | 31 +++--- src/slic3r/GUI/GLModel.cpp | 32 +++++- src/slic3r/GUI/GLModel.hpp | 2 + src/slic3r/GUI/GLShadersManager.cpp | 3 +- src/slic3r/GUI/Gizmos/GLGizmosManager.hpp | 4 +- 6 files changed, 89 insertions(+), 97 deletions(-) diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 83e4502e642..8d279c419a4 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -334,8 +334,11 @@ void GLCanvas3D::LayersEditing::render_overlay(const GLCanvas3D& canvas) { render_variable_layer_height_dialog(canvas); const Rect& bar_rect = get_bar_rect_viewport(canvas); - render_background_texture(canvas, bar_rect); - render_curve(bar_rect); + m_profile.dirty = m_profile.old_bar_rect != bar_rect; + render_active_object_annotations(canvas, bar_rect); + render_profile(bar_rect); + m_profile.old_bar_rect = bar_rect; + m_profile.dirty = false; } float GLCanvas3D::LayersEditing::get_cursor_z_relative(const GLCanvas3D& canvas) @@ -409,7 +412,7 @@ std::string GLCanvas3D::LayersEditing::get_tooltip(const GLCanvas3D& canvas) con return ret; } -void GLCanvas3D::LayersEditing::render_background_texture(const GLCanvas3D& canvas, const Rect& bar_rect) +void GLCanvas3D::LayersEditing::render_active_object_annotations(const GLCanvas3D& canvas, const Rect& bar_rect) { if (!m_enabled) return; @@ -430,25 +433,39 @@ void GLCanvas3D::LayersEditing::render_background_texture(const GLCanvas3D& canv glsafe(::glBindTexture(GL_TEXTURE_2D, m_z_texture_id)); // Render the color bar - const float l = bar_rect.get_left(); - const float r = bar_rect.get_right(); - const float t = bar_rect.get_top(); - const float b = bar_rect.get_bottom(); + if (!m_profile.background.is_initialized() || m_profile.dirty) { + m_profile.background.reset(); - ::glBegin(GL_QUADS); - ::glNormal3f(0.0f, 0.0f, 1.0f); - ::glTexCoord2f(0.0f, 0.0f); ::glVertex2f(l, b); - ::glTexCoord2f(1.0f, 0.0f); ::glVertex2f(r, b); - ::glTexCoord2f(1.0f, 1.0f); ::glVertex2f(r, t); - ::glTexCoord2f(0.0f, 1.0f); ::glVertex2f(l, t); - glsafe(::glEnd()); + GLModel::Geometry init_data; + init_data.format = { GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P2T2, GLModel::Geometry::EIndexType::USHORT }; + init_data.vertices.reserve(4 * GLModel::Geometry::vertex_stride_floats(init_data.format)); + init_data.indices.reserve(6 * GLModel::Geometry::index_stride_bytes(init_data.format)); + + // vertices + const float l = bar_rect.get_left(); + const float r = bar_rect.get_right(); + const float t = bar_rect.get_top(); + const float b = bar_rect.get_bottom(); + init_data.add_vertex(Vec2f(l, b), Vec2f(0.0f, 0.0f)); + init_data.add_vertex(Vec2f(r, b), Vec2f(1.0f, 0.0f)); + init_data.add_vertex(Vec2f(r, t), Vec2f(1.0f, 1.0f)); + init_data.add_vertex(Vec2f(l, t), Vec2f(0.0f, 1.0f)); + + // indices + init_data.add_ushort_triangle(0, 1, 2); + init_data.add_ushort_triangle(2, 3, 0); + + m_profile.background.init_from(std::move(init_data)); + } + + m_profile.background.render(); glsafe(::glBindTexture(GL_TEXTURE_2D, 0)); shader->stop_using(); } -void GLCanvas3D::LayersEditing::render_curve(const Rect & bar_rect) +void GLCanvas3D::LayersEditing::render_profile(const Rect& bar_rect) { if (!m_enabled) return; @@ -460,24 +477,21 @@ void GLCanvas3D::LayersEditing::render_curve(const Rect & bar_rect) // Make the vertical bar a bit wider so the layer height curve does not touch the edge of the bar region. const float scale_x = bar_rect.get_width() / float(1.12 * m_slicing_parameters->max_layer_height); const float scale_y = bar_rect.get_height() / m_object_max_z; - const float x = bar_rect.get_left() + float(m_slicing_parameters->layer_height) * scale_x; - - const bool bar_rect_changed = m_profile.old_bar_rect != bar_rect; - m_profile.old_bar_rect = bar_rect; // Baseline - if (!m_profile.baseline.is_initialized() || bar_rect_changed) { - m_profile.old_bar_rect = bar_rect; + if (!m_profile.baseline.is_initialized() || m_profile.dirty) { + m_profile.baseline.reset(); GLModel::Geometry init_data; - init_data.format = { GLModel::Geometry::EPrimitiveType::Lines, GLModel::Geometry::EVertexLayout::P3, GLModel::Geometry::EIndexType::USHORT }; + init_data.format = { GLModel::Geometry::EPrimitiveType::Lines, GLModel::Geometry::EVertexLayout::P2, GLModel::Geometry::EIndexType::USHORT }; init_data.color = ColorRGBA::BLACK(); init_data.vertices.reserve(2 * GLModel::Geometry::vertex_stride_floats(init_data.format)); init_data.indices.reserve(2 * GLModel::Geometry::index_stride_bytes(init_data.format)); // vertices - init_data.add_vertex(Vec3f(x, bar_rect.get_bottom(), 0.0f)); - init_data.add_vertex(Vec3f(x, bar_rect.get_top(), 0.0f)); + const float x = bar_rect.get_left() + float(m_slicing_parameters->layer_height) * scale_x; + init_data.add_vertex(Vec2f(x, bar_rect.get_bottom())); + init_data.add_vertex(Vec2f(x, bar_rect.get_top())); // indices init_data.add_ushort_line(0, 1); @@ -485,21 +499,20 @@ void GLCanvas3D::LayersEditing::render_curve(const Rect & bar_rect) m_profile.baseline.init_from(std::move(init_data)); } - if (!m_profile.profile.is_initialized() || bar_rect_changed || m_profile.old_layer_height_profile != m_layer_height_profile) { + if (!m_profile.profile.is_initialized() || m_profile.dirty || m_profile.old_layer_height_profile != m_layer_height_profile) { m_profile.old_layer_height_profile = m_layer_height_profile; m_profile.profile.reset(); GLModel::Geometry init_data; - init_data.format = { GLModel::Geometry::EPrimitiveType::LineStrip, GLModel::Geometry::EVertexLayout::P3, GLModel::Geometry::EIndexType::UINT }; + init_data.format = { GLModel::Geometry::EPrimitiveType::LineStrip, GLModel::Geometry::EVertexLayout::P2, GLModel::Geometry::EIndexType::UINT }; init_data.color = ColorRGBA::BLUE(); init_data.vertices.reserve(m_layer_height_profile.size() * GLModel::Geometry::vertex_stride_floats(init_data.format)); init_data.indices.reserve(m_layer_height_profile.size() * GLModel::Geometry::index_stride_bytes(init_data.format)); // vertices + indices for (unsigned int i = 0; i < (unsigned int)m_layer_height_profile.size(); i += 2) { - init_data.add_vertex(Vec3f(bar_rect.get_left() + float(m_layer_height_profile[i + 1]) * scale_x, - bar_rect.get_bottom() + float(m_layer_height_profile[i]) * scale_y, - 0.0f)); + init_data.add_vertex(Vec2f(bar_rect.get_left() + float(m_layer_height_profile[i + 1]) * scale_x, + bar_rect.get_bottom() + float(m_layer_height_profile[i]) * scale_y)); init_data.add_uint_index(i / 2); } @@ -659,49 +672,6 @@ float GLCanvas3D::LayersEditing::thickness_bar_width(const GLCanvas3D & canvas) * THICKNESS_BAR_WIDTH; } -Size::Size() - : m_width(0) - , m_height(0) -{ -} - -Size::Size(int width, int height, float scale_factor) - : m_width(width) - , m_height(height) - , m_scale_factor(scale_factor) -{ -} - -int Size::get_width() const -{ - return m_width; -} - -void Size::set_width(int width) -{ - m_width = width; -} - -int Size::get_height() const -{ - return m_height; -} - -void Size::set_height(int height) -{ - m_height = height; -} - -int Size::get_scale_factor() const -{ - return m_scale_factor; -} - -void Size::set_scale_factor(int scale_factor) -{ - m_scale_factor = scale_factor; -} - const Point GLCanvas3D::Mouse::Drag::Invalid_2D_Point(INT_MAX, INT_MAX); const Vec3d GLCanvas3D::Mouse::Drag::Invalid_3D_Point(DBL_MAX, DBL_MAX, DBL_MAX); const int GLCanvas3D::Mouse::Drag::MoveThresholdPx = 5; diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp index ceb9eacc76a..084293e54e1 100644 --- a/src/slic3r/GUI/GLCanvas3D.hpp +++ b/src/slic3r/GUI/GLCanvas3D.hpp @@ -62,25 +62,24 @@ class RetinaHelper; class Size { - int m_width; - int m_height; - float m_scale_factor; + int m_width{ 0 }; + int m_height{ 0 }; + float m_scale_factor{ 1.0f }; public: - Size(); - Size(int width, int height, float scale_factor = 1.0); + Size() = default; + Size(int width, int height, float scale_factor = 1.0f) : m_width(width), m_height(height), m_scale_factor(scale_factor) {} - int get_width() const; - void set_width(int width); + int get_width() const { return m_width; } + void set_width(int width) { m_width = width; } - int get_height() const; - void set_height(int height); + int get_height() const { return m_height; } + void set_height(int height) { m_height = height; } - int get_scale_factor() const; - void set_scale_factor(int height); + float get_scale_factor() const { return m_scale_factor; } + void set_scale_factor(float factor) { m_scale_factor = factor; } }; - class RenderTimerEvent : public wxEvent { public: @@ -261,8 +260,10 @@ class GLCanvas3D { GLModel baseline; GLModel profile; + GLModel background; Rect old_bar_rect; std::vector old_layer_height_profile; + bool dirty{ false }; }; Profile m_profile; @@ -303,10 +304,8 @@ class GLCanvas3D private: bool is_initialized() const; void generate_layer_height_texture(); - - void render_background_texture(const GLCanvas3D& canvas, const Rect& bar_rect); - void render_curve(const Rect& bar_rect); - + void render_active_object_annotations(const GLCanvas3D& canvas, const Rect& bar_rect); + void render_profile(const Rect& bar_rect); void update_slicing_parameters(); static float thickness_bar_width(const GLCanvas3D& canvas); diff --git a/src/slic3r/GUI/GLModel.cpp b/src/slic3r/GUI/GLModel.cpp index affd4cc8616..57b14715ea1 100644 --- a/src/slic3r/GUI/GLModel.cpp +++ b/src/slic3r/GUI/GLModel.cpp @@ -24,6 +24,15 @@ void GLModel::Geometry::add_vertex(const Vec2f& position) vertices.emplace_back(position.y()); } +void GLModel::Geometry::add_vertex(const Vec2f& position, const Vec2f& tex_coord) +{ + assert(format.vertex_layout == EVertexLayout::P2T2); + vertices.emplace_back(position.x()); + vertices.emplace_back(position.y()); + vertices.emplace_back(tex_coord.x()); + vertices.emplace_back(tex_coord.y()); +} + void GLModel::Geometry::add_vertex(const Vec3f& position) { assert(format.vertex_layout == EVertexLayout::P3); @@ -331,8 +340,11 @@ bool GLModel::Geometry::has_tex_coord(const Format& format) void GLModel::init_from(Geometry&& data) { - if (is_initialized()) // call reset() if you want to reuse this model + if (is_initialized()) { + // call reset() if you want to reuse this model + assert(false); return; + } if (data.vertices.empty() || data.indices.empty()) { assert(false); @@ -353,10 +365,18 @@ void GLModel::init_from(Geometry&& data) } } +void GLModel::init_from(const TriangleMesh& mesh) +{ + init_from(mesh.its); +} + void GLModel::init_from(const indexed_triangle_set& its) { - if (is_initialized()) // call reset() if you want to reuse this model + if (is_initialized()) { + // call reset() if you want to reuse this model + assert(false); return; + } if (its.vertices.empty() || its.indices.empty()){ assert(false); @@ -389,8 +409,11 @@ void GLModel::init_from(const indexed_triangle_set& its) void GLModel::init_from(const Polygons& polygons, float z) { - if (is_initialized()) // call reset() if you want to reuse this model + if (is_initialized()) { + // call reset() if you want to reuse this model + assert(false); return; + } if (polygons.empty()) { assert(false); @@ -443,8 +466,7 @@ bool GLModel::init_from_file(const std::string& filename) return false; } - const TriangleMesh mesh = model.mesh(); - init_from(mesh.its); + init_from(model.mesh()); m_filename = filename; diff --git a/src/slic3r/GUI/GLModel.hpp b/src/slic3r/GUI/GLModel.hpp index 3b1d20cea16..54f96edaa53 100644 --- a/src/slic3r/GUI/GLModel.hpp +++ b/src/slic3r/GUI/GLModel.hpp @@ -60,6 +60,7 @@ namespace GUI { ColorRGBA color{ ColorRGBA::BLACK() }; void add_vertex(const Vec2f& position); + void add_vertex(const Vec2f& position, const Vec2f& tex_coord); void add_vertex(const Vec3f& position); void add_vertex(const Vec3f& position, const Vec3f& normal); @@ -141,6 +142,7 @@ namespace GUI { size_t indices_size_bytes() const { return indices_count() * Geometry::index_stride_bytes(m_render_data.geometry.format); } void init_from(Geometry&& data); + void init_from(const TriangleMesh& mesh); void init_from(const indexed_triangle_set& its); void init_from(const Polygons& polygons, float z); bool init_from_file(const std::string& filename); diff --git a/src/slic3r/GUI/GLShadersManager.cpp b/src/slic3r/GUI/GLShadersManager.cpp index 6b39c44f58f..5585d2f7fb5 100644 --- a/src/slic3r/GUI/GLShadersManager.cpp +++ b/src/slic3r/GUI/GLShadersManager.cpp @@ -33,8 +33,7 @@ std::pair GLShadersManager::init() bool valid = true; - // basic shader, used to render selection bbox, gizmo cut plane and grabbers connections, - // gizmo move grabbers connections, gizmo scale grabbers connections + // basic shader, used to render all what was previously rendered using the immediate mode valid &= append_shader("flat", { "flat.vs", "flat.fs" }); // used to render bed axes and model, selection hints, gcode sequential view marker model, preview shells, options in gcode preview valid &= append_shader("gouraud_light", { "gouraud_light.vs", "gouraud_light.fs" }); diff --git a/src/slic3r/GUI/Gizmos/GLGizmosManager.hpp b/src/slic3r/GUI/Gizmos/GLGizmosManager.hpp index 6237d4e1933..12c97e9ac4d 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosManager.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosManager.hpp @@ -40,14 +40,14 @@ class Rect Rect() = default; Rect(float left, float top, float right, float bottom) : m_left(left) , m_top(top) , m_right(right) , m_bottom(bottom) {} - bool operator == (const Rect& other) { + bool operator == (const Rect& other) const { if (std::abs(m_left - other.m_left) > EPSILON) return false; if (std::abs(m_top - other.m_top) > EPSILON) return false; if (std::abs(m_right - other.m_right) > EPSILON) return false; if (std::abs(m_bottom - other.m_bottom) > EPSILON) return false; return true; } - bool operator != (const Rect& other) { return !operator==(other); } + bool operator != (const Rect& other) const { return !operator==(other); } float get_left() const { return m_left; } void set_left(float left) { m_left = left; } From 04ad26f611312084ec20d91b86bca23c36be7160 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Sat, 21 Oct 2023 17:16:45 +0800 Subject: [PATCH 08/99] Tech ENABLE_GLBEGIN_GLEND_REMOVAL - Background rendering (cherry picked from commit prusa3d/PrusaSlicer@eda55701a278c5daa090a355e66fe6095082730f) --- resources/shaders/background.fs | 11 +++++ resources/shaders/background.vs | 9 ++++ src/slic3r/GUI/GLCanvas3D.cpp | 67 ++++++++++++++++------------- src/slic3r/GUI/GLCanvas3D.hpp | 3 +- src/slic3r/GUI/GLShadersManager.cpp | 2 + 5 files changed, 61 insertions(+), 31 deletions(-) create mode 100644 resources/shaders/background.fs create mode 100644 resources/shaders/background.vs diff --git a/resources/shaders/background.fs b/resources/shaders/background.fs new file mode 100644 index 00000000000..b1484408988 --- /dev/null +++ b/resources/shaders/background.fs @@ -0,0 +1,11 @@ +#version 110 + +uniform vec4 top_color; +uniform vec4 bottom_color; + +varying vec2 tex_coord; + +void main() +{ + gl_FragColor = mix(bottom_color, top_color, tex_coord.y); +} diff --git a/resources/shaders/background.vs b/resources/shaders/background.vs new file mode 100644 index 00000000000..b7c1d92c0e4 --- /dev/null +++ b/resources/shaders/background.vs @@ -0,0 +1,9 @@ +#version 110 + +varying vec2 tex_coord; + +void main() +{ + gl_Position = gl_Vertex; + tex_coord = gl_MultiTexCoord0.xy; +} diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 8d279c419a4..5e342ec85ed 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -78,26 +78,19 @@ static constexpr const float TRACKBALLSIZE = 0.8f; -static Slic3r::ColorRGB DEFAULT_BG_LIGHT_COLOR = {0.906f, 0.906f, 0.906f}; -static Slic3r::ColorRGB DEFAULT_BG_LIGHT_COLOR_DARK = {0.329f, 0.329f, 0.353f}; -static Slic3r::ColorRGB ERROR_BG_LIGHT_COLOR = {0.753f, 0.192f, 0.039f}; -static Slic3r::ColorRGB ERROR_BG_LIGHT_COLOR_DARK = {0.753f, 0.192f, 0.039f}; +static Slic3r::ColorRGBA DEFAULT_BG_LIGHT_COLOR = { 0.906f, 0.906f, 0.906f, 1.0f }; +static Slic3r::ColorRGBA DEFAULT_BG_LIGHT_COLOR_DARK = { 0.329f, 0.329f, 0.353f, 1.0f }; +static Slic3r::ColorRGBA ERROR_BG_LIGHT_COLOR = { 0.753f, 0.192f, 0.039f, 1.0f }; +static Slic3r::ColorRGBA ERROR_BG_LIGHT_COLOR_DARK = { 0.753f, 0.192f, 0.039f, 1.0f }; void GLCanvas3D::update_render_colors() { - DEFAULT_BG_LIGHT_COLOR = { - RenderColor::colors[RenderCol_3D_Background].x, - RenderColor::colors[RenderCol_3D_Background].y, - RenderColor::colors[RenderCol_3D_Background].z, - }; + DEFAULT_BG_LIGHT_COLOR = ImGuiWrapper::from_ImVec4(RenderColor::colors[RenderCol_3D_Background]); } void GLCanvas3D::load_render_colors() { - RenderColor::colors[RenderCol_3D_Background] = ImVec4(DEFAULT_BG_LIGHT_COLOR.r(), - DEFAULT_BG_LIGHT_COLOR.g(), - DEFAULT_BG_LIGHT_COLOR.b(), - 1.0f); + RenderColor::colors[RenderCol_3D_Background] = ImGuiWrapper::to_ImVec4(DEFAULT_BG_LIGHT_COLOR); } //static constexpr const float AXES_COLOR[3][3] = { { 1.0f, 0.0f, 0.0f }, { 0.0f, 1.0f, 0.0f }, { 0.0f, 0.0f, 1.0f } }; @@ -6610,7 +6603,7 @@ void GLCanvas3D::_rectangular_selection_picking_pass() _update_volumes_hover_state(); } -void GLCanvas3D::_render_background() const +void GLCanvas3D::_render_background() { bool use_error_color = false; if (wxGetApp().is_editor()) { @@ -6642,27 +6635,41 @@ void GLCanvas3D::_render_background() const // Draws a bottom to top gradient over the complete screen. glsafe(::glDisable(GL_DEPTH_TEST)); - ::glBegin(GL_QUADS); + ColorRGBA background_color = m_is_dark ? DEFAULT_BG_LIGHT_COLOR_DARK : DEFAULT_BG_LIGHT_COLOR; + ColorRGBA error_background_color = m_is_dark ? ERROR_BG_LIGHT_COLOR_DARK : ERROR_BG_LIGHT_COLOR; + const ColorRGBA bottom_color = use_error_color ? error_background_color : background_color; - ColorRGB background_color = m_is_dark ? DEFAULT_BG_LIGHT_COLOR_DARK : DEFAULT_BG_LIGHT_COLOR; - ColorRGB error_background_color = m_is_dark ? ERROR_BG_LIGHT_COLOR_DARK : ERROR_BG_LIGHT_COLOR; + if (!m_background.is_initialized() || m_background.get_color() != bottom_color) { + m_background.reset(); - if (use_error_color) - ::glColor3fv(error_background_color.data()); - else - ::glColor3fv(background_color.data()); + GLModel::Geometry init_data; + init_data.format = { GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P2T2, GLModel::Geometry::EIndexType::USHORT }; + init_data.color = bottom_color; + init_data.vertices.reserve(4 * GLModel::Geometry::vertex_stride_floats(init_data.format)); + init_data.indices.reserve(6 * GLModel::Geometry::index_stride_bytes(init_data.format)); - ::glVertex2f(-1.0f, -1.0f); - ::glVertex2f(1.0f, -1.0f); + // vertices + init_data.add_vertex(Vec2f(-1.0f, -1.0f), Vec2f(0.0f, 0.0f)); + init_data.add_vertex(Vec2f(1.0f, -1.0f), Vec2f(1.0f, 0.0f)); + init_data.add_vertex(Vec2f(1.0f, 1.0f), Vec2f(1.0f, 1.0f)); + init_data.add_vertex(Vec2f(-1.0f, 1.0f), Vec2f(0.0f, 1.0f)); - if (use_error_color) - ::glColor3fv(error_background_color.data()); - else - ::glColor3fv(background_color.data()); + // indices + init_data.add_ushort_triangle(0, 1, 2); + init_data.add_ushort_triangle(2, 3, 0); - ::glVertex2f(1.0f, 1.0f); - ::glVertex2f(-1.0f, 1.0f); - glsafe(::glEnd()); + m_background.init_from(std::move(init_data)); + } + + GLShaderProgram* shader = wxGetApp().get_shader("background"); + if (shader != nullptr) { + shader->start_using(); + shader->set_uniform("top_color", use_error_color ? ERROR_BG_LIGHT_COLOR : DEFAULT_BG_LIGHT_COLOR); + shader->set_uniform("bottom_color", bottom_color); + + m_background.render(); + shader->stop_using(); + } glsafe(::glEnable(GL_DEPTH_TEST)); diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp index 084293e54e1..efae16d7eeb 100644 --- a/src/slic3r/GUI/GLCanvas3D.hpp +++ b/src/slic3r/GUI/GLCanvas3D.hpp @@ -714,6 +714,7 @@ class GLCanvas3D CameraTarget m_camera_target; #endif // ENABLE_SHOW_CAMERA_TARGET + GLModel m_background; public: explicit GLCanvas3D(wxGLCanvas* canvas, Bed3D &bed); ~GLCanvas3D(); @@ -1119,7 +1120,7 @@ class GLCanvas3D void _picking_pass(); void _rectangular_selection_picking_pass(); - void _render_background() const; + void _render_background(); void _render_bed(bool bottom, bool show_axes); void _render_bed_for_picking(bool bottom); //BBS: add part plate related logic diff --git a/src/slic3r/GUI/GLShadersManager.cpp b/src/slic3r/GUI/GLShadersManager.cpp index 5585d2f7fb5..c7bd5cdccce 100644 --- a/src/slic3r/GUI/GLShadersManager.cpp +++ b/src/slic3r/GUI/GLShadersManager.cpp @@ -35,6 +35,8 @@ std::pair GLShadersManager::init() // basic shader, used to render all what was previously rendered using the immediate mode valid &= append_shader("flat", { "flat.vs", "flat.fs" }); + // used to render 3D scene background + valid &= append_shader("background", { "background.vs", "background.fs" }); // used to render bed axes and model, selection hints, gcode sequential view marker model, preview shells, options in gcode preview valid &= append_shader("gouraud_light", { "gouraud_light.vs", "gouraud_light.fs" }); //used to render thumbnail From 7907426d008dc47bbcd986fdc467f853c046f917 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Sat, 21 Oct 2023 17:32:34 +0800 Subject: [PATCH 09/99] Tech ENABLE_GLBEGIN_GLEND_REMOVAL - Textures rendering (cherry picked from commit prusa3d/PrusaSlicer@1a47211bfc1543eae4c653a9404d380a7a2aa837) --- resources/shaders/flat_texture.fs | 10 +++++ resources/shaders/flat_texture.vs | 9 +++++ src/slic3r/GUI/GLCanvas3D.cpp | 3 +- src/slic3r/GUI/GLShadersManager.cpp | 2 + src/slic3r/GUI/GLTexture.cpp | 38 ++++++++++++------ src/slic3r/GUI/GLTexture.hpp | 10 ++--- src/slic3r/GUI/Gizmos/GLGizmosManager.cpp | 48 +++++++++++------------ 7 files changed, 76 insertions(+), 44 deletions(-) create mode 100644 resources/shaders/flat_texture.fs create mode 100644 resources/shaders/flat_texture.vs diff --git a/resources/shaders/flat_texture.fs b/resources/shaders/flat_texture.fs new file mode 100644 index 00000000000..ffe193b1c00 --- /dev/null +++ b/resources/shaders/flat_texture.fs @@ -0,0 +1,10 @@ +#version 110 + +uniform sampler2D uniform_texture; + +varying vec2 tex_coord; + +void main() +{ + gl_FragColor = texture2D(uniform_texture, tex_coord); +} diff --git a/resources/shaders/flat_texture.vs b/resources/shaders/flat_texture.vs new file mode 100644 index 00000000000..27addc7526a --- /dev/null +++ b/resources/shaders/flat_texture.vs @@ -0,0 +1,9 @@ +#version 110 + +varying vec2 tex_coord; + +void main() +{ + gl_Position = ftransform(); + tex_coord = gl_MultiTexCoord0.xy; +} diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 5e342ec85ed..175f2f6148b 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -6639,12 +6639,11 @@ void GLCanvas3D::_render_background() ColorRGBA error_background_color = m_is_dark ? ERROR_BG_LIGHT_COLOR_DARK : ERROR_BG_LIGHT_COLOR; const ColorRGBA bottom_color = use_error_color ? error_background_color : background_color; - if (!m_background.is_initialized() || m_background.get_color() != bottom_color) { + if (!m_background.is_initialized()) { m_background.reset(); GLModel::Geometry init_data; init_data.format = { GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P2T2, GLModel::Geometry::EIndexType::USHORT }; - init_data.color = bottom_color; init_data.vertices.reserve(4 * GLModel::Geometry::vertex_stride_floats(init_data.format)); init_data.indices.reserve(6 * GLModel::Geometry::index_stride_bytes(init_data.format)); diff --git a/src/slic3r/GUI/GLShadersManager.cpp b/src/slic3r/GUI/GLShadersManager.cpp index c7bd5cdccce..e544296714d 100644 --- a/src/slic3r/GUI/GLShadersManager.cpp +++ b/src/slic3r/GUI/GLShadersManager.cpp @@ -35,6 +35,8 @@ std::pair GLShadersManager::init() // basic shader, used to render all what was previously rendered using the immediate mode valid &= append_shader("flat", { "flat.vs", "flat.fs" }); + // basic shader for textures, used to render textures + valid &= append_shader("flat_texture", { "flat_texture.vs", "flat_texture.fs" }); // used to render 3D scene background valid &= append_shader("background", { "background.vs", "background.fs" }); // used to render bed axes and model, selection hints, gcode sequential view marker model, preview shells, options in gcode preview diff --git a/src/slic3r/GUI/GLTexture.cpp b/src/slic3r/GUI/GLTexture.cpp index 0b158669431..6b75f490c70 100644 --- a/src/slic3r/GUI/GLTexture.cpp +++ b/src/slic3r/GUI/GLTexture.cpp @@ -8,6 +8,8 @@ #include "3DScene.hpp" #include "OpenGLManager.hpp" +#include "GUI_App.hpp" +#include "GLModel.hpp" #include @@ -125,11 +127,7 @@ void GLTexture::Compressor::compress() GLTexture::Quad_UVs GLTexture::FullTextureUVs = { { 0.0f, 1.0f }, { 1.0f, 1.0f }, { 1.0f, 0.0f }, { 0.0f, 0.0f } }; GLTexture::GLTexture() - : m_id(0) - , m_width(0) - , m_height(0) - , m_source("") - , m_compressor(*this) + : m_compressor(*this) { } @@ -664,12 +662,30 @@ void GLTexture::render_sub_texture(unsigned int tex_id, float left, float right, glsafe(::glBindTexture(GL_TEXTURE_2D, (GLuint)tex_id)); - ::glBegin(GL_QUADS); - ::glTexCoord2f(uvs.left_bottom.u, uvs.left_bottom.v); ::glVertex2f(left, bottom); - ::glTexCoord2f(uvs.right_bottom.u, uvs.right_bottom.v); ::glVertex2f(right, bottom); - ::glTexCoord2f(uvs.right_top.u, uvs.right_top.v); ::glVertex2f(right, top); - ::glTexCoord2f(uvs.left_top.u, uvs.left_top.v); ::glVertex2f(left, top); - glsafe(::glEnd()); + GLModel::Geometry init_data; + init_data.format = { GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P2T2, GLModel::Geometry::EIndexType::USHORT }; + init_data.vertices.reserve(4 * GLModel::Geometry::vertex_stride_floats(init_data.format)); + init_data.indices.reserve(6 * GLModel::Geometry::index_stride_bytes(init_data.format)); + + // vertices + init_data.add_vertex(Vec2f(left, bottom), Vec2f(uvs.left_bottom.u, uvs.left_bottom.v)); + init_data.add_vertex(Vec2f(right, bottom), Vec2f(uvs.right_bottom.u, uvs.right_bottom.v)); + init_data.add_vertex(Vec2f(right, top), Vec2f(uvs.right_top.u, uvs.right_top.v)); + init_data.add_vertex(Vec2f(left, top), Vec2f(uvs.left_top.u, uvs.left_top.v)); + + // indices + init_data.add_ushort_triangle(0, 1, 2); + init_data.add_ushort_triangle(2, 3, 0); + + GLModel model; + model.init_from(std::move(init_data)); + + GLShaderProgram* shader = wxGetApp().get_shader("flat_texture"); + if (shader != nullptr) { + shader->start_using(); + model.render(); + shader->stop_using(); + } glsafe(::glBindTexture(GL_TEXTURE_2D, 0)); diff --git a/src/slic3r/GUI/GLTexture.hpp b/src/slic3r/GUI/GLTexture.hpp index d898a10bdff..9af4f8a872e 100644 --- a/src/slic3r/GUI/GLTexture.hpp +++ b/src/slic3r/GUI/GLTexture.hpp @@ -64,8 +64,8 @@ namespace GUI { struct UV { - float u; - float v; + float u{ 0.0f }; + float v{ 0.0f }; }; struct Quad_UVs @@ -79,9 +79,9 @@ namespace GUI { static Quad_UVs FullTextureUVs; protected: - unsigned int m_id; - int m_width; - int m_height; + unsigned int m_id{ 0 }; + int m_width{ 0 }; + int m_height{ 0 }; std::string m_source; Compressor m_compressor; diff --git a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp index 8f13dc81438..0acfd3eb1ec 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp @@ -1279,40 +1279,36 @@ void GLGizmosManager::update_after_undo_redo(const UndoRedo::Snapshot& snapshot) void GLGizmosManager::render_background(float left, float top, float right, float bottom, float border) const { - unsigned int tex_id = m_background_texture.texture.get_id(); - float tex_width = (float)m_background_texture.texture.get_width(); - float tex_height = (float)m_background_texture.texture.get_height(); - if ((tex_id != 0) && (tex_width > 0) && (tex_height > 0)) - { + const unsigned int tex_id = m_background_texture.texture.get_id(); + const float tex_width = float(m_background_texture.texture.get_width()); + const float tex_height = float(m_background_texture.texture.get_height()); + if (tex_id != 0 && tex_width > 0 && tex_height > 0) { //BBS: GUI refactor: remove the corners of gizmo - float inv_tex_width = (tex_width != 0.0f) ? 1.0f / tex_width : 0.0f; - float inv_tex_height = (tex_height != 0.0f) ? 1.0f / tex_height : 0.0f; + const float inv_tex_width = (tex_width != 0.0f) ? 1.0f / tex_width : 0.0f; + const float inv_tex_height = (tex_height != 0.0f) ? 1.0f / tex_height : 0.0f; - float internal_left_uv = (float)m_background_texture.metadata.left * inv_tex_width; - float internal_right_uv = 1.0f - (float)m_background_texture.metadata.right * inv_tex_width; - float internal_top_uv = 1.0f - (float)m_background_texture.metadata.top * inv_tex_height; - float internal_bottom_uv = (float)m_background_texture.metadata.bottom * inv_tex_height; + const float internal_left_uv = (float)m_background_texture.metadata.left * inv_tex_width; + const float internal_right_uv = 1.0f - (float)m_background_texture.metadata.right * inv_tex_width; + const float internal_top_uv = 1.0f - (float)m_background_texture.metadata.top * inv_tex_height; + const float internal_bottom_uv = (float)m_background_texture.metadata.bottom * inv_tex_height; GLTexture::render_sub_texture(tex_id, left, right, bottom, top, { { internal_left_uv, internal_bottom_uv }, { internal_right_uv, internal_bottom_uv }, { internal_right_uv, internal_top_uv }, { internal_left_uv, internal_top_uv } }); /* - float inv_tex_width = (tex_width != 0.0f) ? 1.0f / tex_width : 0.0f; - float inv_tex_height = (tex_height != 0.0f) ? 1.0f / tex_height : 0.0f; - - float internal_left = left + border; - float internal_right = right - border; - float internal_top = top - border; - float internal_bottom = bottom + border; + const float internal_left = left + border; + const float internal_right = right - border; + const float internal_top = top - border; + const float internal_bottom = bottom + border; // float left_uv = 0.0f; - float right_uv = 1.0f; - float top_uv = 1.0f; - float bottom_uv = 0.0f; - - float internal_left_uv = (float)m_background_texture.metadata.left * inv_tex_width; - float internal_right_uv = 1.0f - (float)m_background_texture.metadata.right * inv_tex_width; - float internal_top_uv = 1.0f - (float)m_background_texture.metadata.top * inv_tex_height; - float internal_bottom_uv = (float)m_background_texture.metadata.bottom * inv_tex_height; + const float right_uv = 1.0f; + const float top_uv = 1.0f; + const float bottom_uv = 0.0f; + + const float internal_left_uv = float(m_background_texture.metadata.left) * inv_tex_width; + const float internal_right_uv = 1.0f - float(m_background_texture.metadata.right) * inv_tex_width; + const float internal_top_uv = 1.0f - float(m_background_texture.metadata.top) * inv_tex_height; + const float internal_bottom_uv = float(m_background_texture.metadata.bottom) * inv_tex_height; // top-left corner GLTexture::render_sub_texture(tex_id, left, internal_left, internal_top, top, { { internal_left_uv, internal_bottom_uv }, { internal_right_uv, internal_bottom_uv }, { internal_right_uv, internal_top_uv }, { internal_left_uv, internal_top_uv } }); From 499b9d1be85867a03973b69c5dbbeb22f51f57a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Hejl?= Date: Sat, 21 Oct 2023 17:51:49 +0800 Subject: [PATCH 10/99] =?UTF-8?q?=EF=BB=BFFix=20various=20memory=20leaks?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit (cherry picked from commit prusa3d/PrusaSlicer@deb17c59204db6d5308899cb4c428a23fa400851) --- src/libslic3r/ExtrusionEntityCollection.cpp | 7 +-- src/libslic3r/Semver.hpp | 28 +++++++-- src/slic3r/GUI/BedShapeDialog.hpp | 1 + src/slic3r/GUI/GLCanvas3D.cpp | 24 +++++--- src/slic3r/GUI/GUI_ObjectList.cpp | 1 + src/slic3r/GUI/GUI_ObjectList.hpp | 2 +- src/slic3r/GUI/Tab.cpp | 67 +++++++++++---------- 7 files changed, 79 insertions(+), 51 deletions(-) diff --git a/src/libslic3r/ExtrusionEntityCollection.cpp b/src/libslic3r/ExtrusionEntityCollection.cpp index 391ac2d5872..e6ae1edd4d3 100644 --- a/src/libslic3r/ExtrusionEntityCollection.cpp +++ b/src/libslic3r/ExtrusionEntityCollection.cpp @@ -56,12 +56,9 @@ ExtrusionEntityCollection::operator ExtrusionPaths() const return paths; } -ExtrusionEntity* ExtrusionEntityCollection::clone() const +ExtrusionEntity *ExtrusionEntityCollection::clone() const { - ExtrusionEntityCollection* coll = new ExtrusionEntityCollection(*this); - for (size_t i = 0; i < coll->entities.size(); ++i) - coll->entities[i] = this->entities[i]->clone(); - return coll; + return new ExtrusionEntityCollection(*this); } void ExtrusionEntityCollection::reverse() diff --git a/src/libslic3r/Semver.hpp b/src/libslic3r/Semver.hpp index cdc96f108b5..4d64b1c7db2 100644 --- a/src/libslic3r/Semver.hpp +++ b/src/libslic3r/Semver.hpp @@ -110,10 +110,30 @@ class Semver void set_maj(int maj) { ver.major = maj; } void set_min(int min) { ver.minor = min; } void set_patch(int patch) { ver.patch = patch; } - void set_metadata(boost::optional meta) { ver.metadata = meta ? strdup(*meta) : nullptr; } - void set_metadata(const char *meta) { ver.metadata = meta ? strdup(meta) : nullptr; } - void set_prerelease(boost::optional pre) { ver.prerelease = pre ? strdup(*pre) : nullptr; } - void set_prerelease(const char *pre) { ver.prerelease = pre ? strdup(pre) : nullptr; } + void set_metadata(boost::optional meta) + { + if (ver.metadata) + free(ver.metadata); + ver.metadata = meta ? strdup(*meta) : nullptr; + } + void set_metadata(const char *meta) + { + if (ver.metadata) + free(ver.metadata); + ver.metadata = meta ? strdup(meta) : nullptr; + } + void set_prerelease(boost::optional pre) + { + if (ver.prerelease) + free(ver.prerelease); + ver.prerelease = pre ? strdup(*pre) : nullptr; + } + void set_prerelease(const char *pre) + { + if (ver.prerelease) + free(ver.prerelease); + ver.prerelease = pre ? strdup(pre) : nullptr; + } // Comparison bool operator<(const Semver &b) const { return ::semver_compare(ver, b.ver) == -1; } diff --git a/src/slic3r/GUI/BedShapeDialog.hpp b/src/slic3r/GUI/BedShapeDialog.hpp index 20201faf0f7..912faf6bfb9 100644 --- a/src/slic3r/GUI/BedShapeDialog.hpp +++ b/src/slic3r/GUI/BedShapeDialog.hpp @@ -18,6 +18,7 @@ namespace GUI { class ConfigOptionsGroup; using ConfigOptionsGroupShp = std::shared_ptr; +using ConfigOptionsGroupWkp = std::weak_ptr; struct BedShape { diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 175f2f6148b..419e3b048ad 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -8703,10 +8703,14 @@ void GLCanvas3D::_load_print_object_toolpaths(const PrintObject& print_object, c BOOST_LOG_TRIVIAL(debug) << "Loading print object toolpaths in parallel - finalizing results" << m_volumes.log_memory_info() << log_memory_info(); // Remove empty volumes from the newly added volumes. - m_volumes.volumes.erase( - std::remove_if(m_volumes.volumes.begin() + volumes_cnt_initial, m_volumes.volumes.end(), - [](const GLVolume *volume) { return volume->empty(); }), - m_volumes.volumes.end()); + { + for (auto ptr_it = m_volumes.volumes.begin() + volumes_cnt_initial; ptr_it != m_volumes.volumes.end(); ++ptr_it) + if ((*ptr_it)->empty()) { + delete *ptr_it; + *ptr_it = nullptr; + } + m_volumes.volumes.erase(std::remove(m_volumes.volumes.begin() + volumes_cnt_initial, m_volumes.volumes.end(), nullptr), m_volumes.volumes.end()); + } for (size_t i = volumes_cnt_initial; i < m_volumes.volumes.size(); ++i) { GLVolume* v = m_volumes.volumes[i]; v->is_outside = ! build_volume.all_paths_inside_vertices_and_normals_interleaved(v->indexed_vertex_array.vertices_and_normals_interleaved, v->indexed_vertex_array.bounding_box()); @@ -8872,10 +8876,14 @@ void GLCanvas3D::_load_wipe_tower_toolpaths(const BuildVolume& build_volume, con BOOST_LOG_TRIVIAL(debug) << "Loading wipe tower toolpaths in parallel - finalizing results" << m_volumes.log_memory_info() << log_memory_info(); // Remove empty volumes from the newly added volumes. - m_volumes.volumes.erase( - std::remove_if(m_volumes.volumes.begin() + volumes_cnt_initial, m_volumes.volumes.end(), - [](const GLVolume *volume) { return volume->empty(); }), - m_volumes.volumes.end()); + { + for (auto ptr_it = m_volumes.volumes.begin() + volumes_cnt_initial; ptr_it != m_volumes.volumes.end(); ++ptr_it) + if ((*ptr_it)->empty()) { + delete *ptr_it; + *ptr_it = nullptr; + } + m_volumes.volumes.erase(std::remove(m_volumes.volumes.begin() + volumes_cnt_initial, m_volumes.volumes.end(), nullptr), m_volumes.volumes.end()); + } for (size_t i = volumes_cnt_initial; i < m_volumes.volumes.size(); ++i) { GLVolume* v = m_volumes.volumes[i]; v->is_outside = ! build_volume.all_paths_inside_vertices_and_normals_interleaved(v->indexed_vertex_array.vertices_and_normals_interleaved, v->indexed_vertex_array.bounding_box()); diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp index 24f44a12a10..5e5eee38062 100644 --- a/src/slic3r/GUI/GUI_ObjectList.cpp +++ b/src/slic3r/GUI/GUI_ObjectList.cpp @@ -304,6 +304,7 @@ ObjectList::ObjectList(wxWindow* parent) : ObjectList::~ObjectList() { + delete m_objects_model; } void ObjectList::set_min_height() diff --git a/src/slic3r/GUI/GUI_ObjectList.hpp b/src/slic3r/GUI/GUI_ObjectList.hpp index 125c7480371..f4a6f0320a5 100644 --- a/src/slic3r/GUI/GUI_ObjectList.hpp +++ b/src/slic3r/GUI/GUI_ObjectList.hpp @@ -205,7 +205,7 @@ class ObjectList : public wxDataViewCtrl public: ObjectList(wxWindow* parent); - ~ObjectList(); + ~ObjectList() override; void set_min_height(); void update_min_height(); diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index 3ad2c440c32..ffacda6d63d 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -2572,8 +2572,8 @@ bool Tab::validate_custom_gcode(const wxString& title, const std::string& gcode) return !invalid; } -static void validate_custom_gcode_cb(Tab* tab, ConfigOptionsGroupShp opt_group, const t_config_option_key& opt_key, const boost::any& value) { - tab->validate_custom_gcodes_was_shown = !Tab::validate_custom_gcode(opt_group->title, boost::any_cast(value)); +static void validate_custom_gcode_cb(Tab* tab, const wxString& title, const t_config_option_key& opt_key, const boost::any& value) { + tab->validate_custom_gcodes_was_shown = !Tab::validate_custom_gcode(title, boost::any_cast(value)); tab->update_dirty(); tab->on_value_change(opt_key, value); } @@ -2590,18 +2590,19 @@ void TabFilament::add_filament_overrides_page() //BBS line = optgroup->create_single_option_line(optgroup->get_option(opt_key)); - line.near_label_widget = [this, optgroup, opt_key, opt_index](wxWindow* parent) { + line.near_label_widget = [this, optgroup_wk = ConfigOptionsGroupWkp(optgroup), opt_key, opt_index](wxWindow* parent) { wxCheckBox* check_box = new wxCheckBox(parent, wxID_ANY, ""); - check_box->Bind(wxEVT_CHECKBOX, [optgroup, opt_key, opt_index](wxCommandEvent& evt) { + check_box->Bind(wxEVT_CHECKBOX, [optgroup_wk, opt_key, opt_index](wxCommandEvent& evt) { const bool is_checked = evt.IsChecked(); - Field* field = optgroup->get_fieldc(opt_key, opt_index); - if (field != nullptr) { - field->toggle(is_checked); - if (is_checked) - field->set_last_meaningful_value(); - else - field->set_na_value(); + if (auto optgroup_sh = optgroup_wk.lock(); optgroup_sh) { + if (Field *field = optgroup_sh->get_fieldc(opt_key, opt_index); field != nullptr) { + field->toggle(is_checked); + if (is_checked) + field->set_last_meaningful_value(); + else + field->set_na_value(); + } } }, check_box->GetId()); @@ -2758,7 +2759,7 @@ void TabFilament::build() line.append_option(optgroup->get_option("textured_plate_temp")); optgroup->append_line(line); - optgroup->m_on_change = [this, optgroup](t_config_option_key opt_key, boost::any value) + optgroup->m_on_change = [this](t_config_option_key opt_key, boost::any value) { DynamicPrintConfig& filament_config = wxGetApp().preset_bundle->filaments.get_edited_preset().config; @@ -2853,8 +2854,8 @@ void TabFilament::build() page = add_options_page(L("Advanced"), "advanced"); optgroup = page->new_optgroup(L("Filament start G-code"), L"param_gcode", 0); - optgroup->m_on_change = [this, optgroup](const t_config_option_key& opt_key, const boost::any& value) { - validate_custom_gcode_cb(this, optgroup, opt_key, value); + optgroup->m_on_change = [this, &optgroup_title = optgroup->title](const t_config_option_key& opt_key, const boost::any& value) { + validate_custom_gcode_cb(this, optgroup_title, opt_key, value); }; option = optgroup->get_option("filament_start_gcode"); option.opt.full_width = true; @@ -2863,8 +2864,8 @@ void TabFilament::build() optgroup->append_single_option_line(option); optgroup = page->new_optgroup(L("Filament end G-code"), L"param_gcode", 0); - optgroup->m_on_change = [this, optgroup](const t_config_option_key& opt_key, const boost::any& value) { - validate_custom_gcode_cb(this, optgroup, opt_key, value); + optgroup->m_on_change = [this, &optgroup_title = optgroup->title](const t_config_option_key& opt_key, const boost::any& value) { + validate_custom_gcode_cb(this, optgroup_title, opt_key, value); }; option = optgroup->get_option("filament_end_gcode"); option.opt.full_width = true; @@ -3170,8 +3171,8 @@ void TabPrinter::build_fff() const int notes_field_height = 25; // 250 page = add_options_page(L("Machine gcode"), "cog"); optgroup = page->new_optgroup(L("Machine start G-code"), L"param_gcode", 0); - optgroup->m_on_change = [this, optgroup](const t_config_option_key& opt_key, const boost::any& value) { - validate_custom_gcode_cb(this, optgroup, opt_key, value); + optgroup->m_on_change = [this, &optgroup_title = optgroup->title](const t_config_option_key& opt_key, const boost::any& value) { + validate_custom_gcode_cb(this, optgroup_title, opt_key, value); }; option = optgroup->get_option("machine_start_gcode"); option.opt.full_width = true; @@ -3180,8 +3181,8 @@ void TabPrinter::build_fff() optgroup->append_single_option_line(option); optgroup = page->new_optgroup(L("Machine end G-code"), L"param_gcode", 0); - optgroup->m_on_change = [this, optgroup](const t_config_option_key& opt_key, const boost::any& value) { - validate_custom_gcode_cb(this, optgroup, opt_key, value); + optgroup->m_on_change = [this, &optgroup_title = optgroup->title](const t_config_option_key& opt_key, const boost::any& value) { + validate_custom_gcode_cb(this, optgroup_title, opt_key, value); }; option = optgroup->get_option("machine_end_gcode"); option.opt.full_width = true; @@ -3190,8 +3191,8 @@ void TabPrinter::build_fff() optgroup->append_single_option_line(option); optgroup = page->new_optgroup(L("Before layer change G-code"),"param_gcode", 0); - optgroup->m_on_change = [this, optgroup](const t_config_option_key& opt_key, const boost::any& value) { - validate_custom_gcode_cb(this, optgroup, opt_key, value); + optgroup->m_on_change = [this, &optgroup_title = optgroup->title](const t_config_option_key& opt_key, const boost::any& value) { + validate_custom_gcode_cb(this, optgroup_title, opt_key, value); }; option = optgroup->get_option("before_layer_change_gcode"); option.opt.full_width = true; @@ -3200,8 +3201,8 @@ void TabPrinter::build_fff() optgroup->append_single_option_line(option); optgroup = page->new_optgroup(L("Layer change G-code"), L"param_gcode", 0); - optgroup->m_on_change = [this, optgroup](const t_config_option_key& opt_key, const boost::any& value) { - validate_custom_gcode_cb(this, optgroup, opt_key, value); + optgroup->m_on_change = [this, &optgroup_title = optgroup->title](const t_config_option_key& opt_key, const boost::any& value) { + validate_custom_gcode_cb(this, optgroup_title, opt_key, value); }; option = optgroup->get_option("layer_change_gcode"); option.opt.full_width = true; @@ -3210,8 +3211,8 @@ void TabPrinter::build_fff() optgroup->append_single_option_line(option); optgroup = page->new_optgroup(L("Time lapse G-code"), L"param_gcode", 0); - optgroup->m_on_change = [this, optgroup](const t_config_option_key& opt_key, const boost::any& value) { - validate_custom_gcode_cb(this, optgroup, opt_key, value); + optgroup->m_on_change = [this, &optgroup_title = optgroup->title](const t_config_option_key& opt_key, const boost::any& value) { + validate_custom_gcode_cb(this, optgroup_title, opt_key, value); }; option = optgroup->get_option("time_lapse_gcode"); option.opt.full_width = true; @@ -3220,8 +3221,8 @@ void TabPrinter::build_fff() optgroup->append_single_option_line(option); optgroup = page->new_optgroup(L("Change filament G-code"), L"param_gcode", 0); - optgroup->m_on_change = [this, optgroup](const t_config_option_key& opt_key, const boost::any& value) { - validate_custom_gcode_cb(this, optgroup, opt_key, value); + optgroup->m_on_change = [this, &optgroup_title = optgroup->title](const t_config_option_key& opt_key, const boost::any& value) { + validate_custom_gcode_cb(this, optgroup_title, opt_key, value); }; option = optgroup->get_option("change_filament_gcode"); option.opt.full_width = true; @@ -3230,8 +3231,8 @@ void TabPrinter::build_fff() optgroup->append_single_option_line(option); optgroup = page->new_optgroup(L("Pause G-code"), L"param_gcode", 0); - optgroup->m_on_change = [this, optgroup](const t_config_option_key& opt_key, const boost::any& value) { - validate_custom_gcode_cb(this, optgroup, opt_key, value); + optgroup->m_on_change = [this, &optgroup_title = optgroup->title](const t_config_option_key& opt_key, const boost::any& value) { + validate_custom_gcode_cb(this, optgroup_title, opt_key, value); }; option = optgroup->get_option("machine_pause_gcode"); option.opt.is_code = true; @@ -3239,8 +3240,8 @@ void TabPrinter::build_fff() optgroup->append_single_option_line(option); optgroup = page->new_optgroup(L("Template Custom G-code"), L"param_gcode", 0); - optgroup->m_on_change = [this, optgroup](const t_config_option_key& opt_key, const boost::any& value) { - validate_custom_gcode_cb(this, optgroup, opt_key, value); + optgroup->m_on_change = [this, &optgroup_title = optgroup->title](const t_config_option_key& opt_key, const boost::any& value) { + validate_custom_gcode_cb(this, optgroup_title, opt_key, value); }; option = optgroup->get_option("template_custom_gcode"); option.opt.is_code = true; @@ -3468,7 +3469,7 @@ if (is_marlin_flavor) auto optgroup = page->new_optgroup(L("Single extruder multimaterial setup")); optgroup->append_single_option_line("single_extruder_multi_material", "semm"); // Orca: we only support Single Extruder Multi Material, so it's always enabled - // optgroup->m_on_change = [this, optgroup](const t_config_option_key &opt_key, const boost::any &value) { + // optgroup->m_on_change = [this](const t_config_option_key &opt_key, const boost::any &value) { // wxTheApp->CallAfter([this, opt_key, value]() { // if (opt_key == "single_extruder_multi_material") { // build_unregular_pages(); From f9de4ec3991329ac9bf497ccb7a67344b00fce81 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Sat, 21 Oct 2023 23:35:34 +0800 Subject: [PATCH 11/99] Tech ENABLE_GLBEGIN_GLEND_REMOVAL - Removed Slic3r::GUI::GeometryBuffer from 3DBed.hpp and replaced with GLModel (cherry picked from commit prusa3d/PrusaSlicer@6b041429f6f137add530c900c3160d431286366f) --- resources/shaders/printbed.fs | 2 +- resources/shaders/printbed.vs | 9 +- src/slic3r/GUI/3DBed.cpp | 145 +++++----- src/slic3r/GUI/3DBed.hpp | 19 +- src/slic3r/GUI/GLModel.cpp | 24 +- src/slic3r/GUI/GLModel.hpp | 2 + src/slic3r/GUI/PartPlate.cpp | 507 ++++++++++++++-------------------- src/slic3r/GUI/PartPlate.hpp | 88 +++--- 8 files changed, 354 insertions(+), 442 deletions(-) diff --git a/resources/shaders/printbed.fs b/resources/shaders/printbed.fs index d1316ca2fe8..bef07515801 100644 --- a/resources/shaders/printbed.fs +++ b/resources/shaders/printbed.fs @@ -1,6 +1,6 @@ #version 110 -const vec3 back_color_dark = vec3(0.235, 0.235, 0.235); +const vec3 back_color_dark = vec3(0.235, 0.235, 0.235); const vec3 back_color_light = vec3(0.365, 0.365, 0.365); uniform sampler2D texture; diff --git a/resources/shaders/printbed.vs b/resources/shaders/printbed.vs index 7633017f12c..3b3f8875d20 100644 --- a/resources/shaders/printbed.vs +++ b/resources/shaders/printbed.vs @@ -1,14 +1,9 @@ #version 110 -attribute vec3 v_position; -attribute vec2 v_tex_coords; - varying vec2 tex_coords; void main() { - gl_Position = gl_ModelViewProjectionMatrix * vec4(v_position.x, v_position.y, v_position.z, 1.0); - // the following line leads to crash on some Intel graphics card - //gl_Position = gl_ModelViewProjectionMatrix * vec4(v_position, 1.0); - tex_coords = v_tex_coords; + gl_Position = ftransform(); + tex_coords = gl_MultiTexCoord0.xy; } diff --git a/src/slic3r/GUI/3DBed.cpp b/src/slic3r/GUI/3DBed.cpp index 786cd401331..68d2d89f851 100644 --- a/src/slic3r/GUI/3DBed.cpp +++ b/src/slic3r/GUI/3DBed.cpp @@ -35,6 +35,53 @@ static const Slic3r::ColorRGBA DEFAULT_TRANSPARENT_GRID_COLOR = { 0.9f, 0.9f, 0 namespace Slic3r { namespace GUI { +bool init_model_from_poly(GLModel &model, const ExPolygon &poly, float z) +{ + if (poly.empty()) + return false; + + const std::vector triangles = triangulate_expolygon_2f(poly, NORMALS_UP); + if (triangles.empty() || triangles.size() % 3 != 0) + return false; + + const GLModel::Geometry::EIndexType index_type = (triangles.size() < 65536) ? GLModel::Geometry::EIndexType::USHORT : GLModel::Geometry::EIndexType::UINT; + + GLModel::Geometry init_data; + init_data.format = { GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3T2, index_type }; + + Vec2f min = triangles.front(); + Vec2f max = min; + for (const Vec2f &v : triangles) { + min = min.cwiseMin(v).eval(); + max = max.cwiseMax(v).eval(); + } + + const Vec2f size = max - min; + if (size.x() <= 0.0f || size.y() <= 0.0f) + return false; + + Vec2f inv_size = size.cwiseInverse(); + inv_size.y() *= -1.0f; + + unsigned int vertices_counter = 0; + for (const Vec2f &v : triangles) { + const Vec3f p = {v.x(), v.y(), z}; + init_data.add_vertex(p, (Vec2f)(v - min).cwiseProduct(inv_size).eval()); + ++vertices_counter; + if (vertices_counter % 3 == 0) { + if (index_type == GLModel::Geometry::EIndexType::USHORT) + init_data.add_ushort_triangle((unsigned short)vertices_counter - 3, (unsigned short)vertices_counter - 2, (unsigned short)vertices_counter - 1); + else + init_data.add_uint_triangle(vertices_counter - 3, vertices_counter - 2, vertices_counter - 1); + } + } + + model.init_from(std::move(init_data)); + + return true; +} + +/* bool GeometryBuffer::set_from_triangles(const std::vector &triangles, float z) { if (triangles.empty()) { @@ -133,6 +180,7 @@ const float* GeometryBuffer::get_vertices_data() const { return (m_vertices.size() > 0) ? (const float*)m_vertices.data() : nullptr; } +*/ const float Bed3D::Axes::DefaultStemRadius = 0.5f; const float Bed3D::Axes::DefaultStemLength = 25.0f; @@ -261,25 +309,9 @@ bool Bed3D::set_shape(const Pointfs& printable_area, const double printable_heig //BBS: add part plate logic //BBS add default bed -#if 1 - ExPolygon poly{ Polygon::new_scale(printable_area) }; -#else - ExPolygon poly; - for (const Vec2d& p : printable_area) { - poly.contour.append(Point(scale_(p(0) + m_position.x()), scale_(p(1) + m_position.y()))); - } -#endif - - calc_triangles(poly); - - //no need gridline for 3dbed - //const BoundingBox& bed_bbox = poly.contour.bounding_box(); - //calc_gridlines(poly, bed_bbox); - - //m_polygon = offset(poly.contour, (float)bed_bbox.radius() * 1.7f, jtRound, scale_(0.5))[0]; + m_triangles.reset(); if (with_reset) { - this->release_VBOs(); //m_texture.reset(); m_model.reset(); } @@ -390,39 +422,6 @@ BoundingBoxf3 Bed3D::calc_extended_bounding_box(bool consider_model_offset) cons return out; } -void Bed3D::calc_triangles(const ExPolygon& poly) -{ - if (! m_triangles.set_from_triangles(triangulate_expolygon_2f(poly, NORMALS_UP), GROUND_Z)) - BOOST_LOG_TRIVIAL(error) << "Unable to create bed triangles"; -} - -void Bed3D::calc_gridlines(const ExPolygon& poly, const BoundingBox& bed_bbox) -{ - /*Polylines axes_lines; - for (coord_t x = bed_bbox.min.x(); x <= bed_bbox.max.x(); x += scale_(10.0)) { - Polyline line; - line.append(Point(x, bed_bbox.min.y())); - line.append(Point(x, bed_bbox.max.y())); - axes_lines.push_back(line); - } - for (coord_t y = bed_bbox.min.y(); y <= bed_bbox.max.y(); y += scale_(10.0)) { - Polyline line; - line.append(Point(bed_bbox.min.x(), y)); - line.append(Point(bed_bbox.max.x(), y)); - axes_lines.push_back(line); - } - - // clip with a slightly grown expolygon because our lines lay on the contours and may get erroneously clipped - Lines gridlines = to_lines(intersection_pl(axes_lines, offset(poly, (float)SCALED_EPSILON))); - - // append bed contours - Lines contour_lines = to_lines(poly); - std::copy(contour_lines.begin(), contour_lines.end(), std::back_inserter(gridlines)); - - if (!m_gridlines.set_from_lines(gridlines, GROUND_Z)) - BOOST_LOG_TRIVIAL(error) << "Unable to create bed grid lines\n";*/ -} - // Try to match the print bed shape with the shape of an active profile. If such a match exists, // return the print bed model. std::tuple Bed3D::detect_type(const Pointfs& shape) @@ -626,9 +625,10 @@ void Bed3D::update_model_offset() const const_cast(m_extended_bounding_box) = calc_extended_bounding_box(); } -GeometryBuffer Bed3D::update_bed_triangles() const +void Bed3D::update_bed_triangles() { - GeometryBuffer new_triangles; + m_triangles.reset(); + Vec3d shift = m_extended_bounding_box.center(); shift(2) = -0.03; Vec3d* model_offset_ptr = const_cast(&m_model_offset); @@ -636,7 +636,7 @@ GeometryBuffer Bed3D::update_bed_triangles() const //BBS: TODO: hack for default bed BoundingBoxf3 build_volume; - if (!m_build_volume.valid()) return new_triangles; + if (!m_build_volume.valid()) return; auto bed_ext = get_extents(m_bed_shape); (*model_offset_ptr)(0) = m_build_volume.bounding_volume2d().min.x() - bed_ext.min.x(); (*model_offset_ptr)(1) = m_build_volume.bounding_volume2d().min.y() - bed_ext.min.y(); @@ -648,12 +648,11 @@ GeometryBuffer Bed3D::update_bed_triangles() const new_bed_shape.push_back(new_point); } ExPolygon poly{ Polygon::new_scale(new_bed_shape) }; - if (!new_triangles.set_from_triangles(triangulate_expolygon_2f(poly, NORMALS_UP), GROUND_Z)) { - ; + if (!init_model_from_poly(m_triangles, poly, GROUND_Z)) { + BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << ":Unable to update plate triangles\n"; } // update extended bounding box const_cast(m_extended_bounding_box) = calc_extended_bounding_box(); - return new_triangles; } void Bed3D::render_model() @@ -700,46 +699,34 @@ void Bed3D::render_default(bool bottom) bool picking = false; m_texture.reset(); - const unsigned int triangles_vcount = m_triangles.get_vertices_count(); - GeometryBuffer default_triangles = update_bed_triangles(); - if (triangles_vcount > 0) { - const bool has_model = !m_model.get_filename().empty(); + update_bed_triangles(); + + GLShaderProgram *shader = wxGetApp().get_shader("flat"); + if (shader != nullptr) { + shader->start_using(); glsafe(::glEnable(GL_DEPTH_TEST)); glsafe(::glEnable(GL_BLEND)); glsafe(::glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)); - glsafe(::glEnableClientState(GL_VERTEX_ARRAY)); - - if (!has_model && !bottom) { + if (m_model.get_filename().empty() && !bottom) { // draw background glsafe(::glDepthMask(GL_FALSE)); - glsafe(::glColor4fv(picking ? PICKING_MODEL_COLOR.data() : DEFAULT_MODEL_COLOR.data())); - glsafe(::glNormal3d(0.0f, 0.0f, 1.0f)); - glsafe(::glVertexPointer(3, GL_FLOAT, default_triangles.get_vertex_data_size(), (GLvoid*)default_triangles.get_vertices_data())); - glsafe(::glDrawArrays(GL_TRIANGLES, 0, (GLsizei)triangles_vcount)); + m_triangles.set_color(picking ? PICKING_MODEL_COLOR : DEFAULT_MODEL_COLOR); + m_triangles.render(); glsafe(::glDepthMask(GL_TRUE)); } /*if (!picking) { // draw grid glsafe(::glLineWidth(1.5f * m_scale_factor)); - glsafe(::glColor4fv(has_model && !bottom ? DEFAULT_SOLID_GRID_COLOR.data() : DEFAULT_TRANSPARENT_GRID_COLOR.data())); - glsafe(::glVertexPointer(3, GL_FLOAT, default_triangles.get_vertex_data_size(), (GLvoid*)m_gridlines.get_vertices_data())); - glsafe(::glDrawArrays(GL_LINES, 0, (GLsizei)m_gridlines.get_vertices_count())); + m_gridlines.set_color(picking ? DEFAULT_SOLID_GRID_COLOR : DEFAULT_TRANSPARENT_GRID_COLOR); + m_gridlines.render(); }*/ - glsafe(::glDisableClientState(GL_VERTEX_ARRAY)); - glsafe(::glDisable(GL_BLEND)); - } -} -void Bed3D::release_VBOs() -{ - if (m_vbo_id > 0) { - glsafe(::glDeleteBuffers(1, &m_vbo_id)); - m_vbo_id = 0; + shader->stop_using(); } } diff --git a/src/slic3r/GUI/3DBed.hpp b/src/slic3r/GUI/3DBed.hpp index 7bb4ebfb74d..661dee47b7e 100644 --- a/src/slic3r/GUI/3DBed.hpp +++ b/src/slic3r/GUI/3DBed.hpp @@ -5,7 +5,8 @@ #include "3DScene.hpp" #include "GLModel.hpp" -#include +#include "libslic3r/BuildVolume.hpp" +#include "libslic3r/ExPolygon.hpp" #include #include @@ -15,6 +16,7 @@ namespace GUI { class GLCanvas3D; +/* class GeometryBuffer { struct Vertex @@ -38,6 +40,9 @@ class GeometryBuffer size_t get_tex_coords_offset() const { return (size_t)(3 * sizeof(float)); } unsigned int get_vertices_count() const { return (unsigned int)m_vertices.size(); } }; +*/ + +bool init_model_from_poly(GLModel &model, const ExPolygon &poly, float z); class Bed3D { @@ -91,14 +96,13 @@ class Bed3D BoundingBoxf3 m_extended_bounding_box; // Slightly expanded print bed polygon, for collision detection. //Polygon m_polygon; - GeometryBuffer m_triangles; - //GeometryBuffer m_gridlines; + GLModel m_triangles; + //GLModel m_gridlines; GLTexture m_texture; // temporary texture shown until the main texture has still no levels compressed //GLTexture m_temp_texture; GLModel m_model; Vec3d m_model_offset{ Vec3d::Zero() }; - unsigned int m_vbo_id{ 0 }; Axes m_axes; float m_scale_factor{ 1.0f }; @@ -109,7 +113,7 @@ class Bed3D public: Bed3D() = default; - ~Bed3D() { release_VBOs(); } + ~Bed3D() = default; // Update print bed model from configuration. // Return true if the bed shape changed, so the calee will update the UI. @@ -151,11 +155,9 @@ class Bed3D //BBS: add partplate related logic // Calculate an extended bounding box from axes and current model for visualization purposes. BoundingBoxf3 calc_extended_bounding_box(bool consider_model_offset = true) const; - void calc_triangles(const ExPolygon& poly); - void calc_gridlines(const ExPolygon& poly, const BoundingBox& bed_bbox); void update_model_offset() const; //BBS: with offset - GeometryBuffer update_bed_triangles() const; + void update_bed_triangles(); static std::tuple detect_type(const Pointfs& shape); void render_internal(GLCanvas3D& canvas, bool bottom, float scale_factor, bool show_axes); @@ -165,7 +167,6 @@ class Bed3D void render_model(); void render_custom(GLCanvas3D& canvas, bool bottom); void render_default(bool bottom); - void release_VBOs(); }; } // GUI diff --git a/src/slic3r/GUI/GLModel.cpp b/src/slic3r/GUI/GLModel.cpp index 57b14715ea1..e1d18a70cb9 100644 --- a/src/slic3r/GUI/GLModel.cpp +++ b/src/slic3r/GUI/GLModel.cpp @@ -41,6 +41,16 @@ void GLModel::Geometry::add_vertex(const Vec3f& position) vertices.emplace_back(position.z()); } +void GLModel::Geometry::add_vertex(const Vec3f& position, const Vec2f& tex_coord) +{ + assert(format.vertex_layout == EVertexLayout::P3T2); + vertices.emplace_back(position.x()); + vertices.emplace_back(position.y()); + vertices.emplace_back(position.z()); + vertices.emplace_back(tex_coord.x()); + vertices.emplace_back(tex_coord.y()); +} + void GLModel::Geometry::add_vertex(const Vec3f& position, const Vec3f& normal) { assert(format.vertex_layout == EVertexLayout::P3N3); @@ -227,6 +237,7 @@ size_t GLModel::Geometry::vertex_stride_floats(const Format& format) case EVertexLayout::P2: { return 2; } case EVertexLayout::P2T2: { return 4; } case EVertexLayout::P3: { return 3; } + case EVertexLayout::P3T2: { return 5; } case EVertexLayout::P3N3: { return 6; } default: { assert(false); return 0; } }; @@ -239,6 +250,7 @@ size_t GLModel::Geometry::position_stride_floats(const Format& format) case EVertexLayout::P2: case EVertexLayout::P2T2: { return 2; } case EVertexLayout::P3: + case EVertexLayout::P3T2: case EVertexLayout::P3N3: { return 3; } default: { assert(false); return 0; } }; @@ -251,6 +263,7 @@ size_t GLModel::Geometry::position_offset_floats(const Format& format) case EVertexLayout::P2: case EVertexLayout::P2T2: case EVertexLayout::P3: + case EVertexLayout::P3T2: case EVertexLayout::P3N3: { return 0; } default: { assert(false); return 0; } }; @@ -278,7 +291,8 @@ size_t GLModel::Geometry::tex_coord_stride_floats(const Format& format) { switch (format.vertex_layout) { - case EVertexLayout::P2T2: { return 2; } + case EVertexLayout::P2T2: + case EVertexLayout::P3T2: { return 2; } default: { assert(false); return 0; } }; } @@ -288,6 +302,7 @@ size_t GLModel::Geometry::tex_coord_offset_floats(const Format& format) switch (format.vertex_layout) { case EVertexLayout::P2T2: { return 2; } + case EVertexLayout::P3T2: { return 3; } default: { assert(false); return 0; } }; } @@ -309,6 +324,7 @@ bool GLModel::Geometry::has_position(const Format& format) case EVertexLayout::P2: case EVertexLayout::P2T2: case EVertexLayout::P3: + case EVertexLayout::P3T2: case EVertexLayout::P3N3: { return true; } default: { assert(false); return false; } }; @@ -320,7 +336,8 @@ bool GLModel::Geometry::has_normal(const Format& format) { case EVertexLayout::P2: case EVertexLayout::P2T2: - case EVertexLayout::P3: { return false; } + case EVertexLayout::P3: + case EVertexLayout::P3T2: { return false; } case EVertexLayout::P3N3: { return true; } default: { assert(false); return false; } }; @@ -330,7 +347,8 @@ bool GLModel::Geometry::has_tex_coord(const Format& format) { switch (format.vertex_layout) { - case EVertexLayout::P2T2: { return true; } + case EVertexLayout::P2T2: + case EVertexLayout::P3T2: { return true; } case EVertexLayout::P2: case EVertexLayout::P3: case EVertexLayout::P3N3: { return false; } diff --git a/src/slic3r/GUI/GLModel.hpp b/src/slic3r/GUI/GLModel.hpp index 54f96edaa53..fae1c63153a 100644 --- a/src/slic3r/GUI/GLModel.hpp +++ b/src/slic3r/GUI/GLModel.hpp @@ -38,6 +38,7 @@ namespace GUI { P2, // position 2 floats P2T2, // position 2 floats + texture coords 2 floats P3, // position 3 floats + P3T2, // position 3 floats + texture coords 2 floats P3N3, // position 3 floats + normal 3 floats }; @@ -62,6 +63,7 @@ namespace GUI { void add_vertex(const Vec2f& position); void add_vertex(const Vec2f& position, const Vec2f& tex_coord); void add_vertex(const Vec3f& position); + void add_vertex(const Vec3f& position, const Vec2f& tex_coord); void add_vertex(const Vec3f& position, const Vec3f& normal); void add_ushort_index(unsigned short id); diff --git a/src/slic3r/GUI/PartPlate.cpp b/src/slic3r/GUI/PartPlate.cpp index 546fd65546b..67137e16212 100644 --- a/src/slic3r/GUI/PartPlate.cpp +++ b/src/slic3r/GUI/PartPlate.cpp @@ -151,7 +151,6 @@ PartPlate::~PartPlate() clear(); //if (m_quadric != nullptr) // ::gluDeleteQuadric(m_quadric); - release_opengl_resource(); //boost::nowide::remove(m_tmp_gcode_path.c_str()); } @@ -170,7 +169,6 @@ void PartPlate::init() m_print_index = -1; m_print = nullptr; - m_plate_name_vbo_id = 0; } BedType PartPlate::get_bed_type(bool load_from_project) const @@ -333,17 +331,71 @@ void PartPlate::calc_bounding_boxes() const { } } -void PartPlate::calc_triangles(const ExPolygon& poly) { - if (!m_triangles.set_from_triangles(triangulate_expolygon_2f(poly, NORMALS_UP), GROUND_Z)) +void PartPlate::calc_triangles(const ExPolygon &poly) +{ + m_triangles.reset(); + + if (!init_model_from_poly(m_triangles, poly, GROUND_Z)) BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << ":Unable to create plate triangles\n"; } -void PartPlate::calc_exclude_triangles(const ExPolygon& poly) { - if (!m_exclude_triangles.set_from_triangles(triangulate_expolygon_2f(poly, NORMALS_UP), GROUND_Z)) +void PartPlate::calc_exclude_triangles(const ExPolygon &poly) +{ + m_exclude_triangles.reset(); + + if (!init_model_from_poly(m_exclude_triangles, poly, GROUND_Z)) BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << ":Unable to create exclude triangles\n"; } +static bool init_model_from_lines(GLModel &model, const Lines &lines, float z) +{ + const GLModel::Geometry::EIndexType index_type = (lines.size() < 65536 / 2) ? GLModel::Geometry::EIndexType::USHORT : GLModel::Geometry::EIndexType::UINT; + + GLModel::Geometry init_data; + init_data.format = { GLModel::Geometry::EPrimitiveType::Lines, GLModel::Geometry::EVertexLayout::P3, index_type }; + + for (const auto &l : lines) { + init_data.add_vertex(Vec3f(unscale(l.a.x()), unscale(l.a.y()), z)); + init_data.add_vertex(Vec3f(unscale(l.b.x()), unscale(l.b.y()), z)); + const unsigned int vertices_counter = (unsigned int)init_data.vertices_count(); + if (index_type == GLModel::Geometry::EIndexType::USHORT) + init_data.add_ushort_line((unsigned short)vertices_counter - 2, (unsigned short)vertices_counter - 1); + else + init_data.add_uint_line(vertices_counter - 2, vertices_counter - 1); + } + + model.init_from(std::move(init_data)); + + return true; +} + +static bool init_model_from_lines(GLModel &model, const Lines3 &lines) +{ + const GLModel::Geometry::EIndexType index_type = (lines.size() < 65536 / 2) ? GLModel::Geometry::EIndexType::USHORT : + GLModel::Geometry::EIndexType::UINT; + + GLModel::Geometry init_data; + init_data.format = {GLModel::Geometry::EPrimitiveType::Lines, GLModel::Geometry::EVertexLayout::P3, index_type}; + + for (const auto &l : lines) { + init_data.add_vertex(Vec3f(unscale(l.a.x()), unscale(l.a.y()), unscale(l.a.z()))); + init_data.add_vertex(Vec3f(unscale(l.b.x()), unscale(l.b.y()), unscale(l.b.z()))); + const unsigned int vertices_counter = (unsigned int) init_data.vertices_count(); + if (index_type == GLModel::Geometry::EIndexType::USHORT) + init_data.add_ushort_line((unsigned short) vertices_counter - 2, (unsigned short) vertices_counter - 1); + else + init_data.add_uint_line(vertices_counter - 2, vertices_counter - 1); + } + + model.init_from(std::move(init_data)); + + return true; +} + void PartPlate::calc_gridlines(const ExPolygon& poly, const BoundingBox& pp_bbox) { + m_gridlines.reset(); + m_gridlines_bolder.reset(); + Polylines axes_lines, axes_lines_bolder; int count = 0; for (coord_t x = pp_bbox.min(0); x <= pp_bbox.max(0); x += scale_(10.0)) { @@ -379,14 +431,18 @@ void PartPlate::calc_gridlines(const ExPolygon& poly, const BoundingBox& pp_bbox Lines contour_lines = to_lines(poly); std::copy(contour_lines.begin(), contour_lines.end(), std::back_inserter(gridlines)); - if (!m_gridlines.set_from_lines(gridlines, GROUND_Z_GRIDLINE)) + if (!init_model_from_lines(m_gridlines, gridlines, GROUND_Z_GRIDLINE)) BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << "Unable to create bed grid lines\n"; - if (!m_gridlines_bolder.set_from_lines(gridlines_bolder, GROUND_Z_GRIDLINE)) + if (!init_model_from_lines(m_gridlines_bolder, gridlines_bolder, GROUND_Z_GRIDLINE)) BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << "Unable to create bed grid lines\n"; } void PartPlate::calc_height_limit() { + m_height_limit_common.reset(); + m_height_limit_bottom.reset(); + m_height_limit_top.reset(); + Lines3 bottom_h_lines, top_lines, top_h_lines, common_lines; int shape_count = m_shape.size(); float first_z = 0.02f; @@ -418,18 +474,20 @@ void PartPlate::calc_height_limit() { //std::copy(bottom_lines.begin(), bottom_lines.end(), std::back_inserter(bottom_h_lines)); std::copy(top_lines.begin(), top_lines.end(), std::back_inserter(top_h_lines)); - if (!m_height_limit_common.set_from_3d_Lines(common_lines)) + if (!init_model_from_lines(m_height_limit_common, common_lines)) BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << "Unable to create height limit bottom lines\n"; - if (!m_height_limit_bottom.set_from_3d_Lines(bottom_h_lines)) + if (!init_model_from_lines(m_height_limit_bottom, bottom_h_lines)) BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << "Unable to create height limit bottom lines\n"; - if (!m_height_limit_top.set_from_3d_Lines(top_h_lines)) + if (!init_model_from_lines(m_height_limit_top, top_h_lines)) BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << "Unable to create height limit top lines\n"; } -void PartPlate::calc_vertex_for_number(int index, bool one_number, GeometryBuffer &buffer) +void PartPlate::calc_vertex_for_number(int index, bool one_number, GLModel &buffer) { + buffer.reset(); + ExPolygon poly; #if 0 //in the up area Vec2d& p = m_shape[2]; @@ -449,13 +507,14 @@ void PartPlate::calc_vertex_for_number(int index, bool one_number, GeometryBuffe poly.contour.append({ scale_(p(0) + PARTPLATE_ICON_GAP_LEFT + PARTPLATE_ICON_SIZE - offset_x), scale_(p(1) + PARTPLATE_ICON_SIZE - PARTPLATE_TEXT_OFFSET_Y)}); poly.contour.append({ scale_(p(0) + PARTPLATE_ICON_GAP_LEFT + offset_x), scale_(p(1) + PARTPLATE_ICON_SIZE - PARTPLATE_TEXT_OFFSET_Y) }); #endif - auto triangles = triangulate_expolygon_2f(poly, NORMALS_UP); - if (!buffer.set_from_triangles(triangles, GROUND_Z)) + if (!init_model_from_poly(buffer, poly, GROUND_Z)) BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << "Unable to generate geometry buffers for icons\n"; } -void PartPlate::calc_vertex_for_icons(int index, GeometryBuffer &buffer) +void PartPlate::calc_vertex_for_icons(int index, GLModel &buffer) { + buffer.reset(); + ExPolygon poly; auto bed_ext = get_extents(m_shape); Vec2d p = bed_ext[2]; @@ -468,13 +527,14 @@ void PartPlate::calc_vertex_for_icons(int index, GeometryBuffer &buffer) poly.contour.append({ scale_(p(0) + PARTPLATE_ICON_GAP_LEFT + PARTPLATE_ICON_SIZE), scale_(p(1) - index * (PARTPLATE_ICON_SIZE + PARTPLATE_ICON_GAP_Y)- PARTPLATE_ICON_GAP_TOP)}); poly.contour.append({ scale_(p(0) + PARTPLATE_ICON_GAP_LEFT), scale_(p(1) - index * (PARTPLATE_ICON_SIZE + PARTPLATE_ICON_GAP_Y)- PARTPLATE_ICON_GAP_TOP) }); - auto triangles = triangulate_expolygon_2f(poly, NORMALS_UP); - if (!buffer.set_from_triangles(triangles, GROUND_Z)) + if (!init_model_from_poly(buffer, poly, GROUND_Z)) BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << "Unable to generate geometry buffers for icons\n"; } -void PartPlate::calc_vertex_for_icons_background(int icon_count, GeometryBuffer &buffer) +void PartPlate::calc_vertex_for_icons_background(int icon_count, GLModel &buffer) { + buffer.reset(); + ExPolygon poly; auto bed_ext = get_extents(m_shape); Vec2d p = bed_ext[2]; @@ -484,38 +544,36 @@ void PartPlate::calc_vertex_for_icons_background(int icon_count, GeometryBuffer poly.contour.append({ scale_(p(0) + PARTPLATE_ICON_GAP_LEFT + PARTPLATE_ICON_SIZE), scale_(p(1) - PARTPLATE_ICON_GAP_TOP)}); poly.contour.append({ scale_(p(0) + PARTPLATE_ICON_GAP_LEFT), scale_(p(1) - PARTPLATE_ICON_GAP_TOP) }); - auto triangles = triangulate_expolygon_2f(poly, NORMALS_UP); - if (!buffer.set_from_triangles(triangles, GROUND_Z)) + if (!init_model_from_poly(buffer, poly, GROUND_Z)) BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << "Unable to generate geometry buffers for icons\n"; } -void PartPlate::render_background(bool force_default_color) const { - unsigned int triangles_vcount = m_triangles.get_vertices_count(); - +void PartPlate::render_background(bool force_default_color) +{ //return directly for current plate if (m_selected && !force_default_color) return; // draw background glsafe(::glDepthMask(GL_FALSE)); + ColorRGBA color; if (!force_default_color) { if (m_selected) { - glsafe(::glColor4fv(PartPlate::SELECT_COLOR.data())); + color = PartPlate::SELECT_COLOR; } else { - glsafe(m_partplate_list->m_is_dark ? ::glColor4fv(PartPlate::UNSELECT_DARK_COLOR.data()) : ::glColor4fv(PartPlate::UNSELECT_COLOR.data())); + color = m_partplate_list->m_is_dark ? PartPlate::UNSELECT_DARK_COLOR : PartPlate::UNSELECT_COLOR; } } else { - glsafe(::glColor4fv(PartPlate::DEFAULT_COLOR.data())); + color = PartPlate::DEFAULT_COLOR; } - glsafe(::glNormal3d(0.0f, 0.0f, 1.0f)); - glsafe(::glVertexPointer(3, GL_FLOAT, m_triangles.get_vertex_data_size(), (GLvoid*)m_triangles.get_vertices_data())); - glsafe(::glDrawArrays(GL_TRIANGLES, 0, (GLsizei)triangles_vcount)); + m_triangles.set_color(color); + m_triangles.render(); glsafe(::glDepthMask(GL_TRUE)); } -void PartPlate::render_logo_texture(GLTexture &logo_texture, const GeometryBuffer& logo_buffer, bool bottom, unsigned int vbo_id) const +void PartPlate::render_logo_texture(GLTexture &logo_texture, GLModel& logo_buffer, bool bottom) { //check valid if (logo_texture.unsent_compressed_data_available()) { @@ -523,7 +581,7 @@ void PartPlate::render_logo_texture(GLTexture &logo_texture, const GeometryBuffe logo_texture.send_compressed_data_to_gpu(); } - if (logo_buffer.get_vertices_count() > 0) { + if (logo_buffer.is_initialized()) { GLShaderProgram* shader = wxGetApp().get_shader("printbed"); if (shader != nullptr) { shader->start_using(); @@ -532,44 +590,25 @@ void PartPlate::render_logo_texture(GLTexture &logo_texture, const GeometryBuffe //glsafe(::glEnable(GL_DEPTH_TEST)); glsafe(::glDepthMask(GL_FALSE)); - if (bottom) - glsafe(::glFrontFace(GL_CW)); - unsigned int stride = logo_buffer.get_vertex_data_size(); + glsafe(::glEnable(GL_BLEND)); + glsafe(::glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)); - GLint position_id = shader->get_attrib_location("v_position"); - GLint tex_coords_id = shader->get_attrib_location("v_tex_coords"); - if (position_id != -1) { - glsafe(::glEnableVertexAttribArray(position_id)); - } - if (tex_coords_id != -1) { - glsafe(::glEnableVertexAttribArray(tex_coords_id)); - } + if (bottom) + glsafe(::glFrontFace(GL_CW)); // show the temporary texture while no compressed data is available GLuint tex_id = (GLuint)logo_texture.get_id(); glsafe(::glBindTexture(GL_TEXTURE_2D, tex_id)); - glsafe(::glBindBuffer(GL_ARRAY_BUFFER, vbo_id)); - - if (position_id != -1) - glsafe(::glVertexAttribPointer(position_id, 3, GL_FLOAT, GL_FALSE, stride, (GLvoid*)(intptr_t)logo_buffer.get_position_offset())); - if (tex_coords_id != -1) - glsafe(::glVertexAttribPointer(tex_coords_id, 2, GL_FLOAT, GL_FALSE, stride, (GLvoid*)(intptr_t)logo_buffer.get_tex_coords_offset())); - glsafe(::glDrawArrays(GL_TRIANGLES, 0, (GLsizei)logo_buffer.get_vertices_count())); - - if (tex_coords_id != -1) - glsafe(::glDisableVertexAttribArray(tex_coords_id)); - - if (position_id != -1) - glsafe(::glDisableVertexAttribArray(position_id)); - - glsafe(::glBindBuffer(GL_ARRAY_BUFFER, 0)); + logo_buffer.render(); glsafe(::glBindTexture(GL_TEXTURE_2D, 0)); if (bottom) glsafe(::glFrontFace(GL_CCW)); + glsafe(::glDisable(GL_BLEND)); + glsafe(::glDepthMask(GL_TRUE)); shader->stop_using(); @@ -577,7 +616,7 @@ void PartPlate::render_logo_texture(GLTexture &logo_texture, const GeometryBuffe } } -void PartPlate::render_logo(bool bottom, bool render_cali) const +void PartPlate::render_logo(bool bottom, bool render_cali) { if (!m_partplate_list->render_bedtype_logo) { // render third-party printer texture logo @@ -643,15 +682,8 @@ void PartPlate::render_logo(bool bottom, bool render_cali) const //canvas.request_extra_frame(); } - if (m_vbo_id == 0) { - unsigned int* vbo_id_ptr = const_cast(&m_vbo_id); - glsafe(::glGenBuffers(1, vbo_id_ptr)); - glsafe(::glBindBuffer(GL_ARRAY_BUFFER, *vbo_id_ptr)); - glsafe(::glBufferData(GL_ARRAY_BUFFER, (GLsizeiptr)m_logo_triangles.get_vertices_data_size(), (const GLvoid*)m_logo_triangles.get_vertices_data(), GL_STATIC_DRAW)); - glsafe(::glBindBuffer(GL_ARRAY_BUFFER, 0)); - } - if (m_vbo_id != 0 && m_logo_triangles.get_vertices_count() > 0) - render_logo_texture(m_partplate_list->m_logo_texture, m_logo_triangles, bottom, m_vbo_id); + if (m_logo_triangles.is_initialized()) + render_logo_texture(m_partplate_list->m_logo_texture, m_logo_triangles, bottom); return; } @@ -669,7 +701,7 @@ void PartPlate::render_logo(bool bottom, bool render_cali) const // render bed textures for (auto &part : m_partplate_list->bed_texture_info[bed_type_idx].parts) { if (part.texture) { - if (part.buffer && part.buffer->get_vertices_count() > 0 + if (part.buffer && part.buffer->is_initialized() //&& part.vbo_id != 0 ) { if (part.offset.x() != m_origin.x() || part.offset.y() != m_origin.y()) { @@ -678,8 +710,7 @@ void PartPlate::render_logo(bool bottom, bool render_cali) const } render_logo_texture(*(part.texture), *(part.buffer), - bottom, - part.vbo_id); + bottom); } } } @@ -688,29 +719,27 @@ void PartPlate::render_logo(bool bottom, bool render_cali) const if (render_cali) { for (auto& part : m_partplate_list->cali_texture_info.parts) { if (part.texture) { - if (part.buffer && part.buffer->get_vertices_count() > 0) { + if (part.buffer && part.buffer->is_initialized()) { if (part.offset.x() != m_origin.x() || part.offset.y() != m_origin.y()) { part.offset = Vec2d(m_origin.x(), m_origin.y()); part.update_buffer(); } render_logo_texture(*(part.texture), *(part.buffer), - bottom, - part.vbo_id); + bottom); } } } } } -void PartPlate::render_exclude_area(bool force_default_color) const { +void PartPlate::render_exclude_area(bool force_default_color) { if (force_default_color) //for thumbnail case return; - unsigned int triangles_vcount = m_exclude_triangles.get_vertices_count(); ColorRGBA select_color{ 0.765f, 0.7686f, 0.7686f, 1.0f }; ColorRGBA unselect_color{ 0.9f, 0.9f, 0.9f, 1.0f }; - ColorRGBA default_color{ 0.9f, 0.9f, 0.9f, 1.0f }; + //ColorRGBA default_color{ 0.9f, 0.9f, 0.9f, 1.0f }; // draw exclude area glsafe(::glDepthMask(GL_FALSE)); @@ -722,9 +751,8 @@ void PartPlate::render_exclude_area(bool force_default_color) const { glsafe(::glColor4fv(unselect_color.data())); } - glsafe(::glNormal3d(0.0f, 0.0f, 1.0f)); - glsafe(::glVertexPointer(3, GL_FLOAT, m_exclude_triangles.get_vertex_data_size(), (GLvoid*)m_exclude_triangles.get_vertices_data())); - glsafe(::glDrawArrays(GL_TRIANGLES, 0, (GLsizei)triangles_vcount)); + m_exclude_triangles.set_color(m_selected ? select_color : unselect_color); + m_exclude_triangles.render(); glsafe(::glDepthMask(GL_TRUE)); } @@ -741,99 +769,68 @@ void PartPlate::render_exclude_area(bool force_default_color) const { glsafe(::glDepthMask(GL_TRUE)); }*/ -void PartPlate::render_grid(bool bottom) const { +void PartPlate::render_grid(bool bottom) { //glsafe(::glEnable(GL_MULTISAMPLE)); // draw grid glsafe(::glLineWidth(1.0f * m_scale_factor)); + + ColorRGBA color; if (bottom) - glsafe(::glColor4fv(LINE_BOTTOM_COLOR.data())); + color = LINE_BOTTOM_COLOR; else { if (m_selected) - glsafe(m_partplate_list->m_is_dark ? ::glColor4fv(LINE_TOP_SEL_DARK_COLOR.data()) : ::glColor4fv(LINE_TOP_SEL_COLOR.data())); + color = m_partplate_list->m_is_dark ? LINE_TOP_SEL_DARK_COLOR : LINE_TOP_SEL_COLOR; else - glsafe(m_partplate_list->m_is_dark ? ::glColor4fv(LINE_TOP_DARK_COLOR.data()) : ::glColor4fv(LINE_TOP_COLOR.data())); + color = m_partplate_list->m_is_dark ? LINE_TOP_DARK_COLOR : LINE_TOP_COLOR; } - glsafe(::glVertexPointer(3, GL_FLOAT, m_gridlines.get_vertex_data_size(), (GLvoid*)m_gridlines.get_vertices_data())); - glsafe(::glDrawArrays(GL_LINES, 0, (GLsizei)m_gridlines.get_vertices_count())); + m_gridlines.set_color(color); + m_gridlines.render(); glsafe(::glLineWidth(2.0f * m_scale_factor)); - glsafe(::glVertexPointer(3, GL_FLOAT, m_gridlines_bolder.get_vertex_data_size(), (GLvoid*)m_gridlines_bolder.get_vertices_data())); - glsafe(::glDrawArrays(GL_LINES, 0, (GLsizei)m_gridlines_bolder.get_vertices_count())); + m_gridlines_bolder.set_color(color); + m_gridlines_bolder.render(); } -void PartPlate::render_height_limit(PartPlate::HeightLimitMode mode) const +void PartPlate::render_height_limit(PartPlate::HeightLimitMode mode) { if (m_print && m_print->config().print_sequence == PrintSequence::ByObject && mode != HEIGHT_LIMIT_NONE) { // draw lower limit glsafe(::glLineWidth(3.0f * m_scale_factor)); - glsafe(::glColor4fv(HEIGHT_LIMIT_BOTTOM_COLOR.data())); - glsafe(::glVertexPointer(3, GL_FLOAT, m_height_limit_common.get_vertex_data_size(), (GLvoid*)m_height_limit_common.get_vertices_data())); - glsafe(::glDrawArrays(GL_LINES, 0, (GLsizei)m_height_limit_common.get_vertices_count())); + m_height_limit_common.set_color(HEIGHT_LIMIT_BOTTOM_COLOR); + m_height_limit_common.render(); if ((mode == HEIGHT_LIMIT_BOTTOM) || (mode == HEIGHT_LIMIT_BOTH)) { glsafe(::glLineWidth(3.0f * m_scale_factor)); - glsafe(::glColor4fv(HEIGHT_LIMIT_BOTTOM_COLOR.data())); - glsafe(::glVertexPointer(3, GL_FLOAT, m_height_limit_bottom.get_vertex_data_size(), (GLvoid*)m_height_limit_bottom.get_vertices_data())); - glsafe(::glDrawArrays(GL_LINES, 0, (GLsizei)m_height_limit_bottom.get_vertices_count())); + m_height_limit_bottom.set_color(HEIGHT_LIMIT_BOTTOM_COLOR); + m_height_limit_bottom.render(); } // draw upper limit if ((mode == HEIGHT_LIMIT_TOP) || (mode == HEIGHT_LIMIT_BOTH)){ - glsafe(::glLineWidth(3.0f * m_scale_factor)); - glsafe(::glColor4fv(HEIGHT_LIMIT_TOP_COLOR.data())); - glsafe(::glVertexPointer(3, GL_FLOAT, m_height_limit_top.get_vertex_data_size(), (GLvoid*)m_height_limit_top.get_vertices_data())); - glsafe(::glDrawArrays(GL_LINES, 0, (GLsizei)m_height_limit_top.get_vertices_count())); + glsafe(::glLineWidth(3.0f * m_scale_factor)); + m_height_limit_top.set_color(HEIGHT_LIMIT_TOP_COLOR); + m_height_limit_top.render(); } } } - -void PartPlate::render_icon_texture(int position_id, int tex_coords_id, const GeometryBuffer &buffer, GLTexture &texture, unsigned int &vbo_id) const +void PartPlate::render_icon_texture(GLModel &buffer, GLTexture &texture) { - if (vbo_id == 0) { - glsafe(::glGenBuffers(1, &vbo_id)); - glsafe(::glBindBuffer(GL_ARRAY_BUFFER, vbo_id)); - glsafe(::glBufferData(GL_ARRAY_BUFFER, (GLsizeiptr)buffer.get_vertices_data_size(), (const GLvoid*)buffer.get_vertices_data(), GL_STATIC_DRAW)); - glsafe(::glBindBuffer(GL_ARRAY_BUFFER, 0)); - } - - unsigned int stride = buffer.get_vertex_data_size(); GLuint tex_id = (GLuint)texture.get_id(); glsafe(::glBindTexture(GL_TEXTURE_2D, tex_id)); - glsafe(::glBindBuffer(GL_ARRAY_BUFFER, vbo_id)); - if (position_id != -1) - glsafe(::glVertexAttribPointer(position_id, 3, GL_FLOAT, GL_FALSE, stride, (GLvoid*)(intptr_t)buffer.get_position_offset())); - if (tex_coords_id != -1) - glsafe(::glVertexAttribPointer(tex_coords_id, 2, GL_FLOAT, GL_FALSE, stride, (GLvoid*)(intptr_t)buffer.get_tex_coords_offset())); - glsafe(::glDrawArrays(GL_TRIANGLES, 0, (GLsizei)buffer.get_vertices_count())); - - glsafe(::glBindBuffer(GL_ARRAY_BUFFER, 0)); + buffer.render(); glsafe(::glBindTexture(GL_TEXTURE_2D, 0)); } -void PartPlate::render_plate_name_texture(int position_id, int tex_coords_id) + +void PartPlate::render_plate_name_texture() { if (m_name_texture.get_id() == 0) generate_plate_name_texture(); - if (m_plate_name_vbo_id == 0 && m_plate_name_icon.get_vertices_data_size() > 0) { - glsafe(::glGenBuffers(1, &m_plate_name_vbo_id)); - glsafe(::glBindBuffer(GL_ARRAY_BUFFER, m_plate_name_vbo_id)); - glsafe(::glBufferData(GL_ARRAY_BUFFER, (GLsizeiptr)m_plate_name_icon.get_vertices_data_size(), (const GLvoid*)m_plate_name_icon.get_vertices_data(), GL_STATIC_DRAW)); - glsafe(::glBindBuffer(GL_ARRAY_BUFFER, 0)); - } - - unsigned int stride = m_plate_name_icon.get_vertex_data_size(); GLuint tex_id = (GLuint)m_name_texture.get_id(); glsafe(::glBindTexture(GL_TEXTURE_2D, tex_id)); - glsafe(::glBindBuffer(GL_ARRAY_BUFFER, m_plate_name_vbo_id)); - if (position_id != -1) - glsafe(::glVertexAttribPointer(position_id, 3, GL_FLOAT, GL_FALSE, stride, (GLvoid*)(intptr_t)m_plate_name_icon.get_position_offset())); - if (tex_coords_id != -1) - glsafe(::glVertexAttribPointer(tex_coords_id, 2, GL_FLOAT, GL_FALSE, stride, (GLvoid*)(intptr_t)m_plate_name_icon.get_tex_coords_offset())); - glsafe(::glDrawArrays(GL_TRIANGLES, 0, (GLsizei)m_plate_name_icon.get_vertices_count())); - - glsafe(::glBindBuffer(GL_ARRAY_BUFFER, 0)); + m_plate_name_icon.render(); glsafe(::glBindTexture(GL_TEXTURE_2D, 0)); } @@ -865,92 +862,72 @@ void PartPlate::render_icons(bool bottom, bool only_name, int hover_id) // glsafe(::glFrontFace(GL_CW)); glsafe(::glDepthMask(GL_FALSE)); - GLint position_id = shader->get_attrib_location("v_position"); - GLint tex_coords_id = shader->get_attrib_location("v_tex_coords"); - if (position_id != -1) { - glsafe(::glEnableVertexAttribArray(position_id)); - } - if (tex_coords_id != -1) { - glsafe(::glEnableVertexAttribArray(tex_coords_id)); - } + glsafe(::glEnable(GL_BLEND)); + glsafe(::glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)); + if (!only_name) { if (hover_id == 1) { - render_icon_texture(position_id, tex_coords_id, m_del_icon, m_partplate_list->m_del_hovered_texture, - m_del_vbo_id); + render_icon_texture(m_del_icon, m_partplate_list->m_del_hovered_texture); show_tooltip(_u8L("Remove current plate (if not last one)")); } else - render_icon_texture(position_id, tex_coords_id, m_del_icon, m_partplate_list->m_del_texture, - m_del_vbo_id); + render_icon_texture(m_del_icon, m_partplate_list->m_del_texture); if (hover_id == 2) { - render_icon_texture(position_id, tex_coords_id, m_orient_icon, - m_partplate_list->m_orient_hovered_texture, m_orient_vbo_id); + render_icon_texture(m_orient_icon, m_partplate_list->m_orient_hovered_texture); show_tooltip(_u8L("Auto orient objects on current plate")); } else - render_icon_texture(position_id, tex_coords_id, m_orient_icon, m_partplate_list->m_orient_texture, - m_orient_vbo_id); + render_icon_texture(m_orient_icon, m_partplate_list->m_orient_texture); if (hover_id == 3) { - render_icon_texture(position_id, tex_coords_id, m_arrange_icon, - m_partplate_list->m_arrange_hovered_texture, m_arrange_vbo_id); + render_icon_texture(m_arrange_icon, m_partplate_list->m_arrange_hovered_texture); show_tooltip(_u8L("Arrange objects on current plate")); } else - render_icon_texture(position_id, tex_coords_id, m_arrange_icon, m_partplate_list->m_arrange_texture, - m_arrange_vbo_id); + render_icon_texture(m_arrange_icon, m_partplate_list->m_arrange_texture); if (hover_id == 4) { if (this->is_locked()) { - render_icon_texture(position_id, tex_coords_id, m_lock_icon, - m_partplate_list->m_locked_hovered_texture, m_lock_vbo_id); + render_icon_texture(m_lock_icon, + m_partplate_list->m_locked_hovered_texture); show_tooltip(_u8L("Unlock current plate")); } else { - render_icon_texture(position_id, tex_coords_id, m_lock_icon, - m_partplate_list->m_lockopen_hovered_texture, m_lock_vbo_id); + render_icon_texture(m_lock_icon, + m_partplate_list->m_lockopen_hovered_texture); show_tooltip(_u8L("Lock current plate")); } } else { if (this->is_locked()) - render_icon_texture(position_id, tex_coords_id, m_lock_icon, m_partplate_list->m_locked_texture, - m_lock_vbo_id); + render_icon_texture(m_lock_icon, m_partplate_list->m_locked_texture); else - render_icon_texture(position_id, tex_coords_id, m_lock_icon, m_partplate_list->m_lockopen_texture, - m_lock_vbo_id); + render_icon_texture(m_lock_icon, m_partplate_list->m_lockopen_texture); } if (m_partplate_list->render_plate_settings) { if (hover_id == 5) { if (get_bed_type() == BedType::btDefault && get_print_seq() == PrintSequence::ByDefault && get_first_layer_print_sequence().empty()) - render_icon_texture(position_id, tex_coords_id, m_plate_settings_icon, m_partplate_list->m_plate_settings_hovered_texture, m_plate_settings_vbo_id); + render_icon_texture(m_plate_settings_icon, m_partplate_list->m_plate_settings_hovered_texture); else - render_icon_texture(position_id, tex_coords_id, m_plate_settings_icon, - m_partplate_list->m_plate_settings_changed_hovered_texture, - m_plate_settings_vbo_id); + render_icon_texture(m_plate_settings_icon, m_partplate_list->m_plate_settings_changed_hovered_texture); show_tooltip(_u8L("Customize current plate")); } else { if (get_bed_type() == BedType::btDefault && get_print_seq() == PrintSequence::ByDefault && get_first_layer_print_sequence().empty()) - render_icon_texture(position_id, tex_coords_id, m_plate_settings_icon, m_partplate_list->m_plate_settings_texture, m_plate_settings_vbo_id); + render_icon_texture(m_plate_settings_icon, m_partplate_list->m_plate_settings_texture); else - render_icon_texture(position_id, tex_coords_id, m_plate_settings_icon, - m_partplate_list->m_plate_settings_changed_texture, m_plate_settings_vbo_id); + render_icon_texture(m_plate_settings_icon, m_partplate_list->m_plate_settings_changed_texture); } } if (m_plate_index >= 0 && m_plate_index < MAX_PLATE_COUNT) { - render_icon_texture(position_id, tex_coords_id, m_plate_idx_icon, - m_partplate_list->m_idx_textures[m_plate_index], m_plate_idx_vbo_id); + render_icon_texture(m_plate_idx_icon, m_partplate_list->m_idx_textures[m_plate_index]); } } - render_plate_name_texture(position_id, tex_coords_id); - if (tex_coords_id != -1) - glsafe(::glDisableVertexAttribArray(tex_coords_id)); + render_plate_name_texture(); - if (position_id != -1) - glsafe(::glDisableVertexAttribArray(position_id)); + glsafe(::glDisable(GL_BLEND)); //if (bottom) // glsafe(::glFrontFace(GL_CCW)); @@ -960,7 +937,7 @@ void PartPlate::render_icons(bool bottom, bool only_name, int hover_id) } } -void PartPlate::render_only_numbers(bool bottom) const +void PartPlate::render_only_numbers(bool bottom) { GLShaderProgram* shader = wxGetApp().get_shader("printbed"); if (shader != nullptr) { @@ -973,24 +950,14 @@ void PartPlate::render_only_numbers(bool bottom) const // glsafe(::glFrontFace(GL_CW)); glsafe(::glDepthMask(GL_FALSE)); - GLint position_id = shader->get_attrib_location("v_position"); - GLint tex_coords_id = shader->get_attrib_location("v_tex_coords"); - if (position_id != -1) { - glsafe(::glEnableVertexAttribArray(position_id)); - } - if (tex_coords_id != -1) { - glsafe(::glEnableVertexAttribArray(tex_coords_id)); - } + glsafe(::glEnable(GL_BLEND)); + glsafe(::glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)); if (m_plate_index >=0 && m_plate_index < MAX_PLATE_COUNT) { - render_icon_texture(position_id, tex_coords_id, m_plate_idx_icon, m_partplate_list->m_idx_textures[m_plate_index], m_plate_idx_vbo_id); + render_icon_texture(m_plate_idx_icon, m_partplate_list->m_idx_textures[m_plate_index]); } - if (tex_coords_id != -1) - glsafe(::glDisableVertexAttribArray(tex_coords_id)); - - if (position_id != -1) - glsafe(::glDisableVertexAttribArray(position_id)); + glsafe(::glDisable(GL_BLEND)); //if (bottom) // glsafe(::glFrontFace(GL_CCW)); @@ -1000,20 +967,24 @@ void PartPlate::render_only_numbers(bool bottom) const } } -void PartPlate::render_rectangle_for_picking(const GeometryBuffer &buffer, const ColorRGBA render_color) const +void PartPlate::render_rectangle_for_picking(GLModel &buffer, const ColorRGBA render_color) { - unsigned int triangles_vcount = buffer.get_vertices_count(); + glsafe(::glDisable(GL_DEPTH_TEST)); - //glsafe(::glDepthMask(GL_FALSE)); - glsafe(::glEnableClientState(GL_VERTEX_ARRAY)); - glsafe(::glColor4fv(render_color.data())); - glsafe(::glNormal3d(0.0f, 0.0f, 1.0f)); - glsafe(::glVertexPointer(3, GL_FLOAT, buffer.get_vertex_data_size(), (GLvoid*)buffer.get_vertices_data())); - glsafe(::glDrawArrays(GL_TRIANGLES, 0, (GLsizei)triangles_vcount)); - glsafe(::glDisableClientState(GL_VERTEX_ARRAY)); - //glsafe(::glDepthMask(GL_TRUE)); + GLShaderProgram *shader = wxGetApp().get_shader("flat"); + if (shader != nullptr) { + shader->start_using(); + + //glsafe(::glDepthMask(GL_FALSE)); + buffer.set_color(render_color); + buffer.render(); + //glsafe(::glDepthMask(GL_TRUE)); + + shader->stop_using(); + } } +/* void PartPlate::render_label(GLCanvas3D& canvas) const { std::string label = (boost::format("Plate %1%") % (m_plate_index + 1)).str(); const Camera& camera = wxGetApp().plater()->get_camera(); @@ -1229,8 +1200,9 @@ void PartPlate::render_right_arrow(const ColorRGBA render_color, bool use_lighti glsafe(::glDisable(GL_LIGHTING)); #endif } +*/ -void PartPlate::on_render_for_picking() const { +void PartPlate::on_render_for_picking() { //glsafe(::glDisable(GL_DEPTH_TEST)); int hover_id = 0; ColorRGBA color = picking_color_component(hover_id); @@ -1274,42 +1246,6 @@ ColorRGBA PartPlate::picking_color_component(int idx) const }; } -void PartPlate::release_opengl_resource() -{ - if (m_vbo_id > 0) { - glsafe(::glDeleteBuffers(1, &m_vbo_id)); - m_vbo_id = 0; - } - if (m_del_vbo_id > 0) { - glsafe(::glDeleteBuffers(1, &m_del_vbo_id)); - m_del_vbo_id = 0; - } - if (m_orient_vbo_id > 0) { - glsafe(::glDeleteBuffers(1, &m_orient_vbo_id)); - m_orient_vbo_id = 0; - } - if (m_arrange_vbo_id > 0) { - glsafe(::glDeleteBuffers(1, &m_arrange_vbo_id)); - m_arrange_vbo_id = 0; - } - if (m_lock_vbo_id > 0) { - glsafe(::glDeleteBuffers(1, &m_lock_vbo_id)); - m_lock_vbo_id = 0; - } - if (m_plate_settings_vbo_id > 0) { - glsafe(::glDeleteBuffers(1, &m_plate_settings_vbo_id)); - m_plate_settings_vbo_id = 0; - } - if (m_plate_idx_vbo_id > 0) { - glsafe(::glDeleteBuffers(1, &m_plate_idx_vbo_id)); - m_plate_idx_vbo_id = 0; - } - if (m_plate_name_vbo_id > 0) { - glsafe(::glDeleteBuffers(1, &m_plate_name_vbo_id)); - m_plate_name_vbo_id = 0; - } -} - std::vector PartPlate::get_extruders(bool conside_custom_gcode) const { std::vector plate_extruders; @@ -1746,6 +1682,8 @@ Vec3d PartPlate::get_center_origin() void PartPlate::generate_plate_name_texture() { + m_plate_name_icon.reset(); + // generate m_name_texture texture from m_name with generate_from_text_string m_name_texture.reset(); auto text = m_name.empty()? _L("Untitled") : from_u8(m_name); @@ -1768,14 +1706,8 @@ void PartPlate::generate_plate_name_texture() poly.contour.append({ scale_(p(0) + PARTPLATE_ICON_GAP_LEFT + w - offset_x), scale_(p(1) - PARTPLATE_TEXT_OFFSET_Y)}); poly.contour.append({ scale_(p(0) + PARTPLATE_ICON_GAP_LEFT + offset_x), scale_(p(1) - PARTPLATE_TEXT_OFFSET_Y) }); - auto triangles = triangulate_expolygon_2f(poly, NORMALS_UP); - if (!m_plate_name_icon.set_from_triangles(triangles, GROUND_Z)) + if (!init_model_from_poly(m_plate_name_icon, poly, GROUND_Z)) BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << "Unable to generate geometry buffers for icons\n"; - - if (m_plate_name_vbo_id > 0) { - glsafe(::glDeleteBuffers(1, &m_plate_name_vbo_id)); - m_plate_name_vbo_id = 0; - } } void PartPlate::set_plate_name(const std::string& name) { @@ -2481,11 +2413,9 @@ bool PartPlate::set_shape(const Pointfs& shape, const Pointfs& exclude_areas, Ve ExPolygon logo_poly; generate_logo_polygon(logo_poly); - if (!m_logo_triangles.set_from_triangles(triangulate_expolygon_2f(logo_poly, NORMALS_UP), GROUND_Z+0.02f)) + m_logo_triangles.reset(); + if (!init_model_from_poly(m_logo_triangles, logo_poly, GROUND_Z + 0.02f)) BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << ":Unable to create logo triangles\n"; - else { - ; - } ExPolygon poly; /*for (const Vec2d& p : m_shape) { @@ -2519,8 +2449,6 @@ bool PartPlate::set_shape(const Pointfs& shape, const Pointfs& exclude_areas, Ve calc_height_limit(); - release_opengl_resource(); - return true; } @@ -2567,40 +2495,45 @@ bool PartPlate::intersects(const BoundingBoxf3& bb) const void PartPlate::render(bool bottom, bool only_body, bool force_background_color, HeightLimitMode mode, int hover_id, bool render_cali) { - glsafe(::glEnable(GL_DEPTH_TEST)); - glsafe(::glEnable(GL_BLEND)); - glsafe(::glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)); - glsafe(::glEnableClientState(GL_VERTEX_ARRAY)); + GLShaderProgram *shader = wxGetApp().get_shader("flat"); + if (shader != nullptr) { + shader->start_using(); + glsafe(::glEnable(GL_DEPTH_TEST)); + glsafe(::glEnable(GL_BLEND)); + glsafe(::glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)); - if (!bottom) { - // draw background - render_background(force_background_color); + if (!bottom) { + // draw background + render_background(force_background_color); - render_exclude_area(force_background_color); - } + render_exclude_area(force_background_color); + } - render_grid(bottom); + render_grid(bottom); - if (!bottom && m_selected && !force_background_color) { - if (m_partplate_list) - render_logo(bottom, m_partplate_list->render_cali_logo && render_cali); - else - render_logo(bottom); - } + render_height_limit(mode); - render_height_limit(mode); + glsafe(::glDisable(GL_BLEND)); - render_icons(bottom, only_body, hover_id); - if (!force_background_color){ - render_only_numbers(bottom); - } - glsafe(::glDisableClientState(GL_VERTEX_ARRAY)); - glsafe(::glDisable(GL_BLEND)); + // if (with_label) { + // render_label(canvas); + // } + + glsafe(::glDisable(GL_DEPTH_TEST)); + shader->stop_using(); + } + + if (!bottom && m_selected && !force_background_color) { + if (m_partplate_list) + render_logo(bottom, m_partplate_list->render_cali_logo && render_cali); + else + render_logo(bottom); + } - //if (with_label) { - // render_label(canvas); - //} - glsafe(::glDisable(GL_DEPTH_TEST)); + render_icons(bottom, only_body, hover_id); + if (!force_background_color) { + render_only_numbers(bottom); + } } void PartPlate::set_selected() { @@ -3162,10 +3095,6 @@ void PartPlateList::release_icon_textures() part.texture->reset(); delete part.texture; } - if (part.vbo_id != 0) { - glsafe(::glDeleteBuffers(1, &part.vbo_id)); - part.vbo_id = 0; - } if (part.buffer) { delete part.buffer; } @@ -5078,19 +5007,11 @@ void PartPlateList::BedTextureInfo::TexturePart::update_buffer() } if (!buffer) - buffer = new GeometryBuffer(); + buffer = new GLModel(); - if (buffer->set_from_triangles(triangulate_expolygon_2f(poly, NORMALS_UP), GROUND_Z + 0.02f)) { - if (vbo_id != 0) { - glsafe(::glDeleteBuffers(1, &vbo_id)); - vbo_id = 0; - } - unsigned int* vbo_id_ptr = const_cast(&vbo_id); - glsafe(::glGenBuffers(1, vbo_id_ptr)); - glsafe(::glBindBuffer(GL_ARRAY_BUFFER, *vbo_id_ptr)); - glsafe(::glBufferData(GL_ARRAY_BUFFER, (GLsizeiptr)buffer->get_vertices_data_size(), (const GLvoid*)buffer->get_vertices_data(), GL_STATIC_DRAW)); - glsafe(::glBindBuffer(GL_ARRAY_BUFFER, 0)); - } else { + buffer->reset(); + + if (!init_model_from_poly(*buffer, poly, GROUND_Z + 0.02f)) { BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << ":Unable to create buffer triangles\n"; } } diff --git a/src/slic3r/GUI/PartPlate.hpp b/src/slic3r/GUI/PartPlate.hpp index fc3da753151..9fcadf05980 100644 --- a/src/slic3r/GUI/PartPlate.hpp +++ b/src/slic3r/GUI/PartPlate.hpp @@ -115,28 +115,21 @@ class PartPlate : public ObjectBase Transform3d m_grabber_trans_matrix; Slic3r::Geometry::Transformation position; std::vector positions; - unsigned int m_vbo_id{ 0 }; - GeometryBuffer m_triangles; - GeometryBuffer m_exclude_triangles; - GeometryBuffer m_logo_triangles; - GeometryBuffer m_gridlines; - GeometryBuffer m_gridlines_bolder; - GeometryBuffer m_height_limit_common; - GeometryBuffer m_height_limit_bottom; - GeometryBuffer m_height_limit_top; - GeometryBuffer m_del_icon; - //GeometryBuffer m_del_and_background_icon; - mutable unsigned int m_del_vbo_id{ 0 }; - GeometryBuffer m_arrange_icon; - mutable unsigned int m_arrange_vbo_id{ 0 }; - GeometryBuffer m_orient_icon; - mutable unsigned int m_orient_vbo_id{ 0 }; - GeometryBuffer m_lock_icon; - mutable unsigned int m_lock_vbo_id{ 0 }; - GeometryBuffer m_plate_settings_icon; - mutable unsigned int m_plate_settings_vbo_id{ 0 }; - GeometryBuffer m_plate_idx_icon; - mutable unsigned int m_plate_idx_vbo_id{ 0 }; + GLModel m_triangles; + GLModel m_exclude_triangles; + GLModel m_logo_triangles; + GLModel m_gridlines; + GLModel m_gridlines_bolder; + GLModel m_height_limit_common; + GLModel m_height_limit_bottom; + GLModel m_height_limit_top; + GLModel m_del_icon; + //GLModel m_del_and_background_icon; + GLModel m_arrange_icon; + GLModel m_orient_icon; + GLModel m_lock_icon; + GLModel m_plate_settings_icon; + GLModel m_plate_idx_icon; GLTexture m_texture; mutable ColorRGBA m_grabber_color; @@ -152,8 +145,7 @@ class PartPlate : public ObjectBase // SoftFever // part plate name std::string m_name; - GeometryBuffer m_plate_name_icon; - mutable unsigned int m_plate_name_vbo_id{ 0 }; + GLModel m_plate_name_icon; GLTexture m_name_texture; wxCoord m_name_texture_width; wxCoord m_name_texture_height; @@ -168,31 +160,30 @@ class PartPlate : public ObjectBase void calc_exclude_triangles(const ExPolygon& poly); void calc_gridlines(const ExPolygon& poly, const BoundingBox& pp_bbox); void calc_height_limit(); - void calc_vertex_for_number(int index, bool one_number, GeometryBuffer &buffer); - void calc_vertex_for_icons(int index, GeometryBuffer &buffer); - void calc_vertex_for_icons_background(int icon_count, GeometryBuffer &buffer); - void render_background(bool force_default_color = false) const; - void render_logo(bool bottom, bool render_cali = true) const; - void render_logo_texture(GLTexture& logo_texture, const GeometryBuffer& logo_buffer, bool bottom, unsigned int vbo_id) const; - void render_exclude_area(bool force_default_color) const; + void calc_vertex_for_number(int index, bool one_number, GLModel &buffer); + void calc_vertex_for_icons(int index, GLModel &buffer); + void calc_vertex_for_icons_background(int icon_count, GLModel &buffer); + void render_background(bool force_default_color = false); + void render_logo(bool bottom, bool render_cali = true); + void render_logo_texture(GLTexture &logo_texture, GLModel &logo_buffer, bool bottom); + void render_exclude_area(bool force_default_color); //void render_background_for_picking(const ColorRGBA render_color) const; - void render_grid(bool bottom) const; - void render_height_limit(PartPlate::HeightLimitMode mode = HEIGHT_LIMIT_BOTH) const; - void render_label(GLCanvas3D& canvas) const; - void render_grabber(const ColorRGBA render_color, bool use_lighting) const; - void render_face(float x_size, float y_size) const; - void render_arrows(const ColorRGBA render_color, bool use_lighting) const; - void render_left_arrow(const ColorRGBA render_color, bool use_lighting) const; - void render_right_arrow(const ColorRGBA render_color, bool use_lighting) const; - void render_icon_texture(int position_id, int tex_coords_id, const GeometryBuffer &buffer, GLTexture &texture, unsigned int &vbo_id) const; + void render_grid(bool bottom); + void render_height_limit(PartPlate::HeightLimitMode mode = HEIGHT_LIMIT_BOTH); + // void render_label(GLCanvas3D& canvas) const; + // void render_grabber(const ColorRGBA render_color, bool use_lighting) const; + // void render_face(float x_size, float y_size) const; + // void render_arrows(const ColorRGBA render_color, bool use_lighting) const; + // void render_left_arrow(const ColorRGBA render_color, bool use_lighting) const; + // void render_right_arrow(const ColorRGBA render_color, bool use_lighting) const; + void render_icon_texture(GLModel &buffer, GLTexture &texture); void show_tooltip(const std::string tooltip); void render_icons(bool bottom, bool only_name = false, int hover_id = -1); - void render_only_numbers(bool bottom) const; - void render_plate_name_texture(int position_id, int tex_coords_id); - void render_rectangle_for_picking(const GeometryBuffer &buffer, const ColorRGBA render_color) const; - void on_render_for_picking() const; + void render_only_numbers(bool bottom); + void render_plate_name_texture(); + void render_rectangle_for_picking(GLModel &buffer, const ColorRGBA render_color); + void on_render_for_picking(); ColorRGBA picking_color_component(int idx) const; - void release_opengl_resource(); public: static const unsigned int PLATE_BASE_ID = 255 * 255 * 253; @@ -351,7 +342,7 @@ class PartPlate : public ObjectBase bool intersects(const BoundingBoxf3& bb) const; void render(bool bottom, bool only_body = false, bool force_background_color = false, HeightLimitMode mode = HEIGHT_LIMIT_NONE, int hover_id = -1, bool render_cali = false); - void render_for_picking() const { on_render_for_picking(); } + void render_for_picking() { on_render_for_picking(); } void set_selected(); void set_unselected(); void set_hover_id(int id) { m_hover_id = id; } @@ -569,18 +560,16 @@ class PartPlateList : public ObjectBase float y; float w; float h; - unsigned int vbo_id; std::string filename; GLTexture* texture { nullptr }; Vec2d offset; - GeometryBuffer* buffer { nullptr }; + GLModel* buffer { nullptr }; TexturePart(float xx, float yy, float ww, float hh, std::string file){ x = xx; y = yy; w = ww; h = hh; filename = file; texture = nullptr; buffer = nullptr; - vbo_id = 0; offset = Vec2d(0, 0); } @@ -593,7 +582,6 @@ class PartPlateList : public ObjectBase this->buffer = part.buffer; this->filename = part.filename; this->texture = part.texture; - this->vbo_id = part.vbo_id; } void update_buffer(); From 6eed22015a24215f2b62758e03903e725c606c17 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Sun, 22 Oct 2023 21:27:55 +0800 Subject: [PATCH 12/99] Tech ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL - Replace GLIndexedVertexArray with GLModel - GLGizmoFlatten::PlaneData::vbo (cherry picked from commit prusa3d/PrusaSlicer@ffa3a1d8fc6b2c85a6399cd91b3a9b2a1d92f82f) --- src/slic3r/GUI/GLModel.cpp | 38 +++++++++++++------- src/slic3r/GUI/GLModel.hpp | 3 ++ src/slic3r/GUI/Gizmos/GLGizmoFlatten.cpp | 44 ++++++++++++++++-------- src/slic3r/GUI/Gizmos/GLGizmoFlatten.hpp | 4 +-- 4 files changed, 61 insertions(+), 28 deletions(-) diff --git a/src/slic3r/GUI/GLModel.cpp b/src/slic3r/GUI/GLModel.cpp index e1d18a70cb9..b34a1811250 100644 --- a/src/slic3r/GUI/GLModel.cpp +++ b/src/slic3r/GUI/GLModel.cpp @@ -17,6 +17,16 @@ namespace Slic3r { namespace GUI { +void GLModel::Geometry::reserve_vertices(size_t vertices_count) +{ + vertices.reserve(vertices_count * vertex_stride_floats(format)); +} + +void GLModel::Geometry::reserve_indices(size_t indices_count) +{ + indices.reserve(indices_count * index_stride_bytes(format)); +} + void GLModel::Geometry::add_vertex(const Vec2f& position) { assert(format.vertex_layout == EVertexLayout::P2); @@ -403,8 +413,8 @@ void GLModel::init_from(const indexed_triangle_set& its) Geometry& data = m_render_data.geometry; data.format = { Geometry::EPrimitiveType::Triangles, Geometry::EVertexLayout::P3N3, Geometry::EIndexType::UINT }; - data.vertices.reserve(3 * its.indices.size() * Geometry::vertex_stride_floats(data.format)); - data.indices.reserve(3 * its.indices.size() * Geometry::index_stride_bytes(data.format)); + data.reserve_vertices(3 * its.indices.size()); + data.reserve_indices(3 * its.indices.size()); // vertices + indices unsigned int vertices_counter = 0; @@ -446,8 +456,8 @@ void GLModel::init_from(const Polygons& polygons, float z) segments_count += polygon.points.size(); } - data.vertices.reserve(2 * segments_count * Geometry::vertex_stride_floats(data.format)); - data.indices.reserve(2 * segments_count * Geometry::index_stride_bytes(data.format)); + data.reserve_vertices(2 * segments_count); + data.reserve_indices(2 * segments_count); // vertices + indices unsigned int vertices_counter = 0; @@ -713,8 +723,8 @@ GLModel::Geometry stilized_arrow(unsigned short resolution, float tip_radius, fl GLModel::Geometry data; data.format = { GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3N3, GLModel::Geometry::EIndexType::USHORT }; - data.vertices.reserve((6 * resolution + 2) * GLModel::Geometry::vertex_stride_floats(data.format)); - data.indices.reserve((6 * resolution * 3) * GLModel::Geometry::index_stride_bytes(data.format)); + data.reserve_vertices(6 * resolution + 2); + data.reserve_indices(6 * resolution * 3); const float angle_step = 2.0f * float(PI) / float(resolution); std::vector cosines(resolution); @@ -787,6 +797,7 @@ GLModel::Geometry stilized_arrow(unsigned short resolution, float tip_radius, fl const unsigned short v3 = (i < resolution - 1) ? i + 5 * resolution + 3 : 5 * resolution + 2; append_triangle(data, 5 * resolution + 1, v3, i + 5 * resolution + 2); } + return data; } @@ -797,8 +808,8 @@ GLModel::Geometry circular_arrow(unsigned short resolution, float radius, float GLModel::Geometry data; data.format = { GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3N3, GLModel::Geometry::EIndexType::USHORT }; - data.vertices.reserve((8 * (resolution + 1) + 30) * GLModel::Geometry::vertex_stride_floats(data.format)); - data.indices.reserve(((8 * resolution + 16) * 3) * GLModel::Geometry::index_stride_bytes(data.format)); + data.reserve_vertices(8 * (resolution + 1) + 30); + data.reserve_indices((8 * resolution + 16) * 3); const float half_thickness = 0.5f * thickness; const float half_stem_width = 0.5f * stem_width; @@ -951,6 +962,7 @@ GLModel::Geometry circular_arrow(unsigned short resolution, float radius, float append_triangle(data, ii, ii + 1, ii + resolution + 2); append_triangle(data, ii, ii + resolution + 2, ii + resolution + 1); } + return data; } @@ -958,8 +970,8 @@ GLModel::Geometry straight_arrow(float tip_width, float tip_height, float stem_w { GLModel::Geometry data; data.format = { GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3N3, GLModel::Geometry::EIndexType::USHORT }; - data.vertices.reserve(42 * GLModel::Geometry::vertex_stride_floats(data.format)); - data.indices.reserve((24 * 3) * GLModel::Geometry::index_stride_bytes(data.format)); + data.reserve_vertices(42); + data.reserve_indices(72); const float half_thickness = 0.5f * thickness; const float half_stem_width = 0.5f * stem_width; @@ -1044,6 +1056,7 @@ GLModel::Geometry straight_arrow(float tip_width, float tip_height, float stem_w append_triangle(data, 14 + ii, 15 + ii, 17 + ii); append_triangle(data, 14 + ii, 17 + ii, 16 + ii); } + return data; } @@ -1054,8 +1067,8 @@ GLModel::Geometry diamond(unsigned short resolution) GLModel::Geometry data; data.format = { GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3N3, GLModel::Geometry::EIndexType::USHORT }; - data.vertices.reserve((resolution + 2) * GLModel::Geometry::vertex_stride_floats(data.format)); - data.indices.reserve(((2 * (resolution + 1)) * 3) * GLModel::Geometry::index_stride_bytes(data.format)); + data.reserve_vertices(resolution + 2); + data.reserve_indices((2 * (resolution + 1)) * 3); const float step = 2.0f * float(PI) / float(resolution); @@ -1082,6 +1095,7 @@ GLModel::Geometry diamond(unsigned short resolution) append_triangle(data, i + 0, resolution + 1, i + 1); } append_triangle(data, resolution - 1, resolution + 1, 0); + return data; } diff --git a/src/slic3r/GUI/GLModel.hpp b/src/slic3r/GUI/GLModel.hpp index fae1c63153a..d81290234f2 100644 --- a/src/slic3r/GUI/GLModel.hpp +++ b/src/slic3r/GUI/GLModel.hpp @@ -60,6 +60,9 @@ namespace GUI { std::vector indices; ColorRGBA color{ ColorRGBA::BLACK() }; + void reserve_vertices(size_t vertices_count); + void reserve_indices(size_t indices_count); + void add_vertex(const Vec2f& position); void add_vertex(const Vec2f& position, const Vec2f& tex_coord); void add_vertex(const Vec3f& position); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoFlatten.cpp b/src/slic3r/GUI/Gizmos/GLGizmoFlatten.cpp index 4ad8136bbaa..b782ffbd6a0 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoFlatten.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoFlatten.cpp @@ -1,6 +1,7 @@ // Include GLGizmoBase.hpp before I18N.hpp as it includes some libigl code, which overrides our localization "L" macro. #include "GLGizmoFlatten.hpp" #include "slic3r/GUI/GLCanvas3D.hpp" +#include "slic3r/GUI/GUI_App.hpp" #include "slic3r/GUI/Gizmos/GLGizmosCommon.hpp" #include "libslic3r/Geometry/ConvexHull.hpp" @@ -62,6 +63,11 @@ void GLGizmoFlatten::on_render() { const Selection& selection = m_parent.get_selection(); + GLShaderProgram* shader = wxGetApp().get_shader("flat"); + if (shader == nullptr) + return; + + shader->start_using(); glsafe(::glClear(GL_DEPTH_BUFFER_BIT)); glsafe(::glEnable(GL_DEPTH_TEST)); @@ -75,24 +81,25 @@ void GLGizmoFlatten::on_render() if (this->is_plane_update_necessary()) update_planes(); for (int i = 0; i < (int)m_planes.size(); ++i) { - if (i == m_hover_id) - glsafe(::glColor4fv(GLGizmoBase::FLATTEN_HOVER_COLOR.data())); - else - glsafe(::glColor4fv(GLGizmoBase::FLATTEN_COLOR.data())); - - if (m_planes[i].vbo.has_VBOs()) - m_planes[i].vbo.render(); + m_planes[i].vbo.set_color(i == m_hover_id ? GLGizmoBase::FLATTEN_HOVER_COLOR : GLGizmoBase::FLATTEN_COLOR); + m_planes[i].vbo.render(); } glsafe(::glPopMatrix()); } glsafe(::glEnable(GL_CULL_FACE)); glsafe(::glDisable(GL_BLEND)); + shader->stop_using(); } void GLGizmoFlatten::on_render_for_picking() { const Selection& selection = m_parent.get_selection(); + GLShaderProgram* shader = wxGetApp().get_shader("flat"); + if (shader == nullptr) + return; + + shader->start_using(); glsafe(::glDisable(GL_DEPTH_TEST)); glsafe(::glDisable(GL_BLEND)); @@ -105,13 +112,14 @@ void GLGizmoFlatten::on_render_for_picking() if (this->is_plane_update_necessary()) update_planes(); for (int i = 0; i < (int)m_planes.size(); ++i) { - glsafe(::glColor4fv(picking_color_component(i).data())); + m_planes[i].vbo.set_color(picking_color_component(i)); m_planes[i].vbo.render(); } glsafe(::glPopMatrix()); } glsafe(::glEnable(GL_CULL_FACE)); + shader->stop_using(); } void GLGizmoFlatten::set_flattening_data(const ModelObject* model_object) @@ -328,12 +336,20 @@ void GLGizmoFlatten::update_planes() // And finally create respective VBOs. The polygon is convex with // the vertices in order, so triangulation is trivial. for (auto& plane : m_planes) { - plane.vbo.reserve(plane.vertices.size()); - for (const auto& vert : plane.vertices) - plane.vbo.push_geometry(vert, plane.normal); - for (size_t i=1; i(), (Vec3f)plane.normal.cast()); + if (index_type == GLModel::Geometry::EIndexType::USHORT) + init_data.add_ushort_index(i); + else + init_data.add_uint_index(i); + } + plane.vbo.init_from(std::move(init_data)); // FIXME: vertices should really be local, they need not // persist now when we use VBOs plane.vertices.clear(); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoFlatten.hpp b/src/slic3r/GUI/Gizmos/GLGizmoFlatten.hpp index ab3c2c7bab1..eb669c74967 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoFlatten.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoFlatten.hpp @@ -2,7 +2,7 @@ #define slic3r_GLGizmoFlatten_hpp_ #include "GLGizmoBase.hpp" -#include "slic3r/GUI/3DScene.hpp" +#include "slic3r/GUI/GLModel.hpp" namespace Slic3r { @@ -22,7 +22,7 @@ class GLGizmoFlatten : public GLGizmoBase struct PlaneData { std::vector vertices; // should be in fact local in update_planes() - GLIndexedVertexArray vbo; + GLModel vbo; Vec3d normal; float area; }; From 269fbaa60ce87f69afde4ab8898c344b665c484e Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Sun, 22 Oct 2023 21:41:32 +0800 Subject: [PATCH 13/99] Tech ENABLE_GLBEGIN_GLEND_REMOVAL - Refactoring to simplify client code of GLModel::Geometry (cherry picked from commit prusa3d/PrusaSlicer@be6b6590be4010d03ead377ba192eacac8c8d14b) --- src/slic3r/GUI/3DScene.cpp | 4 ++-- src/slic3r/GUI/GLCanvas3D.cpp | 16 ++++++------- src/slic3r/GUI/GLSelectionRectangle.cpp | 4 ++-- src/slic3r/GUI/GLTexture.cpp | 4 ++-- src/slic3r/GUI/Gizmos/GLGizmoAdvancedCut.cpp | 4 ++-- src/slic3r/GUI/Gizmos/GLGizmoMove.cpp | 4 ++-- src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp | 4 ++-- src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp | 24 ++++++++++---------- src/slic3r/GUI/Gizmos/GLGizmoScale.cpp | 4 ++-- src/slic3r/GUI/Selection.cpp | 13 ++++++----- 10 files changed, 41 insertions(+), 40 deletions(-) diff --git a/src/slic3r/GUI/3DScene.cpp b/src/slic3r/GUI/3DScene.cpp index 209e77c01b2..52fc96df1b7 100644 --- a/src/slic3r/GUI/3DScene.cpp +++ b/src/slic3r/GUI/3DScene.cpp @@ -353,8 +353,8 @@ void GLVolume::SinkingContours::update() const Polygons polygons = union_(slice_mesh(mesh.its, 0.0f, slicing_params)); for (const ExPolygon& expoly : diff_ex(expand(polygons, float(scale_(HalfWidth))), shrink(polygons, float(scale_(HalfWidth))))) { const std::vector triangulation = triangulate_expolygon_3d(expoly); - init_data.vertices.reserve(init_data.vertices.size() + triangulation.size() * GUI::GLModel::Geometry::vertex_stride_floats(init_data.format)); - init_data.indices.reserve(init_data.indices.size() + triangulation.size() * GUI::GLModel::Geometry::index_stride_bytes(init_data.format)); + init_data.reserve_vertices(init_data.vertices_count() + triangulation.size()); + init_data.reserve_indices(init_data.indices_count() + triangulation.size()); for (const Vec3d& v : triangulation) { init_data.add_vertex((Vec3f)(v.cast() + 0.015f * Vec3f::UnitZ())); // add a small positive z to avoid z-fighting ++vertices_counter; diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 419e3b048ad..14d0254a8e9 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -431,8 +431,8 @@ void GLCanvas3D::LayersEditing::render_active_object_annotations(const GLCanvas3 GLModel::Geometry init_data; init_data.format = { GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P2T2, GLModel::Geometry::EIndexType::USHORT }; - init_data.vertices.reserve(4 * GLModel::Geometry::vertex_stride_floats(init_data.format)); - init_data.indices.reserve(6 * GLModel::Geometry::index_stride_bytes(init_data.format)); + init_data.reserve_vertices(4); + init_data.reserve_indices(6); // vertices const float l = bar_rect.get_left(); @@ -478,8 +478,8 @@ void GLCanvas3D::LayersEditing::render_profile(const Rect& bar_rect) GLModel::Geometry init_data; init_data.format = { GLModel::Geometry::EPrimitiveType::Lines, GLModel::Geometry::EVertexLayout::P2, GLModel::Geometry::EIndexType::USHORT }; init_data.color = ColorRGBA::BLACK(); - init_data.vertices.reserve(2 * GLModel::Geometry::vertex_stride_floats(init_data.format)); - init_data.indices.reserve(2 * GLModel::Geometry::index_stride_bytes(init_data.format)); + init_data.reserve_vertices(2); + init_data.reserve_indices(2); // vertices const float x = bar_rect.get_left() + float(m_slicing_parameters->layer_height) * scale_x; @@ -499,8 +499,8 @@ void GLCanvas3D::LayersEditing::render_profile(const Rect& bar_rect) GLModel::Geometry init_data; init_data.format = { GLModel::Geometry::EPrimitiveType::LineStrip, GLModel::Geometry::EVertexLayout::P2, GLModel::Geometry::EIndexType::UINT }; init_data.color = ColorRGBA::BLUE(); - init_data.vertices.reserve(m_layer_height_profile.size() * GLModel::Geometry::vertex_stride_floats(init_data.format)); - init_data.indices.reserve(m_layer_height_profile.size() * GLModel::Geometry::index_stride_bytes(init_data.format)); + init_data.reserve_vertices(m_layer_height_profile.size() / 2); + init_data.reserve_indices(m_layer_height_profile.size() / 2); // vertices + indices for (unsigned int i = 0; i < (unsigned int)m_layer_height_profile.size(); i += 2) { @@ -6644,8 +6644,8 @@ void GLCanvas3D::_render_background() GLModel::Geometry init_data; init_data.format = { GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P2T2, GLModel::Geometry::EIndexType::USHORT }; - init_data.vertices.reserve(4 * GLModel::Geometry::vertex_stride_floats(init_data.format)); - init_data.indices.reserve(6 * GLModel::Geometry::index_stride_bytes(init_data.format)); + init_data.reserve_vertices(4); + init_data.reserve_indices(6); // vertices init_data.add_vertex(Vec2f(-1.0f, -1.0f), Vec2f(0.0f, 0.0f)); diff --git a/src/slic3r/GUI/GLSelectionRectangle.cpp b/src/slic3r/GUI/GLSelectionRectangle.cpp index 9ae15bbe8e1..e06f0876999 100644 --- a/src/slic3r/GUI/GLSelectionRectangle.cpp +++ b/src/slic3r/GUI/GLSelectionRectangle.cpp @@ -118,8 +118,8 @@ namespace GUI { GLModel::Geometry init_data; init_data.format = { GLModel::Geometry::EPrimitiveType::LineLoop, GLModel::Geometry::EVertexLayout::P2, GLModel::Geometry::EIndexType::USHORT }; - init_data.vertices.reserve(4 * GLModel::Geometry::vertex_stride_floats(init_data.format)); - init_data.indices.reserve(4 * GLModel::Geometry::index_stride_bytes(init_data.format)); + init_data.reserve_vertices(4); + init_data.reserve_indices(4); // vertices init_data.add_vertex(Vec2f(left, bottom)); diff --git a/src/slic3r/GUI/GLTexture.cpp b/src/slic3r/GUI/GLTexture.cpp index 6b75f490c70..69ed23e2ffe 100644 --- a/src/slic3r/GUI/GLTexture.cpp +++ b/src/slic3r/GUI/GLTexture.cpp @@ -664,8 +664,8 @@ void GLTexture::render_sub_texture(unsigned int tex_id, float left, float right, GLModel::Geometry init_data; init_data.format = { GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P2T2, GLModel::Geometry::EIndexType::USHORT }; - init_data.vertices.reserve(4 * GLModel::Geometry::vertex_stride_floats(init_data.format)); - init_data.indices.reserve(6 * GLModel::Geometry::index_stride_bytes(init_data.format)); + init_data.reserve_vertices(4); + init_data.reserve_indices(6); // vertices init_data.add_vertex(Vec2f(left, bottom), Vec2f(uvs.left_bottom.u, uvs.left_bottom.v)); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoAdvancedCut.cpp b/src/slic3r/GUI/Gizmos/GLGizmoAdvancedCut.cpp index 47b3a55ad38..d4a521374e3 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoAdvancedCut.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoAdvancedCut.cpp @@ -885,8 +885,8 @@ void GLGizmoAdvancedCut::render_cut_plane_and_grabbers() GLModel::Geometry init_data; init_data.format = { GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3, GLModel::Geometry::EIndexType::USHORT }; init_data.color = { 0.8f, 0.8f, 0.8f, 0.5f }; - init_data.vertices.reserve(4 * GLModel::Geometry::vertex_stride_floats(init_data.format)); - init_data.indices.reserve(6 * GLModel::Geometry::index_stride_bytes(init_data.format)); + init_data.reserve_vertices(4); + init_data.reserve_vertices(6); // vertices for (const Vec3d &point : plane_points_rot) { diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMove.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMove.cpp index e7c861cb02d..77b1ecdb01b 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMove.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMove.cpp @@ -142,8 +142,8 @@ void GLGizmoMove3D::on_render() GLModel::Geometry init_data; init_data.format = { GLModel::Geometry::EPrimitiveType::Lines, GLModel::Geometry::EVertexLayout::P3, GLModel::Geometry::EIndexType::USHORT }; init_data.color = AXES_COLOR[id]; - init_data.vertices.reserve(2 * GLModel::Geometry::vertex_stride_floats(init_data.format)); - init_data.indices.reserve(2 * GLModel::Geometry::index_stride_bytes(init_data.format)); + init_data.reserve_vertices(2); + init_data.reserve_indices(2); // vertices init_data.add_vertex((Vec3f)center.cast()); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp b/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp index ab7f242ce51..97136491f47 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp @@ -199,8 +199,8 @@ void GLGizmoPainterBase::render_cursor_circle() static const float StepSize = 2.0f * float(PI) / float(StepsCount); init_data.format = { GLModel::Geometry::EPrimitiveType::LineLoop, GLModel::Geometry::EVertexLayout::P3, GLModel::Geometry::EIndexType::USHORT }; init_data.color = { 0.0f, 1.0f, 0.3f, 1.0f }; - init_data.vertices.reserve(StepsCount * GLModel::Geometry::vertex_stride_floats(init_data.format)); - init_data.indices.reserve(StepsCount * GLModel::Geometry::index_stride_bytes(init_data.format)); + init_data.reserve_vertices(StepsCount); + init_data.reserve_indices(StepsCount); // vertices + indices for (unsigned short i = 0; i < StepsCount; ++i) { diff --git a/src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp b/src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp index b58ec86688d..a4a603deecb 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp @@ -230,8 +230,8 @@ void GLGizmoRotate::render_circle(const ColorRGBA& color, bool radius_changed) GLModel::Geometry init_data; init_data.format = { GLModel::Geometry::EPrimitiveType::LineLoop, GLModel::Geometry::EVertexLayout::P3, GLModel::Geometry::EIndexType::USHORT }; - init_data.vertices.reserve(ScaleStepsCount * GLModel::Geometry::vertex_stride_floats(init_data.format)); - init_data.indices.reserve(ScaleStepsCount * GLModel::Geometry::index_stride_bytes(init_data.format)); + init_data.reserve_vertices(ScaleStepsCount); + init_data.reserve_indices(ScaleStepsCount); // vertices + indices for (unsigned short i = 0; i < ScaleStepsCount; ++i) { @@ -257,8 +257,8 @@ void GLGizmoRotate::render_scale(const ColorRGBA& color, bool radius_changed) GLModel::Geometry init_data; init_data.format = { GLModel::Geometry::EPrimitiveType::Lines, GLModel::Geometry::EVertexLayout::P3, GLModel::Geometry::EIndexType::USHORT }; - init_data.vertices.reserve(2 * ScaleStepsCount * GLModel::Geometry::vertex_stride_floats(init_data.format)); - init_data.indices.reserve(2 * ScaleStepsCount * GLModel::Geometry::index_stride_bytes(init_data.format)); + init_data.reserve_vertices(2 * ScaleStepsCount); + init_data.reserve_indices(2 * ScaleStepsCount); // vertices + indices for (unsigned short i = 0; i < ScaleStepsCount; ++i) { @@ -294,8 +294,8 @@ void GLGizmoRotate::render_snap_radii(const ColorRGBA& color, bool radius_change GLModel::Geometry init_data; init_data.format = { GLModel::Geometry::EPrimitiveType::Lines, GLModel::Geometry::EVertexLayout::P3, GLModel::Geometry::EIndexType::USHORT }; - init_data.vertices.reserve(2 * ScaleStepsCount * GLModel::Geometry::vertex_stride_floats(init_data.format)); - init_data.indices.reserve(2 * ScaleStepsCount * GLModel::Geometry::index_stride_bytes(init_data.format)); + init_data.reserve_vertices(2 * ScaleStepsCount); + init_data.reserve_indices(2 * ScaleStepsCount); // vertices + indices for (unsigned short i = 0; i < ScaleStepsCount; ++i) { @@ -327,8 +327,8 @@ void GLGizmoRotate::render_reference_radius(const ColorRGBA& color, bool radius_ GLModel::Geometry init_data; init_data.format = { GLModel::Geometry::EPrimitiveType::Lines, GLModel::Geometry::EVertexLayout::P3, GLModel::Geometry::EIndexType::USHORT }; - init_data.vertices.reserve(2 * GLModel::Geometry::vertex_stride_floats(init_data.format)); - init_data.indices.reserve(2 * GLModel::Geometry::index_stride_bytes(init_data.format)); + init_data.reserve_vertices(2); + init_data.reserve_indices(2); // vertices init_data.add_vertex(Vec3f(0.0f, 0.0f, 0.0f)); @@ -354,8 +354,8 @@ void GLGizmoRotate::render_angle_arc(const ColorRGBA& color, bool radius_changed GLModel::Geometry init_data; init_data.format = { GLModel::Geometry::EPrimitiveType::LineStrip, GLModel::Geometry::EVertexLayout::P3, GLModel::Geometry::EIndexType::USHORT }; - init_data.vertices.reserve((1 + AngleResolution) * GLModel::Geometry::vertex_stride_floats(init_data.format)); - init_data.indices.reserve((1 + AngleResolution) * GLModel::Geometry::index_stride_bytes(init_data.format)); + init_data.reserve_vertices(1 + AngleResolution); + init_data.reserve_indices(1 + AngleResolution); // vertices + indices for (unsigned short i = 0; i <= AngleResolution; ++i) { @@ -379,8 +379,8 @@ void GLGizmoRotate::render_grabber_connection(const ColorRGBA& color, bool radiu GLModel::Geometry init_data; init_data.format = { GLModel::Geometry::EPrimitiveType::Lines, GLModel::Geometry::EVertexLayout::P3, GLModel::Geometry::EIndexType::USHORT }; - init_data.vertices.reserve(2 * GLModel::Geometry::vertex_stride_floats(init_data.format)); - init_data.indices.reserve(2 * GLModel::Geometry::index_stride_bytes(init_data.format)); + init_data.reserve_vertices(2); + init_data.reserve_indices(2); // vertices init_data.add_vertex(Vec3f(0.0f, 0.0f, 0.0f)); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoScale.cpp b/src/slic3r/GUI/Gizmos/GLGizmoScale.cpp index 40478f6311b..0db0b4ab4b9 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoScale.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoScale.cpp @@ -280,8 +280,8 @@ void GLGizmoScale3D::render_grabbers_connection(unsigned int id_1, unsigned int GLModel::Geometry init_data; init_data.format = { GLModel::Geometry::EPrimitiveType::Lines, GLModel::Geometry::EVertexLayout::P3, GLModel::Geometry::EIndexType::USHORT }; - init_data.vertices.reserve(2 * GLModel::Geometry::vertex_stride_floats(init_data.format)); - init_data.indices.reserve(2 * GLModel::Geometry::index_stride_bytes(init_data.format)); + init_data.reserve_vertices(2); + init_data.reserve_indices(2); // vertices init_data.add_vertex((Vec3f)m_grabbers[id_1].center.cast()); diff --git a/src/slic3r/GUI/Selection.cpp b/src/slic3r/GUI/Selection.cpp index 21096a01116..cff214537fd 100644 --- a/src/slic3r/GUI/Selection.cpp +++ b/src/slic3r/GUI/Selection.cpp @@ -1559,6 +1559,7 @@ void Selection::render(float scale_factor) return; m_scale_factor = scale_factor; + // render cumulative bounding box of selected volumes render_bounding_box(get_bounding_box(), ColorRGB::WHITE()); render_synchronized_volumes(); } @@ -2167,8 +2168,8 @@ void Selection::render_bounding_box(const BoundingBoxf3& box, const ColorRGB& co GLModel::Geometry init_data; init_data.format = { GLModel::Geometry::EPrimitiveType::Lines, GLModel::Geometry::EVertexLayout::P3, GLModel::Geometry::EIndexType::USHORT }; - init_data.vertices.reserve(48 * GLModel::Geometry::vertex_stride_floats(init_data.format)); - init_data.indices.reserve(48 * GLModel::Geometry::index_stride_bytes(init_data.format)); + init_data.reserve_vertices(48); + init_data.reserve_indices(48); // vertices init_data.add_vertex(Vec3f(b_min.x(), b_min.y(), b_min.z())); @@ -2388,8 +2389,8 @@ void Selection::render_sidebar_layers_hints(const std::string& sidebar_field) GLModel::Geometry init_data; init_data.format = { GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3, GLModel::Geometry::EIndexType::USHORT }; - init_data.vertices.reserve(4 * GLModel::Geometry::vertex_stride_floats(init_data.format)); - init_data.indices.reserve(6 * GLModel::Geometry::index_stride_bytes(init_data.format)); + init_data.reserve_vertices(4); + init_data.reserve_indices(6); // vertices init_data.add_vertex(Vec3f(p1.x(), p1.y(), z1)); @@ -2410,8 +2411,8 @@ void Selection::render_sidebar_layers_hints(const std::string& sidebar_field) GLModel::Geometry init_data; init_data.format = { GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3, GLModel::Geometry::EIndexType::USHORT }; - init_data.vertices.reserve(4 * GLModel::Geometry::vertex_stride_floats(init_data.format)); - init_data.indices.reserve(6 * GLModel::Geometry::index_stride_bytes(init_data.format)); + init_data.reserve_vertices(4); + init_data.reserve_indices(6); // vertices init_data.add_vertex(Vec3f(p1.x(), p1.y(), z2)); From 6d4e0840bcfdeb65ab447975a9395933c53fc93d Mon Sep 17 00:00:00 2001 From: Noisyfox Date: Sun, 22 Oct 2023 21:48:49 +0800 Subject: [PATCH 14/99] Fix move gizmo grabber connection render --- src/slic3r/GUI/Gizmos/GLGizmoMove.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMove.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMove.cpp index 77b1ecdb01b..469dff42f60 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMove.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMove.cpp @@ -135,7 +135,7 @@ void GLGizmoMove3D::on_render() auto render_grabber_connection = [this, ¢er](unsigned int id) { if (m_grabbers[id].enabled) { - if (!m_grabber_connections[id].model.is_initialized() || !m_grabber_connections[id].old_center.isApprox(center)) { + //if (!m_grabber_connections[id].model.is_initialized() || !m_grabber_connections[id].old_center.isApprox(center)) { m_grabber_connections[id].old_center = center; m_grabber_connections[id].model.reset(); @@ -153,7 +153,7 @@ void GLGizmoMove3D::on_render() init_data.add_ushort_line(0, 1); m_grabber_connections[id].model.init_from(std::move(init_data)); - } + //} glLineStipple(1, 0x0FFF); glEnable(GL_LINE_STIPPLE); From 874f39aac1e0249230361e5ac2dd23b5a4a105d2 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Sun, 22 Oct 2023 21:54:42 +0800 Subject: [PATCH 15/99] Tech ENABLE_GLBEGIN_GLEND_REMOVAL - Adapt GLModel::Geometry index format in dependence of data size, where possible (cherry picked from commit prusa3d/PrusaSlicer@4d2d77e99c244c9da18983f6d624d277a9db4fec) --- src/slic3r/GUI/3DBed.cpp | 6 ++++-- src/slic3r/GUI/GLCanvas3D.cpp | 12 +++++++++--- src/slic3r/GUI/Gizmos/GLGizmoFlatten.cpp | 4 ++-- src/slic3r/GUI/PartPlate.cpp | 9 ++++++--- 4 files changed, 21 insertions(+), 10 deletions(-) diff --git a/src/slic3r/GUI/3DBed.cpp b/src/slic3r/GUI/3DBed.cpp index 68d2d89f851..3f29fd65b98 100644 --- a/src/slic3r/GUI/3DBed.cpp +++ b/src/slic3r/GUI/3DBed.cpp @@ -44,10 +44,11 @@ bool init_model_from_poly(GLModel &model, const ExPolygon &poly, float z) if (triangles.empty() || triangles.size() % 3 != 0) return false; - const GLModel::Geometry::EIndexType index_type = (triangles.size() < 65536) ? GLModel::Geometry::EIndexType::USHORT : GLModel::Geometry::EIndexType::UINT; - GLModel::Geometry init_data; + const GLModel::Geometry::EIndexType index_type = (triangles.size() < 65536) ? GLModel::Geometry::EIndexType::USHORT : GLModel::Geometry::EIndexType::UINT; init_data.format = { GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3T2, index_type }; + init_data.reserve_vertices(triangles.size()); + init_data.reserve_indices(triangles.size() / 3); Vec2f min = triangles.front(); Vec2f max = min; @@ -63,6 +64,7 @@ bool init_model_from_poly(GLModel &model, const ExPolygon &poly, float z) Vec2f inv_size = size.cwiseInverse(); inv_size.y() *= -1.0f; + // vertices + indices unsigned int vertices_counter = 0; for (const Vec2f &v : triangles) { const Vec3f p = {v.x(), v.y(), z}; diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 14d0254a8e9..6c53d00b97f 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -497,7 +497,8 @@ void GLCanvas3D::LayersEditing::render_profile(const Rect& bar_rect) m_profile.profile.reset(); GLModel::Geometry init_data; - init_data.format = { GLModel::Geometry::EPrimitiveType::LineStrip, GLModel::Geometry::EVertexLayout::P2, GLModel::Geometry::EIndexType::UINT }; + const GLModel::Geometry::EIndexType index_type = (m_layer_height_profile.size() / 2 < 65536) ? GLModel::Geometry::EIndexType::USHORT : GLModel::Geometry::EIndexType::UINT; + init_data.format = { GLModel::Geometry::EPrimitiveType::LineStrip, GLModel::Geometry::EVertexLayout::P2, index_type }; init_data.color = ColorRGBA::BLUE(); init_data.reserve_vertices(m_layer_height_profile.size() / 2); init_data.reserve_indices(m_layer_height_profile.size() / 2); @@ -506,7 +507,10 @@ void GLCanvas3D::LayersEditing::render_profile(const Rect& bar_rect) for (unsigned int i = 0; i < (unsigned int)m_layer_height_profile.size(); i += 2) { init_data.add_vertex(Vec2f(bar_rect.get_left() + float(m_layer_height_profile[i + 1]) * scale_x, bar_rect.get_bottom() + float(m_layer_height_profile[i]) * scale_y)); - init_data.add_uint_index(i / 2); + if (index_type == GLModel::Geometry::EIndexType::USHORT) + init_data.add_ushort_index((unsigned short)i / 2); + else + init_data.add_uint_index(i / 2); } m_profile.profile.init_from(std::move(init_data)); @@ -891,7 +895,9 @@ void GLCanvas3D::SequentialPrintClearance::set_polygons(const Polygons& polygons const ExPolygons polygons_union = union_ex(polygons); unsigned int vertices_counter = 0; for (const ExPolygon& poly : polygons_union) { - const std::vector triangulation = triangulate_expolygon_3d(poly); + const std::vector triangulation = triangulate_expolygon_3d(poly); + fill_data.reserve_vertices(fill_data.vertices_count() + triangulation.size()); + fill_data.reserve_indices(fill_data.indices_count() + triangulation.size()); for (const Vec3d& v : triangulation) { fill_data.add_vertex((Vec3f)(v.cast() + 0.0125f * Vec3f::UnitZ())); // add a small positive z to avoid z-fighting ++vertices_counter; diff --git a/src/slic3r/GUI/Gizmos/GLGizmoFlatten.cpp b/src/slic3r/GUI/Gizmos/GLGizmoFlatten.cpp index b782ffbd6a0..b67b18dfc3d 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoFlatten.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoFlatten.cpp @@ -345,9 +345,9 @@ void GLGizmoFlatten::update_planes() for (size_t i = 0; i < plane.vertices.size(); ++i) { init_data.add_vertex((Vec3f)plane.vertices[i].cast(), (Vec3f)plane.normal.cast()); if (index_type == GLModel::Geometry::EIndexType::USHORT) - init_data.add_ushort_index(i); + init_data.add_ushort_index((unsigned short)i); else - init_data.add_uint_index(i); + init_data.add_uint_index((unsigned int)i); } plane.vbo.init_from(std::move(init_data)); // FIXME: vertices should really be local, they need not diff --git a/src/slic3r/GUI/PartPlate.cpp b/src/slic3r/GUI/PartPlate.cpp index 67137e16212..27e819b45ad 100644 --- a/src/slic3r/GUI/PartPlate.cpp +++ b/src/slic3r/GUI/PartPlate.cpp @@ -349,10 +349,12 @@ void PartPlate::calc_exclude_triangles(const ExPolygon &poly) static bool init_model_from_lines(GLModel &model, const Lines &lines, float z) { - const GLModel::Geometry::EIndexType index_type = (lines.size() < 65536 / 2) ? GLModel::Geometry::EIndexType::USHORT : GLModel::Geometry::EIndexType::UINT; GLModel::Geometry init_data; + const GLModel::Geometry::EIndexType index_type = (lines.size() < 65536 / 2) ? GLModel::Geometry::EIndexType::USHORT : GLModel::Geometry::EIndexType::UINT; init_data.format = { GLModel::Geometry::EPrimitiveType::Lines, GLModel::Geometry::EVertexLayout::P3, index_type }; + init_data.reserve_vertices(2 * lines.size()); + init_data.reserve_indices(2 * lines.size()); for (const auto &l : lines) { init_data.add_vertex(Vec3f(unscale(l.a.x()), unscale(l.a.y()), z)); @@ -371,11 +373,12 @@ static bool init_model_from_lines(GLModel &model, const Lines &lines, float z) static bool init_model_from_lines(GLModel &model, const Lines3 &lines) { - const GLModel::Geometry::EIndexType index_type = (lines.size() < 65536 / 2) ? GLModel::Geometry::EIndexType::USHORT : - GLModel::Geometry::EIndexType::UINT; GLModel::Geometry init_data; + const GLModel::Geometry::EIndexType index_type = (lines.size() < 65536 / 2) ? GLModel::Geometry::EIndexType::USHORT : GLModel::Geometry::EIndexType::UINT; init_data.format = {GLModel::Geometry::EPrimitiveType::Lines, GLModel::Geometry::EVertexLayout::P3, index_type}; + init_data.reserve_vertices(2 * lines.size()); + init_data.reserve_indices(2 * lines.size()); for (const auto &l : lines) { init_data.add_vertex(Vec3f(unscale(l.a.x()), unscale(l.a.y()), unscale(l.a.z()))); From b7989e3b2f3cc9c176026469a70c65fa11219ad2 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Sun, 22 Oct 2023 22:26:55 +0800 Subject: [PATCH 16/99] Gizmos refactoring - Removed GLModels defined into GLGizmoBase, and mostly unused, to avoid wasting GPU memory. Use a shared GLModel for Gizmos inheriting from GLGizmoPainterBase. Initialization of GLModels moved from constructor to render methods (cherry picked from commit prusa3d/PrusaSlicer@e3d5cd445c7ad74ceaa4e3872ec512a64cb074b8) --- src/slic3r/GUI/Gizmos/GLGizmoBase.cpp | 3 +-- src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp | 19 +++++++++++++++---- src/slic3r/GUI/Gizmos/GLGizmoPainterBase.hpp | 5 +++-- src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp | 19 +------------------ src/slic3r/GUI/Gizmos/GLGizmoRotate.hpp | 3 +-- 5 files changed, 21 insertions(+), 28 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoBase.cpp b/src/slic3r/GUI/Gizmos/GLGizmoBase.cpp index 32308233cac..849470f3817 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoBase.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoBase.cpp @@ -149,8 +149,7 @@ void GLGizmoBase::set_icon_filename(const std::string &filename) { void GLGizmoBase::set_hover_id(int id) { - if (m_grabbers.empty() || (id < (int)m_grabbers.size())) - { + if (m_grabbers.empty() || id < (int)m_grabbers.size()) { m_hover_id = id; on_set_hover_id(); } diff --git a/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp b/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp index 97136491f47..8327402c93a 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp @@ -18,17 +18,21 @@ namespace Slic3r::GUI { +std::shared_ptr GLGizmoPainterBase::s_sphere = nullptr; GLGizmoPainterBase::GLGizmoPainterBase(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id) : GLGizmoBase(parent, icon_filename, sprite_id) { - // Make sphere and save it into a vertex buffer. - m_vbo_sphere.load_its_flat_shading(its_make_sphere(1., (2*M_PI)/24.)); - m_vbo_sphere.finalize_geometry(true); m_vertical_only = false; m_horizontal_only = false; } +GLGizmoPainterBase::~GLGizmoPainterBase() +{ + if (s_sphere != nullptr && s_sphere->has_VBOs()) + s_sphere->release_geometry(); +} + void GLGizmoPainterBase::set_painter_gizmo_data(const Selection& selection) { if (m_state != On) @@ -236,6 +240,12 @@ void GLGizmoPainterBase::render_cursor_circle() void GLGizmoPainterBase::render_cursor_sphere(const Transform3d& trafo) const { + if (s_sphere == nullptr) { + s_sphere = std::make_shared(); + s_sphere->load_its_flat_shading(its_make_sphere(1.0, double(PI) / 12.0)); + s_sphere->finalize_geometry(true); + } + const Transform3d complete_scaling_matrix_inverse = Geometry::Transformation(trafo).get_matrix(true, true, false, true).inverse(); const bool is_left_handed = Geometry::Transformation(trafo).is_left_handed(); @@ -257,7 +267,8 @@ void GLGizmoPainterBase::render_cursor_sphere(const Transform3d& trafo) const render_color = this->get_cursor_sphere_right_button_color(); glsafe(::glColor4fv(render_color.data())); - m_vbo_sphere.render(); + assert(s_sphere != nullptr); + s_sphere->render(); if (is_left_handed) glFrontFace(GL_CCW); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.hpp b/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.hpp index d953c5653ca..2410a87fdc8 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.hpp @@ -12,6 +12,7 @@ #include #include +#include namespace Slic3r::GUI { @@ -217,7 +218,7 @@ class GLGizmoPainterBase : public GLGizmoBase void on_render_for_picking() override {} public: GLGizmoPainterBase(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id); - ~GLGizmoPainterBase() override = default; + virtual ~GLGizmoPainterBase() override; virtual void set_painter_gizmo_data(const Selection& selection); virtual bool gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_position, bool shift_down, bool alt_down, bool control_down); @@ -341,7 +342,7 @@ class GLGizmoPainterBase : public GLGizmoBase const Camera& camera, const std::vector& trafo_matrices) const; - GLIndexedVertexArray m_vbo_sphere; + static std::shared_ptr s_sphere; bool m_internal_stack_active = false; bool m_schedule_update = false; diff --git a/src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp b/src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp index a4a603deecb..ce6b894cb71 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp @@ -31,20 +31,6 @@ GLGizmoRotate::GLGizmoRotate(GLCanvas3D& parent, GLGizmoRotate::Axis axis) , m_axis(axis) {} -GLGizmoRotate::GLGizmoRotate(const GLGizmoRotate& other) - : GLGizmoBase(other.m_parent, other.m_icon_filename, other.m_sprite_id) - , m_axis(other.m_axis) - , m_angle(other.m_angle) - , m_center(other.m_center) - , m_radius(other.m_radius) - , m_snap_coarse_in_radius(other.m_snap_coarse_in_radius) - , m_snap_coarse_out_radius(other.m_snap_coarse_out_radius) - , m_snap_fine_in_radius(other.m_snap_fine_in_radius) - , m_snap_fine_out_radius(other.m_snap_fine_out_radius) -{ -} - - void GLGizmoRotate::set_angle(double angle) { if (std::abs(angle - 2.0 * double(PI)) < EPSILON) @@ -513,13 +499,10 @@ Vec3d GLGizmoRotate::mouse_position_in_local_plane(const Linef3& mouse_ray, cons //BBS: GUI refactor: add obj manipulation GLGizmoRotate3D::GLGizmoRotate3D(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id, GizmoObjectManipulation* obj_manipulation) : GLGizmoBase(parent, icon_filename, sprite_id) + , m_gizmos({ GLGizmoRotate(parent, GLGizmoRotate::X), GLGizmoRotate(parent, GLGizmoRotate::Y), GLGizmoRotate(parent, GLGizmoRotate::Z) }) //BBS: GUI refactor: add obj manipulation , m_object_manipulation(obj_manipulation) { - m_gizmos.emplace_back(parent, GLGizmoRotate::X); - m_gizmos.emplace_back(parent, GLGizmoRotate::Y); - m_gizmos.emplace_back(parent, GLGizmoRotate::Z); - for (unsigned int i = 0; i < 3; ++i) { m_gizmos[i].set_group_id(i); } diff --git a/src/slic3r/GUI/Gizmos/GLGizmoRotate.hpp b/src/slic3r/GUI/Gizmos/GLGizmoRotate.hpp index 61ff0e20a0a..4bd7a6877ef 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoRotate.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoRotate.hpp @@ -57,7 +57,6 @@ class GLGizmoRotate : public GLGizmoBase public: GLGizmoRotate(GLCanvas3D& parent, Axis axis); - GLGizmoRotate(const GLGizmoRotate& other); virtual ~GLGizmoRotate() = default; double get_angle() const { return m_angle; } @@ -94,7 +93,7 @@ class GLGizmoRotate3D : public GLGizmoBase { // BBS: change to protected for subclass access protected: - std::vector m_gizmos; + std::array m_gizmos; //BBS: add size adjust related GizmoObjectManipulation* m_object_manipulation; From baa575b5aa23d58c0e018e41c8da23f2a17aacb7 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Sun, 22 Oct 2023 22:39:08 +0800 Subject: [PATCH 17/99] Tech ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL - Replace GLIndexedVertexArray with GLModel: TriangleSelectorGUI::m_iva_enforcers TriangleSelectorGUI::m_iva_blockers TriangleSelectorGUI::m_iva_seed_fills TriangleSelectorGUI::m_varrays GLGizmoPainterBase::s_sphere (cherry picked from commit prusa3d/PrusaSlicer@8916a0082114c9ebcb7a45ca135a22874fd43c39) --- src/slic3r/GUI/GLModel.cpp | 4 +- src/slic3r/GUI/GLModel.hpp | 2 + src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.hpp | 1 + src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp | 145 +++++++++++-------- src/slic3r/GUI/Gizmos/GLGizmoPainterBase.hpp | 14 +- 5 files changed, 100 insertions(+), 66 deletions(-) diff --git a/src/slic3r/GUI/GLModel.cpp b/src/slic3r/GUI/GLModel.cpp index b34a1811250..64471f3f26f 100644 --- a/src/slic3r/GUI/GLModel.cpp +++ b/src/slic3r/GUI/GLModel.cpp @@ -561,8 +561,8 @@ void GLModel::render() const Geometry& data = m_render_data.geometry; - GLenum mode = get_primitive_mode(data.format); - GLenum index_type = get_index_type(data.format); + const GLenum mode = get_primitive_mode(data.format); + const GLenum index_type = get_index_type(data.format); const size_t vertex_stride_bytes = Geometry::vertex_stride_bytes(data.format); const bool position = Geometry::has_position(data.format); diff --git a/src/slic3r/GUI/GLModel.hpp b/src/slic3r/GUI/GLModel.hpp index d81290234f2..f1b9279fd6a 100644 --- a/src/slic3r/GUI/GLModel.hpp +++ b/src/slic3r/GUI/GLModel.hpp @@ -86,6 +86,8 @@ namespace GUI { unsigned int extract_uint_index(size_t id) const; unsigned short extract_ushort_index(size_t id) const; + bool is_empty() const { return vertices.empty() || indices.empty(); } + size_t vertices_count() const { return vertices.size() / vertex_stride_floats(format); } size_t indices_count() const { return indices.size() / index_stride_bytes(format); } diff --git a/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.hpp b/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.hpp index 23e782fa1ce..f9a5c375721 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.hpp @@ -5,6 +5,7 @@ //BBS #include "libslic3r/Print.hpp" #include "libslic3r/ObjectID.hpp" +#include "slic3r/GUI/3DScene.hpp" #include diff --git a/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp b/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp index 8327402c93a..a3c3283250a 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp @@ -18,7 +18,7 @@ namespace Slic3r::GUI { -std::shared_ptr GLGizmoPainterBase::s_sphere = nullptr; +std::shared_ptr GLGizmoPainterBase::s_sphere = nullptr; GLGizmoPainterBase::GLGizmoPainterBase(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id) : GLGizmoBase(parent, icon_filename, sprite_id) @@ -29,8 +29,8 @@ GLGizmoPainterBase::GLGizmoPainterBase(GLCanvas3D& parent, const std::string& ic GLGizmoPainterBase::~GLGizmoPainterBase() { - if (s_sphere != nullptr && s_sphere->has_VBOs()) - s_sphere->release_geometry(); + if (s_sphere != nullptr) + s_sphere.reset(); } void GLGizmoPainterBase::set_painter_gizmo_data(const Selection& selection) @@ -241,11 +241,14 @@ void GLGizmoPainterBase::render_cursor_circle() void GLGizmoPainterBase::render_cursor_sphere(const Transform3d& trafo) const { if (s_sphere == nullptr) { - s_sphere = std::make_shared(); - s_sphere->load_its_flat_shading(its_make_sphere(1.0, double(PI) / 12.0)); - s_sphere->finalize_geometry(true); + s_sphere = std::make_shared(); + s_sphere->init_from(its_make_sphere(1.0, double(PI) / 12.0)); } + GLShaderProgram* shader = wxGetApp().get_shader("flat"); + if (shader == nullptr) + return; + const Transform3d complete_scaling_matrix_inverse = Geometry::Transformation(trafo).get_matrix(true, true, false, true).inverse(); const bool is_left_handed = Geometry::Transformation(trafo).is_left_handed(); @@ -265,11 +268,13 @@ void GLGizmoPainterBase::render_cursor_sphere(const Transform3d& trafo) const render_color = this->get_cursor_sphere_left_button_color(); else if (m_button_down == Button::Right) render_color = this->get_cursor_sphere_right_button_color(); - glsafe(::glColor4fv(render_color.data())); + shader->start_using(); assert(s_sphere != nullptr); + s_sphere->set_color(render_color); s_sphere->render(); + shader->stop_using(); if (is_left_handed) glFrontFace(GL_CCW); @@ -1066,19 +1071,16 @@ void TriangleSelectorGUI::render(ImGuiWrapper* imgui) shader->set_uniform("offset_depth_buffer", true); for (auto iva : {std::make_pair(&m_iva_enforcers, enforcers_color), std::make_pair(&m_iva_blockers, blockers_color)}) { - if (iva.first->has_VBOs()) { - shader->set_uniform("uniform_color", iva.second); - iva.first->render(); - } + iva.first->set_color(iva.second); + iva.first->render(); } - for (auto &iva : m_iva_seed_fills) - if (iva.has_VBOs()) { - size_t color_idx = &iva - &m_iva_seed_fills.front(); - const ColorRGBA& color = TriangleSelectorGUI::get_seed_fill_color(color_idx == 1 ? enforcers_color : - color_idx == 2 ? blockers_color : - GLVolume::NEUTRAL_COLOR); - shader->set_uniform("uniform_color", color); + for (auto& iva : m_iva_seed_fills) { + size_t color_idx = &iva - &m_iva_seed_fills.front(); + const ColorRGBA& color = TriangleSelectorGUI::get_seed_fill_color(color_idx == 1 ? enforcers_color : + color_idx == 2 ? blockers_color : + GLVolume::NEUTRAL_COLOR); + iva.set_color(color); iva.render(); } @@ -1110,11 +1112,21 @@ void TriangleSelectorGUI::update_render_data() int blc_cnt = 0; std::vector seed_fill_cnt(m_iva_seed_fills.size(), 0); - for (auto *iva : {&m_iva_enforcers, &m_iva_blockers}) - iva->release_geometry(); + for (auto* iva : { &m_iva_enforcers, &m_iva_blockers }) { + iva->reset(); + } + + for (auto& iva : m_iva_seed_fills) { + iva.reset(); + } - for (auto &iva : m_iva_seed_fills) - iva.release_geometry(); + GLModel::Geometry iva_enforcers_data; + iva_enforcers_data.format = { GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3N3, GLModel::Geometry::EIndexType::UINT }; + GLModel::Geometry iva_blockers_data; + iva_blockers_data.format = { GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3N3, GLModel::Geometry::EIndexType::UINT }; + std::array iva_seed_fills_data; + for (auto& data : iva_seed_fills_data) + data.format = { GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3N3, GLModel::Geometry::EIndexType::UINT }; for (const Triangle &tr : m_triangles) { bool is_valid = tr.valid(); @@ -1125,9 +1137,9 @@ void TriangleSelectorGUI::update_render_data() continue; int tr_state = int(tr.get_state()); - GLIndexedVertexArray &iva = tr.is_selected_by_seed_fill() ? m_iva_seed_fills[tr_state] : - tr.get_state() == EnforcerBlockerType::ENFORCER ? m_iva_enforcers : - m_iva_blockers; + GLModel::Geometry &iva = tr.is_selected_by_seed_fill() ? iva_seed_fills_data[tr_state] : + tr.get_state() == EnforcerBlockerType::ENFORCER ? iva_enforcers_data : + iva_blockers_data; int &cnt = tr.is_selected_by_seed_fill() ? seed_fill_cnt[tr_state] : tr.get_state() == EnforcerBlockerType::ENFORCER ? enf_cnt : blc_cnt; @@ -1137,18 +1149,21 @@ void TriangleSelectorGUI::update_render_data() //FIXME the normal may likely be pulled from m_triangle_selectors, but it may not be worth the effort // or the current implementation may be more cache friendly. const Vec3f n = (v1 - v0).cross(v2 - v1).normalized(); - iva.push_geometry(v0, n); - iva.push_geometry(v1, n); - iva.push_geometry(v2, n); - iva.push_triangle(cnt, cnt + 1, cnt + 2); + iva.add_vertex(v0, n); + iva.add_vertex(v1, n); + iva.add_vertex(v2, n); + iva.add_uint_triangle((unsigned int)cnt, (unsigned int)cnt + 1, (unsigned int)cnt + 2); cnt += 3; } - for (auto *iva : {&m_iva_enforcers, &m_iva_blockers}) - iva->finalize_geometry(true); - - for (auto &iva : m_iva_seed_fills) - iva.finalize_geometry(true); + if (!iva_enforcers_data.is_empty()) + m_iva_enforcers.init_from(std::move(iva_enforcers_data)); + if (!iva_blockers_data.is_empty()) + m_iva_blockers.init_from(std::move(iva_blockers_data)); + for (size_t i = 0; i < m_iva_seed_fills.size(); ++i) { + if (!iva_seed_fills_data[i].is_empty()) + m_iva_seed_fills[i].init_from(std::move(iva_seed_fills_data[i])); + } m_paint_contour.release_geometry(); std::vector contour_edges = this->get_seed_fill_contour(); @@ -1689,59 +1704,73 @@ void TriangleSelectorGUI::render_debug(ImGuiWrapper* imgui) }; for (auto& va : m_varrays) - va.release_geometry(); + va.reset(); std::array cnts; ::glScalef(1.01f, 1.01f, 1.01f); + std::array varrays_data; + for (auto& data : varrays_data) + data.format = { GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3N3, GLModel::Geometry::EIndexType::UINT }; + for (int tr_id=0; tr_idpush_geometry(double(m_vertices[tr.verts_idxs[i]].v[0]), - double(m_vertices[tr.verts_idxs[i]].v[1]), - double(m_vertices[tr.verts_idxs[i]].v[2]), - 0., 0., 1.); - va->push_triangle(*cnt, - *cnt+1, - *cnt+2); + for (int i = 0; i < 3; ++i) { + va->add_vertex(m_vertices[tr.verts_idxs[i]].v, Vec3f(0.0f, 0.0f, 1.0f)); + } + va->add_uint_triangle((unsigned int)*cnt, (unsigned int)*cnt + 1, (unsigned int)*cnt + 2); *cnt += 3; } + for (int i = 0; i < 3; ++i) { + if (!varrays_data[i].is_empty()) + m_varrays[i].init_from(std::move(varrays_data[i])); + } + + GLShaderProgram* curr_shader = wxGetApp().get_current_shader(); + if (curr_shader != nullptr) + curr_shader->stop_using(); + + GLShaderProgram* shader = wxGetApp().get_shader("flat"); + if (shader != nullptr) { + shader->start_using(); + ::glPolygonMode( GL_FRONT_AND_BACK, GL_LINE ); for (vtype i : {ORIGINAL, SPLIT, INVALID}) { - GLIndexedVertexArray& va = m_varrays[i]; - va.finalize_geometry(true); - if (va.has_VBOs()) { - switch (i) { - case ORIGINAL : ::glColor3f(0.f, 0.f, 1.f); break; - case SPLIT : ::glColor3f(1.f, 0.f, 0.f); break; - case INVALID : ::glColor3f(1.f, 1.f, 0.f); break; - } - va.render(); + GLModel& va = m_varrays[i]; + switch (i) { + case ORIGINAL: va.set_color({ 0.0f, 0.0f, 1.0f, 1.0f }); break; + case SPLIT: va.set_color({ 1.0f, 0.0f, 0.0f, 1.0f }); break; + case INVALID: va.set_color({ 1.0f, 1.0f, 0.0f, 1.0f }); break; } + va.render(); } ::glPolygonMode( GL_FRONT_AND_BACK, GL_FILL ); -} -#endif + shader->stop_using(); + } + if (curr_shader != nullptr) + curr_shader->start_using(); +} +#endif // PRUSASLICER_TRIANGLE_SELECTOR_DEBUG } // namespace Slic3r::GUI diff --git a/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.hpp b/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.hpp index 2410a87fdc8..34ea73f5363 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.hpp @@ -3,7 +3,7 @@ #include "GLGizmoBase.hpp" -#include "slic3r/GUI/3DScene.hpp" +#include "slic3r/GUI/GLModel.hpp" #include "libslic3r/ObjectID.hpp" #include "libslic3r/TriangleSelector.hpp" @@ -104,10 +104,12 @@ class TriangleSelectorGUI : public TriangleSelector { private: void update_render_data(); - GLIndexedVertexArray m_iva_enforcers; - GLIndexedVertexArray m_iva_blockers; - std::array m_iva_seed_fills; - std::array m_varrays; + GLModel m_iva_enforcers; + GLModel m_iva_blockers; + std::array m_iva_seed_fills; +#ifdef PRUSASLICER_TRIANGLE_SELECTOR_DEBUG + std::array m_varrays; +#endif // PRUSASLICER_TRIANGLE_SELECTOR_DEBUG protected: GLPaintContour m_paint_contour; @@ -342,7 +344,7 @@ class GLGizmoPainterBase : public GLGizmoBase const Camera& camera, const std::vector& trafo_matrices) const; - static std::shared_ptr s_sphere; + static std::shared_ptr s_sphere; bool m_internal_stack_active = false; bool m_schedule_update = false; From fc1c8c25659354128b49fcbbe9bbe279a8d20428 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Mon, 23 Oct 2023 10:52:49 +0800 Subject: [PATCH 18/99] Tech ENABLE_GLBEGIN_GLEND_REMOVAL - Removed Slic3r::GUI::GLPaintContour from GLGizmoPainterBase.hpp/.cpp and replaced with GLModel (cherry picked from commit prusa3d/PrusaSlicer@df3d6703577041714da55ea13f21db18384b40fe) --- src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp | 195 ++++++------------- src/slic3r/GUI/Gizmos/GLGizmoPainterBase.hpp | 44 +---- 2 files changed, 68 insertions(+), 171 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp b/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp index a3c3283250a..4ef92a7ac23 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp @@ -255,7 +255,7 @@ void GLGizmoPainterBase::render_cursor_sphere(const Transform3d& trafo) const glsafe(::glPushMatrix()); glsafe(::glMultMatrixd(trafo.data())); // Inverse matrix of the instance scaling is applied so that the mark does not scale with the object. - glsafe(::glTranslatef(m_rr.hit(0), m_rr.hit(1), m_rr.hit(2))); + glsafe(::glTranslatef(m_rr.hit.x(), m_rr.hit.y(), m_rr.hit.z())); glsafe(::glMultMatrixd(complete_scaling_matrix_inverse.data())); glsafe(::glScaled(m_cursor_radius, m_cursor_radius, m_cursor_radius)); @@ -1076,28 +1076,16 @@ void TriangleSelectorGUI::render(ImGuiWrapper* imgui) } for (auto& iva : m_iva_seed_fills) { - size_t color_idx = &iva - &m_iva_seed_fills.front(); - const ColorRGBA& color = TriangleSelectorGUI::get_seed_fill_color(color_idx == 1 ? enforcers_color : - color_idx == 2 ? blockers_color : - GLVolume::NEUTRAL_COLOR); - iva.set_color(color); - iva.render(); - } - - if (m_paint_contour.has_VBO()) { - ScopeGuard guard_gouraud([shader]() { shader->start_using(); }); - shader->stop_using(); - - auto *contour_shader = wxGetApp().get_shader("mm_contour"); - contour_shader->start_using(); - - glsafe(::glDepthFunc(GL_LEQUAL)); - m_paint_contour.render(); - glsafe(::glDepthFunc(GL_LESS)); - - contour_shader->stop_using(); + size_t color_idx = &iva - &m_iva_seed_fills.front(); + const ColorRGBA& color = TriangleSelectorGUI::get_seed_fill_color(color_idx == 1 ? enforcers_color : + color_idx == 2 ? blockers_color : + GLVolume::NEUTRAL_COLOR); + iva.set_color(color); + iva.render(); } + render_paint_contour(); + #ifdef PRUSASLICER_TRIANGLE_SELECTOR_DEBUG if (imgui) render_debug(imgui); @@ -1165,24 +1153,7 @@ void TriangleSelectorGUI::update_render_data() m_iva_seed_fills[i].init_from(std::move(iva_seed_fills_data[i])); } - m_paint_contour.release_geometry(); - std::vector contour_edges = this->get_seed_fill_contour(); - m_paint_contour.contour_vertices.reserve(contour_edges.size() * 6); - for (const Vec2i &edge : contour_edges) { - m_paint_contour.contour_vertices.emplace_back(m_vertices[edge(0)].v.x()); - m_paint_contour.contour_vertices.emplace_back(m_vertices[edge(0)].v.y()); - m_paint_contour.contour_vertices.emplace_back(m_vertices[edge(0)].v.z()); - - m_paint_contour.contour_vertices.emplace_back(m_vertices[edge(1)].v.x()); - m_paint_contour.contour_vertices.emplace_back(m_vertices[edge(1)].v.y()); - m_paint_contour.contour_vertices.emplace_back(m_vertices[edge(1)].v.z()); - } - - m_paint_contour.contour_indices.assign(m_paint_contour.contour_vertices.size() / 3, 0); - std::iota(m_paint_contour.contour_indices.begin(), m_paint_contour.contour_indices.end(), 0); - m_paint_contour.contour_indices_size = m_paint_contour.contour_indices.size(); - - m_paint_contour.finalize_geometry(); + update_paint_contour(); } // BBS @@ -1195,8 +1166,10 @@ float TriangleSelectorPatch::gap_area = TriangleSelectorPatch::GapAreaMin; void TriangleSelectorPatch::render(ImGuiWrapper* imgui) { - if (m_update_render_data) + if (m_update_render_data) { update_render_data(); + m_update_render_data = false; + } auto* shader = wxGetApp().get_current_shader(); if (!shader) @@ -1239,22 +1212,7 @@ void TriangleSelectorPatch::render(ImGuiWrapper* imgui) } } - if (m_paint_contour.has_VBO()) - { - ScopeGuard guard_mm_gouraud([shader]() { shader->start_using(); }); - shader->stop_using(); - - auto* contour_shader = wxGetApp().get_shader("mm_contour"); - contour_shader->start_using(); - - glsafe(::glDepthFunc(GL_LEQUAL)); - m_paint_contour.render(); - glsafe(::glDepthFunc(GL_LESS)); - - contour_shader->stop_using(); - } - - m_update_render_data = false; + render_paint_contour(); } void TriangleSelectorPatch::update_triangles_per_type() @@ -1477,25 +1435,7 @@ void TriangleSelectorPatch::update_render_data() } //BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(", before paint_contour"); - - m_paint_contour.release_geometry(); - std::vector contour_edges = this->get_seed_fill_contour(); - m_paint_contour.contour_vertices.reserve(contour_edges.size() * 6); - for (const Vec2i& edge : contour_edges) { - m_paint_contour.contour_vertices.emplace_back(m_vertices[edge(0)].v.x()); - m_paint_contour.contour_vertices.emplace_back(m_vertices[edge(0)].v.y()); - m_paint_contour.contour_vertices.emplace_back(m_vertices[edge(0)].v.z()); - - m_paint_contour.contour_vertices.emplace_back(m_vertices[edge(1)].v.x()); - m_paint_contour.contour_vertices.emplace_back(m_vertices[edge(1)].v.y()); - m_paint_contour.contour_vertices.emplace_back(m_vertices[edge(1)].v.z()); - } - - m_paint_contour.contour_indices.assign(m_paint_contour.contour_vertices.size() / 3, 0); - std::iota(m_paint_contour.contour_indices.begin(), m_paint_contour.contour_indices.end(), 0); - m_paint_contour.contour_indices_size = m_paint_contour.contour_indices.size(); - - m_paint_contour.finalize_geometry(); + update_paint_contour(); //BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(", exit"); } @@ -1610,64 +1550,6 @@ void TriangleSelectorPatch::finalize_triangle_indices() } } -void GLPaintContour::render() const -{ - assert(this->m_contour_VBO_id != 0); - assert(this->m_contour_EBO_id != 0); - - glsafe(::glLineWidth(4.0f)); - - glsafe(::glBindBuffer(GL_ARRAY_BUFFER, this->m_contour_VBO_id)); - glsafe(::glVertexPointer(3, GL_FLOAT, 3 * sizeof(float), nullptr)); - - glsafe(::glEnableClientState(GL_VERTEX_ARRAY)); - - if (this->contour_indices_size > 0) { - glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, this->m_contour_EBO_id)); - glsafe(::glDrawElements(GL_LINES, GLsizei(this->contour_indices_size), GL_UNSIGNED_INT, nullptr)); - glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0)); - } - - glsafe(::glDisableClientState(GL_VERTEX_ARRAY)); - - glsafe(::glBindBuffer(GL_ARRAY_BUFFER, 0)); -} - -void GLPaintContour::finalize_geometry() -{ - assert(this->m_contour_VBO_id == 0); - assert(this->m_contour_EBO_id == 0); - - if (!this->contour_vertices.empty()) { - glsafe(::glGenBuffers(1, &this->m_contour_VBO_id)); - glsafe(::glBindBuffer(GL_ARRAY_BUFFER, this->m_contour_VBO_id)); - glsafe(::glBufferData(GL_ARRAY_BUFFER, this->contour_vertices.size() * sizeof(float), this->contour_vertices.data(), GL_STATIC_DRAW)); - glsafe(::glBindBuffer(GL_ARRAY_BUFFER, 0)); - this->contour_vertices.clear(); - } - - if (!this->contour_indices.empty()) { - glsafe(::glGenBuffers(1, &this->m_contour_EBO_id)); - glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, this->m_contour_EBO_id)); - glsafe(::glBufferData(GL_ELEMENT_ARRAY_BUFFER, this->contour_indices.size() * sizeof(unsigned int), this->contour_indices.data(), GL_STATIC_DRAW)); - glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0)); - this->contour_indices.clear(); - } -} - -void GLPaintContour::release_geometry() -{ - if (this->m_contour_VBO_id) { - glsafe(::glDeleteBuffers(1, &this->m_contour_VBO_id)); - this->m_contour_VBO_id = 0; - } - if (this->m_contour_EBO_id) { - glsafe(::glDeleteBuffers(1, &this->m_contour_EBO_id)); - this->m_contour_EBO_id = 0; - } - this->clear(); -} - #ifdef PRUSASLICER_TRIANGLE_SELECTOR_DEBUG void TriangleSelectorGUI::render_debug(ImGuiWrapper* imgui) { @@ -1773,4 +1655,51 @@ void TriangleSelectorGUI::render_debug(ImGuiWrapper* imgui) } #endif // PRUSASLICER_TRIANGLE_SELECTOR_DEBUG +void TriangleSelectorGUI::update_paint_contour() +{ + m_paint_contour.reset(); + + GLModel::Geometry init_data; + const std::vector contour_edges = this->get_seed_fill_contour(); + const GLModel::Geometry::EIndexType index_type = (2 * contour_edges.size() < 65536) ? GLModel::Geometry::EIndexType::USHORT : GLModel::Geometry::EIndexType::UINT; + init_data.format = { GLModel::Geometry::EPrimitiveType::Lines, GLModel::Geometry::EVertexLayout::P3, index_type }; + init_data.reserve_vertices(2 * contour_edges.size()); + init_data.reserve_indices(2 * contour_edges.size()); + // vertices + indices + unsigned int vertices_count = 0; + for (const Vec2i& edge : contour_edges) { + init_data.add_vertex(m_vertices[edge(0)].v); + init_data.add_vertex(m_vertices[edge(1)].v); + vertices_count += 2; + if (index_type == GLModel::Geometry::EIndexType::USHORT) + init_data.add_ushort_line((unsigned short)vertices_count - 2, (unsigned short)vertices_count - 1); + else + init_data.add_uint_line(vertices_count - 2, vertices_count - 1); + } + + if (!init_data.is_empty()) + m_paint_contour.init_from(std::move(init_data)); +} + +void TriangleSelectorGUI::render_paint_contour() +{ + auto* curr_shader = wxGetApp().get_current_shader(); + if (curr_shader != nullptr) + curr_shader->stop_using(); + + auto* contour_shader = wxGetApp().get_shader("mm_contour"); + if (contour_shader != nullptr) { + contour_shader->start_using(); + + glsafe(::glDepthFunc(GL_LEQUAL)); + m_paint_contour.render(); + glsafe(::glDepthFunc(GL_LESS)); + + contour_shader->stop_using(); + } + + if (curr_shader != nullptr) + curr_shader->start_using(); +} + } // namespace Slic3r::GUI diff --git a/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.hpp b/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.hpp index 34ea73f5363..c4f2cb5e29c 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.hpp @@ -28,42 +28,6 @@ enum class PainterGizmoType { MMU_SEGMENTATION }; -class GLPaintContour -{ -public: - GLPaintContour() = default; - - void render() const; - - inline bool has_VBO() const { return this->m_contour_EBO_id != 0; } - - // Release the geometry data, release OpenGL VBOs. - void release_geometry(); - - // Finalize the initialization of the contour geometry and the indices, upload both to OpenGL VBO objects - // and possibly releasing it if it has been loaded into the VBOs. - void finalize_geometry(); - - void clear() - { - this->contour_vertices.clear(); - this->contour_indices.clear(); - this->contour_indices_size = 0; - } - - std::vector contour_vertices; - std::vector contour_indices; - - // When the triangle indices are loaded into the graphics card as Vertex Buffer Objects, - // the above mentioned std::vectors are cleared and the following variables keep their original length. - size_t contour_indices_size{0}; - - // IDs of the Vertex Array Objects, into which the geometry has been loaded. - // Zero if the VBOs are not sent to GPU yet. - GLuint m_contour_VBO_id{0}; - GLuint m_contour_EBO_id{0}; -}; - class TriangleSelectorGUI : public TriangleSelector { public: explicit TriangleSelectorGUI(const TriangleMesh& mesh, float edge_limit = 0.6f) @@ -82,7 +46,7 @@ class TriangleSelectorGUI : public TriangleSelector { { m_update_render_data = true; m_paint_changed |= paint_changed; - }; + } // BBS static ColorRGBA enforcers_color; @@ -112,7 +76,11 @@ class TriangleSelectorGUI : public TriangleSelector { #endif // PRUSASLICER_TRIANGLE_SELECTOR_DEBUG protected: - GLPaintContour m_paint_contour; + GLModel m_paint_contour; + + void update_paint_contour(); + void render_paint_contour(); + bool m_need_wireframe {false}; }; From 8107057e17d0c00a5ee9439244ee6c0f0d61e2d4 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Mon, 23 Oct 2023 11:11:25 +0800 Subject: [PATCH 19/99] Tech ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL - Replace GLIndexedVertexArray with GLModel: MeshClipper::m_vertex_array (cherry picked from commit prusa3d/PrusaSlicer@be6922795d6408a31050e4a3878aacb11334f83b) --- src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp | 17 +++------ src/slic3r/GUI/Gizmos/GLGizmosCommon.hpp | 1 + src/slic3r/GUI/MeshUtils.cpp | 46 ++++++++++++++++++------ src/slic3r/GUI/MeshUtils.hpp | 9 ++--- src/slic3r/Utils/UndoRedo.cpp | 1 + 5 files changed, 47 insertions(+), 27 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp b/src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp index fc6decbaa8e..392a2db878c 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp @@ -218,15 +218,9 @@ void InstancesHider::render_cut() const clipper->set_limiting_plane(ClippingPlane::ClipsNothing()); glsafe(::glPushMatrix()); - if (mv->is_model_part()) - glsafe(::glColor3f(0.8f, 0.3f, 0.0f)); - else { - const ColorRGBA color = color_from_model_volume(*mv); - glsafe(::glColor4fv(color.data())); - } glsafe(::glPushAttrib(GL_DEPTH_TEST)); glsafe(::glDisable(GL_DEPTH_TEST)); - clipper->render_cut(); + clipper->render_cut(mv->is_model_part() ? ColorRGBA(0.8f, 0.3f, 0.0f, 1.0f) : color_from_model_volume(*mv)); glsafe(::glPopAttrib()); glsafe(::glPopMatrix()); @@ -435,8 +429,7 @@ void ObjectClipper::render_cut() const clipper->set_limiting_plane(ClippingPlane(Vec3d::UnitZ(), -SINKING_Z_THRESHOLD)); glsafe(::glPushMatrix()); // BBS - glsafe(::glColor3f(0.25f, 0.25f, 0.25f)); - clipper->render_cut(); + clipper->render_cut({ 0.25f, 0.25f, 0.25f, 1.0f }); glsafe(::glPopMatrix()); ++clipper_id; @@ -584,8 +577,7 @@ void SupportsClipper::render_cut() const m_clipper->set_transformation(supports_trafo); glsafe(::glPushMatrix()); - glsafe(::glColor3f(1.0f, 0.f, 0.37f)); - m_clipper->render_cut(); + m_clipper->render_cut({ 1.0f, 0.f, 0.37f, 1.0f }); glsafe(::glPopMatrix()); } @@ -734,8 +726,7 @@ void ModelObjectsClipper::render_cut() const clipper->set_transformation(trafo); glsafe(::glPushMatrix()); // BBS - glsafe(::glColor3f(0.25f, 0.25f, 0.25f)); - clipper->render_cut(); + clipper->render_cut({0.25f, 0.25f, 0.25f, 1.0f}); glsafe(::glPopMatrix()); ++clipper_id; diff --git a/src/slic3r/GUI/Gizmos/GLGizmosCommon.hpp b/src/slic3r/GUI/Gizmos/GLGizmosCommon.hpp index f4211dfb59c..6c42052cd5e 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosCommon.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosCommon.hpp @@ -4,6 +4,7 @@ #include #include +#include "slic3r/GUI/3DScene.hpp" #include "slic3r/GUI/MeshUtils.hpp" #include "libslic3r/SLA/Hollowing.hpp" diff --git a/src/slic3r/GUI/MeshUtils.cpp b/src/slic3r/GUI/MeshUtils.cpp index cd9a617f4bb..64d9be08269 100644 --- a/src/slic3r/GUI/MeshUtils.cpp +++ b/src/slic3r/GUI/MeshUtils.cpp @@ -6,6 +6,7 @@ #include "libslic3r/ClipperUtils.hpp" #include "libslic3r/Model.hpp" +#include "slic3r/GUI/GUI_App.hpp" #include "slic3r/GUI/Camera.hpp" #include @@ -67,13 +68,25 @@ void MeshClipper::set_transformation(const Geometry::Transformation& trafo) -void MeshClipper::render_cut() +void MeshClipper::render_cut(const ColorRGBA& color) { if (! m_triangles_valid) recalculate_triangles(); - if (m_vertex_array.has_VBOs()) - m_vertex_array.render(); + GLShaderProgram* curr_shader = wxGetApp().get_current_shader(); + if (curr_shader != nullptr) + curr_shader->stop_using(); + + GLShaderProgram* shader = wxGetApp().get_shader("flat"); + if (shader != nullptr) { + shader->start_using(); + m_model.set_color(color); + m_model.render(); + shader->stop_using(); + } + + if (curr_shader != nullptr) + curr_shader->start_using(); } bool MeshClipper::is_projection_inside_cut(const Vec3d &point_in) const @@ -189,15 +202,28 @@ void MeshClipper::recalculate_triangles() tr.pretranslate(0.001 * m_plane.get_normal().normalized()); // to avoid z-fighting - m_vertex_array.release_geometry(); - for (auto it=m_triangles2d.cbegin(); it != m_triangles2d.cend(); it=it+3) { - m_vertex_array.push_geometry(tr * Vec3d((*(it+0))(0), (*(it+0))(1), height_mesh), up); - m_vertex_array.push_geometry(tr * Vec3d((*(it+1))(0), (*(it+1))(1), height_mesh), up); - m_vertex_array.push_geometry(tr * Vec3d((*(it+2))(0), (*(it+2))(1), height_mesh), up); + m_model.reset(); + + GLModel::Geometry init_data; + const GLModel::Geometry::EIndexType index_type = (m_triangles2d.size() < 65536) ? GLModel::Geometry::EIndexType::USHORT : GLModel::Geometry::EIndexType::UINT; + init_data.format = { GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3N3, index_type }; + init_data.reserve_vertices(m_triangles2d.size()); + init_data.reserve_indices(m_triangles2d.size()); + + // vertices + indices + for (auto it = m_triangles2d.cbegin(); it != m_triangles2d.cend(); it = it + 3) { + init_data.add_vertex((Vec3f)(tr * Vec3d((*(it + 0)).x(), (*(it + 0)).y(), height_mesh)).cast(), (Vec3f)up.cast()); + init_data.add_vertex((Vec3f)(tr * Vec3d((*(it + 1)).x(), (*(it + 1)).y(), height_mesh)).cast(), (Vec3f)up.cast()); + init_data.add_vertex((Vec3f)(tr * Vec3d((*(it + 2)).x(), (*(it + 2)).y(), height_mesh)).cast(), (Vec3f)up.cast()); const size_t idx = it - m_triangles2d.cbegin(); - m_vertex_array.push_triangle(idx, idx+1, idx+2); + if (index_type == GLModel::Geometry::EIndexType::USHORT) + init_data.add_ushort_triangle((unsigned short)idx, (unsigned short)idx + 1, (unsigned short)idx + 2); + else + init_data.add_uint_triangle((unsigned int)idx, (unsigned int)idx + 1, (unsigned int)idx + 2); } - m_vertex_array.finalize_geometry(true); + + if (!init_data.is_empty()) + m_model.init_from(std::move(init_data)); m_triangles_valid = true; } diff --git a/src/slic3r/GUI/MeshUtils.hpp b/src/slic3r/GUI/MeshUtils.hpp index 123b8a78525..db0bf1c0aaf 100644 --- a/src/slic3r/GUI/MeshUtils.hpp +++ b/src/slic3r/GUI/MeshUtils.hpp @@ -6,7 +6,7 @@ #include "libslic3r/SLA/IndexedMesh.hpp" #include "admesh/stl.h" -#include "slic3r/GUI/3DScene.hpp" +#include "slic3r/GUI/GLModel.hpp" #include @@ -69,7 +69,8 @@ class ClippingPlane // MeshClipper class cuts a mesh and is able to return a triangulated cut. -class MeshClipper { +class MeshClipper +{ public: // Inform MeshClipper about which plane we want to use to cut the mesh // This is supposed to be in world coordinates. @@ -92,7 +93,7 @@ class MeshClipper { // Render the triangulated cut. Transformation matrices should // be set in world coords. - void render_cut(); + void render_cut(const ColorRGBA& color); bool is_projection_inside_cut(const Vec3d &point) const; bool has_valid_contour() const; @@ -106,7 +107,7 @@ class MeshClipper { ClippingPlane m_plane; ClippingPlane m_limiting_plane = ClippingPlane::ClipsNothing(); std::vector m_triangles2d; - GLIndexedVertexArray m_vertex_array; + GLModel m_model; bool m_triangles_valid = false; struct CutIsland diff --git a/src/slic3r/Utils/UndoRedo.cpp b/src/slic3r/Utils/UndoRedo.cpp index 56a5172ab33..eaf90c73490 100644 --- a/src/slic3r/Utils/UndoRedo.cpp +++ b/src/slic3r/Utils/UndoRedo.cpp @@ -21,6 +21,7 @@ #include #include +#include "slic3r/GUI/3DScene.hpp" #include #ifndef NDEBUG From 12dbbf2d1c057afafe46ab3b92c29959a6ad6a4a Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Mon, 23 Oct 2023 11:23:24 +0800 Subject: [PATCH 20/99] Tech ENABLE_GLBEGIN_GLEND_REMOVAL - Another refactoring to simplify client code of GLModel::Geometry (cherry picked from commit prusa3d/PrusaSlicer@fa1ff1c35768e09fdb7270f563f62abb558cd966) --- src/slic3r/GUI/3DBed.cpp | 5 ++--- src/slic3r/GUI/GLCanvas3D.cpp | 5 ++--- src/slic3r/GUI/GLModel.cpp | 5 +++++ src/slic3r/GUI/GLModel.hpp | 12 +++++++----- src/slic3r/GUI/Gizmos/GLGizmoFlatten.cpp | 5 ++--- src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp | 5 ++--- src/slic3r/GUI/MeshUtils.cpp | 5 ++--- src/slic3r/GUI/PartPlate.cpp | 10 ++++------ 8 files changed, 26 insertions(+), 26 deletions(-) diff --git a/src/slic3r/GUI/3DBed.cpp b/src/slic3r/GUI/3DBed.cpp index 3f29fd65b98..26b6c899088 100644 --- a/src/slic3r/GUI/3DBed.cpp +++ b/src/slic3r/GUI/3DBed.cpp @@ -45,8 +45,7 @@ bool init_model_from_poly(GLModel &model, const ExPolygon &poly, float z) return false; GLModel::Geometry init_data; - const GLModel::Geometry::EIndexType index_type = (triangles.size() < 65536) ? GLModel::Geometry::EIndexType::USHORT : GLModel::Geometry::EIndexType::UINT; - init_data.format = { GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3T2, index_type }; + init_data.format = { GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3T2, GLModel::Geometry::index_type(triangles.size()) }; init_data.reserve_vertices(triangles.size()); init_data.reserve_indices(triangles.size() / 3); @@ -71,7 +70,7 @@ bool init_model_from_poly(GLModel &model, const ExPolygon &poly, float z) init_data.add_vertex(p, (Vec2f)(v - min).cwiseProduct(inv_size).eval()); ++vertices_counter; if (vertices_counter % 3 == 0) { - if (index_type == GLModel::Geometry::EIndexType::USHORT) + if (init_data.format.index_type == GLModel::Geometry::EIndexType::USHORT) init_data.add_ushort_triangle((unsigned short)vertices_counter - 3, (unsigned short)vertices_counter - 2, (unsigned short)vertices_counter - 1); else init_data.add_uint_triangle(vertices_counter - 3, vertices_counter - 2, vertices_counter - 1); diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 6c53d00b97f..c627837b4a7 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -497,8 +497,7 @@ void GLCanvas3D::LayersEditing::render_profile(const Rect& bar_rect) m_profile.profile.reset(); GLModel::Geometry init_data; - const GLModel::Geometry::EIndexType index_type = (m_layer_height_profile.size() / 2 < 65536) ? GLModel::Geometry::EIndexType::USHORT : GLModel::Geometry::EIndexType::UINT; - init_data.format = { GLModel::Geometry::EPrimitiveType::LineStrip, GLModel::Geometry::EVertexLayout::P2, index_type }; + init_data.format = { GLModel::Geometry::EPrimitiveType::LineStrip, GLModel::Geometry::EVertexLayout::P2, GLModel::Geometry::index_type(m_layer_height_profile.size() / 2) }; init_data.color = ColorRGBA::BLUE(); init_data.reserve_vertices(m_layer_height_profile.size() / 2); init_data.reserve_indices(m_layer_height_profile.size() / 2); @@ -507,7 +506,7 @@ void GLCanvas3D::LayersEditing::render_profile(const Rect& bar_rect) for (unsigned int i = 0; i < (unsigned int)m_layer_height_profile.size(); i += 2) { init_data.add_vertex(Vec2f(bar_rect.get_left() + float(m_layer_height_profile[i + 1]) * scale_x, bar_rect.get_bottom() + float(m_layer_height_profile[i]) * scale_y)); - if (index_type == GLModel::Geometry::EIndexType::USHORT) + if (init_data.format.index_type == GLModel::Geometry::EIndexType::USHORT) init_data.add_ushort_index((unsigned short)i / 2); else init_data.add_uint_index(i / 2); diff --git a/src/slic3r/GUI/GLModel.cpp b/src/slic3r/GUI/GLModel.cpp index 64471f3f26f..0cb7bfc96b7 100644 --- a/src/slic3r/GUI/GLModel.cpp +++ b/src/slic3r/GUI/GLModel.cpp @@ -327,6 +327,11 @@ size_t GLModel::Geometry::index_stride_bytes(const Format& format) }; } +GLModel::Geometry::EIndexType GLModel::Geometry::index_type(size_t vertices_count) +{ + return (vertices_count < 65536) ? EIndexType::USHORT : EIndexType::UINT; +} + bool GLModel::Geometry::has_position(const Format& format) { switch (format.vertex_layout) diff --git a/src/slic3r/GUI/GLModel.hpp b/src/slic3r/GUI/GLModel.hpp index f1b9279fd6a..98feaaad0ad 100644 --- a/src/slic3r/GUI/GLModel.hpp +++ b/src/slic3r/GUI/GLModel.hpp @@ -63,11 +63,11 @@ namespace GUI { void reserve_vertices(size_t vertices_count); void reserve_indices(size_t indices_count); - void add_vertex(const Vec2f& position); - void add_vertex(const Vec2f& position, const Vec2f& tex_coord); - void add_vertex(const Vec3f& position); - void add_vertex(const Vec3f& position, const Vec2f& tex_coord); - void add_vertex(const Vec3f& position, const Vec3f& normal); + void add_vertex(const Vec2f& position); // EVertexLayout::P2 + void add_vertex(const Vec2f& position, const Vec2f& tex_coord); // EVertexLayout::P2T2 + void add_vertex(const Vec3f& position); // EVertexLayout::P3 + void add_vertex(const Vec3f& position, const Vec2f& tex_coord); // EVertexLayout::P3T2 + void add_vertex(const Vec3f& position, const Vec3f& normal); // EVertexLayout::P3N3 void add_ushort_index(unsigned short id); void add_uint_index(unsigned int id); @@ -115,6 +115,8 @@ namespace GUI { static size_t index_stride_bytes(const Format& format); + static EIndexType index_type(size_t vertices_count); + static bool has_position(const Format& format); static bool has_normal(const Format& format); static bool has_tex_coord(const Format& format); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoFlatten.cpp b/src/slic3r/GUI/Gizmos/GLGizmoFlatten.cpp index b67b18dfc3d..71ce1097949 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoFlatten.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoFlatten.cpp @@ -337,14 +337,13 @@ void GLGizmoFlatten::update_planes() // the vertices in order, so triangulation is trivial. for (auto& plane : m_planes) { GLModel::Geometry init_data; - const GLModel::Geometry::EIndexType index_type = (plane.vertices.size() < 65536) ? GLModel::Geometry::EIndexType::USHORT : GLModel::Geometry::EIndexType::UINT; - init_data.format = { GLModel::Geometry::EPrimitiveType::TriangleFan, GLModel::Geometry::EVertexLayout::P3N3, index_type }; + init_data.format = { GLModel::Geometry::EPrimitiveType::TriangleFan, GLModel::Geometry::EVertexLayout::P3N3, GLModel::Geometry::index_type(plane.vertices.size()) }; init_data.reserve_vertices(plane.vertices.size()); init_data.reserve_indices(plane.vertices.size()); // vertices + indices for (size_t i = 0; i < plane.vertices.size(); ++i) { init_data.add_vertex((Vec3f)plane.vertices[i].cast(), (Vec3f)plane.normal.cast()); - if (index_type == GLModel::Geometry::EIndexType::USHORT) + if (init_data.format.index_type == GLModel::Geometry::EIndexType::USHORT) init_data.add_ushort_index((unsigned short)i); else init_data.add_uint_index((unsigned int)i); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp b/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp index 4ef92a7ac23..6a6919b2bea 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp @@ -1661,8 +1661,7 @@ void TriangleSelectorGUI::update_paint_contour() GLModel::Geometry init_data; const std::vector contour_edges = this->get_seed_fill_contour(); - const GLModel::Geometry::EIndexType index_type = (2 * contour_edges.size() < 65536) ? GLModel::Geometry::EIndexType::USHORT : GLModel::Geometry::EIndexType::UINT; - init_data.format = { GLModel::Geometry::EPrimitiveType::Lines, GLModel::Geometry::EVertexLayout::P3, index_type }; + init_data.format = { GLModel::Geometry::EPrimitiveType::Lines, GLModel::Geometry::EVertexLayout::P3, GLModel::Geometry::index_type(2 * contour_edges.size()) }; init_data.reserve_vertices(2 * contour_edges.size()); init_data.reserve_indices(2 * contour_edges.size()); // vertices + indices @@ -1671,7 +1670,7 @@ void TriangleSelectorGUI::update_paint_contour() init_data.add_vertex(m_vertices[edge(0)].v); init_data.add_vertex(m_vertices[edge(1)].v); vertices_count += 2; - if (index_type == GLModel::Geometry::EIndexType::USHORT) + if (init_data.format.index_type == GLModel::Geometry::EIndexType::USHORT) init_data.add_ushort_line((unsigned short)vertices_count - 2, (unsigned short)vertices_count - 1); else init_data.add_uint_line(vertices_count - 2, vertices_count - 1); diff --git a/src/slic3r/GUI/MeshUtils.cpp b/src/slic3r/GUI/MeshUtils.cpp index 64d9be08269..3cdf5b63686 100644 --- a/src/slic3r/GUI/MeshUtils.cpp +++ b/src/slic3r/GUI/MeshUtils.cpp @@ -205,8 +205,7 @@ void MeshClipper::recalculate_triangles() m_model.reset(); GLModel::Geometry init_data; - const GLModel::Geometry::EIndexType index_type = (m_triangles2d.size() < 65536) ? GLModel::Geometry::EIndexType::USHORT : GLModel::Geometry::EIndexType::UINT; - init_data.format = { GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3N3, index_type }; + init_data.format = { GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3N3, GLModel::Geometry::index_type(m_triangles2d.size()) }; init_data.reserve_vertices(m_triangles2d.size()); init_data.reserve_indices(m_triangles2d.size()); @@ -216,7 +215,7 @@ void MeshClipper::recalculate_triangles() init_data.add_vertex((Vec3f)(tr * Vec3d((*(it + 1)).x(), (*(it + 1)).y(), height_mesh)).cast(), (Vec3f)up.cast()); init_data.add_vertex((Vec3f)(tr * Vec3d((*(it + 2)).x(), (*(it + 2)).y(), height_mesh)).cast(), (Vec3f)up.cast()); const size_t idx = it - m_triangles2d.cbegin(); - if (index_type == GLModel::Geometry::EIndexType::USHORT) + if (init_data.format.index_type == GLModel::Geometry::EIndexType::USHORT) init_data.add_ushort_triangle((unsigned short)idx, (unsigned short)idx + 1, (unsigned short)idx + 2); else init_data.add_uint_triangle((unsigned int)idx, (unsigned int)idx + 1, (unsigned int)idx + 2); diff --git a/src/slic3r/GUI/PartPlate.cpp b/src/slic3r/GUI/PartPlate.cpp index 27e819b45ad..ee7f3bc47e2 100644 --- a/src/slic3r/GUI/PartPlate.cpp +++ b/src/slic3r/GUI/PartPlate.cpp @@ -351,8 +351,7 @@ static bool init_model_from_lines(GLModel &model, const Lines &lines, float z) { GLModel::Geometry init_data; - const GLModel::Geometry::EIndexType index_type = (lines.size() < 65536 / 2) ? GLModel::Geometry::EIndexType::USHORT : GLModel::Geometry::EIndexType::UINT; - init_data.format = { GLModel::Geometry::EPrimitiveType::Lines, GLModel::Geometry::EVertexLayout::P3, index_type }; + init_data.format = { GLModel::Geometry::EPrimitiveType::Lines, GLModel::Geometry::EVertexLayout::P3, GLModel::Geometry::index_type(2 * lines.size()) }; init_data.reserve_vertices(2 * lines.size()); init_data.reserve_indices(2 * lines.size()); @@ -360,7 +359,7 @@ static bool init_model_from_lines(GLModel &model, const Lines &lines, float z) init_data.add_vertex(Vec3f(unscale(l.a.x()), unscale(l.a.y()), z)); init_data.add_vertex(Vec3f(unscale(l.b.x()), unscale(l.b.y()), z)); const unsigned int vertices_counter = (unsigned int)init_data.vertices_count(); - if (index_type == GLModel::Geometry::EIndexType::USHORT) + if (init_data.format.index_type == GLModel::Geometry::EIndexType::USHORT) init_data.add_ushort_line((unsigned short)vertices_counter - 2, (unsigned short)vertices_counter - 1); else init_data.add_uint_line(vertices_counter - 2, vertices_counter - 1); @@ -375,8 +374,7 @@ static bool init_model_from_lines(GLModel &model, const Lines3 &lines) { GLModel::Geometry init_data; - const GLModel::Geometry::EIndexType index_type = (lines.size() < 65536 / 2) ? GLModel::Geometry::EIndexType::USHORT : GLModel::Geometry::EIndexType::UINT; - init_data.format = {GLModel::Geometry::EPrimitiveType::Lines, GLModel::Geometry::EVertexLayout::P3, index_type}; + init_data.format = {GLModel::Geometry::EPrimitiveType::Lines, GLModel::Geometry::EVertexLayout::P3, GLModel::Geometry::index_type(2 * lines.size())}; init_data.reserve_vertices(2 * lines.size()); init_data.reserve_indices(2 * lines.size()); @@ -384,7 +382,7 @@ static bool init_model_from_lines(GLModel &model, const Lines3 &lines) init_data.add_vertex(Vec3f(unscale(l.a.x()), unscale(l.a.y()), unscale(l.a.z()))); init_data.add_vertex(Vec3f(unscale(l.b.x()), unscale(l.b.y()), unscale(l.b.z()))); const unsigned int vertices_counter = (unsigned int) init_data.vertices_count(); - if (index_type == GLModel::Geometry::EIndexType::USHORT) + if (init_data.format.index_type == GLModel::Geometry::EIndexType::USHORT) init_data.add_ushort_line((unsigned short) vertices_counter - 2, (unsigned short) vertices_counter - 1); else init_data.add_uint_line(vertices_counter - 2, vertices_counter - 1); From 10243b3a8c32c2dfb03137360e02f4b4d93f9d43 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Mon, 23 Oct 2023 11:30:25 +0800 Subject: [PATCH 21/99] Tech ENABLE_GLBEGIN_GLEND_REMOVAL - Removed OpenGL legacy calls from GLCanvas3D::init() (cherry picked from commit prusa3d/PrusaSlicer@aa4714a239d9d224708156c6c15a0d239a7c8a71) --- src/slic3r/GUI/GLCanvas3D.cpp | 36 +++-------------------------------- 1 file changed, 3 insertions(+), 33 deletions(-) diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index c627837b4a7..895517753ca 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -1169,36 +1169,6 @@ bool GLCanvas3D::init() glsafe(::glEnable(GL_BLEND)); glsafe(::glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)); - // Set antialiasing / multisampling - glsafe(::glDisable(GL_LINE_SMOOTH)); - glsafe(::glDisable(GL_POLYGON_SMOOTH)); - - // ambient lighting - GLfloat ambient[4] = { 0.3f, 0.3f, 0.3f, 1.0f }; - glsafe(::glLightModelfv(GL_LIGHT_MODEL_AMBIENT, ambient)); - - glsafe(::glEnable(GL_LIGHT0)); - glsafe(::glEnable(GL_LIGHT1)); - - // light from camera - GLfloat specular_cam[4] = { 0.3f, 0.3f, 0.3f, 1.0f }; - glsafe(::glLightfv(GL_LIGHT1, GL_SPECULAR, specular_cam)); - GLfloat diffuse_cam[4] = { 0.2f, 0.2f, 0.2f, 1.0f }; - glsafe(::glLightfv(GL_LIGHT1, GL_DIFFUSE, diffuse_cam)); - - // light from above - GLfloat specular_top[4] = { 0.2f, 0.2f, 0.2f, 1.0f }; - glsafe(::glLightfv(GL_LIGHT0, GL_SPECULAR, specular_top)); - GLfloat diffuse_top[4] = { 0.5f, 0.5f, 0.5f, 1.0f }; - glsafe(::glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse_top)); - - // Enables Smooth Color Shading; try GL_FLAT for (lack of) fun. - glsafe(::glShadeModel(GL_SMOOTH)); - - // A handy trick -- have surface material mirror the color. - glsafe(::glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE)); - glsafe(::glEnable(GL_COLOR_MATERIAL)); - if (m_multisample_allowed) glsafe(::glEnable(GL_MULTISAMPLE)); @@ -8194,11 +8164,11 @@ void GLCanvas3D::_render_sla_slices() if (!bottom_obj_triangles.empty() || !top_obj_triangles.empty() || !bottom_sup_triangles.empty() || !top_sup_triangles.empty()) { for (const SLAPrintObject::Instance& inst : obj->instances()) { glsafe(::glPushMatrix()); - glsafe(::glTranslated(unscale(inst.shift.x()), unscale(inst.shift.y()), 0)); - glsafe(::glRotatef(Geometry::rad2deg(inst.rotation), 0.0, 0.0, 1.0)); + glsafe(::glTranslated(unscale(inst.shift.x()), unscale(inst.shift.y()), 0.0)); + glsafe(::glRotatef(Geometry::rad2deg(inst.rotation), 0.0f, 0.0f, 1.0f)); if (obj->is_left_handed()) // The polygons are mirrored by X. - glsafe(::glScalef(-1.0, 1.0, 1.0)); + glsafe(::glScalef(-1.0f, 1.0f, 1.0f)); glsafe(::glEnableClientState(GL_VERTEX_ARRAY)); glsafe(::glColor3f(1.0f, 0.37f, 0.0f)); if (!bottom_obj_triangles.empty()) { From dde64acf72f50698096456db1466656f2a474a65 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Mon, 23 Oct 2023 11:35:43 +0800 Subject: [PATCH 22/99] Tech ENABLE_GLBEGIN_GLEND_REMOVAL - SLA caps rendered using GLModel (cherry picked from commit prusa3d/PrusaSlicer@c9ff260d13690eb32527900599487712a77e1657) --- src/slic3r/GUI/GLCanvas3D.cpp | 103 +++++++++++++++++++--------------- src/slic3r/GUI/GLCanvas3D.hpp | 10 ++-- 2 files changed, 64 insertions(+), 49 deletions(-) diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 895517753ca..d9ffac10157 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -8096,32 +8096,54 @@ void GLCanvas3D::_render_sla_slices() if (!obj->is_step_done(slaposSliceSupports)) continue; - SlaCap::ObjectIdToTrianglesMap::iterator it_caps_bottom = m_sla_caps[0].triangles.find(i); - SlaCap::ObjectIdToTrianglesMap::iterator it_caps_top = m_sla_caps[1].triangles.find(i); + SlaCap::ObjectIdToModelsMap::iterator it_caps_bottom = m_sla_caps[0].triangles.find(i); + SlaCap::ObjectIdToModelsMap::iterator it_caps_top = m_sla_caps[1].triangles.find(i); { if (it_caps_bottom == m_sla_caps[0].triangles.end()) it_caps_bottom = m_sla_caps[0].triangles.emplace(i, SlaCap::Triangles()).first; if (!m_sla_caps[0].matches(clip_min_z)) { m_sla_caps[0].z = clip_min_z; - it_caps_bottom->second.object.clear(); - it_caps_bottom->second.supports.clear(); + it_caps_bottom->second.object.reset(); + it_caps_bottom->second.supports.reset(); } if (it_caps_top == m_sla_caps[1].triangles.end()) it_caps_top = m_sla_caps[1].triangles.emplace(i, SlaCap::Triangles()).first; if (!m_sla_caps[1].matches(clip_max_z)) { m_sla_caps[1].z = clip_max_z; - it_caps_top->second.object.clear(); - it_caps_top->second.supports.clear(); + it_caps_top->second.object.reset(); + it_caps_top->second.supports.reset(); } } - Pointf3s &bottom_obj_triangles = it_caps_bottom->second.object; - Pointf3s &bottom_sup_triangles = it_caps_bottom->second.supports; - Pointf3s &top_obj_triangles = it_caps_top->second.object; - Pointf3s &top_sup_triangles = it_caps_top->second.supports; + GLModel& bottom_obj_triangles = it_caps_bottom->second.object; + GLModel& bottom_sup_triangles = it_caps_bottom->second.supports; + GLModel& top_obj_triangles = it_caps_top->second.object; + GLModel& top_sup_triangles = it_caps_top->second.supports; + + auto init_model = [](GLModel& model, const Pointf3s& triangles, const ColorRGBA& color) { + GLModel::Geometry init_data; + init_data.format = { GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3, GLModel::Geometry::index_type(triangles.size()) }; + init_data.reserve_vertices(triangles.size()); + init_data.reserve_indices(triangles.size() / 3); + init_data.color = color; + + unsigned int vertices_count = 0; + for (const Vec3d& v : triangles) { + init_data.add_vertex((Vec3f)v.cast()); + ++vertices_count; + if (vertices_count % 3 == 0) { + if (init_data.format.index_type == GLModel::Geometry::EIndexType::USHORT) + init_data.add_ushort_triangle((unsigned short)vertices_count - 3, (unsigned short)vertices_count - 2, (unsigned short)vertices_count - 1); + else + init_data.add_uint_triangle(vertices_count - 3, vertices_count - 2, vertices_count - 1); + } + } - if ((bottom_obj_triangles.empty() || bottom_sup_triangles.empty() || top_obj_triangles.empty() || top_sup_triangles.empty()) && - !obj->get_slice_index().empty()) - { + if (!init_data.is_empty()) + model.init_from(std::move(init_data)); + }; + + if ((!bottom_obj_triangles.is_initialized() || !bottom_sup_triangles.is_initialized() || + !top_obj_triangles.is_initialized() || !top_sup_triangles.is_initialized()) && !obj->get_slice_index().empty()) { double layer_height = print->default_object_config().layer_height.value; double initial_layer_height = print->material_config().initial_layer_height.value; bool left_handed = obj->is_left_handed(); @@ -8142,55 +8164,48 @@ void GLCanvas3D::_render_sla_slices() const ExPolygons& obj_bottom = slice_low.get_slice(soModel); const ExPolygons& sup_bottom = slice_low.get_slice(soSupport); // calculate model bottom cap - if (bottom_obj_triangles.empty() && !obj_bottom.empty()) - bottom_obj_triangles = triangulate_expolygons_3d(obj_bottom, clip_min_z - plane_shift_z, ! left_handed); + // calculate model bottom cap + if (!bottom_obj_triangles.is_initialized() && !obj_bottom.empty()) + init_model(bottom_obj_triangles, triangulate_expolygons_3d(obj_bottom, clip_min_z - plane_shift_z, !left_handed), { 1.0f, 0.37f, 0.0f, 1.0f }); // calculate support bottom cap - if (bottom_sup_triangles.empty() && !sup_bottom.empty()) - bottom_sup_triangles = triangulate_expolygons_3d(sup_bottom, clip_min_z - plane_shift_z, ! left_handed); + if (!bottom_sup_triangles.is_initialized() && !sup_bottom.empty()) + init_model(bottom_sup_triangles, triangulate_expolygons_3d(sup_bottom, clip_min_z - plane_shift_z, !left_handed), { 1.0f, 0.0f, 0.37f, 1.0f }); } if (slice_high.is_valid()) { const ExPolygons& obj_top = slice_high.get_slice(soModel); const ExPolygons& sup_top = slice_high.get_slice(soSupport); // calculate model top cap - if (top_obj_triangles.empty() && !obj_top.empty()) - top_obj_triangles = triangulate_expolygons_3d(obj_top, clip_max_z + plane_shift_z, left_handed); + // calculate model top cap + if (!top_obj_triangles.is_initialized() && !obj_top.empty()) + init_model(top_obj_triangles, triangulate_expolygons_3d(obj_top, clip_max_z + plane_shift_z, left_handed), { 1.0f, 0.37f, 0.0f, 1.0f }); // calculate support top cap - if (top_sup_triangles.empty() && !sup_top.empty()) - top_sup_triangles = triangulate_expolygons_3d(sup_top, clip_max_z + plane_shift_z, left_handed); + if (!top_sup_triangles.is_initialized() && !sup_top.empty()) + init_model(top_sup_triangles, triangulate_expolygons_3d(sup_top, clip_max_z + plane_shift_z, left_handed), { 1.0f, 0.0f, 0.37f, 1.0f }); } } - if (!bottom_obj_triangles.empty() || !top_obj_triangles.empty() || !bottom_sup_triangles.empty() || !top_sup_triangles.empty()) { - for (const SLAPrintObject::Instance& inst : obj->instances()) { + GLShaderProgram* shader = wxGetApp().get_shader("flat"); + if (shader != nullptr) { + shader->start_using(); + + for (const SLAPrintObject::Instance& inst : obj->instances()) { glsafe(::glPushMatrix()); glsafe(::glTranslated(unscale(inst.shift.x()), unscale(inst.shift.y()), 0.0)); glsafe(::glRotatef(Geometry::rad2deg(inst.rotation), 0.0f, 0.0f, 1.0f)); - if (obj->is_left_handed()) + if (obj->is_left_handed()) // The polygons are mirrored by X. glsafe(::glScalef(-1.0f, 1.0f, 1.0f)); - glsafe(::glEnableClientState(GL_VERTEX_ARRAY)); - glsafe(::glColor3f(1.0f, 0.37f, 0.0f)); - if (!bottom_obj_triangles.empty()) { - glsafe(::glVertexPointer(3, GL_DOUBLE, 0, (GLdouble*)bottom_obj_triangles.front().data())); - glsafe(::glDrawArrays(GL_TRIANGLES, 0, bottom_obj_triangles.size())); - } - if (! top_obj_triangles.empty()) { - glsafe(::glVertexPointer(3, GL_DOUBLE, 0, (GLdouble*)top_obj_triangles.front().data())); - glsafe(::glDrawArrays(GL_TRIANGLES, 0, top_obj_triangles.size())); - } - glsafe(::glColor3f(1.0f, 0.0f, 0.37f)); - if (! bottom_sup_triangles.empty()) { - glsafe(::glVertexPointer(3, GL_DOUBLE, 0, (GLdouble*)bottom_sup_triangles.front().data())); - glsafe(::glDrawArrays(GL_TRIANGLES, 0, bottom_sup_triangles.size())); - } - if (! top_sup_triangles.empty()) { - glsafe(::glVertexPointer(3, GL_DOUBLE, 0, (GLdouble*)top_sup_triangles.front().data())); - glsafe(::glDrawArrays(GL_TRIANGLES, 0, top_sup_triangles.size())); - } - glsafe(::glDisableClientState(GL_VERTEX_ARRAY)); + + bottom_obj_triangles.render(); + top_obj_triangles.render(); + bottom_sup_triangles.render(); + top_sup_triangles.render(); + glsafe(::glPopMatrix()); } + + shader->stop_using(); } } } diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp index efae16d7eeb..2199b7e5e06 100644 --- a/src/slic3r/GUI/GLCanvas3D.hpp +++ b/src/slic3r/GUI/GLCanvas3D.hpp @@ -355,12 +355,12 @@ class GLCanvas3D { struct Triangles { - Pointf3s object; - Pointf3s supports; + GLModel object; + GLModel supports; }; - typedef std::map ObjectIdToTrianglesMap; + typedef std::map ObjectIdToModelsMap; double z; - ObjectIdToTrianglesMap triangles; + ObjectIdToModelsMap triangles; SlaCap() { reset(); } void reset() { z = DBL_MAX; triangles.clear(); } @@ -526,7 +526,7 @@ class GLCanvas3D std::array m_clipping_planes; ClippingPlane m_camera_clipping_plane; bool m_use_clipping_planes; - SlaCap m_sla_caps[2]; + std::array m_sla_caps; std::string m_sidebar_field; // when true renders an extra frame by not resetting m_dirty to false // see request_extra_frame() From dd51ce3b90287a7eb7851e689ea03056b77d7b76 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Mon, 23 Oct 2023 11:38:15 +0800 Subject: [PATCH 23/99] Follow-up of fdf8b11d4cfa793d1e45d82560d4bd97d0466d40 - Fixed GLGizmoSlaSupports::render_points() (cherry picked from commit prusa3d/PrusaSlicer@0c74081f7dd33ebeb4e6f2c179e728520b19febb) --- src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp index 8745274f4b2..b5ead52fd6f 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp @@ -127,13 +127,12 @@ void GLGizmoSlaSupports::render_points(const Selection& selection, bool picking) if (! has_points && ! has_holes) return; - GLShaderProgram* shader = picking ? nullptr : wxGetApp().get_shader("gouraud_light"); - if (shader != nullptr) - shader->start_using(); - ScopeGuard guard([shader]() { - if (shader != nullptr) - shader->stop_using(); - }); + GLShaderProgram* shader = wxGetApp().get_shader(picking ? "flat" : "gouraud_light"); + if (shader == nullptr) + return; + + shader->start_using(); + ScopeGuard guard([shader]() { shader->stop_using(); }); const GLVolume* vol = selection.get_volume(*selection.get_volume_idxs().begin()); const Transform3d& instance_scaling_matrix_inverse = vol->get_instance_transformation().get_matrix(true, true, false, true).inverse(); @@ -176,7 +175,7 @@ void GLGizmoSlaSupports::render_points(const Selection& selection, bool picking) m_cone.set_color(render_color); m_sphere.set_color(render_color); - if (shader && !picking) + if (!picking) shader->set_uniform("emission_factor", 0.5f); // Inverse matrix of the instance scaling is applied so that the mark does not scale with the object. @@ -228,8 +227,7 @@ void GLGizmoSlaSupports::render_points(const Selection& selection, bool picking) if (has_holes && ! picking) { render_color = { 0.7f, 0.7f, 0.7f, 0.7f }; m_cylinder.set_color(render_color); - if (shader) - shader->set_uniform("emission_factor", 0.5f); + shader->set_uniform("emission_factor", 0.5f); for (const sla::DrainHole& drain_hole : m_c->selection_info()->model_object()->sla_drain_holes) { if (is_mesh_point_clipped(drain_hole.pos.cast())) continue; From d1b0743735ea4ddf5844ca1e0ee1571f2a3d8d13 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Mon, 23 Oct 2023 11:47:22 +0800 Subject: [PATCH 24/99] Removed obsolete member variable GLCanvas3D::m_color_by (cherry picked from commit prusa3d/PrusaSlicer@5089d1460d172e29164e313e806457181a67daef) --- src/OrcaSlicer.cpp | 2 +- src/slic3r/GUI/3DScene.cpp | 8 ++------ src/slic3r/GUI/3DScene.hpp | 2 -- src/slic3r/GUI/GCodeViewer.cpp | 2 +- src/slic3r/GUI/GLCanvas3D.cpp | 10 ++-------- src/slic3r/GUI/GLCanvas3D.hpp | 4 ---- src/slic3r/Utils/CalibUtils.cpp | 2 +- 7 files changed, 7 insertions(+), 23 deletions(-) diff --git a/src/OrcaSlicer.cpp b/src/OrcaSlicer.cpp index 8ee2d442bab..127efa712d5 100644 --- a/src/OrcaSlicer.cpp +++ b/src/OrcaSlicer.cpp @@ -2353,7 +2353,7 @@ int CLI::run(int argc, char **argv) // continue; for (int instance_idx = 0; instance_idx < (int)model_object.instances.size(); ++ instance_idx) { const ModelInstance &model_instance = *model_object.instances[instance_idx]; - glvolume_collection.load_object_volume(&model_object, obj_idx, volume_idx, instance_idx, "volume", true, false, true); + glvolume_collection.load_object_volume(&model_object, obj_idx, volume_idx, instance_idx, true, false, true); //glvolume_collection.volumes.back()->geometry_id = key.geometry_id; std::string color = filament_color?filament_color->get_at(extruder_id - 1):"#00FF00"; diff --git a/src/slic3r/GUI/3DScene.cpp b/src/slic3r/GUI/3DScene.cpp index 52fc96df1b7..4d3d79923d6 100644 --- a/src/slic3r/GUI/3DScene.cpp +++ b/src/slic3r/GUI/3DScene.cpp @@ -1008,13 +1008,12 @@ std::vector GLVolumeCollection::load_object( const ModelObject *model_object, int obj_idx, const std::vector &instance_idxs, - const std::string &color_by, bool opengl_initialized) { std::vector volumes_idx; for (int volume_idx = 0; volume_idx < int(model_object->volumes.size()); ++volume_idx) for (int instance_idx : instance_idxs) - volumes_idx.emplace_back(this->GLVolumeCollection::load_object_volume(model_object, obj_idx, volume_idx, instance_idx, color_by, opengl_initialized)); + volumes_idx.emplace_back(this->GLVolumeCollection::load_object_volume(model_object, obj_idx, volume_idx, instance_idx, opengl_initialized)); return volumes_idx; } @@ -1023,7 +1022,6 @@ int GLVolumeCollection::load_object_volume( int obj_idx, int volume_idx, int instance_idx, - const std::string &color_by, bool opengl_initialized, bool in_assemble_view, bool use_loaded_id) @@ -1032,9 +1030,7 @@ 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(); - ColorRGBA color = GLVolume::MODEL_COLOR[((color_by == "volume") ? volume_idx : obj_idx) % 4]; - color.a(model_volume->is_model_part() ? 0.7f : 0.4f); - this->volumes.emplace_back(new GLVolume(color)); + this->volumes.emplace_back(new GLVolume()); GLVolume& v = *this->volumes.back(); v.set_color(color_from_model_volume(*model_volume)); v.name = model_volume->name; diff --git a/src/slic3r/GUI/3DScene.hpp b/src/slic3r/GUI/3DScene.hpp index b9030ac4f7e..83101754b58 100644 --- a/src/slic3r/GUI/3DScene.hpp +++ b/src/slic3r/GUI/3DScene.hpp @@ -630,7 +630,6 @@ class GLVolumeCollection const ModelObject *model_object, int obj_idx, const std::vector &instance_idxs, - const std::string &color_by, bool opengl_initialized); int load_object_volume( @@ -638,7 +637,6 @@ class GLVolumeCollection int obj_idx, int volume_idx, int instance_idx, - const std::string &color_by, bool opengl_initialized, bool in_assemble_view = false, bool use_loaded_id = false); diff --git a/src/slic3r/GUI/GCodeViewer.cpp b/src/slic3r/GUI/GCodeViewer.cpp index 36e27b26359..7f3fa3d3b11 100644 --- a/src/slic3r/GUI/GCodeViewer.cpp +++ b/src/slic3r/GUI/GCodeViewer.cpp @@ -3138,7 +3138,7 @@ void GCodeViewer::load_shells(const Print& print, bool initialized, bool force_p instance_ids.resize(instance_index); size_t current_volumes_count = m_shells.volumes.volumes.size(); - m_shells.volumes.load_object(model_obj, object_idx, instance_ids, "object", initialized); + m_shells.volumes.load_object(model_obj, object_idx, instance_ids, initialized); // adjust shells' z if raft is present const SlicingParameters& slicing_parameters = obj->slicing_parameters(); diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index d9ffac10157..6aa3a5fcf56 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -1111,7 +1111,6 @@ GLCanvas3D::GLCanvas3D(wxGLCanvas* canvas, Bed3D &bed) , m_moving(false) , m_tab_down(false) , m_cursor_type(Standard) - , m_color_by("volume") , m_reload_delayed(false) #if ENABLE_RENDER_PICKING_PASS , m_show_picking_texture(false) @@ -1438,11 +1437,6 @@ Camera& GLCanvas3D::get_camera() return camera; } -void GLCanvas3D::set_color_by(const std::string& value) -{ - m_color_by = value; -} - void GLCanvas3D::refresh_camera_scene_box() { wxGetApp().plater()->get_camera().set_scene_box(scene_bounding_box()); @@ -2142,7 +2136,7 @@ std::vector GLCanvas3D::load_object(const ModelObject& model_object, int ob instance_idxs.emplace_back(i); } } - return m_volumes.load_object(&model_object, obj_idx, instance_idxs, m_color_by, m_initialized); + return m_volumes.load_object(&model_object, obj_idx, instance_idxs, m_initialized); } std::vector GLCanvas3D::load_object(const Model& model, int obj_idx) @@ -2453,7 +2447,7 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re // Note the index of the loaded volume, so that we can reload the main model GLVolume with the hollowed mesh // later in this function. it->volume_idx = m_volumes.volumes.size(); - m_volumes.load_object_volume(&model_object, obj_idx, volume_idx, instance_idx, m_color_by, m_initialized, m_canvas_type == ECanvasType::CanvasAssembleView); + m_volumes.load_object_volume(&model_object, obj_idx, volume_idx, instance_idx, m_initialized, m_canvas_type == ECanvasType::CanvasAssembleView); m_volumes.volumes.back()->geometry_id = key.geometry_id; update_object_list = true; } else { diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp index 2199b7e5e06..f9103c75cd8 100644 --- a/src/slic3r/GUI/GLCanvas3D.hpp +++ b/src/slic3r/GUI/GLCanvas3D.hpp @@ -577,8 +577,6 @@ class GLCanvas3D // I just don't want to do it now before a release (Lukas Matena 24.3.2019) bool m_render_sla_auxiliaries; - std::string m_color_by; - bool m_reload_delayed; #if ENABLE_RENDER_PICKING_PASS @@ -789,8 +787,6 @@ class GLCanvas3D bool get_use_clipping_planes() const { return m_use_clipping_planes; } const std::array &get_clipping_planes() const { return m_clipping_planes; }; - void set_color_by(const std::string& value); - void refresh_camera_scene_box(); BoundingBoxf3 volumes_bounding_box(bool current_plate_only = false) const; diff --git a/src/slic3r/Utils/CalibUtils.cpp b/src/slic3r/Utils/CalibUtils.cpp index 62ad2a36f80..82382293f86 100644 --- a/src/slic3r/Utils/CalibUtils.cpp +++ b/src/slic3r/Utils/CalibUtils.cpp @@ -926,7 +926,7 @@ void CalibUtils::process_and_store_3mf(Model *model, const DynamicPrintConfig &f const ModelVolume &model_volume = *model_object.volumes[volume_idx]; for (int instance_idx = 0; instance_idx < (int)model_object.instances.size(); ++ instance_idx) { const ModelInstance &model_instance = *model_object.instances[instance_idx]; - glvolume_collection.load_object_volume(&model_object, obj_idx, volume_idx, instance_idx, "volume", true, false, true); + glvolume_collection.load_object_volume(&model_object, obj_idx, volume_idx, instance_idx, true, false, true); glvolume_collection.volumes.back()->set_render_color(new_color); glvolume_collection.volumes.back()->set_color(new_color); //glvolume_collection.volumes.back()->printable = model_instance.printable; From d85bbcba501fa5b799391ed62ecd86d12540416e Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Mon, 23 Oct 2023 11:59:14 +0800 Subject: [PATCH 25/99] Tech ENABLE_GLBEGIN_GLEND_REMOVAL - Fixed bug in rendering gizmo rotate (cherry picked from commit prusa3d/PrusaSlicer@5fcb618f96064d8dbd5803dc3d773b37b81cde49) --- src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp b/src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp index ce6b894cb71..e102fb0fe7b 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp @@ -134,15 +134,14 @@ void GLGizmoRotate::on_render() if (shader != nullptr) { shader->start_using(); - const float radius = Offset + m_parent.get_selection().get_bounding_box().radius(); - const bool radius_changed = std::abs(m_old_radius - radius) > EPSILON; - m_old_radius = radius; + const bool radius_changed = std::abs(m_old_radius - m_radius) > EPSILON; + m_old_radius = m_radius; ColorRGBA color((m_hover_id != -1) ? m_drag_color : m_highlight_color); render_circle(color, radius_changed); if (m_hover_id != -1) { - const bool hover_radius_changed = std::abs(m_old_hover_radius - radius) > EPSILON; - m_old_hover_radius = radius; + const bool hover_radius_changed = std::abs(m_old_hover_radius - m_radius) > EPSILON; + m_old_hover_radius = m_radius; render_scale(color, hover_radius_changed); render_snap_radii(color, hover_radius_changed); From d09dc36ff1ad38ab7ade060ce8f737775bc9236a Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Mon, 23 Oct 2023 17:02:29 +0800 Subject: [PATCH 26/99] Tech ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL - Replace GLIndexedVertexArray with GLModel: GLVolume geometry + removed class GLIndexedVertexArray from codebase (cherry picked from commit prusa3d/PrusaSlicer@1eac357739d44fcdcfbbb742b888b51ce8858bba) --- src/OrcaSlicer.cpp | 2 +- src/libslic3r/BuildVolume.hpp | 3 + src/slic3r/CMakeLists.txt | 4 +- src/slic3r/GUI/3DScene.cpp | 1094 ++++++----------- src/slic3r/GUI/3DScene.hpp | 276 +---- src/slic3r/GUI/GCodeViewer.cpp | 18 +- src/slic3r/GUI/GCodeViewer.hpp | 6 +- src/slic3r/GUI/GLCanvas3D.cpp | 231 ++-- src/slic3r/GUI/GLModel.cpp | 163 ++- src/slic3r/GUI/GLModel.hpp | 43 +- src/slic3r/GUI/Gizmos/GLGizmoFaceDetector.cpp | 23 +- src/slic3r/GUI/Gizmos/GLGizmoFaceDetector.hpp | 2 +- src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp | 6 +- src/slic3r/GUI/Gizmos/GLGizmosManager.cpp | 2 +- src/slic3r/GUI/ImGuiWrapper.cpp | 18 +- src/slic3r/Utils/CalibUtils.cpp | 2 +- 16 files changed, 764 insertions(+), 1129 deletions(-) diff --git a/src/OrcaSlicer.cpp b/src/OrcaSlicer.cpp index 127efa712d5..c8ba1cdd313 100644 --- a/src/OrcaSlicer.cpp +++ b/src/OrcaSlicer.cpp @@ -2353,7 +2353,7 @@ int CLI::run(int argc, char **argv) // continue; for (int instance_idx = 0; instance_idx < (int)model_object.instances.size(); ++ instance_idx) { const ModelInstance &model_instance = *model_object.instances[instance_idx]; - glvolume_collection.load_object_volume(&model_object, obj_idx, volume_idx, instance_idx, true, false, true); + glvolume_collection.load_object_volume(&model_object, obj_idx, volume_idx, instance_idx, false, true); //glvolume_collection.volumes.back()->geometry_id = key.geometry_id; std::string color = filament_color?filament_color->get_at(extruder_id - 1):"#00FF00"; diff --git a/src/libslic3r/BuildVolume.hpp b/src/libslic3r/BuildVolume.hpp index 4ab007f8b8c..0df41f1be55 100644 --- a/src/libslic3r/BuildVolume.hpp +++ b/src/libslic3r/BuildVolume.hpp @@ -93,6 +93,9 @@ class BuildVolume // Called on initial G-code preview on OpenGL vertex buffer interleaved normals and vertices. bool all_paths_inside_vertices_and_normals_interleaved(const std::vector& paths, const Eigen::AlignedBox& bbox, bool ignore_bottom = true) const; + const std::pair, std::vector>& top_bottom_convex_hull_decomposition_scene() const { return m_top_bottom_convex_hull_decomposition_scene; } + const std::pair, std::vector>& top_bottom_convex_hull_decomposition_bed() const { return m_top_bottom_convex_hull_decomposition_bed; } + private: // Source definition of the print bed geometry (PrintConfig::printable_area) std::vector m_bed_shape; diff --git a/src/slic3r/CMakeLists.txt b/src/slic3r/CMakeLists.txt index 61dc8c9491f..d9ad26a6eeb 100644 --- a/src/slic3r/CMakeLists.txt +++ b/src/slic3r/CMakeLists.txt @@ -131,8 +131,8 @@ set(SLIC3R_GUI_SOURCES GUI/Gizmos/GLGizmoSimplify.hpp GUI/Gizmos/GLGizmoMmuSegmentation.cpp GUI/Gizmos/GLGizmoMmuSegmentation.hpp - GUI/Gizmos/GLGizmoFaceDetector.cpp - GUI/Gizmos/GLGizmoFaceDetector.hpp + #GUI/Gizmos/GLGizmoFaceDetector.cpp + #GUI/Gizmos/GLGizmoFaceDetector.hpp GUI/Gizmos/GLGizmoSeam.cpp GUI/Gizmos/GLGizmoSeam.hpp GUI/Gizmos/GLGizmoText.cpp diff --git a/src/slic3r/GUI/3DScene.cpp b/src/slic3r/GUI/3DScene.cpp index 4d3d79923d6..ac533c3365c 100644 --- a/src/slic3r/GUI/3DScene.cpp +++ b/src/slic3r/GUI/3DScene.cpp @@ -1,12 +1,5 @@ -#include "slic3r/GUI/3DScene.hpp" #include -#if ENABLE_SMOOTH_NORMALS -#include -#include -#include -#endif // ENABLE_SMOOTH_NORMALS - #include "3DScene.hpp" #include "GLShader.hpp" #include "GUI_App.hpp" @@ -96,227 +89,6 @@ Slic3r::ColorRGBA adjust_color_for_rendering(const Slic3r::ColorRGBA &colors) namespace Slic3r { -#if ENABLE_SMOOTH_NORMALS -static void smooth_normals_corner(TriangleMesh& mesh, std::vector& normals) -{ - using MapMatrixXfUnaligned = Eigen::Map>; - using MapMatrixXiUnaligned = Eigen::Map>; - - std::vector face_normals = its_face_normals(mesh.its); - - Eigen::MatrixXd vertices = MapMatrixXfUnaligned(mesh.its.vertices.front().data(), - Eigen::Index(mesh.its.vertices.size()), 3).cast(); - Eigen::MatrixXi indices = MapMatrixXiUnaligned(mesh.its.indices.front().data(), - Eigen::Index(mesh.its.indices.size()), 3); - Eigen::MatrixXd in_normals = MapMatrixXfUnaligned(face_normals.front().data(), - Eigen::Index(face_normals.size()), 3).cast(); - Eigen::MatrixXd out_normals; - - igl::per_corner_normals(vertices, indices, in_normals, 1.0, out_normals); - - normals = std::vector(mesh.its.vertices.size()); - for (size_t i = 0; i < mesh.its.indices.size(); ++i) { - for (size_t j = 0; j < 3; ++j) { - normals[mesh.its.indices[i][j]] = out_normals.row(i * 3 + j).cast(); - } - } -} - -static void smooth_normals_vertex(TriangleMesh& mesh, std::vector& normals) -{ - using MapMatrixXfUnaligned = Eigen::Map>; - using MapMatrixXiUnaligned = Eigen::Map>; - - Eigen::MatrixXd vertices = MapMatrixXfUnaligned(mesh.its.vertices.front().data(), - Eigen::Index(mesh.its.vertices.size()), 3).cast(); - Eigen::MatrixXi indices = MapMatrixXiUnaligned(mesh.its.indices.front().data(), - Eigen::Index(mesh.its.indices.size()), 3); - Eigen::MatrixXd out_normals; - -// igl::per_vertex_normals(vertices, indices, igl::PER_VERTEX_NORMALS_WEIGHTING_TYPE_UNIFORM, out_normals); -// igl::per_vertex_normals(vertices, indices, igl::PER_VERTEX_NORMALS_WEIGHTING_TYPE_AREA, out_normals); - igl::per_vertex_normals(vertices, indices, igl::PER_VERTEX_NORMALS_WEIGHTING_TYPE_ANGLE, out_normals); -// igl::per_vertex_normals(vertices, indices, igl::PER_VERTEX_NORMALS_WEIGHTING_TYPE_DEFAULT, out_normals); - - normals = std::vector(mesh.its.vertices.size()); - for (size_t i = 0; i < static_cast(out_normals.rows()); ++i) { - normals[i] = out_normals.row(i).cast(); - } -} -#endif // ENABLE_SMOOTH_NORMALS - -#if ENABLE_SMOOTH_NORMALS -void GLIndexedVertexArray::load_mesh_full_shading(const TriangleMesh& mesh, bool smooth_normals) -#else -void GLIndexedVertexArray::load_mesh_full_shading(const TriangleMesh& mesh) -#endif // ENABLE_SMOOTH_NORMALS -{ - assert(triangle_indices.empty() && vertices_and_normals_interleaved_size == 0); - assert(quad_indices.empty() && triangle_indices_size == 0); - assert(vertices_and_normals_interleaved.size() % 6 == 0 && quad_indices_size == vertices_and_normals_interleaved.size()); - -#if ENABLE_SMOOTH_NORMALS - if (smooth_normals) { - TriangleMesh new_mesh(mesh); - std::vector normals; - smooth_normals_corner(new_mesh, normals); -// smooth_normals_vertex(new_mesh, normals); - - this->vertices_and_normals_interleaved.reserve(this->vertices_and_normals_interleaved.size() + 3 * 2 * new_mesh.its.vertices.size()); - for (size_t i = 0; i < new_mesh.its.vertices.size(); ++i) { - const stl_vertex& v = new_mesh.its.vertices[i]; - const stl_normal& n = normals[i]; - this->push_geometry(v(0), v(1), v(2), n(0), n(1), n(2)); - } - - for (size_t i = 0; i < new_mesh.its.indices.size(); ++i) { - const stl_triangle_vertex_indices& idx = new_mesh.its.indices[i]; - this->push_triangle(idx(0), idx(1), idx(2)); - } - } - else { -#endif // ENABLE_SMOOTH_NORMALS - this->load_its_flat_shading(mesh.its); -#if ENABLE_SMOOTH_NORMALS - } -#endif // ENABLE_SMOOTH_NORMALS -} - -void GLIndexedVertexArray::load_its_flat_shading(const indexed_triangle_set &its) -{ - this->vertices_and_normals_interleaved.reserve(this->vertices_and_normals_interleaved.size() + 3 * 3 * 2 * its.indices.size()); - unsigned int vertices_count = 0; - for (int i = 0; i < int(its.indices.size()); ++ i) { - stl_triangle_vertex_indices face = its.indices[i]; - stl_vertex vertex[3] = { its.vertices[face[0]], its.vertices[face[1]], its.vertices[face[2]] }; - stl_vertex n = face_normal_normalized(vertex); - for (int j = 0; j < 3; ++j) - this->push_geometry(vertex[j](0), vertex[j](1), vertex[j](2), n(0), n(1), n(2)); - this->push_triangle(vertices_count, vertices_count + 1, vertices_count + 2); - vertices_count += 3; - } - BOOST_LOG_TRIVIAL(debug) << __FUNCTION__<< boost::format(", this %1%, indices size %2%, vertices %3%, triangles %4% ") - %this %its.indices.size() %this->vertices_and_normals_interleaved.size() %this->triangle_indices.size() ; -} - -void GLIndexedVertexArray::finalize_geometry(bool opengl_initialized) -{ - assert(this->vertices_and_normals_interleaved_VBO_id == 0); - assert(this->triangle_indices_VBO_id == 0); - assert(this->quad_indices_VBO_id == 0); - - if (! opengl_initialized) { - // Shrink the data vectors to conserve memory in case the data cannot be transfered to the OpenGL driver yet. - this->shrink_to_fit(); - return; - } - - BOOST_LOG_TRIVIAL(debug) << __FUNCTION__<< boost::format(", this %1% ") %this; - if (! this->vertices_and_normals_interleaved.empty()) { - glsafe(::glGenBuffers(1, &this->vertices_and_normals_interleaved_VBO_id)); - glsafe(::glBindBuffer(GL_ARRAY_BUFFER, this->vertices_and_normals_interleaved_VBO_id)); - glsafe(::glBufferData(GL_ARRAY_BUFFER, this->vertices_and_normals_interleaved.size() * 4, this->vertices_and_normals_interleaved.data(), GL_STATIC_DRAW)); - glsafe(::glBindBuffer(GL_ARRAY_BUFFER, 0)); - this->vertices_and_normals_interleaved.clear(); - } - if (! this->triangle_indices.empty()) { - glsafe(::glGenBuffers(1, &this->triangle_indices_VBO_id)); - glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, this->triangle_indices_VBO_id)); - glsafe(::glBufferData(GL_ELEMENT_ARRAY_BUFFER, this->triangle_indices.size() * 4, this->triangle_indices.data(), GL_STATIC_DRAW)); - glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0)); - this->triangle_indices.clear(); - } - if (! this->quad_indices.empty()) { - glsafe(::glGenBuffers(1, &this->quad_indices_VBO_id)); - glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, this->quad_indices_VBO_id)); - glsafe(::glBufferData(GL_ELEMENT_ARRAY_BUFFER, this->quad_indices.size() * 4, this->quad_indices.data(), GL_STATIC_DRAW)); - glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0)); - this->quad_indices.clear(); - } -} - -void GLIndexedVertexArray::release_geometry() -{ - if (this->vertices_and_normals_interleaved_VBO_id) { - glsafe(::glDeleteBuffers(1, &this->vertices_and_normals_interleaved_VBO_id)); - this->vertices_and_normals_interleaved_VBO_id = 0; - } - if (this->triangle_indices_VBO_id) { - glsafe(::glDeleteBuffers(1, &this->triangle_indices_VBO_id)); - this->triangle_indices_VBO_id = 0; - } - if (this->quad_indices_VBO_id) { - glsafe(::glDeleteBuffers(1, &this->quad_indices_VBO_id)); - this->quad_indices_VBO_id = 0; - } - this->clear(); -} - -void GLIndexedVertexArray::render() const -{ - assert(this->vertices_and_normals_interleaved_VBO_id != 0); - assert(this->triangle_indices_VBO_id != 0 || this->quad_indices_VBO_id != 0); - - glsafe(::glBindBuffer(GL_ARRAY_BUFFER, this->vertices_and_normals_interleaved_VBO_id)); - glsafe(::glVertexPointer(3, GL_FLOAT, 6 * sizeof(float), (const void*)(3 * sizeof(float)))); - glsafe(::glNormalPointer(GL_FLOAT, 6 * sizeof(float), nullptr)); - - glsafe(::glEnableClientState(GL_VERTEX_ARRAY)); - glsafe(::glEnableClientState(GL_NORMAL_ARRAY)); - - // Render using the Vertex Buffer Objects. - if (this->triangle_indices_size > 0) { - glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, this->triangle_indices_VBO_id)); - glsafe(::glDrawElements(GL_TRIANGLES, GLsizei(this->triangle_indices_size), GL_UNSIGNED_INT, nullptr)); - glsafe(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0)); - } - if (this->quad_indices_size > 0) { - glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, this->quad_indices_VBO_id)); - glsafe(::glDrawElements(GL_QUADS, GLsizei(this->quad_indices_size), GL_UNSIGNED_INT, nullptr)); - glsafe(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0)); - } - - glsafe(::glDisableClientState(GL_VERTEX_ARRAY)); - glsafe(::glDisableClientState(GL_NORMAL_ARRAY)); - - glsafe(::glBindBuffer(GL_ARRAY_BUFFER, 0)); -} - -void GLIndexedVertexArray::render( - const std::pair& tverts_range, - const std::pair& qverts_range) const -{ - // this method has been called before calling finalize() ? - if (this->vertices_and_normals_interleaved_VBO_id == 0 && !this->vertices_and_normals_interleaved.empty()) - return; - - assert(this->vertices_and_normals_interleaved_VBO_id != 0); - assert(this->triangle_indices_VBO_id != 0 || this->quad_indices_VBO_id != 0); - - // Render using the Vertex Buffer Objects. - glsafe(::glBindBuffer(GL_ARRAY_BUFFER, this->vertices_and_normals_interleaved_VBO_id)); - glsafe(::glVertexPointer(3, GL_FLOAT, 6 * sizeof(float), (const void*)(3 * sizeof(float)))); - glsafe(::glNormalPointer(GL_FLOAT, 6 * sizeof(float), nullptr)); - - glsafe(::glEnableClientState(GL_VERTEX_ARRAY)); - glsafe(::glEnableClientState(GL_NORMAL_ARRAY)); - - if (this->triangle_indices_size > 0) { - glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, this->triangle_indices_VBO_id)); - glsafe(::glDrawElements(GL_TRIANGLES, GLsizei(std::min(this->triangle_indices_size, tverts_range.second - tverts_range.first)), GL_UNSIGNED_INT, (const void*)(tverts_range.first * 4))); - glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0)); - } - if (this->quad_indices_size > 0) { - glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, this->quad_indices_VBO_id)); - glsafe(::glDrawElements(GL_QUADS, GLsizei(std::min(this->quad_indices_size, qverts_range.second - qverts_range.first)), GL_UNSIGNED_INT, (const void*)(qverts_range.first * 4))); - glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0)); - } - - glsafe(::glDisableClientState(GL_VERTEX_ARRAY)); - glsafe(::glDisableClientState(GL_NORMAL_ARRAY)); - - glsafe(::glBindBuffer(GL_ARRAY_BUFFER, 0)); -} const float GLVolume::SinkingContours::HalfWidth = 0.25f; @@ -440,7 +212,6 @@ GLVolume::GLVolume(float r, float g, float b, float a) , force_neutral_color(false) , force_sinking_contours(false) , tverts_range(0, size_t(-1)) - , qverts_range(0, size_t(-1)) { color = { r, g, b, a }; set_render_color(color); @@ -593,34 +364,28 @@ const BoundingBoxf3& GLVolume::transformed_non_sinking_bounding_box() const void GLVolume::set_range(double min_z, double max_z) { - this->qverts_range.first = 0; - this->qverts_range.second = this->indexed_vertex_array.quad_indices_size; this->tverts_range.first = 0; - this->tverts_range.second = this->indexed_vertex_array.triangle_indices_size; - if (! this->print_zs.empty()) { + this->tverts_range.second = this->model.indices_count(); + + if (!this->print_zs.empty()) { // The Z layer range is specified. // First test whether the Z span of this object is not out of (min_z, max_z) completely. - if (this->print_zs.front() > max_z || this->print_zs.back() < min_z) { - this->qverts_range.second = 0; + if (this->print_zs.front() > max_z || this->print_zs.back() < min_z) this->tverts_range.second = 0; - } else { + else { // Then find the lowest layer to be displayed. size_t i = 0; - for (; i < this->print_zs.size() && this->print_zs[i] < min_z; ++ i); - if (i == this->print_zs.size()) { + for (; i < this->print_zs.size() && this->print_zs[i] < min_z; ++i); + if (i == this->print_zs.size()) // This shall not happen. - this->qverts_range.second = 0; this->tverts_range.second = 0; - } else { + else { // Remember start of the layer. - this->qverts_range.first = this->offsets[i * 2]; - this->tverts_range.first = this->offsets[i * 2 + 1]; + this->tverts_range.first = this->offsets[i]; // Some layers are above $min_z. Which? - for (; i < this->print_zs.size() && this->print_zs[i] <= max_z; ++ i); - if (i < this->print_zs.size()) { - this->qverts_range.second = this->offsets[i * 2]; - this->tverts_range.second = this->offsets[i * 2 + 1]; - } + for (; i < this->print_zs.size() && this->print_zs[i] <= max_z; ++i); + if (i < this->print_zs.size()) + this->tverts_range.second = this->offsets[i]; } } } @@ -628,7 +393,7 @@ void GLVolume::set_range(double min_z, double max_z) //BBS: add outline related logic //static unsigned char stencil_data[1284][2944]; -void GLVolume::render(bool with_outline) const +void GLVolume::render(bool with_outline) { if (!is_active) return; @@ -657,19 +422,18 @@ void GLVolume::render(bool with_outline) const color_volume = true; if (mv->mmu_segmentation_facets.timestamp() != mmuseg_ts) { BOOST_LOG_TRIVIAL(debug) << __FUNCTION__<< boost::format(", this %1%, name %2%, current mmuseg_ts %3%, current color size %4%") - %this %this->name %mmuseg_ts %mmuseg_ivas.size() ; - mmuseg_ivas.clear(); + %this %this->name %mmuseg_ts %mmuseg_models.size() ; + mmuseg_models.clear(); std::vector its_per_color; mv->mmu_segmentation_facets.get_facets(*mv, its_per_color); - mmuseg_ivas.resize(its_per_color.size()); + mmuseg_models.resize(its_per_color.size()); for (int idx = 0; idx < its_per_color.size(); idx++) { - mmuseg_ivas[idx].load_its_flat_shading(its_per_color[idx]); - mmuseg_ivas[idx].finalize_geometry(true); + mmuseg_models[idx].init_from(its_per_color[idx]); } mmuseg_ts = mv->mmu_segmentation_facets.timestamp(); BOOST_LOG_TRIVIAL(debug) << __FUNCTION__<< boost::format(", this %1%, name %2%, new mmuseg_ts %3%, new color size %4%") - %this %this->name %mmuseg_ts %mmuseg_ivas.size(); + %this %this->name %mmuseg_ts %mmuseg_models.size(); } } while (0); @@ -683,9 +447,9 @@ void GLVolume::render(bool with_outline) const colors[index].a(render_color.a()); } glsafe(::glMultMatrixd(world_matrix().data())); - for (int idx = 0; idx < mmuseg_ivas.size(); idx++) { - GLIndexedVertexArray& iva = mmuseg_ivas[idx]; - if (iva.triangle_indices_size == 0 && iva.quad_indices_size == 0) + for (int idx = 0; idx < mmuseg_models.size(); idx++) { + GUI::GLModel &m = mmuseg_models[idx]; + if (m.is_empty()) continue; if (shader) { @@ -696,24 +460,27 @@ void GLVolume::render(bool with_outline) const //shader->set_uniform("uniform_color", colors[extruder_id - 1]); //to make black not too hard too see ColorRGBA new_color = adjust_color_for_rendering(colors[extruder_id - 1]); - shader->set_uniform("uniform_color", new_color); + m.set_color(new_color); } else { if (idx <= colors.size()) { //shader->set_uniform("uniform_color", colors[idx - 1]); //to make black not too hard too see ColorRGBA new_color = adjust_color_for_rendering(colors[idx - 1]); - shader->set_uniform("uniform_color", new_color); + m.set_color(new_color); } else { //shader->set_uniform("uniform_color", colors[0]); //to make black not too hard too see ColorRGBA new_color = adjust_color_for_rendering(colors[0]); - shader->set_uniform("uniform_color", new_color); + m.set_color(new_color); } } } - iva.render(this->tverts_range, this->qverts_range); + if (tverts_range == std::make_pair(0, -1)) + m.render(); + else + m.render(this->tverts_range); /*if (force_native_color && (render_color[3] < 1.0)) { BOOST_LOG_TRIVIAL(debug) << __FUNCTION__<< boost::format(", this %1%, name %2%, tverts_range {%3,%4}, qverts_range{%5%, %6%}") %this %this->name %this->tverts_range.first %this->tverts_range.second @@ -723,7 +490,10 @@ void GLVolume::render(bool with_outline) const } else { glsafe(::glMultMatrixd(world_matrix().data())); - this->indexed_vertex_array.render(this->tverts_range, this->qverts_range); + if (tverts_range == std::make_pair(0, -1)) + model.render(); + else + model.render(this->tverts_range); } }; @@ -832,7 +602,7 @@ void GLVolume::render(bool with_outline) const float scale = 1.02f; ColorRGBA body_color = { 1.0f, 1.0f, 1.0f, 1.0f }; //red - shader->set_uniform("uniform_color", body_color); + model.set_color(body_color); shader->set_uniform("is_outline", true); glsafe(::glPopMatrix()); glsafe(::glPushMatrix()); @@ -840,7 +610,10 @@ void GLVolume::render(bool with_outline) const Transform3d matrix = world_matrix(); matrix.scale(scale); glsafe(::glMultMatrixd(matrix.data())); - this->indexed_vertex_array.render(this->tverts_range, this->qverts_range); + if (tverts_range == std::make_pair(0, -1)) + model.render(); + else + model.render(this->tverts_range); //BOOST_LOG_TRIVIAL(info) << boost::format(": %1%, outline render for body, shader name %2%")%__LINE__ %shader->get_name(); shader->set_uniform("is_outline", false); @@ -862,7 +635,7 @@ void GLVolume::render(bool with_outline) const } //BBS add render for simple case -void GLVolume::simple_render(GLShaderProgram* shader, ModelObjectPtrs& model_objects, std::vector& extruder_colors) const +void GLVolume::simple_render(GLShaderProgram* shader, ModelObjectPtrs& model_objects, std::vector& extruder_colors) { if (this->is_left_handed()) glFrontFace(GL_CW); @@ -885,13 +658,12 @@ void GLVolume::simple_render(GLShaderProgram* shader, ModelObjectPtrs& model_obj color_volume = true; if (model_volume->mmu_segmentation_facets.timestamp() != mmuseg_ts) { - mmuseg_ivas.clear(); + mmuseg_models.clear(); std::vector its_per_color; model_volume->mmu_segmentation_facets.get_facets(*model_volume, its_per_color); - mmuseg_ivas.resize(its_per_color.size()); + mmuseg_models.resize(its_per_color.size()); for (int idx = 0; idx < its_per_color.size(); idx++) { - mmuseg_ivas[idx].load_its_flat_shading(its_per_color[idx]); - mmuseg_ivas[idx].finalize_geometry(true); + mmuseg_models[idx].init_from(its_per_color[idx]); } mmuseg_ts = model_volume->mmu_segmentation_facets.timestamp(); @@ -900,9 +672,9 @@ void GLVolume::simple_render(GLShaderProgram* shader, ModelObjectPtrs& model_obj if (color_volume) { glsafe(::glMultMatrixd(world_matrix().data())); - for (int idx = 0; idx < mmuseg_ivas.size(); idx++) { - GLIndexedVertexArray& iva = mmuseg_ivas[idx]; - if (iva.triangle_indices_size == 0 && iva.quad_indices_size == 0) + for (int idx = 0; idx < mmuseg_models.size(); idx++) { + GUI::GLModel &m = mmuseg_models[idx]; + if (m.is_empty()) continue; if (shader) { @@ -910,29 +682,35 @@ void GLVolume::simple_render(GLShaderProgram* shader, ModelObjectPtrs& model_obj int extruder_id = model_volume->extruder_id(); //to make black not too hard too see ColorRGBA new_color = adjust_color_for_rendering(extruder_colors[extruder_id - 1]); - shader->set_uniform("uniform_color", new_color); + m.set_color(new_color); } else { if (idx <= extruder_colors.size()) { //shader->set_uniform("uniform_color", extruder_colors[idx - 1]); //to make black not too hard too see ColorRGBA new_color = adjust_color_for_rendering(extruder_colors[idx - 1]); - shader->set_uniform("uniform_color", new_color); + m.set_color(new_color); } else { //shader->set_uniform("uniform_color", extruder_colors[0]); //to make black not too hard too see ColorRGBA new_color = adjust_color_for_rendering(extruder_colors[0]); - shader->set_uniform("uniform_color", new_color); + m.set_color(new_color); } } } - iva.render(this->tverts_range, this->qverts_range); + if (tverts_range == std::make_pair(0, -1)) + m.render(); + else + m.render(this->tverts_range); } } else { glsafe(::glMultMatrixd(world_matrix().data())); - this->indexed_vertex_array.render(this->tverts_range, this->qverts_range); + if (tverts_range == std::make_pair(0, -1)) + model.render(); + else + model.render(this->tverts_range); } glsafe(::glPopMatrix()); @@ -967,12 +745,12 @@ GLWipeTowerVolume::GLWipeTowerVolume(const std::vector& colors) m_colors = colors; } -void GLWipeTowerVolume::render(bool with_outline) const +void GLWipeTowerVolume::render(bool with_outline) { if (!is_active) return; - if (m_colors.size() == 0 || m_colors.size() != iva_per_colors.size()) + if (m_colors.size() == 0 || m_colors.size() != model_per_colors.size()) return; if (this->is_left_handed()) @@ -983,11 +761,9 @@ void GLWipeTowerVolume::render(bool with_outline) const GLShaderProgram* shader = GUI::wxGetApp().get_current_shader(); for (int i = 0; i < m_colors.size(); i++) { - if (shader) { - ColorRGBA new_color = adjust_color_for_rendering(m_colors[i]); - shader->set_uniform("uniform_color", new_color); - } - this->iva_per_colors[i].render(); + ColorRGBA new_color = adjust_color_for_rendering(m_colors[i]); + this->model_per_colors[i].set_color(new_color); + this->model_per_colors[i].render(); } glsafe(::glPopMatrix()); @@ -1005,24 +781,22 @@ bool GLWipeTowerVolume::IsTransparent() { } std::vector GLVolumeCollection::load_object( - const ModelObject *model_object, - int obj_idx, - const std::vector &instance_idxs, - bool opengl_initialized) + const ModelObject* model_object, + int obj_idx, + const std::vector& instance_idxs) { std::vector volumes_idx; for (int volume_idx = 0; volume_idx < int(model_object->volumes.size()); ++volume_idx) for (int instance_idx : instance_idxs) - volumes_idx.emplace_back(this->GLVolumeCollection::load_object_volume(model_object, obj_idx, volume_idx, instance_idx, opengl_initialized)); + volumes_idx.emplace_back(this->GLVolumeCollection::load_object_volume(model_object, obj_idx, volume_idx, instance_idx)); return volumes_idx; } int GLVolumeCollection::load_object_volume( - const ModelObject *model_object, + const ModelObject* model_object, int obj_idx, int volume_idx, int instance_idx, - bool opengl_initialized, bool in_assemble_view, bool use_loaded_id) { @@ -1034,15 +808,14 @@ int GLVolumeCollection::load_object_volume( GLVolume& v = *this->volumes.back(); v.set_color(color_from_model_volume(*model_volume)); v.name = model_volume->name; + #if ENABLE_SMOOTH_NORMALS - v.indexed_vertex_array.load_mesh(mesh, true); + v.model.init_from(mesh, true); #else - v.indexed_vertex_array.load_mesh(mesh); + v.model.init_from(mesh); #endif // ENABLE_SMOOTH_NORMALS - v.indexed_vertex_array.finalize_geometry(opengl_initialized); v.composite_id = GLVolume::CompositeID(obj_idx, volume_idx, instance_idx); - if (model_volume->is_model_part()) - { + if (model_volume->is_model_part()) { // GLVolume will reference a convex hull from model_volume! v.set_convex_hull(model_volume->get_convex_hull_shared_ptr()); if (extruder_id != -1) @@ -1070,14 +843,13 @@ int GLVolumeCollection::load_object_volume( // This function produces volumes for multiple instances in a single shot, // as some object specific mesh conversions may be expensive. void GLVolumeCollection::load_object_auxiliary( - const SLAPrintObject *print_object, + const SLAPrintObject* print_object, int obj_idx, // pairs of const std::vector>& instances, SLAPrintObjectStep milestone, // Timestamp of the last change of the milestone - size_t timestamp, - bool opengl_initialized) + size_t timestamp) { assert(print_object->is_step_done(milestone)); Transform3d mesh_trafo_inv = print_object->trafo().inverse(); @@ -1091,11 +863,11 @@ void GLVolumeCollection::load_object_auxiliary( this->volumes.emplace_back(new GLVolume((milestone == slaposPad) ? GLVolume::SLA_PAD_COLOR : GLVolume::SLA_SUPPORT_COLOR)); GLVolume& v = *this->volumes.back(); #if ENABLE_SMOOTH_NORMALS - v.indexed_vertex_array.load_mesh(mesh, true); + v.model.init_from(mesh, true); #else - v.indexed_vertex_array.load_mesh(mesh); + v.model.init_from(mesh); #endif // ENABLE_SMOOTH_NORMALS - v.indexed_vertex_array.finalize_geometry(opengl_initialized); + v.model.set_color((milestone == slaposPad) ? GLVolume::SLA_PAD_COLOR : GLVolume::SLA_SUPPORT_COLOR); v.composite_id = GLVolume::CompositeID(obj_idx, -int(milestone), (int)instance_idx.first); v.geometry_id = std::pair(timestamp, model_instance.id().id); // Create a copy of the convex hull mesh for each instance. Use a move operator on the last instance. @@ -1113,7 +885,7 @@ void GLVolumeCollection::load_object_auxiliary( int GLVolumeCollection::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) + float rotation_angle, bool size_unknown, float brim_width) { int plate_idx = obj_idx - 1000; @@ -1146,15 +918,13 @@ int GLVolumeCollection::load_wipe_tower_preview( color.a(0.66f); volumes.emplace_back(new GLWipeTowerVolume(colors)); GLWipeTowerVolume& v = *dynamic_cast(volumes.back()); - v.iva_per_colors.resize(colors.size()); + v.model_per_colors.resize(colors.size()); for (int i = 0; i < colors.size(); i++) { TriangleMesh color_part = make_cube(width, depth / colors.size(), height); color_part.translate({ 0.f, depth * i / colors.size(), 0. }); - v.iva_per_colors[i].load_mesh(color_part); - v.iva_per_colors[i].finalize_geometry(opengl_initialized); + v.model_per_colors[i].init_from(color_part); } - v.indexed_vertex_array.load_mesh(wipe_tower_shell); - v.indexed_vertex_array.finalize_geometry(opengl_initialized); + v.model.init_from(wipe_tower_shell); v.set_convex_hull(wipe_tower_shell); v.set_volume_offset(Vec3d(pos_x, pos_y, 0.0)); v.set_volume_rotation(Vec3d(0., 0., (M_PI / 180.) * rotation_angle)); @@ -1166,21 +936,19 @@ int GLVolumeCollection::load_wipe_tower_preview( return int(volumes.size() - 1); } -GLVolume* GLVolumeCollection::new_toolpath_volume(const ColorRGBA& rgba, size_t reserve_vbo_floats) +GLVolume* GLVolumeCollection::new_toolpath_volume(const ColorRGBA& rgba) { - GLVolume *out = new_nontoolpath_volume(rgba, reserve_vbo_floats); - out->is_extrusion_path = true; - return out; + GLVolume* out = new_nontoolpath_volume(rgba); + out->is_extrusion_path = true; + return out; } -GLVolume* GLVolumeCollection::new_nontoolpath_volume(const ColorRGBA& rgba, size_t reserve_vbo_floats) +GLVolume* GLVolumeCollection::new_nontoolpath_volume(const ColorRGBA& rgba) { - GLVolume *out = new GLVolume(rgba); - out->is_extrusion_path = false; - // Reserving number of vertices (3x position + 3x color) - out->indexed_vertex_array.reserve(reserve_vbo_floats / 6); - this->volumes.emplace_back(out); - return out; + GLVolume* out = new GLVolume(rgba); + out->is_extrusion_path = false; + this->volumes.emplace_back(out); + return out; } GLVolumeWithIdAndZList volumes_to_render(const GLVolumePtrs& volumes, GLVolumeCollection::ERenderType type, const Transform3d& view_matrix, std::function filter_func) @@ -1284,7 +1052,8 @@ void GLVolumeCollection::render( glsafe(::glEnableClientState(GL_VERTEX_ARRAY)); glsafe(::glEnableClientState(GL_NORMAL_ARRAY)); - shader->set_uniform("uniform_color", volume.first->render_color); + if (!volume.first->model.is_initialized()) + shader->set_uniform("uniform_color", volume.first->render_color); shader->set_uniform("z_range", m_z_range, 2); shader->set_uniform("clipping_plane", m_clipping_plane, 4); //BOOST_LOG_TRIVIAL(info) << boost::format("set uniform_color to {%1%, %2%, %3%, %4%}, with_outline=%5%, selected %6%") @@ -1326,6 +1095,7 @@ void GLVolumeCollection::render( #endif // ENABLE_ENVIRONMENT_MAP glcheck(); + volume.first->model.set_color(volume.first->render_color); //BBS: add outline related logic volume.first->render(with_outline && volume.first->selected); @@ -1617,60 +1387,63 @@ std::string GLVolumeCollection::log_memory_info() const return " (GLVolumeCollection RAM: " + format_memsize_MB(this->cpu_memory_used()) + " GPU: " + format_memsize_MB(this->gpu_memory_used()) + " Both: " + format_memsize_MB(this->gpu_memory_used()) + ")"; } -// caller is responsible for supplying NO lines with zero length -static void thick_lines_to_indexed_vertex_array( - const Lines &lines, - const std::vector &widths, - const std::vector &heights, - bool closed, - double top_z, - GLIndexedVertexArray &volume) +static void thick_lines_to_geometry( + const Lines& lines, + const std::vector& widths, + const std::vector& heights, + bool closed, + double top_z, + GUI::GLModel::Geometry& geometry) { - assert(! lines.empty()); + assert(!lines.empty()); if (lines.empty()) return; -#define LEFT 0 -#define RIGHT 1 -#define TOP 2 -#define BOTTOM 3 + enum Direction : unsigned char + { + Left, + Right, + Top, + Bottom + }; // right, left, top, bottom - int idx_prev[4] = { -1, -1, -1, -1 }; - double bottom_z_prev = 0.; - Vec2d b1_prev(Vec2d::Zero()); - Vec2d v_prev(Vec2d::Zero()); - int idx_initial[4] = { -1, -1, -1, -1 }; - double width_initial = 0.; - double bottom_z_initial = 0.0; - double len_prev = 0.0; + std::array idx_prev = { -1, -1, -1, -1 }; + std::array idx_initial = { -1, -1, -1, -1 }; + + double bottom_z_prev = 0.0; + Vec2d b1_prev(Vec2d::Zero()); + Vec2d v_prev(Vec2d::Zero()); + double len_prev = 0.0; + double width_initial = 0.0; + double bottom_z_initial = 0.0; // loop once more in case of closed loops - size_t lines_end = closed ? (lines.size() + 1) : lines.size(); - for (size_t ii = 0; ii < lines_end; ++ ii) { - size_t i = (ii == lines.size()) ? 0 : ii; - const Line &line = lines[i]; - double bottom_z = top_z - heights[i]; - double middle_z = 0.5 * (top_z + bottom_z); - double width = widths[i]; - - bool is_first = (ii == 0); - bool is_last = (ii == lines_end - 1); - bool is_closing = closed && is_last; - - Vec2d v = unscale(line.vector()).normalized(); - double len = unscale(line.length()); - - Vec2d a = unscale(line.a); - Vec2d b = unscale(line.b); + const size_t lines_end = closed ? (lines.size() + 1) : lines.size(); + for (size_t ii = 0; ii < lines_end; ++ii) { + const size_t i = (ii == lines.size()) ? 0 : ii; + const Line& line = lines[i]; + const double bottom_z = top_z - heights[i]; + const double middle_z = 0.5 * (top_z + bottom_z); + const double width = widths[i]; + + const bool is_first = (ii == 0); + const bool is_last = (ii == lines_end - 1); + const bool is_closing = closed && is_last; + + const Vec2d v = unscale(line.vector()).normalized(); + const double len = unscale(line.length()); + + const Vec2d a = unscale(line.a); + const Vec2d b = unscale(line.b); Vec2d a1 = a; Vec2d a2 = a; Vec2d b1 = b; Vec2d b2 = b; { - double dist = 0.5 * width; // scaled - double dx = dist * v(0); - double dy = dist * v(1); + const double dist = 0.5 * width; // scaled + const double dx = dist * v.x(); + const double dy = dist * v.y(); a1 += Vec2d(+dy, -dx); a2 += Vec2d(-dy, +dx); b1 += Vec2d(+dy, -dx); @@ -1678,102 +1451,101 @@ static void thick_lines_to_indexed_vertex_array( } // calculate new XY normals - Vec2d xy_right_normal = unscale(line.normal()).normalized(); + const Vec2d xy_right_normal = unscale(line.normal()).normalized(); - int idx_a[4] = { 0, 0, 0, 0 }; // initialized to avoid warnings - int idx_b[4] = { 0, 0, 0, 0 }; // initialized to avoid warnings - int idx_last = int(volume.vertices_and_normals_interleaved.size() / 6); + std::array idx_a = { 0, 0, 0, 0 }; + std::array idx_b = { 0, 0, 0, 0 }; + int idx_last = int(geometry.vertices_count()); - bool bottom_z_different = bottom_z_prev != bottom_z; + const bool bottom_z_different = bottom_z_prev != bottom_z; bottom_z_prev = bottom_z; - if (!is_first && bottom_z_different) - { + if (!is_first && bottom_z_different) { // Found a change of the layer thickness -> Add a cap at the end of the previous segment. - volume.push_quad(idx_b[BOTTOM], idx_b[LEFT], idx_b[TOP], idx_b[RIGHT]); + geometry.add_uint_triangle(idx_b[Bottom], idx_b[Left], idx_b[Top]); + geometry.add_uint_triangle(idx_b[Bottom], idx_b[Top], idx_b[Right]); } // Share top / bottom vertices if possible. if (is_first) { - idx_a[TOP] = idx_last++; - volume.push_geometry(a(0), a(1), top_z , 0., 0., 1.); - } else { - idx_a[TOP] = idx_prev[TOP]; + idx_a[Top] = idx_last++; + geometry.add_vertex(Vec3f(a.x(), a.y(), top_z), Vec3f(0.0f, 0.0f, 1.0f)); } + else + idx_a[Top] = idx_prev[Top]; if (is_first || bottom_z_different) { // Start of the 1st line segment or a change of the layer thickness while maintaining the print_z. - idx_a[BOTTOM] = idx_last ++; - volume.push_geometry(a(0), a(1), bottom_z, 0., 0., -1.); - idx_a[LEFT ] = idx_last ++; - volume.push_geometry(a2(0), a2(1), middle_z, -xy_right_normal(0), -xy_right_normal(1), 0.0); - idx_a[RIGHT] = idx_last ++; - volume.push_geometry(a1(0), a1(1), middle_z, xy_right_normal(0), xy_right_normal(1), 0.0); - } - else { - idx_a[BOTTOM] = idx_prev[BOTTOM]; + idx_a[Bottom] = idx_last++; + geometry.add_vertex(Vec3f(a.x(), a.y(), bottom_z), Vec3f(0.0f, 0.0f, -1.0f)); + idx_a[Left] = idx_last++; + geometry.add_vertex(Vec3f(a2.x(), a2.y(), middle_z), Vec3f(-xy_right_normal.x(), -xy_right_normal.y(), 0.0f)); + idx_a[Right] = idx_last++; + geometry.add_vertex(Vec3f(a1.x(), a1.y(), middle_z), Vec3f(xy_right_normal.x(), xy_right_normal.y(), 0.0f)); } + else + idx_a[Bottom] = idx_prev[Bottom]; if (is_first) { // Start of the 1st line segment. - width_initial = width; + width_initial = width; bottom_z_initial = bottom_z; - memcpy(idx_initial, idx_a, sizeof(int) * 4); - } else { + idx_initial = idx_a; + } + else { // Continuing a previous segment. // Share left / right vertices if possible. - double v_dot = v_prev.dot(v); + const double v_dot = v_prev.dot(v); // To reduce gpu memory usage, we try to reuse vertices - // To reduce the visual artifacts, due to averaged normals, we allow to reuse vertices only when any of two adjacent edges + // To reduce the visual artifacts, due to averaged normals, we allow to reuse vertices only when any of two adjacent edges // is longer than a fixed threshold. // The following value is arbitrary, it comes from tests made on a bunch of models showing the visual artifacts - double len_threshold = 2.5; + const double len_threshold = 2.5; // Generate new vertices if the angle between adjacent edges is greater than 45 degrees or thresholds conditions are met - bool sharp = (v_dot < 0.707) || (len_prev > len_threshold) || (len > len_threshold); + const bool sharp = (v_dot < 0.707) || (len_prev > len_threshold) || (len > len_threshold); if (sharp) { - if (!bottom_z_different) - { + if (!bottom_z_different) { // Allocate new left / right points for the start of this segment as these points will receive their own normals to indicate a sharp turn. - idx_a[RIGHT] = idx_last++; - volume.push_geometry(a1(0), a1(1), middle_z, xy_right_normal(0), xy_right_normal(1), 0.0); - idx_a[LEFT] = idx_last++; - volume.push_geometry(a2(0), a2(1), middle_z, -xy_right_normal(0), -xy_right_normal(1), 0.0); - if (cross2(v_prev, v) > 0.) { + idx_a[Right] = idx_last++; + geometry.add_vertex(Vec3f(a1.x(), a1.y(), middle_z), Vec3f(xy_right_normal.x(), xy_right_normal.y(), 0.0f)); + idx_a[Left] = idx_last++; + geometry.add_vertex(Vec3f(a2.x(), a2.y(), middle_z), Vec3f(-xy_right_normal.x(), -xy_right_normal.y(), 0.0f)); + if (cross2(v_prev, v) > 0.0) { // Right turn. Fill in the right turn wedge. - volume.push_triangle(idx_prev[RIGHT], idx_a[RIGHT], idx_prev[TOP]); - volume.push_triangle(idx_prev[RIGHT], idx_prev[BOTTOM], idx_a[RIGHT]); + geometry.add_uint_triangle(idx_prev[Right], idx_a[Right], idx_prev[Top]); + geometry.add_uint_triangle(idx_prev[Right], idx_prev[Bottom], idx_a[Right]); } else { // Left turn. Fill in the left turn wedge. - volume.push_triangle(idx_prev[LEFT], idx_prev[TOP], idx_a[LEFT]); - volume.push_triangle(idx_prev[LEFT], idx_a[LEFT], idx_prev[BOTTOM]); + geometry.add_uint_triangle(idx_prev[Left], idx_prev[Top], idx_a[Left]); + geometry.add_uint_triangle(idx_prev[Left], idx_a[Left], idx_prev[Bottom]); } } } - else - { - if (!bottom_z_different) - { + else { + if (!bottom_z_different) { // The two successive segments are nearly collinear. - idx_a[LEFT ] = idx_prev[LEFT]; - idx_a[RIGHT] = idx_prev[RIGHT]; + idx_a[Left] = idx_prev[Left]; + idx_a[Right] = idx_prev[Right]; } } if (is_closing) { if (!sharp) { - if (!bottom_z_different) - { + if (!bottom_z_different) { // Closing a loop with smooth transition. Unify the closing left / right vertices. - memcpy(volume.vertices_and_normals_interleaved.data() + idx_initial[LEFT ] * 6, volume.vertices_and_normals_interleaved.data() + idx_prev[LEFT ] * 6, sizeof(float) * 6); - memcpy(volume.vertices_and_normals_interleaved.data() + idx_initial[RIGHT] * 6, volume.vertices_and_normals_interleaved.data() + idx_prev[RIGHT] * 6, sizeof(float) * 6); - volume.vertices_and_normals_interleaved.erase(volume.vertices_and_normals_interleaved.end() - 12, volume.vertices_and_normals_interleaved.end()); + geometry.set_vertex(idx_initial[Left], geometry.extract_position_3(idx_prev[Left]), geometry.extract_normal_3(idx_prev[Left])); + geometry.set_vertex(idx_initial[Right], geometry.extract_position_3(idx_prev[Right]), geometry.extract_normal_3(idx_prev[Right])); + geometry.remove_vertex(geometry.vertices_count() - 1); + geometry.remove_vertex(geometry.vertices_count() - 1); // Replace the left / right vertex indices to point to the start of the loop. - for (size_t u = volume.quad_indices.size() - 16; u < volume.quad_indices.size(); ++ u) { - if (volume.quad_indices[u] == idx_prev[LEFT]) - volume.quad_indices[u] = idx_initial[LEFT]; - else if (volume.quad_indices[u] == idx_prev[RIGHT]) - volume.quad_indices[u] = idx_initial[RIGHT]; + const size_t indices_count = geometry.indices_count(); + for (size_t u = indices_count - 24; u < indices_count; ++u) { + const unsigned int id = geometry.extract_uint_index(u); + if (id == (unsigned int)idx_prev[Left]) + geometry.set_uint_index(u, (unsigned int)idx_initial[Left]); + else if (id == (unsigned int)idx_prev[Right]) + geometry.set_uint_index(u, (unsigned int)idx_initial[Right]); } } } @@ -1783,235 +1555,232 @@ static void thick_lines_to_indexed_vertex_array( } // Only new allocate top / bottom vertices, if not closing a loop. - if (is_closing) { - idx_b[TOP] = idx_initial[TOP]; - } else { - idx_b[TOP] = idx_last ++; - volume.push_geometry(b(0), b(1), top_z , 0., 0., 1.); + if (is_closing) + idx_b[Top] = idx_initial[Top]; + else { + idx_b[Top] = idx_last++; + geometry.add_vertex(Vec3f(b.x(), b.y(), top_z), Vec3f(0.0f, 0.0f, 1.0f)); } - if (is_closing && (width == width_initial) && (bottom_z == bottom_z_initial)) { - idx_b[BOTTOM] = idx_initial[BOTTOM]; - } else { - idx_b[BOTTOM] = idx_last ++; - volume.push_geometry(b(0), b(1), bottom_z, 0., 0., -1.); + if (is_closing && width == width_initial && bottom_z == bottom_z_initial) + idx_b[Bottom] = idx_initial[Bottom]; + else { + idx_b[Bottom] = idx_last++; + geometry.add_vertex(Vec3f(b.x(), b.y(), bottom_z), Vec3f(0.0f, 0.0f, -1.0f)); } // Generate new vertices for the end of this line segment. - idx_b[LEFT ] = idx_last ++; - volume.push_geometry(b2(0), b2(1), middle_z, -xy_right_normal(0), -xy_right_normal(1), 0.0); - idx_b[RIGHT ] = idx_last ++; - volume.push_geometry(b1(0), b1(1), middle_z, xy_right_normal(0), xy_right_normal(1), 0.0); + idx_b[Left] = idx_last++; + geometry.add_vertex(Vec3f(b2.x(), b2.y(), middle_z), Vec3f(-xy_right_normal.x(), -xy_right_normal.y(), 0.0f)); + idx_b[Right] = idx_last++; + geometry.add_vertex(Vec3f(b1.x(), b1.y(), middle_z), Vec3f(xy_right_normal.x(), xy_right_normal.y(), 0.0f)); - memcpy(idx_prev, idx_b, 4 * sizeof(int)); + idx_prev = idx_b; bottom_z_prev = bottom_z; b1_prev = b1; v_prev = v; len_prev = len; - if (bottom_z_different && (closed || (!is_first && !is_last))) - { + if (bottom_z_different && (closed || (!is_first && !is_last))) { // Found a change of the layer thickness -> Add a cap at the beginning of this segment. - volume.push_quad(idx_a[BOTTOM], idx_a[RIGHT], idx_a[TOP], idx_a[LEFT]); + geometry.add_uint_triangle(idx_a[Bottom], idx_a[Right], idx_a[Top]); + geometry.add_uint_triangle(idx_a[Bottom], idx_a[Top], idx_a[Left]); } - if (! closed) { + if (!closed) { // Terminate open paths with caps. - if (is_first) - volume.push_quad(idx_a[BOTTOM], idx_a[RIGHT], idx_a[TOP], idx_a[LEFT]); + if (is_first) { + geometry.add_uint_triangle(idx_a[Bottom], idx_a[Right], idx_a[Top]); + geometry.add_uint_triangle(idx_a[Bottom], idx_a[Top], idx_a[Left]); + } // We don't use 'else' because both cases are true if we have only one line. - if (is_last) - volume.push_quad(idx_b[BOTTOM], idx_b[LEFT], idx_b[TOP], idx_b[RIGHT]); + if (is_last) { + geometry.add_uint_triangle(idx_b[Bottom], idx_b[Left], idx_b[Top]); + geometry.add_uint_triangle(idx_b[Bottom], idx_b[Top], idx_b[Right]); + } } // Add quads for a straight hollow tube-like segment. // bottom-right face - volume.push_quad(idx_a[BOTTOM], idx_b[BOTTOM], idx_b[RIGHT], idx_a[RIGHT]); + geometry.add_uint_triangle(idx_a[Bottom], idx_b[Bottom], idx_b[Right]); + geometry.add_uint_triangle(idx_a[Bottom], idx_b[Right], idx_a[Right]); // top-right face - volume.push_quad(idx_a[RIGHT], idx_b[RIGHT], idx_b[TOP], idx_a[TOP]); + geometry.add_uint_triangle(idx_a[Right], idx_b[Right], idx_b[Top]); + geometry.add_uint_triangle(idx_a[Right], idx_b[Top], idx_a[Top]); // top-left face - volume.push_quad(idx_a[TOP], idx_b[TOP], idx_b[LEFT], idx_a[LEFT]); + geometry.add_uint_triangle(idx_a[Top], idx_b[Top], idx_b[Left]); + geometry.add_uint_triangle(idx_a[Top], idx_b[Left], idx_a[Left]); // bottom-left face - volume.push_quad(idx_a[LEFT], idx_b[LEFT], idx_b[BOTTOM], idx_a[BOTTOM]); + geometry.add_uint_triangle(idx_a[Left], idx_b[Left], idx_b[Bottom]); + geometry.add_uint_triangle(idx_a[Left], idx_b[Bottom], idx_a[Bottom]); } - -#undef LEFT -#undef RIGHT -#undef TOP -#undef BOTTOM } // caller is responsible for supplying NO lines with zero length -static void thick_lines_to_indexed_vertex_array(const Lines3& lines, +static void thick_lines_to_geometry( + const Lines3& lines, const std::vector& widths, const std::vector& heights, - bool closed, - GLIndexedVertexArray& volume) + bool closed, + GUI::GLModel::Geometry& geometry) { assert(!lines.empty()); if (lines.empty()) return; -#define LEFT 0 -#define RIGHT 1 -#define TOP 2 -#define BOTTOM 3 + enum Direction : unsigned char + { + Left, + Right, + Top, + Bottom + }; // left, right, top, bottom - int idx_initial[4] = { -1, -1, -1, -1 }; - int idx_prev[4] = { -1, -1, -1, -1 }; - double z_prev = 0.0; - double len_prev = 0.0; - Vec3d n_right_prev = Vec3d::Zero(); - Vec3d n_top_prev = Vec3d::Zero(); - Vec3d unit_v_prev = Vec3d::Zero(); - double width_initial = 0.0; + std::array idx_prev = { -1, -1, -1, -1 }; + std::array idx_initial = { -1, -1, -1, -1 }; + + double z_prev = 0.0; + double len_prev = 0.0; + Vec3d n_right_prev = Vec3d::Zero(); + Vec3d n_top_prev = Vec3d::Zero(); + Vec3d unit_v_prev = Vec3d::Zero(); + double width_initial = 0.0; // new vertices around the line endpoints // left, right, top, bottom - Vec3d a[4] = { Vec3d::Zero(), Vec3d::Zero(), Vec3d::Zero(), Vec3d::Zero() }; - Vec3d b[4] = { Vec3d::Zero(), Vec3d::Zero(), Vec3d::Zero(), Vec3d::Zero() }; + std::array a = { Vec3d::Zero(), Vec3d::Zero(), Vec3d::Zero(), Vec3d::Zero() }; + std::array b = { Vec3d::Zero(), Vec3d::Zero(), Vec3d::Zero(), Vec3d::Zero() }; // loop once more in case of closed loops - size_t lines_end = closed ? (lines.size() + 1) : lines.size(); - for (size_t ii = 0; ii < lines_end; ++ii) - { - size_t i = (ii == lines.size()) ? 0 : ii; + const size_t lines_end = closed ? (lines.size() + 1) : lines.size(); + for (size_t ii = 0; ii < lines_end; ++ii) { + const size_t i = (ii == lines.size()) ? 0 : ii; const Line3& line = lines[i]; - double height = heights[i]; - double width = widths[i]; + const double height = heights[i]; + const double width = widths[i]; - Vec3d unit_v = unscale(line.vector()).normalized(); - double len = unscale(line.length()); + const Vec3d unit_v = unscale(line.vector()).normalized(); + const double len = unscale(line.length()); Vec3d n_top = Vec3d::Zero(); Vec3d n_right = Vec3d::Zero(); - if ((line.a(0) == line.b(0)) && (line.a(1) == line.b(1))) - { + if (line.a.x() == line.b.x() && line.a.y() == line.b.y()) { // vertical segment n_top = Vec3d::UnitY(); n_right = Vec3d::UnitX(); - if (line.a(2) < line.b(2)) + if (line.a.z() < line.b.z()) n_right = -n_right; } - else - { + else { // horizontal segment n_right = unit_v.cross(Vec3d::UnitZ()).normalized(); n_top = n_right.cross(unit_v).normalized(); } - Vec3d rl_displacement = 0.5 * width * n_right; - Vec3d tb_displacement = 0.5 * height * n_top; - Vec3d l_a = unscale(line.a); - Vec3d l_b = unscale(line.b); + const Vec3d rl_displacement = 0.5 * width * n_right; + const Vec3d tb_displacement = 0.5 * height * n_top; + const Vec3d l_a = unscale(line.a); + const Vec3d l_b = unscale(line.b); - a[RIGHT] = l_a + rl_displacement; - a[LEFT] = l_a - rl_displacement; - a[TOP] = l_a + tb_displacement; - a[BOTTOM] = l_a - tb_displacement; - b[RIGHT] = l_b + rl_displacement; - b[LEFT] = l_b - rl_displacement; - b[TOP] = l_b + tb_displacement; - b[BOTTOM] = l_b - tb_displacement; + a[Right] = l_a + rl_displacement; + a[Left] = l_a - rl_displacement; + a[Top] = l_a + tb_displacement; + a[Bottom] = l_a - tb_displacement; + b[Right] = l_b + rl_displacement; + b[Left] = l_b - rl_displacement; + b[Top] = l_b + tb_displacement; + b[Bottom] = l_b - tb_displacement; - Vec3d n_bottom = -n_top; - Vec3d n_left = -n_right; + const Vec3d n_bottom = -n_top; + const Vec3d n_left = -n_right; - int idx_a[4]; - int idx_b[4]; - int idx_last = int(volume.vertices_and_normals_interleaved.size() / 6); + std::array idx_a = { 0, 0, 0, 0}; + std::array idx_b = { 0, 0, 0, 0 }; + int idx_last = int(geometry.vertices_count()); - bool z_different = (z_prev != l_a(2)); - z_prev = l_b(2); + const bool z_different = (z_prev != l_a.z()); + z_prev = l_b.z(); // Share top / bottom vertices if possible. - if (ii == 0) - { - idx_a[TOP] = idx_last++; - volume.push_geometry(a[TOP], n_top); + if (ii == 0) { + idx_a[Top] = idx_last++; + geometry.add_vertex((Vec3f)a[Top].cast(), (Vec3f)n_top.cast()); } else - idx_a[TOP] = idx_prev[TOP]; + idx_a[Top] = idx_prev[Top]; - if ((ii == 0) || z_different) - { + if (ii == 0 || z_different) { // Start of the 1st line segment or a change of the layer thickness while maintaining the print_z. - idx_a[BOTTOM] = idx_last++; - volume.push_geometry(a[BOTTOM], n_bottom); - idx_a[LEFT] = idx_last++; - volume.push_geometry(a[LEFT], n_left); - idx_a[RIGHT] = idx_last++; - volume.push_geometry(a[RIGHT], n_right); + idx_a[Bottom] = idx_last++; + geometry.add_vertex((Vec3f)a[Bottom].cast(), (Vec3f)n_bottom.cast()); + idx_a[Left] = idx_last++; + geometry.add_vertex((Vec3f)a[Left].cast(), (Vec3f)n_left.cast()); + idx_a[Right] = idx_last++; + geometry.add_vertex((Vec3f)a[Right].cast(), (Vec3f)n_right.cast()); } else - idx_a[BOTTOM] = idx_prev[BOTTOM]; + idx_a[Bottom] = idx_prev[Bottom]; - if (ii == 0) - { + if (ii == 0) { // Start of the 1st line segment. width_initial = width; - ::memcpy(idx_initial, idx_a, sizeof(int) * 4); + idx_initial = idx_a; } - else - { + else { // Continuing a previous segment. // Share left / right vertices if possible. - double v_dot = unit_v_prev.dot(unit_v); - bool is_right_turn = n_top_prev.dot(unit_v_prev.cross(unit_v)) > 0.0; + const double v_dot = unit_v_prev.dot(unit_v); + const bool is_right_turn = n_top_prev.dot(unit_v_prev.cross(unit_v)) > 0.0; // To reduce gpu memory usage, we try to reuse vertices - // To reduce the visual artifacts, due to averaged normals, we allow to reuse vertices only when any of two adjacent edges + // To reduce the visual artifacts, due to averaged normals, we allow to reuse vertices only when any of two adjacent edges // is longer than a fixed threshold. // The following value is arbitrary, it comes from tests made on a bunch of models showing the visual artifacts - double len_threshold = 2.5; + const double len_threshold = 2.5; // Generate new vertices if the angle between adjacent edges is greater than 45 degrees or thresholds conditions are met - bool is_sharp = (v_dot < 0.707) || (len_prev > len_threshold) || (len > len_threshold); - if (is_sharp) - { + const bool is_sharp = v_dot < 0.707 || len_prev > len_threshold || len > len_threshold; + if (is_sharp) { // Allocate new left / right points for the start of this segment as these points will receive their own normals to indicate a sharp turn. - idx_a[RIGHT] = idx_last++; - volume.push_geometry(a[RIGHT], n_right); - idx_a[LEFT] = idx_last++; - volume.push_geometry(a[LEFT], n_left); + idx_a[Right] = idx_last++; + geometry.add_vertex((Vec3f)a[Right].cast(), (Vec3f)n_right.cast()); + idx_a[Left] = idx_last++; + geometry.add_vertex((Vec3f)a[Left].cast(), (Vec3f)n_left.cast()); - if (is_right_turn) - { + if (is_right_turn) { // Right turn. Fill in the right turn wedge. - volume.push_triangle(idx_prev[RIGHT], idx_a[RIGHT], idx_prev[TOP]); - volume.push_triangle(idx_prev[RIGHT], idx_prev[BOTTOM], idx_a[RIGHT]); + geometry.add_uint_triangle(idx_prev[Right], idx_a[Right], idx_prev[Top]); + geometry.add_uint_triangle(idx_prev[Right], idx_prev[Bottom], idx_a[Right]); } - else - { + else { // Left turn. Fill in the left turn wedge. - volume.push_triangle(idx_prev[LEFT], idx_prev[TOP], idx_a[LEFT]); - volume.push_triangle(idx_prev[LEFT], idx_a[LEFT], idx_prev[BOTTOM]); + geometry.add_uint_triangle(idx_prev[Left], idx_prev[Top], idx_a[Left]); + geometry.add_uint_triangle(idx_prev[Left], idx_a[Left], idx_prev[Bottom]); } } - else - { + else { // The two successive segments are nearly collinear. - idx_a[LEFT] = idx_prev[LEFT]; - idx_a[RIGHT] = idx_prev[RIGHT]; + idx_a[Left] = idx_prev[Left]; + idx_a[Right] = idx_prev[Right]; } - if (ii == lines.size()) - { - if (!is_sharp) - { + if (ii == lines.size()) { + if (!is_sharp) { // Closing a loop with smooth transition. Unify the closing left / right vertices. - ::memcpy(volume.vertices_and_normals_interleaved.data() + idx_initial[LEFT] * 6, volume.vertices_and_normals_interleaved.data() + idx_prev[LEFT] * 6, sizeof(float) * 6); - ::memcpy(volume.vertices_and_normals_interleaved.data() + idx_initial[RIGHT] * 6, volume.vertices_and_normals_interleaved.data() + idx_prev[RIGHT] * 6, sizeof(float) * 6); - volume.vertices_and_normals_interleaved.erase(volume.vertices_and_normals_interleaved.end() - 12, volume.vertices_and_normals_interleaved.end()); + geometry.set_vertex(idx_initial[Left], geometry.extract_position_3(idx_prev[Left]), geometry.extract_normal_3(idx_prev[Left])); + geometry.set_vertex(idx_initial[Right], geometry.extract_position_3(idx_prev[Right]), geometry.extract_normal_3(idx_prev[Right])); + geometry.remove_vertex(geometry.vertices_count() - 1); + geometry.remove_vertex(geometry.vertices_count() - 1); // Replace the left / right vertex indices to point to the start of the loop. - for (size_t u = volume.quad_indices.size() - 16; u < volume.quad_indices.size(); ++u) - { - if (volume.quad_indices[u] == idx_prev[LEFT]) - volume.quad_indices[u] = idx_initial[LEFT]; - else if (volume.quad_indices[u] == idx_prev[RIGHT]) - volume.quad_indices[u] = idx_initial[RIGHT]; + const size_t indices_count = geometry.indices_count(); + for (size_t u = indices_count - 24; u < indices_count; ++u) { + const unsigned int id = geometry.extract_uint_index(u); + if (id == (unsigned int)idx_prev[Left]) + geometry.set_uint_index(u, (unsigned int)idx_initial[Left]); + else if (id == (unsigned int)idx_prev[Right]) + geometry.set_uint_index(u, (unsigned int)idx_initial[Right]); } } @@ -2021,246 +1790,161 @@ static void thick_lines_to_indexed_vertex_array(const Lines3& lines, } // Only new allocate top / bottom vertices, if not closing a loop. - if (closed && (ii + 1 == lines.size())) - idx_b[TOP] = idx_initial[TOP]; - else - { - idx_b[TOP] = idx_last++; - volume.push_geometry(b[TOP], n_top); + if (closed && ii + 1 == lines.size()) + idx_b[Top] = idx_initial[Top]; + else { + idx_b[Top] = idx_last++; + geometry.add_vertex((Vec3f)b[Top].cast(), (Vec3f)n_top.cast()); } - if (closed && (ii + 1 == lines.size()) && (width == width_initial)) - idx_b[BOTTOM] = idx_initial[BOTTOM]; - else - { - idx_b[BOTTOM] = idx_last++; - volume.push_geometry(b[BOTTOM], n_bottom); + if (closed && ii + 1 == lines.size() && width == width_initial) + idx_b[Bottom] = idx_initial[Bottom]; + else { + idx_b[Bottom] = idx_last++; + geometry.add_vertex((Vec3f)b[Bottom].cast(), (Vec3f)n_bottom.cast()); } // Generate new vertices for the end of this line segment. - idx_b[LEFT] = idx_last++; - volume.push_geometry(b[LEFT], n_left); - idx_b[RIGHT] = idx_last++; - volume.push_geometry(b[RIGHT], n_right); + idx_b[Left] = idx_last++; + geometry.add_vertex((Vec3f)b[Left].cast(), (Vec3f)n_left.cast()); + idx_b[Right] = idx_last++; + geometry.add_vertex((Vec3f)b[Right].cast(), (Vec3f)n_right.cast()); - ::memcpy(idx_prev, idx_b, 4 * sizeof(int)); + idx_prev = idx_b; n_right_prev = n_right; n_top_prev = n_top; unit_v_prev = unit_v; len_prev = len; - if (!closed) - { + if (!closed) { // Terminate open paths with caps. - if (i == 0) - volume.push_quad(idx_a[BOTTOM], idx_a[RIGHT], idx_a[TOP], idx_a[LEFT]); + if (i == 0) { + geometry.add_uint_triangle(idx_a[Bottom], idx_a[Right], idx_a[Top]); + geometry.add_uint_triangle(idx_a[Bottom], idx_a[Top], idx_a[Left]); + } // We don't use 'else' because both cases are true if we have only one line. - if (i + 1 == lines.size()) - volume.push_quad(idx_b[BOTTOM], idx_b[LEFT], idx_b[TOP], idx_b[RIGHT]); + if (i + 1 == lines.size()) { + geometry.add_uint_triangle(idx_b[Bottom], idx_b[Left], idx_b[Top]); + geometry.add_uint_triangle(idx_b[Bottom], idx_b[Top], idx_b[Right]); + } } // Add quads for a straight hollow tube-like segment. // bottom-right face - volume.push_quad(idx_a[BOTTOM], idx_b[BOTTOM], idx_b[RIGHT], idx_a[RIGHT]); + geometry.add_uint_triangle(idx_a[Bottom], idx_b[Bottom], idx_b[Right]); + geometry.add_uint_triangle(idx_a[Bottom], idx_b[Right], idx_a[Right]); // top-right face - volume.push_quad(idx_a[RIGHT], idx_b[RIGHT], idx_b[TOP], idx_a[TOP]); + geometry.add_uint_triangle(idx_a[Right], idx_b[Right], idx_b[Top]); + geometry.add_uint_triangle(idx_a[Right], idx_b[Top], idx_a[Top]); // top-left face - volume.push_quad(idx_a[TOP], idx_b[TOP], idx_b[LEFT], idx_a[LEFT]); + geometry.add_uint_triangle(idx_a[Top], idx_b[Top], idx_b[Left]); + geometry.add_uint_triangle(idx_a[Top], idx_b[Left], idx_a[Left]); // bottom-left face - volume.push_quad(idx_a[LEFT], idx_b[LEFT], idx_b[BOTTOM], idx_a[BOTTOM]); - } - -#undef LEFT -#undef RIGHT -#undef TOP -#undef BOTTOM -} - -static void point_to_indexed_vertex_array(const Vec3crd& point, - double width, - double height, - GLIndexedVertexArray& volume) -{ - // builds a double piramid, with vertices on the local axes, around the point - - Vec3d center = unscale(point); - - double scale_factor = 1.0; - double w = scale_factor * width; - double h = scale_factor * height; - - // new vertices ids - int idx_last = int(volume.vertices_and_normals_interleaved.size() / 6); - int idxs[6]; - for (int i = 0; i < 6; ++i) - { - idxs[i] = idx_last + i; + geometry.add_uint_triangle(idx_a[Left], idx_b[Left], idx_b[Bottom]); + geometry.add_uint_triangle(idx_a[Left], idx_b[Bottom], idx_a[Bottom]); } - - Vec3d displacement_x(w, 0.0, 0.0); - Vec3d displacement_y(0.0, w, 0.0); - Vec3d displacement_z(0.0, 0.0, h); - - Vec3d unit_x(1.0, 0.0, 0.0); - Vec3d unit_y(0.0, 1.0, 0.0); - Vec3d unit_z(0.0, 0.0, 1.0); - - // vertices - volume.push_geometry(center - displacement_x, -unit_x); // idxs[0] - volume.push_geometry(center + displacement_x, unit_x); // idxs[1] - volume.push_geometry(center - displacement_y, -unit_y); // idxs[2] - volume.push_geometry(center + displacement_y, unit_y); // idxs[3] - volume.push_geometry(center - displacement_z, -unit_z); // idxs[4] - volume.push_geometry(center + displacement_z, unit_z); // idxs[5] - - // top piramid faces - volume.push_triangle(idxs[0], idxs[2], idxs[5]); - volume.push_triangle(idxs[2], idxs[1], idxs[5]); - volume.push_triangle(idxs[1], idxs[3], idxs[5]); - volume.push_triangle(idxs[3], idxs[0], idxs[5]); - - // bottom piramid faces - volume.push_triangle(idxs[2], idxs[0], idxs[4]); - volume.push_triangle(idxs[1], idxs[2], idxs[4]); - volume.push_triangle(idxs[3], idxs[1], idxs[4]); - volume.push_triangle(idxs[0], idxs[3], idxs[4]); } void _3DScene::thick_lines_to_verts( - const Lines &lines, - const std::vector &widths, - const std::vector &heights, - bool closed, - double top_z, - GLVolume &volume) -{ - thick_lines_to_indexed_vertex_array(lines, widths, heights, closed, top_z, volume.indexed_vertex_array); -} - -void _3DScene::thick_lines_to_verts(const Lines3& lines, + const Lines& lines, const std::vector& widths, const std::vector& heights, - bool closed, - GLVolume& volume) -{ - thick_lines_to_indexed_vertex_array(lines, widths, heights, closed, volume.indexed_vertex_array); -} - -static void thick_point_to_verts(const Vec3crd& point, - double width, - double height, - GLVolume& volume) -{ - point_to_indexed_vertex_array(point, width, height, volume.indexed_vertex_array); -} - -void _3DScene::extrusionentity_to_verts(const Polyline &polyline, float width, float height, float print_z, GLVolume& volume) + bool closed, + double top_z, + GUI::GLModel::Geometry& geometry) { - if (polyline.size() >= 2) { - size_t num_segments = polyline.size() - 1; - thick_lines_to_verts(polyline.lines(), std::vector(num_segments, width), std::vector(num_segments, height), false, print_z, volume); - } + thick_lines_to_geometry(lines, widths, heights, closed, top_z, geometry); } -// Fill in the qverts and tverts with quads and triangles for the extrusion_path. -void _3DScene::extrusionentity_to_verts(const ExtrusionPath &extrusion_path, float print_z, GLVolume &volume) +void _3DScene::thick_lines_to_verts( + const Lines3& lines, + const std::vector& widths, + const std::vector& heights, + bool closed, + GUI::GLModel::Geometry& geometry) { - extrusionentity_to_verts(extrusion_path.polyline, extrusion_path.width, extrusion_path.height, print_z, volume); + thick_lines_to_geometry(lines, widths, heights, closed, geometry); } // Fill in the qverts and tverts with quads and triangles for the extrusion_path. -void _3DScene::extrusionentity_to_verts(const ExtrusionPath &extrusion_path, float print_z, const Point ©, GLVolume &volume) +void _3DScene::extrusionentity_to_verts(const ExtrusionPath& extrusion_path, float print_z, const Point& copy, GUI::GLModel::Geometry& geometry) { Polyline polyline = extrusion_path.polyline; polyline.remove_duplicate_points(); polyline.translate(copy); - Lines lines = polyline.lines(); + const Lines lines = polyline.lines(); std::vector widths(lines.size(), extrusion_path.width); std::vector heights(lines.size(), extrusion_path.height); - thick_lines_to_verts(lines, widths, heights, false, print_z, volume); + thick_lines_to_verts(lines, widths, heights, false, print_z, geometry); } // Fill in the qverts and tverts with quads and triangles for the extrusion_loop. -void _3DScene::extrusionentity_to_verts(const ExtrusionLoop &extrusion_loop, float print_z, const Point ©, GLVolume &volume) +void _3DScene::extrusionentity_to_verts(const ExtrusionLoop& extrusion_loop, float print_z, const Point& copy, GUI::GLModel::Geometry& geometry) { Lines lines; std::vector widths; std::vector heights; - for (const ExtrusionPath &extrusion_path : extrusion_loop.paths) { + for (const ExtrusionPath& extrusion_path : extrusion_loop.paths) { Polyline polyline = extrusion_path.polyline; polyline.remove_duplicate_points(); polyline.translate(copy); - Lines lines_this = polyline.lines(); + const Lines lines_this = polyline.lines(); append(lines, lines_this); widths.insert(widths.end(), lines_this.size(), extrusion_path.width); heights.insert(heights.end(), lines_this.size(), extrusion_path.height); } - thick_lines_to_verts(lines, widths, heights, true, print_z, volume); + thick_lines_to_verts(lines, widths, heights, true, print_z, geometry); } // Fill in the qverts and tverts with quads and triangles for the extrusion_multi_path. -void _3DScene::extrusionentity_to_verts(const ExtrusionMultiPath &extrusion_multi_path, float print_z, const Point ©, GLVolume &volume) +void _3DScene::extrusionentity_to_verts(const ExtrusionMultiPath& extrusion_multi_path, float print_z, const Point& copy, GUI::GLModel::Geometry& geometry) { Lines lines; std::vector widths; std::vector heights; - for (const ExtrusionPath &extrusion_path : extrusion_multi_path.paths) { + for (const ExtrusionPath& extrusion_path : extrusion_multi_path.paths) { Polyline polyline = extrusion_path.polyline; polyline.remove_duplicate_points(); polyline.translate(copy); - Lines lines_this = polyline.lines(); + const Lines lines_this = polyline.lines(); append(lines, lines_this); widths.insert(widths.end(), lines_this.size(), extrusion_path.width); heights.insert(heights.end(), lines_this.size(), extrusion_path.height); } - thick_lines_to_verts(lines, widths, heights, false, print_z, volume); + thick_lines_to_verts(lines, widths, heights, false, print_z, geometry); } -void _3DScene::extrusionentity_to_verts(const ExtrusionEntityCollection &extrusion_entity_collection, float print_z, const Point ©, GLVolume &volume) +void _3DScene::extrusionentity_to_verts(const ExtrusionEntityCollection& extrusion_entity_collection, float print_z, const Point& copy, GUI::GLModel::Geometry& geometry) { - for (const ExtrusionEntity *extrusion_entity : extrusion_entity_collection.entities) - extrusionentity_to_verts(extrusion_entity, print_z, copy, volume); + for (const ExtrusionEntity* extrusion_entity : extrusion_entity_collection.entities) + extrusionentity_to_verts(extrusion_entity, print_z, copy, geometry); } -void _3DScene::extrusionentity_to_verts(const ExtrusionEntity *extrusion_entity, float print_z, const Point ©, GLVolume &volume) +void _3DScene::extrusionentity_to_verts(const ExtrusionEntity* extrusion_entity, float print_z, const Point& copy, GUI::GLModel::Geometry& geometry) { if (extrusion_entity != nullptr) { - auto *extrusion_path = dynamic_cast(extrusion_entity); + auto* extrusion_path = dynamic_cast(extrusion_entity); if (extrusion_path != nullptr) - extrusionentity_to_verts(*extrusion_path, print_z, copy, volume); + extrusionentity_to_verts(*extrusion_path, print_z, copy, geometry); else { - auto *extrusion_loop = dynamic_cast(extrusion_entity); + auto* extrusion_loop = dynamic_cast(extrusion_entity); if (extrusion_loop != nullptr) - extrusionentity_to_verts(*extrusion_loop, print_z, copy, volume); + extrusionentity_to_verts(*extrusion_loop, print_z, copy, geometry); else { - auto *extrusion_multi_path = dynamic_cast(extrusion_entity); + auto* extrusion_multi_path = dynamic_cast(extrusion_entity); if (extrusion_multi_path != nullptr) - extrusionentity_to_verts(*extrusion_multi_path, print_z, copy, volume); + extrusionentity_to_verts(*extrusion_multi_path, print_z, copy, geometry); else { - auto *extrusion_entity_collection = dynamic_cast(extrusion_entity); + auto* extrusion_entity_collection = dynamic_cast(extrusion_entity); if (extrusion_entity_collection != nullptr) - extrusionentity_to_verts(*extrusion_entity_collection, print_z, copy, volume); - else { + extrusionentity_to_verts(*extrusion_entity_collection, print_z, copy, geometry); + else throw Slic3r::RuntimeError("Unexpected extrusion_entity type in to_verts()"); - } } } } } } -void _3DScene::polyline3_to_verts(const Polyline3& polyline, double width, double height, GLVolume& volume) -{ - Lines3 lines = polyline.lines(); - std::vector widths(lines.size(), width); - std::vector heights(lines.size(), height); - thick_lines_to_verts(lines, widths, heights, false, volume); -} - -void _3DScene::point3_to_verts(const Vec3crd& point, double width, double height, GLVolume& volume) -{ - thick_point_to_verts(point, width, height, volume); -} - } // namespace Slic3r diff --git a/src/slic3r/GUI/3DScene.hpp b/src/slic3r/GUI/3DScene.hpp index 83101754b58..5c01e22f9c4 100644 --- a/src/slic3r/GUI/3DScene.hpp +++ b/src/slic3r/GUI/3DScene.hpp @@ -57,207 +57,6 @@ using ModelObjectPtrs = std::vector; // Return appropriate color based on the ModelVolume. 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. -class GLIndexedVertexArray { -public: - // Only Eigen types of Nx16 size are vectorized. This bounding box will not be vectorized. - static_assert(sizeof(Eigen::AlignedBox) == 24, "Eigen::AlignedBox is not being vectorized, thus it does not need to be aligned"); - using BoundingBox = Eigen::AlignedBox; - - GLIndexedVertexArray() { m_bounding_box.setEmpty(); } - GLIndexedVertexArray(const GLIndexedVertexArray &rhs) : - vertices_and_normals_interleaved(rhs.vertices_and_normals_interleaved), - triangle_indices(rhs.triangle_indices), - quad_indices(rhs.quad_indices), - m_bounding_box(rhs.m_bounding_box) - { assert(!rhs.has_VBOs()); m_bounding_box.setEmpty(); } - GLIndexedVertexArray(GLIndexedVertexArray &&rhs) : - vertices_and_normals_interleaved(std::move(rhs.vertices_and_normals_interleaved)), - triangle_indices(std::move(rhs.triangle_indices)), - quad_indices(std::move(rhs.quad_indices)), - m_bounding_box(rhs.m_bounding_box) - { assert(! rhs.has_VBOs()); } - - ~GLIndexedVertexArray() { release_geometry(); } - - GLIndexedVertexArray& operator=(const GLIndexedVertexArray &rhs) - { - assert(vertices_and_normals_interleaved_VBO_id == 0); - assert(triangle_indices_VBO_id == 0); - assert(quad_indices_VBO_id == 0); - assert(rhs.vertices_and_normals_interleaved_VBO_id == 0); - assert(rhs.triangle_indices_VBO_id == 0); - assert(rhs.quad_indices_VBO_id == 0); - this->vertices_and_normals_interleaved = rhs.vertices_and_normals_interleaved; - this->triangle_indices = rhs.triangle_indices; - this->quad_indices = rhs.quad_indices; - this->m_bounding_box = rhs.m_bounding_box; - this->vertices_and_normals_interleaved_size = rhs.vertices_and_normals_interleaved_size; - this->triangle_indices_size = rhs.triangle_indices_size; - this->quad_indices_size = rhs.quad_indices_size; - return *this; - } - - GLIndexedVertexArray& operator=(GLIndexedVertexArray &&rhs) - { - assert(vertices_and_normals_interleaved_VBO_id == 0); - assert(triangle_indices_VBO_id == 0); - assert(quad_indices_VBO_id == 0); - assert(rhs.vertices_and_normals_interleaved_VBO_id == 0); - assert(rhs.triangle_indices_VBO_id == 0); - assert(rhs.quad_indices_VBO_id == 0); - this->vertices_and_normals_interleaved = std::move(rhs.vertices_and_normals_interleaved); - this->triangle_indices = std::move(rhs.triangle_indices); - this->quad_indices = std::move(rhs.quad_indices); - this->m_bounding_box = rhs.m_bounding_box; - this->vertices_and_normals_interleaved_size = rhs.vertices_and_normals_interleaved_size; - this->triangle_indices_size = rhs.triangle_indices_size; - this->quad_indices_size = rhs.quad_indices_size; - return *this; - } - - // Vertices and their normals, interleaved to be used by void glInterleavedArrays(GL_N3F_V3F, 0, x) - std::vector vertices_and_normals_interleaved; - std::vector triangle_indices; - std::vector quad_indices; - - // When the geometry data is loaded into the graphics card as Vertex Buffer Objects, - // the above mentioned std::vectors are cleared and the following variables keep their original length. - size_t vertices_and_normals_interleaved_size{ 0 }; - size_t triangle_indices_size{ 0 }; - size_t quad_indices_size{ 0 }; - - // IDs of the Vertex Array Objects, into which the geometry has been loaded. - // Zero if the VBOs are not sent to GPU yet. - unsigned int vertices_and_normals_interleaved_VBO_id{ 0 }; - unsigned int triangle_indices_VBO_id{ 0 }; - unsigned int quad_indices_VBO_id{ 0 }; - -#if ENABLE_SMOOTH_NORMALS - void load_mesh_full_shading(const TriangleMesh& mesh, bool smooth_normals = false); - void load_mesh(const TriangleMesh& mesh, bool smooth_normals = false) { this->load_mesh_full_shading(mesh, smooth_normals); } -#else - void load_mesh_full_shading(const TriangleMesh& mesh); - void load_mesh(const TriangleMesh& mesh) { this->load_mesh_full_shading(mesh); } -#endif // ENABLE_SMOOTH_NORMALS - - void load_its_flat_shading(const indexed_triangle_set &its); - - inline bool has_VBOs() const { return vertices_and_normals_interleaved_VBO_id != 0; } - - inline void reserve(size_t sz) { - this->vertices_and_normals_interleaved.reserve(sz * 6); - this->triangle_indices.reserve(sz * 3); - this->quad_indices.reserve(sz * 4); - } - - inline void push_geometry(float x, float y, float z, float nx, float ny, float nz) { - assert(this->vertices_and_normals_interleaved_VBO_id == 0); - if (this->vertices_and_normals_interleaved_VBO_id != 0) - return; - - if (this->vertices_and_normals_interleaved.size() + 6 > this->vertices_and_normals_interleaved.capacity()) - this->vertices_and_normals_interleaved.reserve(next_highest_power_of_2(this->vertices_and_normals_interleaved.size() + 6)); - this->vertices_and_normals_interleaved.emplace_back(nx); - this->vertices_and_normals_interleaved.emplace_back(ny); - this->vertices_and_normals_interleaved.emplace_back(nz); - this->vertices_and_normals_interleaved.emplace_back(x); - this->vertices_and_normals_interleaved.emplace_back(y); - this->vertices_and_normals_interleaved.emplace_back(z); - - this->vertices_and_normals_interleaved_size = this->vertices_and_normals_interleaved.size(); - m_bounding_box.extend(Vec3f(x, y, z)); - }; - - inline void push_geometry(double x, double y, double z, double nx, double ny, double nz) { - push_geometry(float(x), float(y), float(z), float(nx), float(ny), float(nz)); - } - - template - inline void push_geometry(const Eigen::MatrixBase& p, const Eigen::MatrixBase& n) { - push_geometry(float(p(0)), float(p(1)), float(p(2)), float(n(0)), float(n(1)), float(n(2))); - } - - inline void push_triangle(int idx1, int idx2, int idx3) { - assert(this->vertices_and_normals_interleaved_VBO_id == 0); - if (this->vertices_and_normals_interleaved_VBO_id != 0) - return; - - if (this->triangle_indices.size() + 3 > this->vertices_and_normals_interleaved.capacity()) - this->triangle_indices.reserve(next_highest_power_of_2(this->triangle_indices.size() + 3)); - this->triangle_indices.emplace_back(idx1); - this->triangle_indices.emplace_back(idx2); - this->triangle_indices.emplace_back(idx3); - this->triangle_indices_size = this->triangle_indices.size(); - }; - - inline void push_quad(int idx1, int idx2, int idx3, int idx4) { - assert(this->vertices_and_normals_interleaved_VBO_id == 0); - if (this->vertices_and_normals_interleaved_VBO_id != 0) - return; - - if (this->quad_indices.size() + 4 > this->vertices_and_normals_interleaved.capacity()) - this->quad_indices.reserve(next_highest_power_of_2(this->quad_indices.size() + 4)); - this->quad_indices.emplace_back(idx1); - this->quad_indices.emplace_back(idx2); - this->quad_indices.emplace_back(idx3); - this->quad_indices.emplace_back(idx4); - this->quad_indices_size = this->quad_indices.size(); - }; - - // Finalize the initialization of the geometry & indices, - // upload the geometry and indices to OpenGL VBO objects - // and shrink the allocated data, possibly relasing it if it has been loaded into the VBOs. - void finalize_geometry(bool opengl_initialized); - // Release the geometry data, release OpenGL VBOs. - void release_geometry(); - - void render() const; - void render(const std::pair& tverts_range, const std::pair& qverts_range) const; - - // Is there any geometry data stored? - bool empty() const { return vertices_and_normals_interleaved_size == 0; } - - void clear() { - this->vertices_and_normals_interleaved.clear(); - this->triangle_indices.clear(); - this->quad_indices.clear(); - vertices_and_normals_interleaved_size = 0; - triangle_indices_size = 0; - quad_indices_size = 0; - m_bounding_box.setEmpty(); - } - - // Shrink the internal storage to tighly fit the data stored. - void shrink_to_fit() { - this->vertices_and_normals_interleaved.shrink_to_fit(); - this->triangle_indices.shrink_to_fit(); - this->quad_indices.shrink_to_fit(); - } - - const BoundingBox& bounding_box() const { return m_bounding_box; } - - // Return an estimate of the memory consumed by this class. - size_t cpu_memory_used() const { return sizeof(*this) + vertices_and_normals_interleaved.capacity() * sizeof(float) + triangle_indices.capacity() * sizeof(int) + quad_indices.capacity() * sizeof(int); } - // Return an estimate of the memory held by GPU vertex buffers. - size_t gpu_memory_used() const - { - size_t memsize = 0; - if (this->vertices_and_normals_interleaved_VBO_id != 0) - memsize += this->vertices_and_normals_interleaved_size * 4; - if (this->triangle_indices_VBO_id != 0) - memsize += this->triangle_indices_size * 4; - if (this->quad_indices_VBO_id != 0) - memsize += this->quad_indices_size * 4; - return memsize; - } - size_t total_memory_used() const { return this->cpu_memory_used() + this->gpu_memory_used(); } - -private: - BoundingBox m_bounding_box; -}; - class GLVolume { public: std::string name; @@ -400,15 +199,13 @@ class GLVolume { // Is mouse or rectangle selection over this object to select/deselect it ? EHoverState hover; - // Interleaved triangles & normals with indexed triangles & quads. - GLIndexedVertexArray indexed_vertex_array; + GUI::GLModel model; // BBS - mutable std::vector mmuseg_ivas; + mutable std::vector mmuseg_models; mutable ObjectBase::Timestamp mmuseg_ts; // Ranges of triangle and quad indices to be rendered. std::pair tverts_range; - std::pair qverts_range; // If the qverts or tverts contain thick extrusions, then offsets keeps pointers of the starts // of the extrusions per layer. @@ -418,13 +215,7 @@ class GLVolume { // Bounding box of this volume, in unscaled coordinates. BoundingBoxf3 bounding_box() const { - BoundingBoxf3 out; - if (! this->indexed_vertex_array.bounding_box().isEmpty()) { - out.min = this->indexed_vertex_array.bounding_box().min().cast(); - out.max = this->indexed_vertex_array.bounding_box().max().cast(); - out.defined = true; - }; - return out; + return this->model.get_bounding_box(); } void set_color(const ColorRGBA& rgba) { color = rgba; } @@ -517,18 +308,15 @@ class GLVolume { // convex hull const TriangleMesh* convex_hull() const { return m_convex_hull.get(); } - bool empty() const { return this->indexed_vertex_array.empty(); } + bool empty() const { return this->model.is_empty(); } void set_range(double low, double high); //BBS: add outline related logic and add virtual specifier - virtual void render(bool with_outline = false) const; + virtual void render(bool with_outline = false); //BBS: add simple render function for thumbnail - void simple_render(GLShaderProgram* shader, ModelObjectPtrs& model_objects, std::vector& extruder_colors) const; - - void finalize_geometry(bool opengl_initialized) { this->indexed_vertex_array.finalize_geometry(opengl_initialized); } - void release_geometry() { this->indexed_vertex_array.release_geometry(); } + void simple_render(GLShaderProgram* shader, ModelObjectPtrs& model_objects, std::vector& extruder_colors); void set_bounding_boxes_as_dirty() { m_transformed_bounding_box.reset(); @@ -545,11 +333,11 @@ class GLVolume { // Return an estimate of the memory consumed by this class. size_t cpu_memory_used() const { - //FIXME what to do wih m_convex_hull? - return sizeof(*this) - sizeof(this->indexed_vertex_array) + this->indexed_vertex_array.cpu_memory_used() + this->print_zs.capacity() * sizeof(coordf_t) + this->offsets.capacity() * sizeof(size_t); + return sizeof(*this) + this->model.cpu_memory_used() + this->print_zs.capacity() * sizeof(coordf_t) + + this->offsets.capacity() * sizeof(size_t); } // Return an estimate of the memory held by GPU vertex buffers. - size_t gpu_memory_used() const { return this->indexed_vertex_array.gpu_memory_used(); } + size_t gpu_memory_used() const { return this->model.gpu_memory_used(); } size_t total_memory_used() const { return this->cpu_memory_used() + this->gpu_memory_used(); } }; @@ -557,9 +345,9 @@ class GLVolume { class GLWipeTowerVolume : public GLVolume { public: GLWipeTowerVolume(const std::vector& colors); - virtual void render(bool with_outline = false) const; + virtual void render(bool with_outline = false); - std::vector iva_per_colors; + std::vector model_per_colors; bool IsTransparent(); private: @@ -627,17 +415,15 @@ class GLVolumeCollection ~GLVolumeCollection() { clear(); } std::vector load_object( - const ModelObject *model_object, + const ModelObject* model_object, int obj_idx, - const std::vector &instance_idxs, - bool opengl_initialized); + const std::vector& instance_idxs); int load_object_volume( - const ModelObject *model_object, + const ModelObject* model_object, int obj_idx, int volume_idx, int instance_idx, - bool opengl_initialized, bool in_assemble_view = false, bool use_loaded_id = false); @@ -649,14 +435,13 @@ class GLVolumeCollection const std::vector>& instances, SLAPrintObjectStep milestone, // Timestamp of the last change of the milestone - size_t timestamp, - bool opengl_initialized); + size_t timestamp); 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); + int obj_idx, float pos_x, float pos_y, float width, float depth, float height, float rotation_angle, bool size_unknown, float brim_width); - 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); + GLVolume* new_toolpath_volume(const ColorRGBA& rgba); + GLVolume* new_nontoolpath_volume(const ColorRGBA& rgba); int get_selection_support_threshold_angle(bool&) const; // Render the volumes by OpenGL. @@ -667,13 +452,6 @@ class GLVolumeCollection std::function filter_func = std::function(), bool with_outline = true) const; - // Finalize the initialization of the geometry & indices, - // upload the geometry and indices to OpenGL VBO objects - // and shrink the allocated data, possibly relasing it if it has been loaded into the VBOs. - void finalize_geometry(bool opengl_initialized) { for (auto* v : volumes) v->finalize_geometry(opengl_initialized); } - // Release the geometry data assigned to the volumes. - // If OpenGL VBOs were allocated, an OpenGL context has to be active to release them. - void release_geometry() { for (auto *v : volumes) v->release_geometry(); } // Clear the geometry void clear() { for (auto *v : volumes) delete v; volumes.clear(); } @@ -724,17 +502,13 @@ GLVolumeWithIdAndZList volumes_to_render(const GLVolumePtrs& volumes, GLVolumeCo struct _3DScene { - static void thick_lines_to_verts(const Lines& lines, const std::vector& widths, const std::vector& heights, bool closed, double top_z, GLVolume& volume); - static void thick_lines_to_verts(const Lines3& lines, const std::vector& widths, const std::vector& heights, bool closed, GLVolume& volume); - static void extrusionentity_to_verts(const Polyline &polyline, float width, float height, float print_z, GLVolume& volume); - static void extrusionentity_to_verts(const ExtrusionPath& extrusion_path, float print_z, GLVolume& volume); - static void extrusionentity_to_verts(const ExtrusionPath& extrusion_path, float print_z, const Point& copy, GLVolume& volume); - static void extrusionentity_to_verts(const ExtrusionLoop& extrusion_loop, float print_z, const Point& copy, GLVolume& volume); - static void extrusionentity_to_verts(const ExtrusionMultiPath& extrusion_multi_path, float print_z, const Point& copy, GLVolume& volume); - static void extrusionentity_to_verts(const ExtrusionEntityCollection& extrusion_entity_collection, float print_z, const Point& copy, GLVolume& volume); - static void extrusionentity_to_verts(const ExtrusionEntity* extrusion_entity, float print_z, const Point& copy, GLVolume& volume); - static void polyline3_to_verts(const Polyline3& polyline, double width, double height, GLVolume& volume); - static void point3_to_verts(const Vec3crd& point, double width, double height, GLVolume& volume); + static void thick_lines_to_verts(const Lines& lines, const std::vector& widths, const std::vector& heights, bool closed, double top_z, GUI::GLModel::Geometry& geometry); + static void thick_lines_to_verts(const Lines3& lines, const std::vector& widths, const std::vector& heights, bool closed, GUI::GLModel::Geometry& geometry); + static void extrusionentity_to_verts(const ExtrusionPath& extrusion_path, float print_z, const Point& copy, GUI::GLModel::Geometry& geometry); + static void extrusionentity_to_verts(const ExtrusionLoop& extrusion_loop, float print_z, const Point& copy, GUI::GLModel::Geometry& geometry); + static void extrusionentity_to_verts(const ExtrusionMultiPath& extrusion_multi_path, float print_z, const Point& copy, GUI::GLModel::Geometry& geometry); + static void extrusionentity_to_verts(const ExtrusionEntityCollection& extrusion_entity_collection, float print_z, const Point& copy, GUI::GLModel::Geometry& geometry); + static void extrusionentity_to_verts(const ExtrusionEntity* extrusion_entity, float print_z, const Point& copy, GUI::GLModel::Geometry& geometry); }; } diff --git a/src/slic3r/GUI/GCodeViewer.cpp b/src/slic3r/GUI/GCodeViewer.cpp index 7f3fa3d3b11..675af85d22b 100644 --- a/src/slic3r/GUI/GCodeViewer.cpp +++ b/src/slic3r/GUI/GCodeViewer.cpp @@ -920,7 +920,7 @@ std::vector GCodeViewer::get_plater_extruder() //BBS: always load shell at preview void GCodeViewer::load(const GCodeProcessorResult& gcode_result, const Print& print, const BuildVolume& build_volume, - const std::vector& exclude_bounding_box, bool initialized, ConfigOptionMode mode, bool only_gcode) + const std::vector& exclude_bounding_box, ConfigOptionMode mode, bool only_gcode) { // avoid processing if called with the same gcode_result if (m_last_result_id == gcode_result.id) { @@ -975,7 +975,7 @@ m_sequential_view.m_show_gcode_window = false; //BBS: always load shell at preview /*if (wxGetApp().is_editor()) { - //load_shells(print, initialized); + load_shells(print); } else {*/ //BBS: add only gcode mode @@ -3088,9 +3088,9 @@ void GCodeViewer::load_toolpaths(const GCodeProcessorResult& gcode_result, const } //BBS: always load shell when preview -void GCodeViewer::load_shells(const Print& print, bool initialized, bool force_previewing) +void GCodeViewer::load_shells(const Print& print, bool force_previewing) { - BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(": initialized=%1%, force_previewing=%2%")%initialized %force_previewing; + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(": force_previewing=%1%") %force_previewing; if ((print.id().id == m_shells.print_id)&&(print.get_modified_count() == m_shells.print_modify_count)) { //BBS: update force previewing logic if (force_previewing) @@ -3138,7 +3138,7 @@ void GCodeViewer::load_shells(const Print& print, bool initialized, bool force_p instance_ids.resize(instance_index); size_t current_volumes_count = m_shells.volumes.volumes.size(); - m_shells.volumes.load_object(model_obj, object_idx, instance_ids, initialized); + m_shells.volumes.load_object(model_obj, object_idx, instance_ids); // adjust shells' z if raft is present const SlicingParameters& slicing_parameters = obj->slicing_parameters(); @@ -4080,14 +4080,6 @@ void GCodeViewer::render_shells() if (shader == nullptr) return; - // when the background processing is enabled, it may happen that the shells data have been loaded - // before opengl has been initialized for the preview canvas. - // when this happens, the volumes' data have not been sent to gpu yet. - for (GLVolume* v : m_shells.volumes.volumes) { - if (!v->indexed_vertex_array.has_VBOs()) - v->finalize_geometry(true); - } - glsafe(::glEnable(GL_DEPTH_TEST)); // glsafe(::glDepthMask(GL_FALSE)); diff --git a/src/slic3r/GUI/GCodeViewer.hpp b/src/slic3r/GUI/GCodeViewer.hpp index 2bb2542f24f..fa638f0a081 100644 --- a/src/slic3r/GUI/GCodeViewer.hpp +++ b/src/slic3r/GUI/GCodeViewer.hpp @@ -810,7 +810,7 @@ mutable bool m_no_render_path { false }; // extract rendering data from the given parameters //BBS: add only gcode mode void load(const GCodeProcessorResult& gcode_result, const Print& print, const BuildVolume& build_volume, - const std::vector& exclude_bounding_box, bool initialized, ConfigOptionMode mode, bool only_gcode = false); + const std::vector& exclude_bounding_box, ConfigOptionMode mode, bool only_gcode = false); // recalculate ranges in dependence of what is visible and sets tool/print colors void refresh(const GCodeProcessorResult& gcode_result, const std::vector& str_tool_colors); void refresh_render_paths(); @@ -820,7 +820,7 @@ mutable bool m_no_render_path { false }; void reset(); //BBS: always load shell at preview void reset_shell(); - void load_shells(const Print& print, bool initialized, bool force_previewing = false); + void load_shells(const Print& print, bool force_previewing = false); void set_shells_on_preview(bool is_previewing) { m_shells.previewing = is_previewing; } //BBS: add all plates filament statistics void render_all_plates_stats(const std::vector& gcode_result_list, bool show = true) const; @@ -900,7 +900,7 @@ mutable bool m_no_render_path { false }; private: void load_toolpaths(const GCodeProcessorResult& gcode_result, const BuildVolume& build_volume, const std::vector& exclude_bounding_box); //BBS: always load shell at preview - //void load_shells(const Print& print, bool initialized); + //void load_shells(const Print& print); void refresh_render_paths(bool keep_sequential_current_first, bool keep_sequential_current_last) const; void render_toolpaths(); void render_shells(); diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 6aa3a5fcf56..f66a59fb120 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -97,10 +97,6 @@ void GLCanvas3D::load_render_colors() // Number of floats static constexpr const size_t MAX_VERTEX_BUFFER_SIZE = 131072 * 6; // 3.15MB -// Reserve size in number of floats. -static constexpr const size_t VERTEX_BUFFER_RESERVE_SIZE = 131072 * 2; // 1.05MB -// Reserve size in number of floats, maximum sum of all preallocated buffers. -//static constexpr const size_t VERTEX_BUFFER_RESERVE_SIZE_SUM_MAX = 1024 * 1024 * 128 / 4; // 128MB namespace Slic3r { namespace GUI { @@ -1175,10 +1171,6 @@ bool GLCanvas3D::init() if (m_main_toolbar.is_enabled()) m_layers_editing.init(); - // on linux the gl context is not valid until the canvas is not shown on screen - // we defer the geometry finalization of volumes until the first call to render() - m_volumes.finalize_geometry(true); - BOOST_LOG_TRIVIAL(info) <<__FUNCTION__<< ": before gizmo init"; if (m_gizmos.is_enabled() && !m_gizmos.init()) std::cout << "Unable to initialize gizmos: please, check that all the required textures are available" << std::endl; @@ -2136,7 +2128,7 @@ std::vector GLCanvas3D::load_object(const ModelObject& model_object, int ob instance_idxs.emplace_back(i); } } - return m_volumes.load_object(&model_object, obj_idx, instance_idxs, m_initialized); + return m_volumes.load_object(&model_object, obj_idx, instance_idxs); } std::vector GLCanvas3D::load_object(const Model& model, int obj_idx) @@ -2447,7 +2439,7 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re // Note the index of the loaded volume, so that we can reload the main model GLVolume with the hollowed mesh // later in this function. it->volume_idx = m_volumes.volumes.size(); - m_volumes.load_object_volume(&model_object, obj_idx, volume_idx, instance_idx, m_initialized, m_canvas_type == ECanvasType::CanvasAssembleView); + m_volumes.load_object_volume(&model_object, obj_idx, volume_idx, instance_idx, m_canvas_type == ECanvasType::CanvasAssembleView); m_volumes.volumes.back()->geometry_id = key.geometry_id; update_object_list = true; } else { @@ -2504,31 +2496,32 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re GLVolume &volume = *m_volumes.volumes[it->volume_idx]; if (! volume.offsets.empty() && state.step[istep].timestamp != volume.offsets.front()) { // The backend either produced a new hollowed mesh, or it invalidated the one that the front end has seen. - volume.indexed_vertex_array.release_geometry(); - if (state.step[istep].state == PrintStateBase::DONE) { + volume.model.reset(); + if (state.step[istep].state == PrintStateBase::DONE) { TriangleMesh mesh = print_object->get_mesh(slaposDrillHoles); assert(! mesh.empty()); mesh.transform(sla_print->sla_trafo(*m_model->objects[volume.object_idx()]).inverse()); #if ENABLE_SMOOTH_NORMALS - volume.indexed_vertex_array.load_mesh(mesh, true); + volume.model.init_from(mesh, true); #else - volume.indexed_vertex_array.load_mesh(mesh); + volume.model.init_from(mesh); #endif // ENABLE_SMOOTH_NORMALS - } else { + } + else { // Reload the original volume. #if ENABLE_SMOOTH_NORMALS - volume.indexed_vertex_array.load_mesh(m_model->objects[volume.object_idx()]->volumes[volume.volume_idx()]->mesh(), true); + volume.model.init_from(m_model->objects[volume.object_idx()]->volumes[volume.volume_idx()]->mesh(), true); #else - volume.indexed_vertex_array.load_mesh(m_model->objects[volume.object_idx()]->volumes[volume.volume_idx()]->mesh()); + volume.model.init_from(m_model->objects[volume.object_idx()]->volumes[volume.volume_idx()]->mesh()); #endif // ENABLE_SMOOTH_NORMALS } - volume.finalize_geometry(true); } //FIXME it is an ugly hack to write the timestamp into the "offsets" field to not have to add another member variable // to the GLVolume. We should refactor GLVolume significantly, so that the GLVolume will not contain member variables // of various concenrs (model vs. 3D print path). volume.offsets = { state.step[istep].timestamp }; - } else if (state.step[istep].state == PrintStateBase::DONE) { + } + else if (state.step[istep].state == PrintStateBase::DONE) { // Check whether there is an existing auxiliary volume to be updated, or a new auxiliary volume to be created. ModelVolumeState key(state.step[istep].timestamp, instance.instance_id.id); auto it = std::lower_bound(aux_volume_state.begin(), aux_volume_state.end(), key, model_volume_state_lower); @@ -2540,7 +2533,8 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re instances[istep].emplace_back(std::pair(instance_idx, print_instance_idx)); else shift_zs[object_idx] = 0.; - } else { + } + else { // Recycling an old GLVolume. Update the Object/Instance indices into the current Model. m_volumes.volumes[it->volume_idx]->composite_id = GLVolume::CompositeID(object_idx, m_volumes.volumes[it->volume_idx]->volume_idx(), instance_idx); m_volumes.volumes[it->volume_idx]->set_instance_transformation(model_object->instances[instance_idx]->get_transformation()); @@ -2550,7 +2544,7 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re for (size_t istep = 0; istep < sla_steps.size(); ++istep) if (!instances[istep].empty()) - m_volumes.load_object_auxiliary(print_object, object_idx, instances[istep], sla_steps[istep], state.step[istep].timestamp, m_initialized); + m_volumes.load_object_auxiliary(print_object, object_idx, instances[istep], sla_steps[istep], state.step[istep].timestamp); } // Shift-up all volumes of the object so that it has the right elevation with respect to the print bed @@ -2614,7 +2608,7 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re int volume_idx_wipe_tower_new = m_volumes.load_wipe_tower_preview( 1000 + plate_id, x + plate_origin(0), y + plate_origin(1), (float)wipe_tower_size(0), (float)wipe_tower_size(1), (float)wipe_tower_size(2), a, - /*!print->is_step_done(psWipeTower)*/ true, brim_width, m_initialized); + /*!print->is_step_done(psWipeTower)*/ true, brim_width); int volume_idx_wipe_tower_old = volume_idxs_wipe_tower_old[plate_id]; if (volume_idx_wipe_tower_old != -1) map_glvolume_old_to_new[volume_idx_wipe_tower_old] = volume_idx_wipe_tower_new; @@ -2687,26 +2681,11 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re m_dirty = true; } -static void reserve_new_volume_finalize_old_volume(GLVolume& vol_new, GLVolume& vol_old, bool gl_initialized, size_t prealloc_size = VERTEX_BUFFER_RESERVE_SIZE) -{ - // Assign the large pre-allocated buffers to the new GLVolume. - vol_new.indexed_vertex_array = std::move(vol_old.indexed_vertex_array); - // Copy the content back to the old GLVolume. - vol_old.indexed_vertex_array = vol_new.indexed_vertex_array; - // Clear the buffers, but keep them pre-allocated. - vol_new.indexed_vertex_array.clear(); - // Just make sure that clear did not clear the reserved memory. - // Reserving number of vertices (3x position + 3x color) - vol_new.indexed_vertex_array.reserve(prealloc_size / 6); - // Finalize the old geometry, possibly move data to the graphics card. - vol_old.finalize_geometry(gl_initialized); -} - void GLCanvas3D::load_shells(const Print& print, bool force_previewing) { if (m_initialized) { - m_gcode_viewer.load_shells(print, m_initialized, force_previewing); + m_gcode_viewer.load_shells(print, force_previewing); m_gcode_viewer.update_shells_color_by_extruder(m_config); } } @@ -2726,7 +2705,7 @@ void GLCanvas3D::load_gcode_preview(const GCodeProcessorResult& gcode_result, co //when load gcode directly, it is too late m_gcode_viewer.init(wxGetApp().get_mode(), wxGetApp().preset_bundle); m_gcode_viewer.load(gcode_result, *this->fff_print(), wxGetApp().plater()->build_volume(), exclude_bounding_box, - m_initialized, wxGetApp().get_mode(), only_gcode); + wxGetApp().get_mode(), only_gcode); if (wxGetApp().is_editor()) { //BBS: always load shell at preview, do this in load_shells @@ -5637,7 +5616,7 @@ void GLCanvas3D::render_thumbnail_internal(ThumbnailData& thumbnail_data, const curr_color = vol->color; ColorRGBA new_color = adjust_color_for_rendering(curr_color); - shader->set_uniform("uniform_color", new_color); + vol->model.set_color(new_color); shader->set_uniform("volume_world_matrix", vol->world_matrix()); //BBS set all volume to orange //shader->set_uniform("uniform_color", orange); @@ -7192,6 +7171,10 @@ void GLCanvas3D::_render_style_editor() void GLCanvas3D::_render_volumes_for_picking() const { + GLShaderProgram* shader = wxGetApp().get_shader("flat"); + if (shader == nullptr) + return; + // do not cull backfaces to show broken geometry, if any glsafe(::glDisable(GL_CULL_FACE)); @@ -7209,8 +7192,10 @@ void GLCanvas3D::_render_volumes_for_picking() const //BBS: remove the bed picking logic const unsigned int id = volume.second.first; //const unsigned int id = 1 + volume.second.first; - glsafe(::glColor4fv(picking_decode(id).data())); - volume.first->render(); + volume.first->model.set_color(picking_decode(id)); + shader->start_using(); + volume.first->render(); + shader->stop_using(); } } @@ -8384,22 +8369,23 @@ void GLCanvas3D::_load_print_toolpaths(const BuildVolume &build_volume) skirt_height = std::min(skirt_height, print_zs.size()); print_zs.erase(print_zs.begin() + skirt_height, print_zs.end()); - GLVolume *volume = m_volumes.new_toolpath_volume(color, VERTEX_BUFFER_RESERVE_SIZE); + GLVolume* volume = m_volumes.new_toolpath_volume(color); + GLModel::Geometry init_data; + init_data.format = { GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3N3, GLModel::Geometry::EIndexType::UINT }; for (size_t i = 0; i < skirt_height; ++ i) { volume->print_zs.emplace_back(print_zs[i]); - volume->offsets.emplace_back(volume->indexed_vertex_array.quad_indices.size()); - volume->offsets.emplace_back(volume->indexed_vertex_array.triangle_indices.size()); + volume->offsets.emplace_back(init_data.indices_count()); //BBS: usage of m_brim are deleted - _3DScene::extrusionentity_to_verts(print->skirt(), print_zs[i], Point(0, 0), *volume); + _3DScene::extrusionentity_to_verts(print->skirt(), print_zs[i], Point(0, 0), init_data); // Ensure that no volume grows over the limits. If the volume is too large, allocate a new one. - if (volume->indexed_vertex_array.vertices_and_normals_interleaved.size() > MAX_VERTEX_BUFFER_SIZE) { - GLVolume &vol = *volume; + if (init_data.vertices_size_bytes() > MAX_VERTEX_BUFFER_SIZE) { + volume->model.init_from(std::move(init_data)); + GLVolume &vol = *volume; volume = m_volumes.new_toolpath_volume(vol.color); - reserve_new_volume_finalize_old_volume(*volume, vol, m_initialized); } } - volume->is_outside = ! build_volume.all_paths_inside_vertices_and_normals_interleaved(volume->indexed_vertex_array.vertices_and_normals_interleaved, volume->indexed_vertex_array.bounding_box()); - volume->indexed_vertex_array.finalize_geometry(m_initialized); + volume->model.init_from(std::move(init_data)); + volume->is_outside = !contains(build_volume, volume->model); } void GLCanvas3D::_load_print_object_toolpaths(const PrintObject& print_object, const BuildVolume& build_volume, const std::vector& str_tool_colors, const std::vector& color_print_values) @@ -8571,7 +8557,10 @@ void GLCanvas3D::_load_print_object_toolpaths(const PrintObject& print_object, c // Allocate the volume before locking. GLVolume *volume = new GLVolume(color); volume->is_extrusion_path = true; - tbb::spin_mutex::scoped_lock lock; + // to prevent sending data to gpu (in the main thread) while + // editing the model geometry + volume->model.disable_render(); + tbb::spin_mutex::scoped_lock lock; // Lock by ROII, so if the emplace_back() fails, the lock will be released. lock.acquire(new_volume_mutex); m_volumes.volumes.emplace_back(volume); @@ -8583,31 +8572,36 @@ void GLCanvas3D::_load_print_object_toolpaths(const PrintObject& print_object, c tbb::blocked_range(0, ctxt.layers.size(), grain_size), [&ctxt, &new_volume, is_selected_separate_extruder, this](const tbb::blocked_range& range) { GLVolumePtrs vols; - auto volume = [&ctxt, &vols](size_t layer_idx, int extruder, int feature) -> GLVolume& { - return *vols[ctxt.color_by_color_print()? + std::vector geometries; + auto select_geometry = [&ctxt, &geometries](size_t layer_idx, int extruder, int feature) -> GLModel::Geometry& { + return geometries[ctxt.color_by_color_print() ? ctxt.color_print_color_idx_by_layer_idx_and_extruder(layer_idx, extruder) : - ctxt.color_by_tool() ? - std::min(ctxt.number_tools() - 1, std::max(extruder - 1, 0)) : - feature - ]; + ctxt.color_by_tool() ? + std::min(ctxt.number_tools() - 1, std::max(extruder - 1, 0)) : + feature + ]; }; if (ctxt.color_by_color_print() || ctxt.color_by_tool()) { - for (size_t i = 0; i < ctxt.number_tools(); ++i) + for (size_t i = 0; i < ctxt.number_tools(); ++i) { vols.emplace_back(new_volume(ctxt.color_tool(i))); + geometries.emplace_back(GLModel::Geometry()); + } } - else + else { vols = { new_volume(ctxt.color_perimeters()), new_volume(ctxt.color_infill()), new_volume(ctxt.color_support()) }; - for (GLVolume *vol : vols) - // Reserving number of vertices (3x position + 3x color) - vol->indexed_vertex_array.reserve(VERTEX_BUFFER_RESERVE_SIZE / 6); + geometries = { GLModel::Geometry(), GLModel::Geometry(), GLModel::Geometry() }; + } + + assert(vols.size() == geometries.size()); + for (GLModel::Geometry& g : geometries) { + g.format = { GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3N3, GLModel::Geometry::EIndexType::UINT }; + } for (size_t idx_layer = range.begin(); idx_layer < range.end(); ++ idx_layer) { const Layer *layer = ctxt.layers[idx_layer]; - if (is_selected_separate_extruder) - { + if (is_selected_separate_extruder) { bool at_least_one_has_correct_extruder = false; - for (const LayerRegion* layerm : layer->regions()) - { + for (const LayerRegion* layerm : layer->regions()) { if (layerm->slices.surfaces.empty()) continue; const PrintRegionConfig& cfg = layerm->region().config(); @@ -8622,12 +8616,14 @@ void GLCanvas3D::_load_print_object_toolpaths(const PrintObject& print_object, c continue; } - for (GLVolume *vol : vols) + for (size_t i = 0; i < vols.size(); ++i) { + GLVolume* vol = vols[i]; if (vol->print_zs.empty() || vol->print_zs.back() != layer->print_z) { vol->print_zs.emplace_back(layer->print_z); - vol->offsets.emplace_back(vol->indexed_vertex_array.quad_indices.size()); - vol->offsets.emplace_back(vol->indexed_vertex_array.triangle_indices.size()); + vol->offsets.emplace_back(geometries[i].indices_count()); } + } + for (const PrintInstance &instance : *ctxt.shifted_copies) { const Point © = instance.shift; for (const LayerRegion *layerm : layer->regions()) { @@ -8641,18 +8637,16 @@ void GLCanvas3D::_load_print_object_toolpaths(const PrintObject& print_object, c } if (ctxt.has_perimeters) _3DScene::extrusionentity_to_verts(layerm->perimeters, float(layer->print_z), copy, - volume(idx_layer, layerm->region().config().wall_filament.value, 0)); + select_geometry(idx_layer, layerm->region().config().wall_filament.value, 0)); if (ctxt.has_infill) { for (const ExtrusionEntity *ee : layerm->fills.entities) { // fill represents infill extrusions of a single island. const auto *fill = dynamic_cast(ee); if (! fill->entities.empty()) _3DScene::extrusionentity_to_verts(*fill, float(layer->print_z), copy, - volume(idx_layer, - is_solid_infill(fill->entities.front()->role()) ? - layerm->region().config().solid_infill_filament : - layerm->region().config().sparse_infill_filament, - 1)); + select_geometry(idx_layer, is_solid_infill(fill->entities.front()->role()) ? + layerm->region().config().solid_infill_filament : + layerm->region().config().sparse_infill_filament, 1)); } } } @@ -8661,28 +8655,25 @@ void GLCanvas3D::_load_print_object_toolpaths(const PrintObject& print_object, c if (support_layer) { for (const ExtrusionEntity *extrusion_entity : support_layer->support_fills.entities) _3DScene::extrusionentity_to_verts(extrusion_entity, float(layer->print_z), copy, - volume(idx_layer, - (extrusion_entity->role() == erSupportMaterial || - extrusion_entity->role() == erSupportTransition) ? - support_layer->object()->config().support_filament : - support_layer->object()->config().support_interface_filament, - 2)); + select_geometry(idx_layer, (extrusion_entity->role() == erSupportMaterial || extrusion_entity->role() == erSupportTransition) ? + support_layer->object()->config().support_filament : + support_layer->object()->config().support_interface_filament, 2)); } } } // Ensure that no volume grows over the limits. If the volume is too large, allocate a new one. for (size_t i = 0; i < vols.size(); ++i) { GLVolume &vol = *vols[i]; - if (vol.indexed_vertex_array.vertices_and_normals_interleaved.size() > MAX_VERTEX_BUFFER_SIZE) { - vols[i] = new_volume(vol.color); - reserve_new_volume_finalize_old_volume(*vols[i], vol, false); - } + if (geometries[i].vertices_size_bytes() > MAX_VERTEX_BUFFER_SIZE) { + vol.model.init_from(std::move(geometries[i])); + vols[i] = new_volume(vol.color); + } } } - for (GLVolume *vol : vols) - // Ideally one would call vol->indexed_vertex_array.finalize() here to move the buffers to the OpenGL driver, - // but this code runs in parallel and the OpenGL driver is not thread safe. - vol->indexed_vertex_array.shrink_to_fit(); + for (size_t i = 0; i < vols.size(); ++i) { + if (!geometries[i].is_empty()) + vols[i]->model.init_from(std::move(geometries[i])); + } }); BOOST_LOG_TRIVIAL(debug) << "Loading print object toolpaths in parallel - finalizing results" << m_volumes.log_memory_info() << log_memory_info(); @@ -8697,8 +8688,9 @@ void GLCanvas3D::_load_print_object_toolpaths(const PrintObject& print_object, c } for (size_t i = volumes_cnt_initial; i < m_volumes.volumes.size(); ++i) { GLVolume* v = m_volumes.volumes[i]; - v->is_outside = ! build_volume.all_paths_inside_vertices_and_normals_interleaved(v->indexed_vertex_array.vertices_and_normals_interleaved, v->indexed_vertex_array.bounding_box()); - v->indexed_vertex_array.finalize_geometry(m_initialized); + v->is_outside = !contains(build_volume, v->model); + // We are done editinig the model, now it can be sent to gpu + v->model.enable_render(); } BOOST_LOG_TRIVIAL(debug) << "Loading print object toolpaths in parallel - end" << m_volumes.log_memory_info() << log_memory_info(); @@ -8718,10 +8710,10 @@ void GLCanvas3D::_load_wipe_tower_toolpaths(const BuildVolume& build_volume, con struct Ctxt { - const Print *print; - const std::vector* tool_colors; - Vec2f wipe_tower_pos; - float wipe_tower_angle; + const Print *print; + const std::vector *tool_colors; + Vec2f wipe_tower_pos; + float wipe_tower_angle; static ColorRGBA color_support() { return ColorRGBA::GREENISH(); } @@ -8771,6 +8763,9 @@ void GLCanvas3D::_load_wipe_tower_toolpaths(const BuildVolume& build_volume, con auto new_volume = [this, &new_volume_mutex](const ColorRGBA& color) { auto *volume = new GLVolume(color); volume->is_extrusion_path = true; + // to prevent sending data to gpu (in the main thread) while + // editing the model geometry + volume->model.disable_render(); tbb::spin_mutex::scoped_lock lock; lock.acquire(new_volume_mutex); m_volumes.volumes.emplace_back(volume); @@ -8784,23 +8779,29 @@ void GLCanvas3D::_load_wipe_tower_toolpaths(const BuildVolume& build_volume, con [&ctxt, &new_volume](const tbb::blocked_range& range) { // Bounding box of this slab of a wipe tower. GLVolumePtrs vols; + std::vector geometries; if (ctxt.color_by_tool()) { - for (size_t i = 0; i < ctxt.number_tools(); ++i) + for (size_t i = 0; i < ctxt.number_tools(); ++i) { vols.emplace_back(new_volume(ctxt.color_tool(i))); + geometries.emplace_back(GLModel::Geometry()); + } } - else + else { vols = { new_volume(ctxt.color_support()) }; - for (GLVolume *volume : vols) - // Reserving number of vertices (3x position + 3x color) - volume->indexed_vertex_array.reserve(VERTEX_BUFFER_RESERVE_SIZE / 6); + geometries = { GLModel::Geometry() }; + } + + assert(vols.size() == geometries.size()); + for (GLModel::Geometry& g : geometries) { + g.format = { GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3N3, GLModel::Geometry::EIndexType::UINT }; + } for (size_t idx_layer = range.begin(); idx_layer < range.end(); ++idx_layer) { const std::vector &layer = ctxt.tool_change(idx_layer); for (size_t i = 0; i < vols.size(); ++i) { GLVolume &vol = *vols[i]; if (vol.print_zs.empty() || vol.print_zs.back() != layer.front().print_z) { vol.print_zs.emplace_back(layer.front().print_z); - vol.offsets.emplace_back(vol.indexed_vertex_array.quad_indices.size()); - vol.offsets.emplace_back(vol.indexed_vertex_array.triangle_indices.size()); + vol.offsets.emplace_back(geometries[i].indices_count()); } } for (const WipeTower::ToolChangeResult &extrusions : layer) { @@ -8843,20 +8844,22 @@ void GLCanvas3D::_load_wipe_tower_toolpaths(const BuildVolume& build_volume, con e_prev = e; } _3DScene::thick_lines_to_verts(lines, widths, heights, lines.front().a == lines.back().b, extrusions.print_z, - *vols[ctxt.volume_idx(e.tool, 0)]); + geometries[ctxt.volume_idx(e.tool, 0)]); } } } for (size_t i = 0; i < vols.size(); ++i) { GLVolume &vol = *vols[i]; - if (vol.indexed_vertex_array.vertices_and_normals_interleaved.size() > MAX_VERTEX_BUFFER_SIZE) { + if (geometries[i].vertices_size_bytes() > MAX_VERTEX_BUFFER_SIZE) { + vol.model.init_from(std::move(geometries[i])); vols[i] = new_volume(vol.color); - reserve_new_volume_finalize_old_volume(*vols[i], vol, false); } } - for (GLVolume *vol : vols) - vol->indexed_vertex_array.shrink_to_fit(); - }); + for (size_t i = 0; i < vols.size(); ++i) { + if (!geometries[i].is_empty()) + vols[i]->model.init_from(std::move(geometries[i])); + } + }); BOOST_LOG_TRIVIAL(debug) << "Loading wipe tower toolpaths in parallel - finalizing results" << m_volumes.log_memory_info() << log_memory_info(); // Remove empty volumes from the newly added volumes. @@ -8870,8 +8873,9 @@ void GLCanvas3D::_load_wipe_tower_toolpaths(const BuildVolume& build_volume, con } for (size_t i = volumes_cnt_initial; i < m_volumes.volumes.size(); ++i) { GLVolume* v = m_volumes.volumes[i]; - v->is_outside = ! build_volume.all_paths_inside_vertices_and_normals_interleaved(v->indexed_vertex_array.vertices_and_normals_interleaved, v->indexed_vertex_array.bounding_box()); - v->indexed_vertex_array.finalize_geometry(m_initialized); + v->is_outside = !contains(build_volume, v->model); + // We are done editinig the model, now it can be sent to gpu + v->model.enable_render(); } BOOST_LOG_TRIVIAL(debug) << "Loading wipe tower toolpaths in parallel - end" << m_volumes.log_memory_info() << log_memory_info(); @@ -8895,11 +8899,10 @@ void GLCanvas3D::_load_sla_shells() m_volumes.volumes.emplace_back(new GLVolume(color)); GLVolume& v = *m_volumes.volumes.back(); #if ENABLE_SMOOTH_NORMALS - v.indexed_vertex_array.load_mesh(mesh, true); + v.model.init_from(mesh, true); #else - v.indexed_vertex_array.load_mesh(mesh); + v.model.init_from(mesh); #endif // ENABLE_SMOOTH_NORMALS - v.indexed_vertex_array.finalize_geometry(m_initialized); v.shader_outside_printer_detection_enabled = outside_printer_detection_enabled; v.composite_id.volume_id = volume_id; v.set_instance_offset(unscale(instance.shift.x(), instance.shift.y(), 0.0)); diff --git a/src/slic3r/GUI/GLModel.cpp b/src/slic3r/GUI/GLModel.cpp index 0cb7bfc96b7..5a174677061 100644 --- a/src/slic3r/GUI/GLModel.cpp +++ b/src/slic3r/GUI/GLModel.cpp @@ -8,15 +8,50 @@ #include "libslic3r/TriangleMesh.hpp" #include "libslic3r/Model.hpp" #include "libslic3r/Polygon.hpp" +#include "libslic3r/BuildVolume.hpp" +#include "libslic3r/Geometry/ConvexHull.hpp" #include #include +#if ENABLE_SMOOTH_NORMALS +#include +#include +#include +#endif // ENABLE_SMOOTH_NORMALS + #include namespace Slic3r { namespace GUI { +#if ENABLE_SMOOTH_NORMALS +static void smooth_normals_corner(const TriangleMesh& mesh, std::vector& normals) +{ + using MapMatrixXfUnaligned = Eigen::Map>; + using MapMatrixXiUnaligned = Eigen::Map>; + + std::vector face_normals = its_face_normals(mesh.its); + + Eigen::MatrixXd vertices = MapMatrixXfUnaligned(mesh.its.vertices.front().data(), + Eigen::Index(mesh.its.vertices.size()), 3).cast(); + Eigen::MatrixXi indices = MapMatrixXiUnaligned(mesh.its.indices.front().data(), + Eigen::Index(mesh.its.indices.size()), 3); + Eigen::MatrixXd in_normals = MapMatrixXfUnaligned(face_normals.front().data(), + Eigen::Index(face_normals.size()), 3).cast(); + Eigen::MatrixXd out_normals; + + igl::per_corner_normals(vertices, indices, in_normals, 1.0, out_normals); + + normals = std::vector(mesh.its.vertices.size()); + for (size_t i = 0; i < mesh.its.indices.size(); ++i) { + for (size_t j = 0; j < 3; ++j) { + normals[mesh.its.indices[i][j]] = out_normals.row(i * 3 + j).cast(); + } + } +} +#endif // ENABLE_SMOOTH_NORMALS + void GLModel::Geometry::reserve_vertices(size_t vertices_count) { vertices.reserve(vertices_count * vertex_stride_floats(format)); @@ -206,6 +241,35 @@ Vec2f GLModel::Geometry::extract_tex_coord_2(size_t id) const return { *(start + 0), *(start + 1) }; } +void GLModel::Geometry::set_vertex(size_t id, const Vec3f& position, const Vec3f& normal) +{ + assert(format.vertex_layout == EVertexLayout::P3N3); + assert(id < vertices_count()); + if (id < vertices_count()) { + float* start = &vertices[id * vertex_stride_floats(format)]; + *(start + 0) = position.x(); + *(start + 1) = position.y(); + *(start + 2) = position.z(); + *(start + 3) = normal.x(); + *(start + 4) = normal.y(); + *(start + 5) = normal.z(); + } +} + +void GLModel::Geometry::set_ushort_index(size_t id, unsigned short index) +{ + assert(id < indices_count()); + if (id < indices_count()) + ::memcpy(indices.data() + id * sizeof(unsigned short), &index, sizeof(unsigned short)); +} + +void GLModel::Geometry::set_uint_index(size_t id, unsigned int index) +{ + assert(id < indices_count()); + if (id < indices_count()) + ::memcpy(indices.data() + id * sizeof(unsigned int), &index, sizeof(unsigned int)); +} + unsigned int GLModel::Geometry::extract_uint_index(size_t id) const { if (format.index_type != EIndexType::UINT) { @@ -218,7 +282,7 @@ unsigned int GLModel::Geometry::extract_uint_index(size_t id) const return -1; } - unsigned int ret = -1; + unsigned int ret = (unsigned int)-1; ::memcpy(&ret, indices.data() + id * index_stride_bytes(format), sizeof(unsigned int)); return ret; } @@ -235,11 +299,21 @@ unsigned short GLModel::Geometry::extract_ushort_index(size_t id) const return -1; } - unsigned short ret = -1; + unsigned short ret = (unsigned short)-1; ::memcpy(&ret, indices.data() + id * index_stride_bytes(format), sizeof(unsigned short)); return ret; } +void GLModel::Geometry::remove_vertex(size_t id) +{ + assert(id < vertices_count()); + if (id < vertices_count()) { + size_t stride = vertex_stride_floats(format); + std::vector::iterator it = vertices.begin() + id * stride; + vertices.erase(it, it + stride); + } +} + size_t GLModel::Geometry::vertex_stride_floats(const Format& format) { switch (format.vertex_layout) @@ -417,21 +491,24 @@ void GLModel::init_from(const indexed_triangle_set& its) } Geometry& data = m_render_data.geometry; - data.format = { Geometry::EPrimitiveType::Triangles, Geometry::EVertexLayout::P3N3, Geometry::EIndexType::UINT }; + data.format = { Geometry::EPrimitiveType::Triangles, Geometry::EVertexLayout::P3N3, GLModel::Geometry::index_type(3 * its.indices.size()) }; data.reserve_vertices(3 * its.indices.size()); data.reserve_indices(3 * its.indices.size()); // vertices + indices unsigned int vertices_counter = 0; for (uint32_t i = 0; i < its.indices.size(); ++i) { - stl_triangle_vertex_indices face = its.indices[i]; - stl_vertex vertex[3] = { its.vertices[face[0]], its.vertices[face[1]], its.vertices[face[2]] }; - stl_vertex n = face_normal_normalized(vertex); + const stl_triangle_vertex_indices face = its.indices[i]; + const stl_vertex vertex[3] = { its.vertices[face[0]], its.vertices[face[1]], its.vertices[face[2]] }; + const stl_vertex n = face_normal_normalized(vertex); for (size_t j = 0; j < 3; ++j) { data.add_vertex(vertex[j], n); } vertices_counter += 3; - data.add_uint_triangle(vertices_counter - 3, vertices_counter - 2, vertices_counter - 1); + if (data.format.index_type == GLModel::Geometry::EIndexType::USHORT) + data.add_ushort_triangle((unsigned short)vertices_counter - 3, (unsigned short)vertices_counter - 2, (unsigned short)vertices_counter - 1); + else + data.add_uint_triangle(vertices_counter - 3, vertices_counter - 2, vertices_counter - 1); } // update bounding box @@ -553,6 +630,17 @@ static GLenum get_index_type(const GLModel::Geometry::Format& format) void GLModel::render() { + render(std::make_pair(0, indices_count())); +} + +void GLModel::render(const std::pair& range) +{ + if (m_render_disabled) + return; + + if (range.second == range.first) + return; + GLShaderProgram* shader = wxGetApp().get_current_shader(); if (shader == nullptr) @@ -570,8 +658,8 @@ void GLModel::render() const GLenum index_type = get_index_type(data.format); const size_t vertex_stride_bytes = Geometry::vertex_stride_bytes(data.format); - const bool position = Geometry::has_position(data.format); - const bool normal = Geometry::has_normal(data.format); + const bool position = Geometry::has_position(data.format); + const bool normal = Geometry::has_normal(data.format); const bool tex_coord = Geometry::has_tex_coord(data.format); glsafe(::glBindBuffer(GL_ARRAY_BUFFER, m_render_data.vbo_id)); @@ -592,7 +680,7 @@ void GLModel::render() shader->set_uniform("uniform_color", data.color); glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_render_data.ibo_id)); - glsafe(::glDrawElements(mode, indices_count(), index_type, nullptr)); + glsafe(::glDrawElements(mode, range.second - range.first + 1, index_type, (const void*)(range.first * Geometry::index_stride_bytes(data.format)))); glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0)); if (tex_coord) @@ -721,6 +809,61 @@ static void append_triangle(GLModel::Geometry& data, unsigned short v1, unsigned data.add_ushort_index(v2); data.add_ushort_index(v3); } + +template +inline bool all_vertices_inside(const GLModel::Geometry& geometry, Fn fn) +{ + const size_t position_stride_floats = geometry.position_stride_floats(geometry.format); + const size_t position_offset_floats = geometry.position_offset_floats(geometry.format); + assert(position_stride_floats == 3); + if (geometry.vertices.empty() || position_stride_floats != 3) + return false; + + for (auto it = geometry.vertices.begin(); it != geometry.vertices.end(); ) { + it += position_offset_floats; + if (!fn({ *it, *(it + 1), *(it + 2) })) + return false; + it += (geometry.vertex_stride_floats(geometry.format) - position_offset_floats - position_stride_floats); + } + return true; +} + +bool contains(const BuildVolume& volume, const GLModel& model, bool ignore_bottom) +{ + static constexpr const double epsilon = BuildVolume::BedEpsilon; + switch (volume.type()) { + case BuildVolume_Type::Rectangle: + { + BoundingBox3Base build_volume = volume.bounding_volume().inflated(epsilon); + if (volume.printable_height() == 0.0) + build_volume.max.z() = std::numeric_limits::max(); + if (ignore_bottom) + build_volume.min.z() = -std::numeric_limits::max(); + const BoundingBoxf3& model_box = model.get_bounding_box(); + return build_volume.contains(model_box.min) && build_volume.contains(model_box.max); + } + case BuildVolume_Type::Circle: + { + const Geometry::Circled& circle = volume.circle(); + const Vec2f c = unscaled(circle.center); + const float r = unscaled(circle.radius) + float(epsilon); + const float r2 = sqr(r); + return volume.printable_height() == 0.0 ? + all_vertices_inside(model.get_geometry(), [c, r2](const Vec3f& p) { return (to_2d(p) - c).squaredNorm() <= r2; }) : + + all_vertices_inside(model.get_geometry(), [c, r2, z = volume.printable_height() + epsilon](const Vec3f& p) { return (to_2d(p) - c).squaredNorm() <= r2 && p.z() <= z; }); + } + case BuildVolume_Type::Convex: + //FIXME doing test on convex hull until we learn to do test on non-convex polygons efficiently. + case BuildVolume_Type::Custom: + return volume.printable_height() == 0.0 ? + all_vertices_inside(model.get_geometry(), [&volume](const Vec3f& p) { return Geometry::inside_convex_polygon(volume.top_bottom_convex_hull_decomposition_bed(), to_2d(p).cast()); }) : + all_vertices_inside(model.get_geometry(), [&volume, z = volume.printable_height() + epsilon](const Vec3f& p) { return Geometry::inside_convex_polygon(volume.top_bottom_convex_hull_decomposition_bed(), to_2d(p).cast()) && p.z() <= z; }); + default: + return true; + } +} + GLModel::Geometry stilized_arrow(unsigned short resolution, float tip_radius, float tip_height, float stem_radius, float stem_height) { resolution = std::max(4, resolution); diff --git a/src/slic3r/GUI/GLModel.hpp b/src/slic3r/GUI/GLModel.hpp index 98feaaad0ad..79c615f31c6 100644 --- a/src/slic3r/GUI/GLModel.hpp +++ b/src/slic3r/GUI/GLModel.hpp @@ -14,6 +14,7 @@ namespace Slic3r { class TriangleMesh; class Polygon; using Polygons = std::vector; +class BuildVolume; namespace GUI { @@ -69,6 +70,11 @@ namespace GUI { void add_vertex(const Vec3f& position, const Vec2f& tex_coord); // EVertexLayout::P3T2 void add_vertex(const Vec3f& position, const Vec3f& normal); // EVertexLayout::P3N3 + void set_vertex(size_t id, const Vec3f& position, const Vec3f& normal); // EVertexLayout::P3N3 + + void set_ushort_index(size_t id, unsigned short index); + void set_uint_index(size_t id, unsigned int index); + void add_ushort_index(unsigned short id); void add_uint_index(unsigned int id); @@ -86,7 +92,9 @@ namespace GUI { unsigned int extract_uint_index(size_t id) const; unsigned short extract_ushort_index(size_t id) const; - bool is_empty() const { return vertices.empty() || indices.empty(); } + void remove_vertex(size_t id); + + bool is_empty() const { return vertices_count() == 0 || indices_count() == 0; } size_t vertices_count() const { return vertices.size() / vertex_stride_floats(format); } size_t indices_count() const { return indices.size() / index_stride_bytes(format); } @@ -133,6 +141,14 @@ namespace GUI { private: RenderData m_render_data; + // By default the vertex and index buffers data are sent to gpu at the first call to render() method. + // If you need to initialize a model from outside the main thread, so that a call to render() may happen + // before the initialization is complete, use the methods: + // disable_render() + // ... do your initialization ... + // enable_render() + // to keep the data on cpu side until needed. + bool m_render_disabled{ false }; BoundingBoxf3 m_bounding_box; std::string m_filename; @@ -150,6 +166,7 @@ namespace GUI { size_t indices_size_bytes() const { return indices_count() * Geometry::index_stride_bytes(m_render_data.geometry.format); } + const Geometry& get_geometry() const { return m_render_data.geometry; } void init_from(Geometry&& data); void init_from(const TriangleMesh& mesh); void init_from(const indexed_triangle_set& its); @@ -161,16 +178,40 @@ namespace GUI { void reset(); void render(); + void render(const std::pair& range); void render_instanced(unsigned int instances_vbo, unsigned int instances_count); bool is_initialized() const { return vertices_count() > 0 && indices_count() > 0; } + bool is_empty() const { return m_render_data.geometry.is_empty(); } const BoundingBoxf3& get_bounding_box() const { return m_bounding_box; } const std::string& get_filename() const { return m_filename; } + bool is_render_disabled() const { return m_render_disabled; } + void enable_render() { m_render_disabled = false; } + void disable_render() { m_render_disabled = true; } + + size_t cpu_memory_used() const { + size_t ret = 0; + if (!m_render_data.geometry.vertices.empty()) + ret += vertices_size_bytes(); + if (!m_render_data.geometry.indices.empty()) + ret += indices_size_bytes(); + return ret; + } + size_t gpu_memory_used() const { + size_t ret = 0; + if (m_render_data.geometry.vertices.empty()) + ret += vertices_size_bytes(); + if (m_render_data.geometry.indices.empty()) + ret += indices_size_bytes(); + return ret; + } + private: bool send_to_gpu(); }; + bool contains(const BuildVolume& volume, const GLModel& model, bool ignore_bottom = true); // create an arrow with cylindrical stem and conical tip, with the given dimensions and resolution // the origin of the arrow is in the center of the stem cap diff --git a/src/slic3r/GUI/Gizmos/GLGizmoFaceDetector.cpp b/src/slic3r/GUI/Gizmos/GLGizmoFaceDetector.cpp index b96be246a3a..90b274decd2 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoFaceDetector.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoFaceDetector.cpp @@ -32,9 +32,9 @@ std::string GLGizmoFaceDetector::on_get_name() const void GLGizmoFaceDetector::on_render() { - if (m_iva.has_VBOs()) { - ::glColor4f(0.f, 0.f, 1.f, 0.4f); - m_iva.render(); + if (model.is_initialized()) { + model.set_color({0.f, 0.f, 1.f, 0.4f}); + model.render(); } } @@ -72,7 +72,7 @@ void GLGizmoFaceDetector::on_render_input_window(float x, float y, float bottom_ void GLGizmoFaceDetector::on_set_state() { if (get_state() == On) { - m_iva.release_geometry(); + model.reset(); display_exterior_face(); } } @@ -94,7 +94,10 @@ void GLGizmoFaceDetector::perform_recognition(const Selection& selection) void GLGizmoFaceDetector::display_exterior_face() { int cnt = 0; - m_iva.release_geometry(); + model.reset(); + + GLModel::Geometry init_data; + init_data.format = { GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3N3, GLModel::Geometry::EIndexType::UINT }; const ModelObjectPtrs& objects = wxGetApp().model().objects; for (ModelObject* mo : objects) { @@ -110,19 +113,15 @@ void GLGizmoFaceDetector::display_exterior_face() continue; for (int i = 0; i < 3; ++i) { - m_iva.push_geometry(double(mv_its.vertices[facet_vert_idxs[i]](0)), - double(mv_its.vertices[facet_vert_idxs[i]](1)), - double(mv_its.vertices[facet_vert_idxs[i]](2)), - 0., 0., 1.); + init_data.add_vertex((Vec3f) mv_its.vertices[facet_vert_idxs[i]].cast(), Vec3f{0.0f, 0.0f, 1.0f}); } - m_iva.push_triangle(cnt, cnt + 1, cnt + 2); + init_data.add_uint_triangle(cnt, cnt + 1, cnt + 2); cnt += 3; } } } - - m_iva.finalize_geometry(true); + model.init_from(std::move(init_data)); } CommonGizmosDataID GLGizmoFaceDetector::on_get_requirements() const diff --git a/src/slic3r/GUI/Gizmos/GLGizmoFaceDetector.hpp b/src/slic3r/GUI/Gizmos/GLGizmoFaceDetector.hpp index c20cf4c2090..c028a3f2b20 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoFaceDetector.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoFaceDetector.hpp @@ -28,7 +28,7 @@ class GLGizmoFaceDetector : public GLGizmoBase void perform_recognition(const Selection& selection); void display_exterior_face(); - GLIndexedVertexArray m_iva; + GUI::GLModel model; double m_sample_interval = {0.5}; }; diff --git a/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp b/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp index b9dc5770d4a..86aa18f8944 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp @@ -894,13 +894,16 @@ void GLGizmoFdmSupports::run_thread() print->set_status(100, L("Support Generated")); goto _finished; } + GLModel::Geometry init_data; + init_data.format = { GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3N3, GLModel::Geometry::EIndexType::UINT }; for (const SupportLayer *support_layer : m_print_instance.print_object->support_layers()) { for (const ExtrusionEntity *extrusion_entity : support_layer->support_fills.entities) { - _3DScene::extrusionentity_to_verts(extrusion_entity, float(support_layer->print_z), m_print_instance.shift, *m_support_volume); + _3DScene::extrusionentity_to_verts(extrusion_entity, float(support_layer->print_z), m_print_instance.shift, init_data); } } + m_support_volume->model.init_from(std::move(init_data)); BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ", finished extrusionentity_to_verts, update status to 100%"; print->set_status(100, L("Support Generated")); @@ -926,7 +929,6 @@ void GLGizmoFdmSupports::run_thread() void GLGizmoFdmSupports::generate_support_volume() { BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ",before finalize_geometry"; - m_support_volume->indexed_vertex_array.finalize_geometry(m_parent.is_initialized()); std::unique_lock lck(m_mutex); m_volume_ready = true; diff --git a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp index 0acfd3eb1ec..1e500ff4067 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp @@ -17,7 +17,7 @@ #include "slic3r/GUI/Gizmos/GLGizmoFdmSupports.hpp" // BBS #include "slic3r/GUI/Gizmos/GLGizmoAdvancedCut.hpp" -#include "slic3r/GUI/Gizmos/GLGizmoFaceDetector.hpp" +//#include "slic3r/GUI/Gizmos/GLGizmoFaceDetector.hpp" #include "slic3r/GUI/Gizmos/GLGizmoHollow.hpp" #include "slic3r/GUI/Gizmos/GLGizmoSeam.hpp" #include "slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.hpp" diff --git a/src/slic3r/GUI/ImGuiWrapper.cpp b/src/slic3r/GUI/ImGuiWrapper.cpp index f061cd79703..bc2e84e9461 100644 --- a/src/slic3r/GUI/ImGuiWrapper.cpp +++ b/src/slic3r/GUI/ImGuiWrapper.cpp @@ -2388,8 +2388,8 @@ void ImGuiWrapper::render_draw_data(ImDrawData *draw_data) { // Avoid rendering when minimized, scale coordinates for retina displays (screen coordinates != framebuffer coordinates) ImGuiIO& io = ImGui::GetIO(); - int fb_width = (int)(draw_data->DisplaySize.x * io.DisplayFramebufferScale.x); - int fb_height = (int)(draw_data->DisplaySize.y * io.DisplayFramebufferScale.y); + const int fb_width = (int)(draw_data->DisplaySize.x * io.DisplayFramebufferScale.x); + const int fb_height = (int)(draw_data->DisplaySize.y * io.DisplayFramebufferScale.y); if (fb_width == 0 || fb_height == 0) return; draw_data->ScaleClipRects(io.DisplayFramebufferScale); @@ -2432,8 +2432,7 @@ void ImGuiWrapper::render_draw_data(ImDrawData *draw_data) // Render command lists ImVec2 pos = draw_data->DisplayPos; - for (int n = 0; n < draw_data->CmdListsCount; n++) - { + for (int n = 0; n < draw_data->CmdListsCount; ++n) { const ImDrawList* cmd_list = draw_data->CmdLists[n]; const ImDrawVert* vtx_buffer = cmd_list->VtxBuffer.Data; const ImDrawIdx* idx_buffer = cmd_list->IdxBuffer.Data; @@ -2441,19 +2440,14 @@ void ImGuiWrapper::render_draw_data(ImDrawData *draw_data) glsafe(::glTexCoordPointer(2, GL_FLOAT, sizeof(ImDrawVert), (const GLvoid*)((const char*)vtx_buffer + IM_OFFSETOF(ImDrawVert, uv)))); glsafe(::glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(ImDrawVert), (const GLvoid*)((const char*)vtx_buffer + IM_OFFSETOF(ImDrawVert, col)))); - for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++) - { + for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; ++cmd_i) { const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i]; if (pcmd->UserCallback) - { // User callback (registered via ImDrawList::AddCallback) pcmd->UserCallback(cmd_list, pcmd); - } - else - { + else { ImVec4 clip_rect = ImVec4(pcmd->ClipRect.x - pos.x, pcmd->ClipRect.y - pos.y, pcmd->ClipRect.z - pos.x, pcmd->ClipRect.w - pos.y); - if (clip_rect.x < fb_width && clip_rect.y < fb_height && clip_rect.z >= 0.0f && clip_rect.w >= 0.0f) - { + if (clip_rect.x < fb_width && clip_rect.y < fb_height && clip_rect.z >= 0.0f && clip_rect.w >= 0.0f) { // Apply scissor/clipping rectangle glsafe(::glScissor((int)clip_rect.x, (int)(fb_height - clip_rect.w), (int)(clip_rect.z - clip_rect.x), (int)(clip_rect.w - clip_rect.y))); diff --git a/src/slic3r/Utils/CalibUtils.cpp b/src/slic3r/Utils/CalibUtils.cpp index 82382293f86..a496d1ff34a 100644 --- a/src/slic3r/Utils/CalibUtils.cpp +++ b/src/slic3r/Utils/CalibUtils.cpp @@ -926,7 +926,7 @@ void CalibUtils::process_and_store_3mf(Model *model, const DynamicPrintConfig &f const ModelVolume &model_volume = *model_object.volumes[volume_idx]; for (int instance_idx = 0; instance_idx < (int)model_object.instances.size(); ++ instance_idx) { const ModelInstance &model_instance = *model_object.instances[instance_idx]; - glvolume_collection.load_object_volume(&model_object, obj_idx, volume_idx, instance_idx, true, false, true); + glvolume_collection.load_object_volume(&model_object, obj_idx, volume_idx, instance_idx, false, true); glvolume_collection.volumes.back()->set_render_color(new_color); glvolume_collection.volumes.back()->set_color(new_color); //glvolume_collection.volumes.back()->printable = model_instance.printable; From 1fedcb61b72022162c5e36b43aac9ab8cb65d932 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Mon, 23 Oct 2023 17:12:30 +0800 Subject: [PATCH 27/99] Tech ENABLE_GLBEGIN_GLEND_REMOVAL - Fix in GLGizmoRotate::render_angle_arc(): Tech ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL - Fix in GLModel::render() (cherry picked from commit prusa3d/PrusaSlicer@237958819644c62e5e4e09b48a49d15f2e77cf3d) --- src/slic3r/GUI/GLModel.cpp | 2 +- src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp | 30 ++++++++++++++----------- src/slic3r/GUI/Gizmos/GLGizmoRotate.hpp | 1 + 3 files changed, 19 insertions(+), 14 deletions(-) diff --git a/src/slic3r/GUI/GLModel.cpp b/src/slic3r/GUI/GLModel.cpp index 5a174677061..e73d7bc4e06 100644 --- a/src/slic3r/GUI/GLModel.cpp +++ b/src/slic3r/GUI/GLModel.cpp @@ -680,7 +680,7 @@ void GLModel::render(const std::pair& range) shader->set_uniform("uniform_color", data.color); glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_render_data.ibo_id)); - glsafe(::glDrawElements(mode, range.second - range.first + 1, index_type, (const void*)(range.first * Geometry::index_stride_bytes(data.format)))); + glsafe(::glDrawElements(mode, range.second - range.first, index_type, (const void*)(range.first * Geometry::index_stride_bytes(data.format)))); glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0)); if (tex_coord) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp b/src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp index e102fb0fe7b..a660d87dcc0 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp @@ -334,22 +334,26 @@ void GLGizmoRotate::render_angle_arc(const ColorRGBA& color, bool radius_changed const float step_angle = float(m_angle) / float(AngleResolution); const float ex_radius = m_radius * (1.0f + GrabberOffset); - if (!m_angle_arc.is_initialized() || radius_changed) { - m_angle_arc.reset(); + const bool angle_changed = std::abs(m_old_angle - m_angle) > EPSILON; + m_old_angle = m_angle; - GLModel::Geometry init_data; - init_data.format = { GLModel::Geometry::EPrimitiveType::LineStrip, GLModel::Geometry::EVertexLayout::P3, GLModel::Geometry::EIndexType::USHORT }; - init_data.reserve_vertices(1 + AngleResolution); - init_data.reserve_indices(1 + AngleResolution); + if (!m_angle_arc.is_initialized() || radius_changed || angle_changed) { + m_angle_arc.reset(); + if (m_angle > 0.0f) { + GLModel::Geometry init_data; + init_data.format = { GLModel::Geometry::EPrimitiveType::LineStrip, GLModel::Geometry::EVertexLayout::P3, GLModel::Geometry::EIndexType::USHORT }; + init_data.reserve_vertices(1 + AngleResolution); + init_data.reserve_indices(1 + AngleResolution); + + // vertices + indices + for (unsigned short i = 0; i <= AngleResolution; ++i) { + const float angle = float(i) * step_angle; + init_data.add_vertex(Vec3f(::cos(angle) * ex_radius, ::sin(angle) * ex_radius, 0.0f)); + init_data.add_ushort_index(i); + } - // vertices + indices - for (unsigned short i = 0; i <= AngleResolution; ++i) { - const float angle = float(i) * step_angle; - init_data.add_vertex(Vec3f(::cos(angle) * ex_radius, ::sin(angle) * ex_radius, 0.0f)); - init_data.add_ushort_index(i); + m_angle_arc.init_from(std::move(init_data)); } - - m_angle_arc.init_from(std::move(init_data)); } m_angle_arc.set_color(color); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoRotate.hpp b/src/slic3r/GUI/Gizmos/GLGizmoRotate.hpp index 4bd7a6877ef..aa4a773b47c 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoRotate.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoRotate.hpp @@ -54,6 +54,7 @@ class GLGizmoRotate : public GLGizmoBase GrabberConnection m_grabber_connection; float m_old_radius{ 0.0f }; float m_old_hover_radius{ 0.0f }; + float m_old_angle{ 0.0f }; public: GLGizmoRotate(GLCanvas3D& parent, Axis axis); From c5b209270cda952ba7efbf898df7889760f57907 Mon Sep 17 00:00:00 2001 From: Noisyfox Date: Mon, 23 Oct 2023 20:30:26 +0800 Subject: [PATCH 28/99] Fix a few issues in cut gizmo --- src/slic3r/GUI/Gizmos/GLGizmoAdvancedCut.cpp | 28 ++++++++------------ 1 file changed, 11 insertions(+), 17 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoAdvancedCut.cpp b/src/slic3r/GUI/Gizmos/GLGizmoAdvancedCut.cpp index d4a521374e3..9bae84b0349 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoAdvancedCut.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoAdvancedCut.cpp @@ -411,32 +411,26 @@ CommonGizmosDataID GLGizmoAdvancedCut::on_get_requirements() const void GLGizmoAdvancedCut::on_start_dragging() { - for (auto gizmo : m_gizmos) { - if (m_hover_id == gizmo.get_group_id()) { - gizmo.start_dragging(); - return; - } + if (m_hover_id == X || m_hover_id == Y || m_hover_id == Z) { + m_gizmos[m_hover_id].start_dragging(); + } else if (m_hover_id == c_connectors_group_id - 1) { + const Selection& selection = m_parent.get_selection(); + const BoundingBoxf3& box = selection.get_bounding_box(); + m_start_movement = m_movement; + m_start_height = m_height; + m_drag_pos = m_move_grabber.center; } - - if (m_hover_id != get_group_id()) - return; - - const Selection& selection = m_parent.get_selection(); - const BoundingBoxf3& box = selection.get_bounding_box(); - m_start_movement = m_movement; - m_start_height = m_height; - m_drag_pos = m_move_grabber.center; - - if (m_hover_id >= c_connectors_group_id) - Plater::TakeSnapshot snapshot(wxGetApp().plater(), "Move connector"); } void GLGizmoAdvancedCut::on_stop_dragging() { if (m_hover_id == X || m_hover_id == Y || m_hover_id == Z) { + m_gizmos[m_hover_id].stop_dragging(); Plater::TakeSnapshot snapshot(wxGetApp().plater(), "Rotate cut plane"); } else if (m_hover_id == c_connectors_group_id - 1) { Plater::TakeSnapshot snapshot(wxGetApp().plater(), "Move cut plane"); + } else if (m_hover_id >= c_connectors_group_id) { + Plater::TakeSnapshot snapshot(wxGetApp().plater(), "Move connector"); } } From e6443b5b27ee79759e0af62179887a96c5d25c0e Mon Sep 17 00:00:00 2001 From: Noisyfox Date: Tue, 24 Oct 2023 10:17:39 +0800 Subject: [PATCH 29/99] Removed empty IMSlider_Utils.hpp --- src/slic3r/CMakeLists.txt | 1 - src/slic3r/GUI/GUI_Preview.cpp | 1 - src/slic3r/GUI/IMSlider_Utils.hpp | 0 3 files changed, 2 deletions(-) delete mode 100644 src/slic3r/GUI/IMSlider_Utils.hpp diff --git a/src/slic3r/CMakeLists.txt b/src/slic3r/CMakeLists.txt index d9ad26a6eeb..21d8fd6c858 100644 --- a/src/slic3r/CMakeLists.txt +++ b/src/slic3r/CMakeLists.txt @@ -348,7 +348,6 @@ set(SLIC3R_GUI_SOURCES GUI/Mouse3DController.hpp GUI/IMSlider.cpp GUI/IMSlider.hpp - GUI/IMSlider_Utils.hpp GUI/Notebook.cpp GUI/Notebook.hpp GUI/TabButton.cpp diff --git a/src/slic3r/GUI/GUI_Preview.cpp b/src/slic3r/GUI/GUI_Preview.cpp index fc10e765e3b..3c76e7d9d8e 100644 --- a/src/slic3r/GUI/GUI_Preview.cpp +++ b/src/slic3r/GUI/GUI_Preview.cpp @@ -2,7 +2,6 @@ #include "libslic3r/libslic3r.h" #include "libslic3r/Layer.hpp" #include "IMSlider.hpp" -#include "IMSlider_Utils.hpp" #include "GUI_Preview.hpp" #include "GUI_App.hpp" #include "GUI.hpp" diff --git a/src/slic3r/GUI/IMSlider_Utils.hpp b/src/slic3r/GUI/IMSlider_Utils.hpp deleted file mode 100644 index e69de29bb2d..00000000000 From 61ed6143e623e32503968b0d436141f0e30146d4 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Tue, 24 Oct 2023 10:20:46 +0800 Subject: [PATCH 30/99] Removed unneeded pairs glPushMatrix()/glPopMatrix() (cherry picked from commit prusa3d/PrusaSlicer@5f9aeb1e3840cc9f9d00a4e2dd6cc5699e00699a) --- src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp | 2 -- src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp | 11 +++-------- src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp | 2 -- 3 files changed, 3 insertions(+), 12 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp b/src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp index c8514ed103c..113ea049928 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp @@ -159,11 +159,9 @@ void GLGizmoHollow::render_points(const Selection& selection, bool picking) q.setFromTwoVectors(Vec3d::UnitZ(), instance_scaling_matrix_inverse * (-drain_hole.normal).cast()); Eigen::AngleAxisd aa(q); glsafe(::glRotated(aa.angle() * (180. / M_PI), aa.axis().x(), aa.axis().y(), aa.axis().z())); - glsafe(::glPushMatrix()); glsafe(::glTranslated(0., 0., -drain_hole.height)); glsafe(::glScaled(drain_hole.radius, drain_hole.radius, drain_hole.height + sla::HoleStickOutLength)); m_cylinder.render(); - glsafe(::glPopMatrix()); if (vol->is_left_handed()) glFrontFace(GL_CCW); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp index b5ead52fd6f..48031ead3f0 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp @@ -202,17 +202,14 @@ void GLGizmoSlaSupports::render_points(const Selection& selection, bool picking) const double cone_height = 0.75; glsafe(::glPushMatrix()); glsafe(::glTranslatef(0.f, 0.f, cone_height + support_point.head_front_radius * RenderPointScale)); - glsafe(::glPushMatrix()); glsafe(::glRotated(180., 1., 0., 0.)); glsafe(::glScaled(cone_radius, cone_radius, cone_height)); m_cone.render(); glsafe(::glPopMatrix()); - glsafe(::glTranslatef(0.f, 0.f, cone_height)); - glsafe(::glPopMatrix()); } glsafe(::glPushMatrix()); - double radius = (double)support_point.head_front_radius * RenderPointScale; + const double radius = (double)support_point.head_front_radius * RenderPointScale; glsafe(::glScaled(radius, radius, radius)); m_sphere.render(); glsafe(::glPopMatrix()); @@ -234,7 +231,7 @@ void GLGizmoSlaSupports::render_points(const Selection& selection, bool picking) // Inverse matrix of the instance scaling is applied so that the mark does not scale with the object. glsafe(::glPushMatrix()); - glsafe(::glTranslatef(drain_hole.pos(0), drain_hole.pos(1), drain_hole.pos(2))); + glsafe(::glTranslatef(drain_hole.pos.x(), drain_hole.pos.y(), drain_hole.pos.z())); glsafe(::glMultMatrixd(instance_scaling_matrix_inverse.data())); if (vol->is_left_handed()) @@ -245,12 +242,10 @@ void GLGizmoSlaSupports::render_points(const Selection& selection, bool picking) Eigen::Quaterniond q; q.setFromTwoVectors(Vec3d{0., 0., 1.}, instance_scaling_matrix_inverse * (-drain_hole.normal).cast()); Eigen::AngleAxisd aa(q); - glsafe(::glRotated(aa.angle() * (180. / M_PI), aa.axis()(0), aa.axis()(1), aa.axis()(2))); - glsafe(::glPushMatrix()); + glsafe(::glRotated(aa.angle() * (180. / M_PI), aa.axis().x(), aa.axis().y(), aa.axis().z())); glsafe(::glTranslated(0., 0., -drain_hole.height)); glsafe(::glScaled(drain_hole.radius, drain_hole.radius, drain_hole.height + sla::HoleStickOutLength)); m_cylinder.render(); - glsafe(::glPopMatrix()); if (vol->is_left_handed()) glFrontFace(GL_CCW); diff --git a/src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp b/src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp index 392a2db878c..3f65a188ef7 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp @@ -724,10 +724,8 @@ void ModelObjectsClipper::render_cut() const auto& clipper = m_clippers[clipper_id]; clipper->set_plane(*m_clp); clipper->set_transformation(trafo); - glsafe(::glPushMatrix()); // BBS clipper->render_cut({0.25f, 0.25f, 0.25f, 1.0f}); - glsafe(::glPopMatrix()); ++clipper_id; } From d8551d7a7dbd7cb3b7bc1ea6679aa03b51b9be65 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Tue, 24 Oct 2023 10:22:34 +0800 Subject: [PATCH 31/99] Tech ENABLE_GLBEGIN_GLEND_REMOVAL - Use 2D vertices to render GLGizmoPainterBase circle (cherry picked from commit prusa3d/PrusaSlicer@5193a158528a81c654bf3d474515017b41543dfd) --- src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp b/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp index 6a6919b2bea..fbc2f25ffaf 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp @@ -201,7 +201,7 @@ void GLGizmoPainterBase::render_cursor_circle() GLModel::Geometry init_data; static const unsigned int StepsCount = 32; static const float StepSize = 2.0f * float(PI) / float(StepsCount); - init_data.format = { GLModel::Geometry::EPrimitiveType::LineLoop, GLModel::Geometry::EVertexLayout::P3, GLModel::Geometry::EIndexType::USHORT }; + init_data.format = { GLModel::Geometry::EPrimitiveType::LineLoop, GLModel::Geometry::EVertexLayout::P2, GLModel::Geometry::EIndexType::USHORT }; init_data.color = { 0.0f, 1.0f, 0.3f, 1.0f }; init_data.reserve_vertices(StepsCount); init_data.reserve_indices(StepsCount); @@ -209,7 +209,7 @@ void GLGizmoPainterBase::render_cursor_circle() // vertices + indices for (unsigned short i = 0; i < StepsCount; ++i) { const float angle = float(i * StepSize); - init_data.add_vertex(Vec3f(center.x() + ::cos(angle) * m_cursor_radius, center.y() + ::sin(angle) * m_cursor_radius, 0.0f)); + init_data.add_vertex(Vec2f(center.x() + ::cos(angle) * m_cursor_radius, center.y() + ::sin(angle) * m_cursor_radius)); init_data.add_ushort_index(i); } From 5fc056edfbc27693675f9119057f72cbe7c40628 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Tue, 24 Oct 2023 10:27:56 +0800 Subject: [PATCH 32/99] Some refactoring into GLGizmoSlaSupports::render_points() (cherry picked from commit prusa3d/PrusaSlicer@5621f00ee694e6aaedb83b190c855395a0df2dc6) --- src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp | 25 +++++++++----------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp index 48031ead3f0..a981d15c725 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp @@ -118,10 +118,10 @@ void GLGizmoSlaSupports::on_render_for_picking() void GLGizmoSlaSupports::render_points(const Selection& selection, bool picking) { - size_t cache_size = m_editing_mode ? m_editing_cache.size() : m_normal_cache.size(); + const size_t cache_size = m_editing_mode ? m_editing_cache.size() : m_normal_cache.size(); - bool has_points = (cache_size != 0); - bool has_holes = (! m_c->hollowed_mesh()->get_hollowed_mesh() + const bool has_points = (cache_size != 0); + const bool has_holes = (! m_c->hollowed_mesh()->get_hollowed_mesh() && ! m_c->selection_info()->model_object()->sla_drain_holes.empty()); if (! has_points && ! has_holes) @@ -135,9 +135,9 @@ void GLGizmoSlaSupports::render_points(const Selection& selection, bool picking) ScopeGuard guard([shader]() { shader->stop_using(); }); const GLVolume* vol = selection.get_volume(*selection.get_volume_idxs().begin()); - const Transform3d& instance_scaling_matrix_inverse = vol->get_instance_transformation().get_matrix(true, true, false, true).inverse(); + const Transform3d instance_scaling_matrix_inverse = vol->get_instance_transformation().get_matrix(true, true, false, true).inverse(); const Transform3d& instance_matrix = vol->get_instance_transformation().get_matrix(); - float z_shift = m_c->selection_info()->get_sla_shift(); + const float z_shift = m_c->selection_info()->get_sla_shift(); glsafe(::glPushMatrix()); glsafe(::glTranslated(0.0, 0.0, z_shift)); @@ -146,7 +146,7 @@ void GLGizmoSlaSupports::render_points(const Selection& selection, bool picking) ColorRGBA render_color; for (size_t i = 0; i < cache_size; ++i) { const sla::SupportPoint& support_point = m_editing_mode ? m_editing_cache[i].support_point : m_normal_cache[i]; - const bool& point_selected = m_editing_mode ? m_editing_cache[i].selected : false; + const bool point_selected = m_editing_mode ? m_editing_cache[i].selected : false; if (is_mesh_point_clipped(support_point.pos.cast())) continue; @@ -180,7 +180,7 @@ void GLGizmoSlaSupports::render_points(const Selection& selection, bool picking) // Inverse matrix of the instance scaling is applied so that the mark does not scale with the object. glsafe(::glPushMatrix()); - glsafe(::glTranslatef(support_point.pos(0), support_point.pos(1), support_point.pos(2))); + glsafe(::glTranslatef(support_point.pos.x(), support_point.pos.y(), support_point.pos.z())); glsafe(::glMultMatrixd(instance_scaling_matrix_inverse.data())); if (vol->is_left_handed()) @@ -195,12 +195,11 @@ void GLGizmoSlaSupports::render_points(const Selection& selection, bool picking) Eigen::Quaterniond q; q.setFromTwoVectors(Vec3d{0., 0., 1.}, instance_scaling_matrix_inverse * m_editing_cache[i].normal.cast()); - Eigen::AngleAxisd aa(q); - glsafe(::glRotated(aa.angle() * (180. / M_PI), aa.axis()(0), aa.axis()(1), aa.axis()(2))); - + const Eigen::AngleAxisd aa(q); + glsafe(::glPushMatrix()); + glsafe(::glRotated(aa.angle() * (180. / M_PI), aa.axis().x(), aa.axis().y(), aa.axis().z())); const double cone_radius = 0.25; // mm const double cone_height = 0.75; - glsafe(::glPushMatrix()); glsafe(::glTranslatef(0.f, 0.f, cone_height + support_point.head_front_radius * RenderPointScale)); glsafe(::glRotated(180., 1., 0., 0.)); glsafe(::glScaled(cone_radius, cone_radius, cone_height)); @@ -208,11 +207,9 @@ void GLGizmoSlaSupports::render_points(const Selection& selection, bool picking) glsafe(::glPopMatrix()); } - glsafe(::glPushMatrix()); const double radius = (double)support_point.head_front_radius * RenderPointScale; glsafe(::glScaled(radius, radius, radius)); m_sphere.render(); - glsafe(::glPopMatrix()); if (vol->is_left_handed()) glFrontFace(GL_CCW); @@ -241,7 +238,7 @@ void GLGizmoSlaSupports::render_points(const Selection& selection, bool picking) Eigen::Quaterniond q; q.setFromTwoVectors(Vec3d{0., 0., 1.}, instance_scaling_matrix_inverse * (-drain_hole.normal).cast()); - Eigen::AngleAxisd aa(q); + const Eigen::AngleAxisd aa(q); glsafe(::glRotated(aa.angle() * (180. / M_PI), aa.axis().x(), aa.axis().y(), aa.axis().z())); glsafe(::glTranslated(0., 0., -drain_hole.height)); glsafe(::glScaled(drain_hole.radius, drain_hole.radius, drain_hole.height + sla::HoleStickOutLength)); From 9f4713eee8afbc57049e9f25a2a8a4164aeef50e Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Mon, 23 Oct 2023 22:47:07 +0800 Subject: [PATCH 33/99] Tech ENABLE_GLBEGIN_GLEND_SHADERS_ATTRIBUTES - Use vertex attributes and matrices in shaders. 1st installment. Shader: flat - Default bed (cherry picked from commit prusa3d/PrusaSlicer@a5ff37013bcab8e5ab999e236e4531e3963ca377) --- resources/shaders/flat_attr.vs | 10 +++++ src/slic3r/GUI/3DBed.cpp | 7 ++- src/slic3r/GUI/Camera.hpp | 1 + src/slic3r/GUI/GLModel.cpp | 67 +++++++++++++++++++++++------ src/slic3r/GUI/GLShadersManager.cpp | 1 + src/slic3r/GUI/PartPlate.cpp | 5 ++- 6 files changed, 77 insertions(+), 14 deletions(-) create mode 100644 resources/shaders/flat_attr.vs diff --git a/resources/shaders/flat_attr.vs b/resources/shaders/flat_attr.vs new file mode 100644 index 00000000000..1b008867579 --- /dev/null +++ b/resources/shaders/flat_attr.vs @@ -0,0 +1,10 @@ +#version 110 + +attribute vec3 v_position; + +uniform mat4 projection_view_model_matrix; + +void main() +{ + gl_Position = projection_view_model_matrix * vec4(v_position, 1.0); +} diff --git a/src/slic3r/GUI/3DBed.cpp b/src/slic3r/GUI/3DBed.cpp index 26b6c899088..55a25c5141d 100644 --- a/src/slic3r/GUI/3DBed.cpp +++ b/src/slic3r/GUI/3DBed.cpp @@ -12,6 +12,8 @@ #include "GUI_App.hpp" #include "GUI_Colors.hpp" #include "GLCanvas3D.hpp" +#include "Plater.hpp" +#include "Camera.hpp" #include @@ -702,10 +704,13 @@ void Bed3D::render_default(bool bottom) update_bed_triangles(); - GLShaderProgram *shader = wxGetApp().get_shader("flat"); + GLShaderProgram* shader = wxGetApp().get_shader("flat_attr"); if (shader != nullptr) { shader->start_using(); + const Transform3d matrix = wxGetApp().plater()->get_camera().get_projection_view_matrix(); + shader->set_uniform("projection_view_model_matrix", matrix); + glsafe(::glEnable(GL_DEPTH_TEST)); glsafe(::glEnable(GL_BLEND)); glsafe(::glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)); diff --git a/src/slic3r/GUI/Camera.hpp b/src/slic3r/GUI/Camera.hpp index 401365ad4e5..4abaedecacb 100644 --- a/src/slic3r/GUI/Camera.hpp +++ b/src/slic3r/GUI/Camera.hpp @@ -92,6 +92,7 @@ struct Camera const std::array& get_viewport() const { return m_viewport; } const Transform3d& get_view_matrix() const { return m_view_matrix; } const Transform3d& get_projection_matrix() const { return m_projection_matrix; } + Transform3d get_projection_view_matrix() const { return m_projection_matrix * m_view_matrix; } //BBS const Eigen::Quaterniond& get_view_rotation() const {return m_view_rotation; } diff --git a/src/slic3r/GUI/GLModel.cpp b/src/slic3r/GUI/GLModel.cpp index e73d7bc4e06..1d2337bc602 100644 --- a/src/slic3r/GUI/GLModel.cpp +++ b/src/slic3r/GUI/GLModel.cpp @@ -664,17 +664,50 @@ void GLModel::render(const std::pair& range) glsafe(::glBindBuffer(GL_ARRAY_BUFFER, m_render_data.vbo_id)); + bool use_attributes = boost::algorithm::iends_with(shader->get_name(), "_attr"); + + int position_id = -1; + int normal_id = -1; + int tex_coord_id = -1; + if (position) { - glsafe(::glVertexPointer(Geometry::position_stride_floats(data.format), GL_FLOAT, vertex_stride_bytes, (const void*)Geometry::position_offset_bytes(data.format))); - glsafe(::glEnableClientState(GL_VERTEX_ARRAY)); + if (use_attributes) { + position_id = shader->get_attrib_location("v_position"); + if (position_id != -1) { + glsafe(::glVertexAttribPointer(position_id, Geometry::position_stride_floats(data.format), GL_FLOAT, GL_FALSE, vertex_stride_bytes, (GLvoid*)Geometry::position_offset_bytes(data.format))); + glsafe(::glEnableVertexAttribArray(position_id)); + } + } + else { + glsafe(::glVertexPointer(Geometry::position_stride_floats(data.format), GL_FLOAT, vertex_stride_bytes, (const void*)Geometry::position_offset_bytes(data.format))); + glsafe(::glEnableClientState(GL_VERTEX_ARRAY)); + } } if (normal) { - glsafe(::glNormalPointer(GL_FLOAT, vertex_stride_bytes, (const void*)Geometry::normal_offset_bytes(data.format))); - glsafe(::glEnableClientState(GL_NORMAL_ARRAY)); + if (use_attributes) { + normal_id = shader->get_attrib_location("v_normal"); + if (normal_id != -1) { + glsafe(::glVertexAttribPointer(normal_id, Geometry::normal_stride_floats(data.format), GL_FLOAT, GL_FALSE, vertex_stride_bytes, (GLvoid*)Geometry::normal_offset_bytes(data.format))); + glsafe(::glEnableVertexAttribArray(normal_id)); + } + } + else { + glsafe(::glNormalPointer(GL_FLOAT, vertex_stride_bytes, (const void*)Geometry::normal_offset_bytes(data.format))); + glsafe(::glEnableClientState(GL_NORMAL_ARRAY)); + } } if (tex_coord) { - glsafe(::glTexCoordPointer(Geometry::tex_coord_stride_floats(data.format), GL_FLOAT, vertex_stride_bytes, (const void*)Geometry::tex_coord_offset_bytes(data.format))); - glsafe(::glEnableClientState(GL_TEXTURE_COORD_ARRAY)); + if (use_attributes) { + tex_coord_id = shader->get_attrib_location("v_tex_coord"); + if (tex_coord_id != -1) { + glsafe(::glVertexAttribPointer(tex_coord_id, Geometry::tex_coord_stride_floats(data.format), GL_FLOAT, GL_FALSE, vertex_stride_bytes, (GLvoid*)Geometry::tex_coord_offset_bytes(data.format))); + glsafe(::glEnableVertexAttribArray(tex_coord_id)); + } + } + else { + glsafe(::glTexCoordPointer(Geometry::tex_coord_stride_floats(data.format), GL_FLOAT, vertex_stride_bytes, (const void*)Geometry::tex_coord_offset_bytes(data.format))); + glsafe(::glEnableClientState(GL_TEXTURE_COORD_ARRAY)); + } } shader->set_uniform("uniform_color", data.color); @@ -683,12 +716,22 @@ void GLModel::render(const std::pair& range) glsafe(::glDrawElements(mode, range.second - range.first, index_type, (const void*)(range.first * Geometry::index_stride_bytes(data.format)))); glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0)); - if (tex_coord) - glsafe(::glDisableClientState(GL_TEXTURE_COORD_ARRAY)); - if (normal) - glsafe(::glDisableClientState(GL_NORMAL_ARRAY)); - if (position) - glsafe(::glDisableClientState(GL_VERTEX_ARRAY)); + if (use_attributes) { + if (tex_coord_id != -1) + glsafe(::glDisableVertexAttribArray(tex_coord_id)); + if (normal_id != -1) + glsafe(::glDisableVertexAttribArray(normal_id)); + if (position_id != -1) + glsafe(::glDisableVertexAttribArray(position_id)); + } + else { + if (tex_coord) + glsafe(::glDisableClientState(GL_TEXTURE_COORD_ARRAY)); + if (normal) + glsafe(::glDisableClientState(GL_NORMAL_ARRAY)); + if (position) + glsafe(::glDisableClientState(GL_VERTEX_ARRAY)); + } glsafe(::glBindBuffer(GL_ARRAY_BUFFER, 0)); } diff --git a/src/slic3r/GUI/GLShadersManager.cpp b/src/slic3r/GUI/GLShadersManager.cpp index e544296714d..c00599805cd 100644 --- a/src/slic3r/GUI/GLShadersManager.cpp +++ b/src/slic3r/GUI/GLShadersManager.cpp @@ -35,6 +35,7 @@ std::pair GLShadersManager::init() // basic shader, used to render all what was previously rendered using the immediate mode valid &= append_shader("flat", { "flat.vs", "flat.fs" }); + valid &= append_shader("flat_attr", { "flat_attr.vs", "flat.fs" }); // basic shader for textures, used to render textures valid &= append_shader("flat_texture", { "flat_texture.vs", "flat_texture.fs" }); // used to render 3D scene background diff --git a/src/slic3r/GUI/PartPlate.cpp b/src/slic3r/GUI/PartPlate.cpp index ee7f3bc47e2..d56b369f380 100644 --- a/src/slic3r/GUI/PartPlate.cpp +++ b/src/slic3r/GUI/PartPlate.cpp @@ -2496,13 +2496,16 @@ bool PartPlate::intersects(const BoundingBoxf3& bb) const void PartPlate::render(bool bottom, bool only_body, bool force_background_color, HeightLimitMode mode, int hover_id, bool render_cali) { - GLShaderProgram *shader = wxGetApp().get_shader("flat"); + GLShaderProgram *shader = wxGetApp().get_shader("flat_attr"); if (shader != nullptr) { shader->start_using(); glsafe(::glEnable(GL_DEPTH_TEST)); glsafe(::glEnable(GL_BLEND)); glsafe(::glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)); + const Transform3d matrix = wxGetApp().plater()->get_camera().get_projection_view_matrix(); + shader->set_uniform("projection_view_model_matrix", matrix); + if (!bottom) { // draw background render_background(force_background_color); From 71fd4084c2864490bab2dc3d7e75ccf88423e237 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Wed, 25 Oct 2023 23:14:53 +0800 Subject: [PATCH 34/99] Tech ENABLE_LEGACY_OPENGL_REMOVAL - porting remaining changes (cherry picked from commit prusa3d/PrusaSlicer@2f572d3cf0f0926ad0041e3c95251439e340fe08 ) --- resources/shaders/background_attr.vs | 12 + resources/shaders/cali.fs | 8 - resources/shaders/cali.vs | 6 - resources/shaders/flat_attr.vs | 5 +- resources/shaders/flat_texture_attr.vs | 15 + resources/shaders/gouraud.fs | 1 - resources/shaders/gouraud.vs | 2 - resources/shaders/gouraud_attr.vs | 77 +++ resources/shaders/gouraud_light_attr.vs | 45 ++ .../shaders/gouraud_light_instanced_attr.vs | 50 ++ resources/shaders/mm_contour_attr.fs | 13 + resources/shaders/mm_contour_attr.vs | 11 + resources/shaders/mm_gouraud_attr.fs | 90 +++ resources/shaders/mm_gouraud_attr.vs | 35 + resources/shaders/options_110.fs | 8 - resources/shaders/options_110.vs | 22 - resources/shaders/options_120.fs | 22 - resources/shaders/options_120.vs | 22 - resources/shaders/printbed.fs | 8 +- resources/shaders/printbed.vs | 4 +- resources/shaders/printbed_attr.vs | 15 + resources/shaders/thumbnail_attr.vs | 51 ++ .../shaders/variable_layer_height_attr.vs | 60 ++ src/OrcaSlicer.cpp | 2 +- src/slic3r/GUI/3DBed.cpp | 71 +- src/slic3r/GUI/3DBed.hpp | 12 +- src/slic3r/GUI/3DScene.cpp | 138 ++-- src/slic3r/GUI/3DScene.hpp | 7 +- src/slic3r/GUI/Camera.hpp | 1 - src/slic3r/GUI/GCodeViewer.cpp | 360 +++++----- src/slic3r/GUI/GLCanvas3D.cpp | 448 ++++++------ src/slic3r/GUI/GLCanvas3D.hpp | 16 +- src/slic3r/GUI/GLModel.cpp | 643 +++++++----------- src/slic3r/GUI/GLModel.hpp | 46 +- src/slic3r/GUI/GLSelectionRectangle.cpp | 52 +- src/slic3r/GUI/GLSelectionRectangle.hpp | 12 +- src/slic3r/GUI/GLShader.cpp | 5 + src/slic3r/GUI/GLShader.hpp | 2 + src/slic3r/GUI/GLShadersManager.cpp | 43 +- src/slic3r/GUI/GLTexture.cpp | 10 +- src/slic3r/GUI/GLToolbar.cpp | 468 +++++++------ src/slic3r/GUI/GLToolbar.hpp | 4 +- src/slic3r/GUI/Gizmos/GLGizmoAdvancedCut.cpp | 58 +- src/slic3r/GUI/Gizmos/GLGizmoBase.cpp | 25 +- src/slic3r/GUI/Gizmos/GLGizmoBase.hpp | 1 + src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp | 14 +- src/slic3r/GUI/Gizmos/GLGizmoFlatten.cpp | 32 +- src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp | 37 +- .../GUI/Gizmos/GLGizmoMmuSegmentation.cpp | 14 +- src/slic3r/GUI/Gizmos/GLGizmoMove.cpp | 37 +- src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp | 134 ++-- src/slic3r/GUI/Gizmos/GLGizmoPainterBase.hpp | 10 +- src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp | 110 ++- src/slic3r/GUI/Gizmos/GLGizmoRotate.hpp | 2 + src/slic3r/GUI/Gizmos/GLGizmoScale.cpp | 20 +- src/slic3r/GUI/Gizmos/GLGizmoSeam.cpp | 14 +- src/slic3r/GUI/Gizmos/GLGizmoSimplify.cpp | 18 +- src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp | 58 +- src/slic3r/GUI/Gizmos/GLGizmoText.cpp | 6 +- src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp | 13 +- src/slic3r/GUI/Gizmos/GLGizmosManager.cpp | 153 ++--- src/slic3r/GUI/Gizmos/GLGizmosManager.hpp | 4 +- src/slic3r/GUI/MeshUtils.cpp | 16 +- src/slic3r/GUI/PartPlate.cpp | 70 +- src/slic3r/GUI/PartPlate.hpp | 12 +- src/slic3r/GUI/Selection.cpp | 186 ++--- src/slic3r/GUI/Selection.hpp | 8 +- src/slic3r/Utils/CalibUtils.cpp | 2 +- 68 files changed, 2142 insertions(+), 1834 deletions(-) create mode 100644 resources/shaders/background_attr.vs delete mode 100644 resources/shaders/cali.fs delete mode 100644 resources/shaders/cali.vs create mode 100644 resources/shaders/flat_texture_attr.vs create mode 100644 resources/shaders/gouraud_attr.vs create mode 100644 resources/shaders/gouraud_light_attr.vs create mode 100644 resources/shaders/gouraud_light_instanced_attr.vs create mode 100644 resources/shaders/mm_contour_attr.fs create mode 100644 resources/shaders/mm_contour_attr.vs create mode 100644 resources/shaders/mm_gouraud_attr.fs create mode 100644 resources/shaders/mm_gouraud_attr.vs delete mode 100644 resources/shaders/options_110.fs delete mode 100644 resources/shaders/options_110.vs delete mode 100644 resources/shaders/options_120.fs delete mode 100644 resources/shaders/options_120.vs create mode 100644 resources/shaders/printbed_attr.vs create mode 100644 resources/shaders/thumbnail_attr.vs create mode 100644 resources/shaders/variable_layer_height_attr.vs diff --git a/resources/shaders/background_attr.vs b/resources/shaders/background_attr.vs new file mode 100644 index 00000000000..9b56ab43a26 --- /dev/null +++ b/resources/shaders/background_attr.vs @@ -0,0 +1,12 @@ +#version 110 + +attribute vec3 v_position; +attribute vec2 v_tex_coord; + +varying vec2 tex_coord; + +void main() +{ + tex_coord = v_tex_coord; + gl_Position = vec4(v_position, 1.0); +} diff --git a/resources/shaders/cali.fs b/resources/shaders/cali.fs deleted file mode 100644 index ab656998df7..00000000000 --- a/resources/shaders/cali.fs +++ /dev/null @@ -1,8 +0,0 @@ -#version 110 - -uniform vec4 uniform_color; - -void main() -{ - gl_FragColor = uniform_color; -} diff --git a/resources/shaders/cali.vs b/resources/shaders/cali.vs deleted file mode 100644 index d0d3ee42a9a..00000000000 --- a/resources/shaders/cali.vs +++ /dev/null @@ -1,6 +0,0 @@ -#version 110 - -void main() -{ - gl_Position = ftransform(); -} diff --git a/resources/shaders/flat_attr.vs b/resources/shaders/flat_attr.vs index 1b008867579..370eedb72de 100644 --- a/resources/shaders/flat_attr.vs +++ b/resources/shaders/flat_attr.vs @@ -2,9 +2,10 @@ attribute vec3 v_position; -uniform mat4 projection_view_model_matrix; +uniform mat4 view_model_matrix; +uniform mat4 projection_matrix; void main() { - gl_Position = projection_view_model_matrix * vec4(v_position, 1.0); + gl_Position = projection_matrix * view_model_matrix * vec4(v_position, 1.0); } diff --git a/resources/shaders/flat_texture_attr.vs b/resources/shaders/flat_texture_attr.vs new file mode 100644 index 00000000000..e59a99da357 --- /dev/null +++ b/resources/shaders/flat_texture_attr.vs @@ -0,0 +1,15 @@ +#version 110 + +attribute vec3 v_position; +attribute vec2 v_tex_coord; + +uniform mat4 view_model_matrix; +uniform mat4 projection_matrix; + +varying vec2 tex_coord; + +void main() +{ + tex_coord = v_tex_coord; + gl_Position = projection_matrix * view_model_matrix * vec4(v_position, 1.0); +} diff --git a/resources/shaders/gouraud.fs b/resources/shaders/gouraud.fs index 3f12a6e92c4..4084efdbf1f 100644 --- a/resources/shaders/gouraud.fs +++ b/resources/shaders/gouraud.fs @@ -48,7 +48,6 @@ varying vec2 intensity; uniform PrintVolumeDetection print_volume; -varying vec4 model_pos; varying vec4 world_pos; varying float world_normal_z; varying vec3 eye_normal; diff --git a/resources/shaders/gouraud.vs b/resources/shaders/gouraud.vs index 79d7a63c072..c8b3d7b335b 100644 --- a/resources/shaders/gouraud.vs +++ b/resources/shaders/gouraud.vs @@ -38,7 +38,6 @@ varying vec2 intensity; varying vec3 clipping_planes_dots; -varying vec4 model_pos; varying vec4 world_pos; varying float world_normal_z; varying vec3 eye_normal; @@ -60,7 +59,6 @@ void main() NdotL = max(dot(eye_normal, LIGHT_FRONT_DIR), 0.0); intensity.x += NdotL * LIGHT_FRONT_DIFFUSE; - model_pos = gl_Vertex; // Point in homogenous coordinates. world_pos = volume_world_matrix * gl_Vertex; diff --git a/resources/shaders/gouraud_attr.vs b/resources/shaders/gouraud_attr.vs new file mode 100644 index 00000000000..87e524c14ae --- /dev/null +++ b/resources/shaders/gouraud_attr.vs @@ -0,0 +1,77 @@ +#version 110 + +#define INTENSITY_CORRECTION 0.6 + +// normalized values for (-0.6/1.31, 0.6/1.31, 1./1.31) +const vec3 LIGHT_TOP_DIR = vec3(-0.4574957, 0.4574957, 0.7624929); +#define LIGHT_TOP_DIFFUSE (0.8 * INTENSITY_CORRECTION) +#define LIGHT_TOP_SPECULAR (0.125 * INTENSITY_CORRECTION) +#define LIGHT_TOP_SHININESS 20.0 + +// normalized values for (1./1.43, 0.2/1.43, 1./1.43) +const vec3 LIGHT_FRONT_DIR = vec3(0.6985074, 0.1397015, 0.6985074); +#define LIGHT_FRONT_DIFFUSE (0.3 * INTENSITY_CORRECTION) +//#define LIGHT_FRONT_SPECULAR (0.0 * INTENSITY_CORRECTION) +//#define LIGHT_FRONT_SHININESS 5.0 + +#define INTENSITY_AMBIENT 0.3 + +const vec3 ZERO = vec3(0.0, 0.0, 0.0); + +struct SlopeDetection +{ + bool actived; + float normal_z; + mat3 volume_world_normal_matrix; +}; + +attribute vec3 v_position; +attribute vec3 v_normal; + +uniform mat4 view_model_matrix; +uniform mat4 projection_matrix; +uniform mat3 normal_matrix; +uniform mat4 volume_world_matrix; +uniform SlopeDetection slope; + +// Clipping plane, x = min z, y = max z. Used by the FFF and SLA previews to clip with a top / bottom plane. +uniform vec2 z_range; +// Clipping plane - general orientation. Used by the SLA gizmo. +uniform vec4 clipping_plane; + +// x = diffuse, y = specular; +varying vec2 intensity; + +varying vec3 clipping_planes_dots; + +varying vec4 world_pos; +varying float world_normal_z; +varying vec3 eye_normal; + +void main() +{ + // First transform the normal into camera space and normalize the result. + eye_normal = normalize(normal_matrix * v_normal); + + // Compute the cos of the angle between the normal and lights direction. The light is directional so the direction is constant for every vertex. + // Since these two are normalized the cosine is the dot product. We also need to clamp the result to the [0,1] range. + float NdotL = max(dot(eye_normal, LIGHT_TOP_DIR), 0.0); + + intensity.x = INTENSITY_AMBIENT + NdotL * LIGHT_TOP_DIFFUSE; + vec4 position = view_model_matrix * vec4(v_position, 1.0); + intensity.y = LIGHT_TOP_SPECULAR * pow(max(dot(-normalize(position.xyz), reflect(-LIGHT_TOP_DIR, eye_normal)), 0.0), LIGHT_TOP_SHININESS); + + // Perform the same lighting calculation for the 2nd light source (no specular applied). + NdotL = max(dot(eye_normal, LIGHT_FRONT_DIR), 0.0); + intensity.x += NdotL * LIGHT_FRONT_DIFFUSE; + + // Point in homogenous coordinates. + world_pos = volume_world_matrix * vec4(v_position, 1.0); + + // z component of normal vector in world coordinate used for slope shading + world_normal_z = slope.actived ? (normalize(slope.volume_world_normal_matrix * v_normal)).z : 0.0; + + gl_Position = projection_matrix * position; + // Fill in the scalars for fragment shader clipping. Fragments with any of these components lower than zero are discarded. + clipping_planes_dots = vec3(dot(world_pos, clipping_plane), world_pos.z - z_range.x, z_range.y - world_pos.z); +} diff --git a/resources/shaders/gouraud_light_attr.vs b/resources/shaders/gouraud_light_attr.vs new file mode 100644 index 00000000000..2e1b5fb429e --- /dev/null +++ b/resources/shaders/gouraud_light_attr.vs @@ -0,0 +1,45 @@ +#version 110 + +#define INTENSITY_CORRECTION 0.6 + +// normalized values for (-0.6/1.31, 0.6/1.31, 1./1.31) +const vec3 LIGHT_TOP_DIR = vec3(-0.4574957, 0.4574957, 0.7624929); +#define LIGHT_TOP_DIFFUSE (0.8 * INTENSITY_CORRECTION) +#define LIGHT_TOP_SPECULAR (0.125 * INTENSITY_CORRECTION) +#define LIGHT_TOP_SHININESS 20.0 + +// normalized values for (1./1.43, 0.2/1.43, 1./1.43) +const vec3 LIGHT_FRONT_DIR = vec3(0.6985074, 0.1397015, 0.6985074); +#define LIGHT_FRONT_DIFFUSE (0.3 * INTENSITY_CORRECTION) + +#define INTENSITY_AMBIENT 0.3 + +attribute vec3 v_position; +attribute vec3 v_normal; + +uniform mat4 view_model_matrix; +uniform mat4 projection_matrix; +uniform mat3 normal_matrix; + +// x = tainted, y = specular; +varying vec2 intensity; + +void main() +{ + // First transform the normal into camera space and normalize the result. + vec3 normal = normalize(normal_matrix * v_normal); + + // Compute the cos of the angle between the normal and lights direction. The light is directional so the direction is constant for every vertex. + // Since these two are normalized the cosine is the dot product. We also need to clamp the result to the [0,1] range. + float NdotL = max(dot(normal, LIGHT_TOP_DIR), 0.0); + + intensity.x = INTENSITY_AMBIENT + NdotL * LIGHT_TOP_DIFFUSE; + vec4 position = view_model_matrix * vec4(v_position, 1.0); + intensity.y = LIGHT_TOP_SPECULAR * pow(max(dot(-normalize(position.xyz), reflect(-LIGHT_TOP_DIR, normal)), 0.0), LIGHT_TOP_SHININESS); + + // Perform the same lighting calculation for the 2nd light source (no specular applied). + NdotL = max(dot(normal, LIGHT_FRONT_DIR), 0.0); + intensity.x += NdotL * LIGHT_FRONT_DIFFUSE; + + gl_Position = projection_matrix * position; +} diff --git a/resources/shaders/gouraud_light_instanced_attr.vs b/resources/shaders/gouraud_light_instanced_attr.vs new file mode 100644 index 00000000000..7069feb65e8 --- /dev/null +++ b/resources/shaders/gouraud_light_instanced_attr.vs @@ -0,0 +1,50 @@ +#version 110 + +#define INTENSITY_CORRECTION 0.6 + +// normalized values for (-0.6/1.31, 0.6/1.31, 1./1.31) +const vec3 LIGHT_TOP_DIR = vec3(-0.4574957, 0.4574957, 0.7624929); +#define LIGHT_TOP_DIFFUSE (0.8 * INTENSITY_CORRECTION) +#define LIGHT_TOP_SPECULAR (0.125 * INTENSITY_CORRECTION) +#define LIGHT_TOP_SHININESS 20.0 + +// normalized values for (1./1.43, 0.2/1.43, 1./1.43) +const vec3 LIGHT_FRONT_DIR = vec3(0.6985074, 0.1397015, 0.6985074); +#define LIGHT_FRONT_DIFFUSE (0.3 * INTENSITY_CORRECTION) + +#define INTENSITY_AMBIENT 0.3 + +// vertex attributes +attribute vec3 v_position; +attribute vec3 v_normal; +// instance attributes +attribute vec3 i_offset; +attribute vec2 i_scales; + +uniform mat4 view_model_matrix; +uniform mat4 projection_matrix; +uniform mat3 normal_matrix; + +// x = tainted, y = specular; +varying vec2 intensity; + +void main() +{ + // First transform the normal into camera space and normalize the result. + vec3 eye_normal = normalize(normal_matrix * v_normal); + + // Compute the cos of the angle between the normal and lights direction. The light is directional so the direction is constant for every vertex. + // Since these two are normalized the cosine is the dot product. We also need to clamp the result to the [0,1] range. + float NdotL = max(dot(eye_normal, LIGHT_TOP_DIR), 0.0); + + intensity.x = INTENSITY_AMBIENT + NdotL * LIGHT_TOP_DIFFUSE; + vec4 world_position = vec4(v_position * vec3(vec2(1.5 * i_scales.x), 1.5 * i_scales.y) + i_offset - vec3(0.0, 0.0, 0.5 * i_scales.y), 1.0); + vec4 eye_position = view_model_matrix * world_position; + intensity.y = LIGHT_TOP_SPECULAR * pow(max(dot(-normalize(eye_position.xyz), reflect(-LIGHT_TOP_DIR, eye_normal)), 0.0), LIGHT_TOP_SHININESS); + + // Perform the same lighting calculation for the 2nd light source (no specular applied). + NdotL = max(dot(eye_normal, LIGHT_FRONT_DIR), 0.0); + intensity.x += NdotL * LIGHT_FRONT_DIFFUSE; + + gl_Position = projection_matrix * eye_position; +} diff --git a/resources/shaders/mm_contour_attr.fs b/resources/shaders/mm_contour_attr.fs new file mode 100644 index 00000000000..14477a59e6e --- /dev/null +++ b/resources/shaders/mm_contour_attr.fs @@ -0,0 +1,13 @@ +#version 110 + +const float EPSILON = 0.0001; + +uniform vec4 uniform_color; + +void main() +{ + gl_FragColor = uniform_color; + // Values inside depth buffer for fragments of the contour of a selected area are offset + // by small epsilon to solve z-fighting between painted triangles and contour lines. + gl_FragDepth = gl_FragCoord.z - EPSILON; +} diff --git a/resources/shaders/mm_contour_attr.vs b/resources/shaders/mm_contour_attr.vs new file mode 100644 index 00000000000..370eedb72de --- /dev/null +++ b/resources/shaders/mm_contour_attr.vs @@ -0,0 +1,11 @@ +#version 110 + +attribute vec3 v_position; + +uniform mat4 view_model_matrix; +uniform mat4 projection_matrix; + +void main() +{ + gl_Position = projection_matrix * view_model_matrix * vec4(v_position, 1.0); +} diff --git a/resources/shaders/mm_gouraud_attr.fs b/resources/shaders/mm_gouraud_attr.fs new file mode 100644 index 00000000000..4ecf7bf70c1 --- /dev/null +++ b/resources/shaders/mm_gouraud_attr.fs @@ -0,0 +1,90 @@ +#version 110 + +#define INTENSITY_CORRECTION 0.6 + +// normalized values for (-0.6/1.31, 0.6/1.31, 1./1.31) +const vec3 LIGHT_TOP_DIR = vec3(-0.4574957, 0.4574957, 0.7624929); +#define LIGHT_TOP_DIFFUSE (0.8 * INTENSITY_CORRECTION) +#define LIGHT_TOP_SPECULAR (0.125 * INTENSITY_CORRECTION) +#define LIGHT_TOP_SHININESS 20.0 + +// normalized values for (1./1.43, 0.2/1.43, 1./1.43) +const vec3 LIGHT_FRONT_DIR = vec3(0.6985074, 0.1397015, 0.6985074); +#define LIGHT_FRONT_DIFFUSE (0.3 * INTENSITY_CORRECTION) + +#define INTENSITY_AMBIENT 0.3 + +const vec3 ZERO = vec3(0.0, 0.0, 0.0); +const float EPSILON = 0.0001; +//BBS: add grey and orange +//const vec3 GREY = vec3(0.9, 0.9, 0.9); +const vec3 ORANGE = vec3(0.8, 0.4, 0.0); +const vec3 LightRed = vec3(0.78, 0.0, 0.0); +const vec3 LightBlue = vec3(0.73, 1.0, 1.0); +uniform vec4 uniform_color; + +uniform bool volume_mirrored; + +uniform mat4 view_model_matrix; +uniform mat3 normal_matrix; + +varying vec3 clipping_planes_dots; +varying vec4 model_pos; +varying vec4 world_pos; + +struct SlopeDetection +{ + bool actived; + float normal_z; + mat3 volume_world_normal_matrix; +}; +uniform SlopeDetection slope; + +void main() +{ + if (any(lessThan(clipping_planes_dots, ZERO))) + discard; + vec3 color = uniform_color.rgb; + float alpha = uniform_color.a; + + vec3 triangle_normal = normalize(cross(dFdx(model_pos.xyz), dFdy(model_pos.xyz))); +#ifdef FLIP_TRIANGLE_NORMALS + triangle_normal = -triangle_normal; +#endif + + if (volume_mirrored) + triangle_normal = -triangle_normal; + + vec3 transformed_normal = normalize(slope.volume_world_normal_matrix * triangle_normal); + + if (slope.actived) { + if(world_pos.z<0.1&&world_pos.z>-0.1) + { + color = LightBlue; + alpha = 1.0; + } + else if( transformed_normal.z < slope.normal_z - EPSILON) + { + color = color * 0.5 + LightRed * 0.5; + alpha = 1.0; + } + } + // First transform the normal into camera space and normalize the result. + vec3 eye_normal = normalize(normal_matrix * triangle_normal); + + // Compute the cos of the angle between the normal and lights direction. The light is directional so the direction is constant for every vertex. + // Since these two are normalized the cosine is the dot product. We also need to clamp the result to the [0,1] range. + float NdotL = max(dot(eye_normal, LIGHT_TOP_DIR), 0.0); + + // x = diffuse, y = specular; + vec2 intensity = vec2(0.0); + intensity.x = INTENSITY_AMBIENT + NdotL * LIGHT_TOP_DIFFUSE; + vec3 position = (view_model_matrix * model_pos).xyz; + intensity.y = LIGHT_TOP_SPECULAR * pow(max(dot(-normalize(position), reflect(-LIGHT_TOP_DIR, eye_normal)), 0.0), LIGHT_TOP_SHININESS); + + // Perform the same lighting calculation for the 2nd light source (no specular applied). + NdotL = max(dot(eye_normal, LIGHT_FRONT_DIR), 0.0); + intensity.x += NdotL * LIGHT_FRONT_DIFFUSE; + + gl_FragColor = vec4(vec3(intensity.y) + color * intensity.x, alpha); +} diff --git a/resources/shaders/mm_gouraud_attr.vs b/resources/shaders/mm_gouraud_attr.vs new file mode 100644 index 00000000000..d51c53b82b3 --- /dev/null +++ b/resources/shaders/mm_gouraud_attr.vs @@ -0,0 +1,35 @@ +#version 110 + +const vec3 ZERO = vec3(0.0, 0.0, 0.0); + +attribute vec3 v_position; + +uniform mat4 view_model_matrix; +uniform mat4 projection_matrix; + +uniform mat4 volume_world_matrix; +// Clipping plane, x = min z, y = max z. Used by the FFF and SLA previews to clip with a top / bottom plane. +uniform vec2 z_range; +// Clipping plane - general orientation. Used by the SLA gizmo. +uniform vec4 clipping_plane; + +varying vec3 clipping_planes_dots; +varying vec4 model_pos; +varying vec4 world_pos; +struct SlopeDetection +{ + bool actived; + float normal_z; + mat3 volume_world_normal_matrix; +}; +uniform SlopeDetection slope; +void main() +{ + model_pos = vec4(v_position, 1.0); + // Point in homogenous coordinates. + world_pos = volume_world_matrix * model_pos; + + gl_Position = projection_matrix * view_model_matrix * model_pos; + // Fill in the scalars for fragment shader clipping. Fragments with any of these components lower than zero are discarded. + clipping_planes_dots = vec3(dot(world_pos, clipping_plane), world_pos.z - z_range.x, z_range.y - world_pos.z); +} diff --git a/resources/shaders/options_110.fs b/resources/shaders/options_110.fs deleted file mode 100644 index ab656998df7..00000000000 --- a/resources/shaders/options_110.fs +++ /dev/null @@ -1,8 +0,0 @@ -#version 110 - -uniform vec4 uniform_color; - -void main() -{ - gl_FragColor = uniform_color; -} diff --git a/resources/shaders/options_110.vs b/resources/shaders/options_110.vs deleted file mode 100644 index 5f2ab23504e..00000000000 --- a/resources/shaders/options_110.vs +++ /dev/null @@ -1,22 +0,0 @@ -#version 110 - -uniform bool use_fixed_screen_size; -uniform float zoom; -uniform float point_size; -uniform float near_plane_height; - -float fixed_screen_size() -{ - return point_size; -} - -float fixed_world_size() -{ - return (gl_Position.w == 1.0) ? zoom * near_plane_height * point_size : near_plane_height * point_size / gl_Position.w; -} - -void main() -{ - gl_Position = ftransform(); - gl_PointSize = use_fixed_screen_size ? fixed_screen_size() : fixed_world_size(); -} diff --git a/resources/shaders/options_120.fs b/resources/shaders/options_120.fs deleted file mode 100644 index e9b61304f26..00000000000 --- a/resources/shaders/options_120.fs +++ /dev/null @@ -1,22 +0,0 @@ -// version 120 is needed for gl_PointCoord -#version 120 - -uniform vec4 uniform_color; -uniform float percent_outline_radius; -uniform float percent_center_radius; - -vec4 calc_color(float radius, vec4 color) -{ - return ((radius < percent_center_radius) || (radius > 1.0 - percent_outline_radius)) ? - vec4(0.5 * color.rgb, color.a) : color; -} - -void main() -{ - vec2 pos = (gl_PointCoord - 0.5) * 2.0; - float radius = length(pos); - if (radius > 1.0) - discard; - - gl_FragColor = calc_color(radius, uniform_color); -} diff --git a/resources/shaders/options_120.vs b/resources/shaders/options_120.vs deleted file mode 100644 index edb503fb2b2..00000000000 --- a/resources/shaders/options_120.vs +++ /dev/null @@ -1,22 +0,0 @@ -#version 120 - -uniform bool use_fixed_screen_size; -uniform float zoom; -uniform float point_size; -uniform float near_plane_height; - -float fixed_screen_size() -{ - return point_size; -} - -float fixed_world_size() -{ - return (gl_Position.w == 1.0) ? zoom * near_plane_height * point_size : near_plane_height * point_size / gl_Position.w; -} - -void main() -{ - gl_Position = ftransform(); - gl_PointSize = use_fixed_screen_size ? fixed_screen_size() : fixed_world_size(); -} diff --git a/resources/shaders/printbed.fs b/resources/shaders/printbed.fs index bef07515801..833dff08f46 100644 --- a/resources/shaders/printbed.fs +++ b/resources/shaders/printbed.fs @@ -7,15 +7,15 @@ uniform sampler2D texture; uniform bool transparent_background; uniform bool svg_source; -varying vec2 tex_coords; +varying vec2 tex_coord; vec4 svg_color() { // takes foreground from texture - vec4 fore_color = texture2D(texture, tex_coords); + vec4 fore_color = texture2D(texture, tex_coord); // calculates radial gradient - vec3 back_color = vec3(mix(back_color_light, back_color_dark, smoothstep(0.0, 0.5, length(abs(tex_coords.xy) - vec2(0.5))))); + vec3 back_color = vec3(mix(back_color_light, back_color_dark, smoothstep(0.0, 0.5, length(abs(tex_coord.xy) - vec2(0.5))))); // blends foreground with background return vec4(mix(back_color, fore_color.rgb, fore_color.a), transparent_background ? fore_color.a : 1.0); @@ -24,7 +24,7 @@ vec4 svg_color() vec4 non_svg_color() { // takes foreground from texture - vec4 color = texture2D(texture, tex_coords); + vec4 color = texture2D(texture, tex_coord); return vec4(color.rgb, transparent_background ? color.a * 0.25 : color.a); } diff --git a/resources/shaders/printbed.vs b/resources/shaders/printbed.vs index 3b3f8875d20..27addc7526a 100644 --- a/resources/shaders/printbed.vs +++ b/resources/shaders/printbed.vs @@ -1,9 +1,9 @@ #version 110 -varying vec2 tex_coords; +varying vec2 tex_coord; void main() { gl_Position = ftransform(); - tex_coords = gl_MultiTexCoord0.xy; + tex_coord = gl_MultiTexCoord0.xy; } diff --git a/resources/shaders/printbed_attr.vs b/resources/shaders/printbed_attr.vs new file mode 100644 index 00000000000..e59a99da357 --- /dev/null +++ b/resources/shaders/printbed_attr.vs @@ -0,0 +1,15 @@ +#version 110 + +attribute vec3 v_position; +attribute vec2 v_tex_coord; + +uniform mat4 view_model_matrix; +uniform mat4 projection_matrix; + +varying vec2 tex_coord; + +void main() +{ + tex_coord = v_tex_coord; + gl_Position = projection_matrix * view_model_matrix * vec4(v_position, 1.0); +} diff --git a/resources/shaders/thumbnail_attr.vs b/resources/shaders/thumbnail_attr.vs new file mode 100644 index 00000000000..a9a3c984b2e --- /dev/null +++ b/resources/shaders/thumbnail_attr.vs @@ -0,0 +1,51 @@ +#version 110 + +#define INTENSITY_CORRECTION 0.6 + +// normalized values for (-0.6/1.31, 0.6/1.31, 1./1.31) +const vec3 LIGHT_TOP_DIR = vec3(-0.4574957, 0.4574957, 0.7624929); +#define LIGHT_TOP_DIFFUSE (0.8 * INTENSITY_CORRECTION) +#define LIGHT_TOP_SPECULAR (0.125 * INTENSITY_CORRECTION) +#define LIGHT_TOP_SHININESS 20.0 + +// normalized values for (1./1.43, 0.2/1.43, 1./1.43) +const vec3 LIGHT_FRONT_DIR = vec3(0.6985074, 0.1397015, 0.6985074); +#define LIGHT_FRONT_DIFFUSE (0.3 * INTENSITY_CORRECTION) + +#define INTENSITY_AMBIENT 0.3 + +attribute vec3 v_position; +attribute vec3 v_normal; + +uniform mat4 view_model_matrix; +uniform mat4 projection_matrix; +uniform mat3 normal_matrix; + +uniform mat4 volume_world_matrix; + +// x = tainted, y = specular; +varying vec2 intensity; +varying vec4 world_pos; + +void main() +{ + // First transform the normal into camera space and normalize the result. + vec3 normal = normalize(normal_matrix * v_normal); + + // Compute the cos of the angle between the normal and lights direction. The light is directional so the direction is constant for every vertex. + // Since these two are normalized the cosine is the dot product. We also need to clamp the result to the [0,1] range. + float NdotL = max(dot(normal, LIGHT_TOP_DIR), 0.0); + + intensity.x = INTENSITY_AMBIENT + NdotL * LIGHT_TOP_DIFFUSE; + vec4 position = view_model_matrix * vec4(v_position, 1.0); + intensity.y = LIGHT_TOP_SPECULAR * pow(max(dot(-normalize(position.xyz), reflect(-LIGHT_TOP_DIR, normal)), 0.0), LIGHT_TOP_SHININESS); + + // Perform the same lighting calculation for the 2nd light source (no specular applied). + NdotL = max(dot(normal, LIGHT_FRONT_DIR), 0.0); + intensity.x += NdotL * LIGHT_FRONT_DIFFUSE; + + // Point in homogenous coordinates. + world_pos = volume_world_matrix * gl_Vertex; + + gl_Position = projection_matrix * position; +} diff --git a/resources/shaders/variable_layer_height_attr.vs b/resources/shaders/variable_layer_height_attr.vs new file mode 100644 index 00000000000..40609bd0d92 --- /dev/null +++ b/resources/shaders/variable_layer_height_attr.vs @@ -0,0 +1,60 @@ +#version 110 + +#define INTENSITY_CORRECTION 0.6 + +const vec3 LIGHT_TOP_DIR = vec3(-0.4574957, 0.4574957, 0.7624929); +#define LIGHT_TOP_DIFFUSE (0.8 * INTENSITY_CORRECTION) +#define LIGHT_TOP_SPECULAR (0.125 * INTENSITY_CORRECTION) +#define LIGHT_TOP_SHININESS 20.0 + +const vec3 LIGHT_FRONT_DIR = vec3(0.6985074, 0.1397015, 0.6985074); +#define LIGHT_FRONT_DIFFUSE (0.3 * INTENSITY_CORRECTION) +//#define LIGHT_FRONT_SPECULAR (0.0 * INTENSITY_CORRECTION) +//#define LIGHT_FRONT_SHININESS 5.0 + +#define INTENSITY_AMBIENT 0.3 + +attribute vec3 v_position; +attribute vec3 v_normal; +attribute vec2 v_tex_coord; + +uniform mat4 view_model_matrix; +uniform mat4 projection_matrix; +uniform mat3 normal_matrix; +uniform mat4 volume_world_matrix; +uniform float object_max_z; + +// x = tainted, y = specular; +varying vec2 intensity; + +varying float object_z; + +void main() +{ + // ===================================================== + // NOTE: + // when object_max_z > 0.0 we are rendering the overlay + // when object_max_z == 0.0 we are rendering the volumes + // ===================================================== + + // First transform the normal into camera space and normalize the result. + vec3 normal = (object_max_z > 0.0) ? vec3(0.0, 0.0, 1.0) : normalize(normal_matrix * v_normal); + + // Compute the cos of the angle between the normal and lights direction. The light is directional so the direction is constant for every vertex. + // Since these two are normalized the cosine is the dot product. We also need to clamp the result to the [0,1] range. + float NdotL = max(dot(normal, LIGHT_TOP_DIR), 0.0); + + intensity.x = INTENSITY_AMBIENT + NdotL * LIGHT_TOP_DIFFUSE; + vec4 position = view_model_matrix * vec4(v_position, 1.0); + intensity.y = LIGHT_TOP_SPECULAR * pow(max(dot(-normalize(position.xyz), reflect(-LIGHT_TOP_DIR, normal)), 0.0), LIGHT_TOP_SHININESS); + + // Perform the same lighting calculation for the 2nd light source (no specular) + NdotL = max(dot(normal, LIGHT_FRONT_DIR), 0.0); + + intensity.x += NdotL * LIGHT_FRONT_DIFFUSE; + + // Scaled to widths of the Z texture. + object_z = (object_max_z > 0.0) ? object_max_z * v_tex_coord.y : (volume_world_matrix * vec4(v_position, 1.0)).z; + + gl_Position = projection_matrix * position; +} diff --git a/src/OrcaSlicer.cpp b/src/OrcaSlicer.cpp index c8ba1cdd313..9c99e6f6864 100644 --- a/src/OrcaSlicer.cpp +++ b/src/OrcaSlicer.cpp @@ -2370,7 +2370,7 @@ int CLI::run(int argc, char **argv) } ThumbnailsParams thumbnail_params; - GLShaderProgram* shader = opengl_mgr.get_shader("thumbnail"); + GLShaderProgram* shader = opengl_mgr.get_shader("thumbnail_attr"); if (!shader) { BOOST_LOG_TRIVIAL(error) << boost::format("can not get shader for rendering thumbnail"); } diff --git a/src/slic3r/GUI/3DBed.cpp b/src/slic3r/GUI/3DBed.cpp index 55a25c5141d..7d3867b3982 100644 --- a/src/slic3r/GUI/3DBed.cpp +++ b/src/slic3r/GUI/3DBed.cpp @@ -47,7 +47,7 @@ bool init_model_from_poly(GLModel &model, const ExPolygon &poly, float z) return false; GLModel::Geometry init_data; - init_data.format = { GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3T2, GLModel::Geometry::index_type(triangles.size()) }; + init_data.format = { GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3T2 }; init_data.reserve_vertices(triangles.size()); init_data.reserve_indices(triangles.size() / 3); @@ -71,12 +71,8 @@ bool init_model_from_poly(GLModel &model, const ExPolygon &poly, float z) const Vec3f p = {v.x(), v.y(), z}; init_data.add_vertex(p, (Vec2f)(v - min).cwiseProduct(inv_size).eval()); ++vertices_counter; - if (vertices_counter % 3 == 0) { - if (init_data.format.index_type == GLModel::Geometry::EIndexType::USHORT) - init_data.add_ushort_triangle((unsigned short)vertices_counter - 3, (unsigned short)vertices_counter - 2, (unsigned short)vertices_counter - 1); - else - init_data.add_uint_triangle(vertices_counter - 3, vertices_counter - 2, vertices_counter - 1); - } + if (vertices_counter % 3 == 0) + init_data.add_triangle(vertices_counter - 3, vertices_counter - 2, vertices_counter - 1); } model.init_from(std::move(init_data)); @@ -210,17 +206,19 @@ void Bed3D::load_render_colors() void Bed3D::Axes::render() { - auto render_axis = [this](const Transform3f& transform) { - glsafe(::glPushMatrix()); - glsafe(::glMultMatrixf(transform.data())); + auto render_axis = [this](GLShaderProgram* shader, const Transform3d& transform) { + const Camera& camera = wxGetApp().plater()->get_camera(); + const Transform3d matrix = camera.get_view_matrix() * transform; + shader->set_uniform("view_model_matrix", matrix); + shader->set_uniform("projection_matrix", camera.get_projection_matrix()); + shader->set_uniform("normal_matrix", (Matrix3d)matrix.matrix().block(0, 0, 3, 3).inverse().transpose()); m_arrow.render(); - glsafe(::glPopMatrix()); }; if (!m_arrow.is_initialized()) m_arrow.init_from(stilized_arrow(16, DefaultTipRadius, DefaultTipLength, DefaultStemRadius, m_stem_length)); - GLShaderProgram* shader = wxGetApp().get_shader("gouraud_light"); + GLShaderProgram* shader = wxGetApp().get_shader("gouraud_light_attr"); if (shader == nullptr) return; @@ -231,15 +229,15 @@ void Bed3D::Axes::render() // x axis m_arrow.set_color(AXIS_X_COLOR); - render_axis(Geometry::assemble_transform(m_origin, { 0.0, 0.5 * M_PI, 0.0 }).cast()); + render_axis(shader, Geometry::assemble_transform(m_origin, { 0.0, 0.5 * M_PI, 0.0 })); // y axis m_arrow.set_color(AXIS_Y_COLOR); - render_axis(Geometry::assemble_transform(m_origin, { -0.5 * M_PI, 0.0, 0.0 }).cast()); + render_axis(shader, Geometry::assemble_transform(m_origin, { -0.5 * M_PI, 0.0, 0.0 })); // z axis m_arrow.set_color(AXIS_Z_COLOR); - render_axis(Geometry::assemble_transform(m_origin).cast()); + render_axis(shader, Geometry::assemble_transform(m_origin)); shader->stop_using(); @@ -362,17 +360,17 @@ void Bed3D::on_change_color_mode(bool is_dark) m_is_dark = is_dark; } -void Bed3D::render(GLCanvas3D& canvas, bool bottom, float scale_factor, bool show_axes) +void Bed3D::render(GLCanvas3D& canvas, const Transform3d& view_matrix, const Transform3d& projection_matrix, bool bottom, float scale_factor, bool show_axes) { - render_internal(canvas, bottom, scale_factor, show_axes); + render_internal(canvas, view_matrix, projection_matrix, bottom, scale_factor, show_axes); } -/*void Bed3D::render_for_picking(GLCanvas3D& canvas, bool bottom, float scale_factor) +/*void Bed3D::render_for_picking(GLCanvas3D& canvas, const Transform3d& view_matrix, const Transform3d& projection_matrix, bool bottom, float scale_factor) { - render_internal(canvas, bottom, scale_factor, false, false, true); + render_internal(canvas, view_matrix, projection_matrix, bottom, scale_factor, false, false, true); }*/ -void Bed3D::render_internal(GLCanvas3D& canvas, bool bottom, float scale_factor, +void Bed3D::render_internal(GLCanvas3D& canvas, const Transform3d& view_matrix, const Transform3d& projection_matrix, bool bottom, float scale_factor, bool show_axes) { m_scale_factor = scale_factor; @@ -386,9 +384,9 @@ void Bed3D::render_internal(GLCanvas3D& canvas, bool bottom, float scale_factor, switch (m_type) { - case Type::System: { render_system(canvas, bottom); break; } + case Type::System: { render_system(canvas, view_matrix, projection_matrix, bottom); break; } default: - case Type::Custom: { render_custom(canvas, bottom); break; } + case Type::Custom: { render_custom(canvas, view_matrix, projection_matrix, bottom); break; } } glsafe(::glDisable(GL_DEPTH_TEST)); @@ -464,10 +462,10 @@ void Bed3D::render_axes() m_axes.render(); } -void Bed3D::render_system(GLCanvas3D& canvas, bool bottom) +void Bed3D::render_system(GLCanvas3D& canvas, const Transform3d& view_matrix, const Transform3d& projection_matrix, bool bottom) { if (!bottom) - render_model(); + render_model(view_matrix, projection_matrix); /*if (show_texture) render_texture(bottom, canvas);*/ @@ -538,9 +536,12 @@ void Bed3D::render_system(GLCanvas3D& canvas, bool bottom) } if (m_triangles.get_vertices_count() > 0) { - GLShaderProgram* shader = wxGetApp().get_shader("printbed"); + GLShaderProgram* shader = wxGetApp().get_shader("printbed_attr"); if (shader != nullptr) { shader->start_using(); + const Camera& camera = wxGetApp().plater()->get_camera(); + shader->set_uniform("view_model_matrix", camera.get_view_matrix()); + shader->set_uniform("projection_matrix", camera.get_projection_matrix()); shader->set_uniform("transparent_background", bottom); shader->set_uniform("svg_source", boost::algorithm::iends_with(m_texture.get_source(), ".svg")); @@ -658,7 +659,7 @@ void Bed3D::update_bed_triangles() const_cast(m_extended_bounding_box) = calc_extended_bounding_box(); } -void Bed3D::render_model() +void Bed3D::render_model(const Transform3d& view_matrix, const Transform3d& projection_matrix) { if (m_model_filename.empty()) return; @@ -670,20 +671,21 @@ void Bed3D::render_model() } if (!m_model.get_filename().empty()) { - GLShaderProgram* shader = wxGetApp().get_shader("gouraud_light"); + GLShaderProgram* shader = wxGetApp().get_shader("gouraud_light_attr"); if (shader != nullptr) { shader->start_using(); shader->set_uniform("emission_factor", 0.0f); - glsafe(::glPushMatrix()); - glsafe(::glTranslated(m_model_offset.x(), m_model_offset.y(), m_model_offset.z())); + const Transform3d matrix = view_matrix * Geometry::assemble_transform(m_model_offset); + shader->set_uniform("view_model_matrix", matrix); + shader->set_uniform("projection_matrix", projection_matrix); + shader->set_uniform("normal_matrix", (Matrix3d)matrix.matrix().block(0, 0, 3, 3).inverse().transpose()); m_model.render(); - glsafe(::glPopMatrix()); shader->stop_using(); } } } -void Bed3D::render_custom(GLCanvas3D& canvas, bool bottom) +void Bed3D::render_custom(GLCanvas3D& canvas, const Transform3d& view_matrix, const Transform3d& projection_matrix, bool bottom) { if (m_model_filename.empty()) { render_default(bottom); @@ -691,7 +693,7 @@ void Bed3D::render_custom(GLCanvas3D& canvas, bool bottom) } if (!bottom) - render_model(); + render_model(view_matrix, projection_matrix); /*if (show_texture) render_texture(bottom, canvas);*/ @@ -708,8 +710,9 @@ void Bed3D::render_default(bool bottom) if (shader != nullptr) { shader->start_using(); - const Transform3d matrix = wxGetApp().plater()->get_camera().get_projection_view_matrix(); - shader->set_uniform("projection_view_model_matrix", matrix); + const Camera& camera = wxGetApp().plater()->get_camera(); + shader->set_uniform("view_model_matrix", camera.get_view_matrix()); + shader->set_uniform("projection_matrix", camera.get_projection_matrix()); glsafe(::glEnable(GL_DEPTH_TEST)); glsafe(::glEnable(GL_BLEND)); diff --git a/src/slic3r/GUI/3DBed.hpp b/src/slic3r/GUI/3DBed.hpp index 661dee47b7e..e72c6f8af6c 100644 --- a/src/slic3r/GUI/3DBed.hpp +++ b/src/slic3r/GUI/3DBed.hpp @@ -146,8 +146,8 @@ class Bed3D bool contains(const Point& point) const; Point point_projection(const Point& point) const; - void render(GLCanvas3D& canvas, bool bottom, float scale_factor, bool show_axes); - //void render_for_picking(GLCanvas3D& canvas, bool bottom, float scale_factor); + void render(GLCanvas3D& canvas, const Transform3d& view_matrix, const Transform3d& projection_matrix, bool bottom, float scale_factor, bool show_axes); + //void render_for_picking(GLCanvas3D& canvas, const Transform3d& view_matrix, const Transform3d& projection_matrix, bool bottom, float scale_factor); void on_change_color_mode(bool is_dark); @@ -159,13 +159,13 @@ class Bed3D //BBS: with offset void update_bed_triangles(); static std::tuple detect_type(const Pointfs& shape); - void render_internal(GLCanvas3D& canvas, bool bottom, float scale_factor, + void render_internal(GLCanvas3D& canvas, const Transform3d& view_matrix, const Transform3d& projection_matrix, bool bottom, float scale_factor, bool show_axes); void render_axes(); - void render_system(GLCanvas3D& canvas, bool bottom); + void render_system(GLCanvas3D& canvas, const Transform3d& view_matrix, const Transform3d& projection_matrix, bool bottom); //void render_texture(bool bottom, GLCanvas3D& canvas); - void render_model(); - void render_custom(GLCanvas3D& canvas, bool bottom); + void render_model(const Transform3d& view_matrix, const Transform3d& projection_matrix); + void render_custom(GLCanvas3D& canvas, const Transform3d& view_matrix, const Transform3d& projection_matrix, bool bottom); void render_default(bool bottom); }; diff --git a/src/slic3r/GUI/3DScene.cpp b/src/slic3r/GUI/3DScene.cpp index ac533c3365c..354dc76c71e 100644 --- a/src/slic3r/GUI/3DScene.cpp +++ b/src/slic3r/GUI/3DScene.cpp @@ -6,6 +6,7 @@ #include "GUI_Colors.hpp" #include "Plater.hpp" #include "BitmapCache.hpp" +#include "Camera.hpp" #include "libslic3r/BuildVolume.hpp" #include "libslic3r/ExtrusionEntity.hpp" @@ -96,10 +97,14 @@ void GLVolume::SinkingContours::render() { update(); - glsafe(::glPushMatrix()); - glsafe(::glTranslated(m_shift.x(), m_shift.y(), m_shift.z())); + GLShaderProgram* shader = GUI::wxGetApp().get_current_shader(); + if (shader == nullptr) + return; + + const GUI::Camera& camera = GUI::wxGetApp().plater()->get_camera(); + shader->set_uniform("view_model_matrix", camera.get_view_matrix() * Geometry::assemble_transform(m_shift)); + shader->set_uniform("projection_matrix", camera.get_projection_matrix()); m_model.render(); - glsafe(::glPopMatrix()); } void GLVolume::SinkingContours::update() @@ -117,7 +122,7 @@ void GLVolume::SinkingContours::update() m_model.reset(); GUI::GLModel::Geometry init_data; - init_data.format = { GUI::GLModel::Geometry::EPrimitiveType::Triangles, GUI::GLModel::Geometry::EVertexLayout::P3, GUI::GLModel::Geometry::EIndexType::UINT }; + init_data.format = { GUI::GLModel::Geometry::EPrimitiveType::Triangles, GUI::GLModel::Geometry::EVertexLayout::P3 }; init_data.color = ColorRGBA::WHITE(); unsigned int vertices_counter = 0; MeshSlicingParams slicing_params; @@ -131,7 +136,7 @@ void GLVolume::SinkingContours::update() init_data.add_vertex((Vec3f)(v.cast() + 0.015f * Vec3f::UnitZ())); // add a small positive z to avoid z-fighting ++vertices_counter; if (vertices_counter % 3 == 0) - init_data.add_uint_triangle(vertices_counter - 3, vertices_counter - 2, vertices_counter - 1); + init_data.add_triangle(vertices_counter - 3, vertices_counter - 2, vertices_counter - 1); } } m_model.init_from(std::move(init_data)); @@ -398,10 +403,17 @@ void GLVolume::render(bool with_outline) if (!is_active) return; + GLShaderProgram* shader = GUI::wxGetApp().get_current_shader(); + if (shader == nullptr) + return; + if (this->is_left_handed()) glFrontFace(GL_CW); glsafe(::glCullFace(GL_BACK)); - glsafe(::glPushMatrix()); + if (with_outline) { + // Error: not supported! + throw Slic3r::InvalidArgument("Render GLVolume with outline is not supported"); + } // BBS: add logic for mmu segmentation rendering auto render_body = [&]() { @@ -446,7 +458,6 @@ void GLVolume::render(bool with_outline) for (int index = 0; index < colors.size(); index++) colors[index].a(render_color.a()); } - glsafe(::glMultMatrixd(world_matrix().data())); for (int idx = 0; idx < mmuseg_models.size(); idx++) { GUI::GLModel &m = mmuseg_models[idx]; if (m.is_empty()) @@ -489,7 +500,6 @@ void GLVolume::render(bool with_outline) } } else { - glsafe(::glMultMatrixd(world_matrix().data())); if (tverts_range == std::make_pair(0, -1)) model.render(); else @@ -498,7 +508,6 @@ void GLVolume::render(bool with_outline) }; //BBS: add logic of outline rendering - GLShaderProgram* shader = GUI::wxGetApp().get_current_shader(); //BOOST_LOG_TRIVIAL(info) << boost::format(": %1%, with_outline %2%, shader %3%.")%__LINE__ %with_outline %shader; if (with_outline && shader != nullptr) { @@ -629,7 +638,6 @@ void GLVolume::render(bool with_outline) render_body(); //BOOST_LOG_TRIVIAL(info) << boost::format(": %1%, normal render.")%__LINE__; } - glsafe(::glPopMatrix()); if (this->is_left_handed()) glFrontFace(GL_CCW); } @@ -640,7 +648,6 @@ void GLVolume::simple_render(GLShaderProgram* shader, ModelObjectPtrs& model_obj if (this->is_left_handed()) glFrontFace(GL_CW); glsafe(::glCullFace(GL_BACK)); - glsafe(::glPushMatrix()); bool color_volume = false; ModelObject* model_object = nullptr; @@ -704,16 +711,12 @@ void GLVolume::simple_render(GLShaderProgram* shader, ModelObjectPtrs& model_obj else m.render(this->tverts_range); } - } - else { - glsafe(::glMultMatrixd(world_matrix().data())); + } else { if (tverts_range == std::make_pair(0, -1)) model.render(); else model.render(this->tverts_range); } - - glsafe(::glPopMatrix()); if (this->is_left_handed()) glFrontFace(GL_CCW); } @@ -997,8 +1000,8 @@ int GLVolumeCollection::get_selection_support_threshold_angle(bool &enable_suppo } //BBS: add outline drawing logic -void GLVolumeCollection::render( - GLVolumeCollection::ERenderType type, bool disable_cullface, const Transform3d &view_matrix, std::function filter_func, bool with_outline) const +void GLVolumeCollection::render(GLVolumeCollection::ERenderType type, bool disable_cullface, const Transform3d& view_matrix, const Transform3d& projection_matrix, + std::function filter_func, bool with_outline) const { GLVolumeWithIdAndZList to_render = volumes_to_render(volumes, type, view_matrix, filter_func); if (to_render.empty()) @@ -1008,8 +1011,9 @@ void GLVolumeCollection::render( if (shader == nullptr) return; - GLShaderProgram* sink_shader = GUI::wxGetApp().get_shader("flat"); - GLShaderProgram* edges_shader = GUI::wxGetApp().get_shader("flat"); + GLShaderProgram* sink_shader = GUI::wxGetApp().get_shader("flat_attr"); + GLShaderProgram* edges_shader = GUI::wxGetApp().get_shader("flat_attr"); + assert(boost::algorithm::iends_with(shader->get_name(), "_attr")); if (type == ERenderType::Transparent) { glsafe(::glEnable(GL_BLEND)); @@ -1049,9 +1053,6 @@ void GLVolumeCollection::render( } shader->start_using(); - glsafe(::glEnableClientState(GL_VERTEX_ARRAY)); - glsafe(::glEnableClientState(GL_NORMAL_ARRAY)); - if (!volume.first->model.is_initialized()) shader->set_uniform("uniform_color", volume.first->render_color); shader->set_uniform("z_range", m_z_range, 2); @@ -1096,6 +1097,10 @@ void GLVolumeCollection::render( glcheck(); volume.first->model.set_color(volume.first->render_color); + const Transform3d matrix = view_matrix * volume.first->world_matrix(); + shader->set_uniform("view_model_matrix", matrix); + shader->set_uniform("projection_matrix", projection_matrix); + shader->set_uniform("normal_matrix", (Matrix3d)matrix.matrix().block(0, 0, 3, 3).inverse().transpose()); //BBS: add outline related logic volume.first->render(with_outline && volume.first->selected); @@ -1106,9 +1111,6 @@ void GLVolumeCollection::render( glsafe(::glBindBuffer(GL_ARRAY_BUFFER, 0)); glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0)); - - glsafe(::glDisableClientState(GL_VERTEX_ARRAY)); - glsafe(::glDisableClientState(GL_NORMAL_ARRAY)); } if (m_show_sinking_contours) { @@ -1462,8 +1464,8 @@ static void thick_lines_to_geometry( if (!is_first && bottom_z_different) { // Found a change of the layer thickness -> Add a cap at the end of the previous segment. - geometry.add_uint_triangle(idx_b[Bottom], idx_b[Left], idx_b[Top]); - geometry.add_uint_triangle(idx_b[Bottom], idx_b[Top], idx_b[Right]); + geometry.add_triangle(idx_b[Bottom], idx_b[Left], idx_b[Top]); + geometry.add_triangle(idx_b[Bottom], idx_b[Top], idx_b[Right]); } // Share top / bottom vertices if possible. @@ -1513,13 +1515,13 @@ static void thick_lines_to_geometry( geometry.add_vertex(Vec3f(a2.x(), a2.y(), middle_z), Vec3f(-xy_right_normal.x(), -xy_right_normal.y(), 0.0f)); if (cross2(v_prev, v) > 0.0) { // Right turn. Fill in the right turn wedge. - geometry.add_uint_triangle(idx_prev[Right], idx_a[Right], idx_prev[Top]); - geometry.add_uint_triangle(idx_prev[Right], idx_prev[Bottom], idx_a[Right]); + geometry.add_triangle(idx_prev[Right], idx_a[Right], idx_prev[Top]); + geometry.add_triangle(idx_prev[Right], idx_prev[Bottom], idx_a[Right]); } else { // Left turn. Fill in the left turn wedge. - geometry.add_uint_triangle(idx_prev[Left], idx_prev[Top], idx_a[Left]); - geometry.add_uint_triangle(idx_prev[Left], idx_a[Left], idx_prev[Bottom]); + geometry.add_triangle(idx_prev[Left], idx_prev[Top], idx_a[Left]); + geometry.add_triangle(idx_prev[Left], idx_a[Left], idx_prev[Bottom]); } } } @@ -1541,11 +1543,11 @@ static void thick_lines_to_geometry( // Replace the left / right vertex indices to point to the start of the loop. const size_t indices_count = geometry.indices_count(); for (size_t u = indices_count - 24; u < indices_count; ++u) { - const unsigned int id = geometry.extract_uint_index(u); + const unsigned int id = geometry.extract_index(u); if (id == (unsigned int)idx_prev[Left]) - geometry.set_uint_index(u, (unsigned int)idx_initial[Left]); + geometry.set_index(u, (unsigned int)idx_initial[Left]); else if (id == (unsigned int)idx_prev[Right]) - geometry.set_uint_index(u, (unsigned int)idx_initial[Right]); + geometry.set_index(u, (unsigned int)idx_initial[Right]); } } } @@ -1582,36 +1584,36 @@ static void thick_lines_to_geometry( if (bottom_z_different && (closed || (!is_first && !is_last))) { // Found a change of the layer thickness -> Add a cap at the beginning of this segment. - geometry.add_uint_triangle(idx_a[Bottom], idx_a[Right], idx_a[Top]); - geometry.add_uint_triangle(idx_a[Bottom], idx_a[Top], idx_a[Left]); + geometry.add_triangle(idx_a[Bottom], idx_a[Right], idx_a[Top]); + geometry.add_triangle(idx_a[Bottom], idx_a[Top], idx_a[Left]); } if (!closed) { // Terminate open paths with caps. if (is_first) { - geometry.add_uint_triangle(idx_a[Bottom], idx_a[Right], idx_a[Top]); - geometry.add_uint_triangle(idx_a[Bottom], idx_a[Top], idx_a[Left]); + geometry.add_triangle(idx_a[Bottom], idx_a[Right], idx_a[Top]); + geometry.add_triangle(idx_a[Bottom], idx_a[Top], idx_a[Left]); } // We don't use 'else' because both cases are true if we have only one line. if (is_last) { - geometry.add_uint_triangle(idx_b[Bottom], idx_b[Left], idx_b[Top]); - geometry.add_uint_triangle(idx_b[Bottom], idx_b[Top], idx_b[Right]); + geometry.add_triangle(idx_b[Bottom], idx_b[Left], idx_b[Top]); + geometry.add_triangle(idx_b[Bottom], idx_b[Top], idx_b[Right]); } } // Add quads for a straight hollow tube-like segment. // bottom-right face - geometry.add_uint_triangle(idx_a[Bottom], idx_b[Bottom], idx_b[Right]); - geometry.add_uint_triangle(idx_a[Bottom], idx_b[Right], idx_a[Right]); + geometry.add_triangle(idx_a[Bottom], idx_b[Bottom], idx_b[Right]); + geometry.add_triangle(idx_a[Bottom], idx_b[Right], idx_a[Right]); // top-right face - geometry.add_uint_triangle(idx_a[Right], idx_b[Right], idx_b[Top]); - geometry.add_uint_triangle(idx_a[Right], idx_b[Top], idx_a[Top]); + geometry.add_triangle(idx_a[Right], idx_b[Right], idx_b[Top]); + geometry.add_triangle(idx_a[Right], idx_b[Top], idx_a[Top]); // top-left face - geometry.add_uint_triangle(idx_a[Top], idx_b[Top], idx_b[Left]); - geometry.add_uint_triangle(idx_a[Top], idx_b[Left], idx_a[Left]); + geometry.add_triangle(idx_a[Top], idx_b[Top], idx_b[Left]); + geometry.add_triangle(idx_a[Top], idx_b[Left], idx_a[Left]); // bottom-left face - geometry.add_uint_triangle(idx_a[Left], idx_b[Left], idx_b[Bottom]); - geometry.add_uint_triangle(idx_a[Left], idx_b[Bottom], idx_a[Bottom]); + geometry.add_triangle(idx_a[Left], idx_b[Left], idx_b[Bottom]); + geometry.add_triangle(idx_a[Left], idx_b[Bottom], idx_a[Bottom]); } } @@ -1751,13 +1753,13 @@ static void thick_lines_to_geometry( if (is_right_turn) { // Right turn. Fill in the right turn wedge. - geometry.add_uint_triangle(idx_prev[Right], idx_a[Right], idx_prev[Top]); - geometry.add_uint_triangle(idx_prev[Right], idx_prev[Bottom], idx_a[Right]); + geometry.add_triangle(idx_prev[Right], idx_a[Right], idx_prev[Top]); + geometry.add_triangle(idx_prev[Right], idx_prev[Bottom], idx_a[Right]); } else { // Left turn. Fill in the left turn wedge. - geometry.add_uint_triangle(idx_prev[Left], idx_prev[Top], idx_a[Left]); - geometry.add_uint_triangle(idx_prev[Left], idx_a[Left], idx_prev[Bottom]); + geometry.add_triangle(idx_prev[Left], idx_prev[Top], idx_a[Left]); + geometry.add_triangle(idx_prev[Left], idx_a[Left], idx_prev[Bottom]); } } else { @@ -1776,11 +1778,11 @@ static void thick_lines_to_geometry( // Replace the left / right vertex indices to point to the start of the loop. const size_t indices_count = geometry.indices_count(); for (size_t u = indices_count - 24; u < indices_count; ++u) { - const unsigned int id = geometry.extract_uint_index(u); + const unsigned int id = geometry.extract_index(u); if (id == (unsigned int)idx_prev[Left]) - geometry.set_uint_index(u, (unsigned int)idx_initial[Left]); + geometry.set_index(u, (unsigned int)idx_initial[Left]); else if (id == (unsigned int)idx_prev[Right]) - geometry.set_uint_index(u, (unsigned int)idx_initial[Right]); + geometry.set_index(u, (unsigned int)idx_initial[Right]); } } @@ -1819,30 +1821,30 @@ static void thick_lines_to_geometry( if (!closed) { // Terminate open paths with caps. if (i == 0) { - geometry.add_uint_triangle(idx_a[Bottom], idx_a[Right], idx_a[Top]); - geometry.add_uint_triangle(idx_a[Bottom], idx_a[Top], idx_a[Left]); + geometry.add_triangle(idx_a[Bottom], idx_a[Right], idx_a[Top]); + geometry.add_triangle(idx_a[Bottom], idx_a[Top], idx_a[Left]); } // We don't use 'else' because both cases are true if we have only one line. if (i + 1 == lines.size()) { - geometry.add_uint_triangle(idx_b[Bottom], idx_b[Left], idx_b[Top]); - geometry.add_uint_triangle(idx_b[Bottom], idx_b[Top], idx_b[Right]); + geometry.add_triangle(idx_b[Bottom], idx_b[Left], idx_b[Top]); + geometry.add_triangle(idx_b[Bottom], idx_b[Top], idx_b[Right]); } } // Add quads for a straight hollow tube-like segment. // bottom-right face - geometry.add_uint_triangle(idx_a[Bottom], idx_b[Bottom], idx_b[Right]); - geometry.add_uint_triangle(idx_a[Bottom], idx_b[Right], idx_a[Right]); + geometry.add_triangle(idx_a[Bottom], idx_b[Bottom], idx_b[Right]); + geometry.add_triangle(idx_a[Bottom], idx_b[Right], idx_a[Right]); // top-right face - geometry.add_uint_triangle(idx_a[Right], idx_b[Right], idx_b[Top]); - geometry.add_uint_triangle(idx_a[Right], idx_b[Top], idx_a[Top]); + geometry.add_triangle(idx_a[Right], idx_b[Right], idx_b[Top]); + geometry.add_triangle(idx_a[Right], idx_b[Top], idx_a[Top]); // top-left face - geometry.add_uint_triangle(idx_a[Top], idx_b[Top], idx_b[Left]); - geometry.add_uint_triangle(idx_a[Top], idx_b[Left], idx_a[Left]); + geometry.add_triangle(idx_a[Top], idx_b[Top], idx_b[Left]); + geometry.add_triangle(idx_a[Top], idx_b[Left], idx_a[Left]); // bottom-left face - geometry.add_uint_triangle(idx_a[Left], idx_b[Left], idx_b[Bottom]); - geometry.add_uint_triangle(idx_a[Left], idx_b[Bottom], idx_a[Bottom]); + geometry.add_triangle(idx_a[Left], idx_b[Left], idx_b[Bottom]); + geometry.add_triangle(idx_a[Left], idx_b[Bottom], idx_a[Bottom]); } } diff --git a/src/slic3r/GUI/3DScene.hpp b/src/slic3r/GUI/3DScene.hpp index 5c01e22f9c4..79e53320b4e 100644 --- a/src/slic3r/GUI/3DScene.hpp +++ b/src/slic3r/GUI/3DScene.hpp @@ -446,11 +446,8 @@ class GLVolumeCollection int get_selection_support_threshold_angle(bool&) const; // Render the volumes by OpenGL. //BBS: add outline drawing logic - void render(ERenderType type, - bool disable_cullface, - const Transform3d & view_matrix, - std::function filter_func = std::function(), - bool with_outline = true) const; + void render(ERenderType type, bool disable_cullface, const Transform3d& view_matrix, const Transform3d& projection_matrix, + std::function filter_func = std::function(), bool with_outline = true) const; // Clear the geometry void clear() { for (auto *v : volumes) delete v; volumes.clear(); } diff --git a/src/slic3r/GUI/Camera.hpp b/src/slic3r/GUI/Camera.hpp index 4abaedecacb..401365ad4e5 100644 --- a/src/slic3r/GUI/Camera.hpp +++ b/src/slic3r/GUI/Camera.hpp @@ -92,7 +92,6 @@ struct Camera const std::array& get_viewport() const { return m_viewport; } const Transform3d& get_view_matrix() const { return m_view_matrix; } const Transform3d& get_projection_matrix() const { return m_projection_matrix; } - Transform3d get_projection_view_matrix() const { return m_projection_matrix * m_view_matrix; } //BBS const Eigen::Quaterniond& get_view_rotation() const {return m_view_rotation; } diff --git a/src/slic3r/GUI/GCodeViewer.cpp b/src/slic3r/GUI/GCodeViewer.cpp index 675af85d22b..c106ed01ec0 100644 --- a/src/slic3r/GUI/GCodeViewer.cpp +++ b/src/slic3r/GUI/GCodeViewer.cpp @@ -307,7 +307,7 @@ void GCodeViewer::SequentialView::Marker::render(int canvas_width, int canvas_he if (!m_visible) return; - GLShaderProgram* shader = wxGetApp().get_shader("gouraud_light"); + GLShaderProgram* shader = wxGetApp().get_shader("gouraud_light_attr"); if (shader == nullptr) return; @@ -317,13 +317,14 @@ void GCodeViewer::SequentialView::Marker::render(int canvas_width, int canvas_he shader->start_using(); shader->set_uniform("emission_factor", 0.0f); - glsafe(::glPushMatrix()); - glsafe(::glMultMatrixf(m_world_transform.data())); + const Camera& camera = wxGetApp().plater()->get_camera(); + const Transform3d matrix = camera.get_view_matrix() * m_world_transform.cast(); + shader->set_uniform("view_model_matrix", matrix); + shader->set_uniform("projection_matrix", camera.get_projection_matrix()); + shader->set_uniform("normal_matrix", (Matrix3d)matrix.matrix().block(0, 0, 3, 3).inverse().transpose()); m_model.render(); - glsafe(::glPopMatrix()); - shader->stop_using(); glsafe(::glDisable(GL_BLEND)); @@ -787,7 +788,7 @@ void GCodeViewer::init(ConfigOptionMode mode, PresetBundle* preset_bundle) case EMoveType::Seam: { // if (wxGetApp().is_gl_version_greater_or_equal_to(3, 3)) { // buffer.render_primitive_type = TBuffer::ERenderPrimitiveType::InstancedModel; -// buffer.shader = "gouraud_light_instanced"; +// buffer.shader = "gouraud_light_instanced_attr"; // buffer.model.model.init_from(diamond(16)); // buffer.model.color = option_color(type); // buffer.model.instances.format = InstanceVBuffer::EFormat::InstancedModel; @@ -798,7 +799,7 @@ void GCodeViewer::init(ConfigOptionMode mode, PresetBundle* preset_bundle) buffer.render_primitive_type = TBuffer::ERenderPrimitiveType::BatchedModel; buffer.vertices.format = VBuffer::EFormat::PositionNormal3; - buffer.shader = "gouraud_light"; + buffer.shader = "gouraud_light_attr"; buffer.model.data = diamond(16); buffer.model.color = option_color(type); @@ -810,13 +811,13 @@ void GCodeViewer::init(ConfigOptionMode mode, PresetBundle* preset_bundle) case EMoveType::Extrude: { buffer.render_primitive_type = TBuffer::ERenderPrimitiveType::Triangle; buffer.vertices.format = VBuffer::EFormat::PositionNormal3; - buffer.shader = "gouraud_light"; + buffer.shader = "gouraud_light_attr"; break; } case EMoveType::Travel: { buffer.render_primitive_type = TBuffer::ERenderPrimitiveType::Line; - buffer.vertices.format = VBuffer::EFormat::PositionNormal3; - buffer.shader = "toolpaths_lines"; + buffer.vertices.format = VBuffer::EFormat::Position; + buffer.shader = "flat_attr"; break; } } @@ -1324,7 +1325,7 @@ void GCodeViewer::_render_calibration_thumbnail_internal(ThumbnailData& thumbnai // 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; @@ -1359,7 +1360,7 @@ void GCodeViewer::_render_calibration_thumbnail_internal(ThumbnailData& thumbnai #if ENABLE_GCODE_VIEWER_STATISTICS auto render_as_batched_model = [this](TBuffer& buffer, GLShaderProgram& shader) { #else - auto render_as_batched_model = [](TBuffer& buffer, GLShaderProgram& shader) { + auto render_as_batched_model = [](TBuffer& buffer, GLShaderProgram& shader, int position_id, int normal_id) { #endif // ENABLE_GCODE_VIEWER_STATISTICS struct Range @@ -1375,12 +1376,16 @@ void GCodeViewer::_render_calibration_thumbnail_internal(ThumbnailData& thumbnai const IBuffer& i_buffer = buffer.indices[j]; buffer_range.last = buffer_range.first + i_buffer.count / indices_per_instance; glsafe(::glBindBuffer(GL_ARRAY_BUFFER, i_buffer.vbo)); - glsafe(::glVertexPointer(buffer.vertices.position_size_floats(), GL_FLOAT, buffer.vertices.vertex_size_bytes(), (const void*)buffer.vertices.position_offset_bytes())); - glsafe(::glEnableClientState(GL_VERTEX_ARRAY)); + if (position_id != -1) { + glsafe(::glVertexAttribPointer(position_id, buffer.vertices.position_size_floats(), GL_FLOAT, GL_FALSE, buffer.vertices.vertex_size_bytes(), (const void*)buffer.vertices.position_offset_bytes())); + glsafe(::glEnableVertexAttribArray(position_id)); + } bool has_normals = buffer.vertices.normal_size_floats() > 0; if (has_normals) { - glsafe(::glNormalPointer(GL_FLOAT, buffer.vertices.vertex_size_bytes(), (const void*)buffer.vertices.normal_offset_bytes())); - glsafe(::glEnableClientState(GL_NORMAL_ARRAY)); + if (normal_id != -1) { + glsafe(::glVertexAttribPointer(normal_id, buffer.vertices.normal_size_floats(), GL_FLOAT, GL_FALSE, buffer.vertices.vertex_size_bytes(), (const void*)buffer.vertices.normal_offset_bytes())); + glsafe(::glEnableVertexAttribArray(normal_id)); + } } glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, i_buffer.ibo)); @@ -1403,11 +1408,11 @@ void GCodeViewer::_render_calibration_thumbnail_internal(ThumbnailData& thumbnai } glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0)); - - if (has_normals) - glsafe(::glDisableClientState(GL_NORMAL_ARRAY)); - - glsafe(::glDisableClientState(GL_VERTEX_ARRAY)); + + if (normal_id != -1) + glsafe(::glDisableVertexAttribArray(normal_id)); + if (position_id != -1) + glsafe(::glDisableVertexAttribArray(position_id)); glsafe(::glBindBuffer(GL_ARRAY_BUFFER, 0)); buffer_range.first = buffer_range.last; @@ -1423,10 +1428,15 @@ void GCodeViewer::_render_calibration_thumbnail_internal(ThumbnailData& thumbnai if (!buffer.visible || !buffer.has_data()) continue; - GLShaderProgram* shader = opengl_manager.get_shader("cali"); + GLShaderProgram* shader = opengl_manager.get_shader("flat_attr"); if (shader != nullptr) { shader->start_using(); + shader->set_uniform("view_model_matrix", camera.get_view_matrix()); + shader->set_uniform("projection_matrix", camera.get_projection_matrix()); + int position_id = shader->get_attrib_location("v_position"); + int normal_id = shader->get_attrib_location("v_normal"); + if (buffer.render_primitive_type == TBuffer::ERenderPrimitiveType::InstancedModel) { //shader->set_uniform("emission_factor", 0.25f); render_as_instanced_model(buffer, *shader); @@ -1434,7 +1444,7 @@ void GCodeViewer::_render_calibration_thumbnail_internal(ThumbnailData& thumbnai } else if (buffer.render_primitive_type == TBuffer::ERenderPrimitiveType::BatchedModel) { //shader->set_uniform("emission_factor", 0.25f); - render_as_batched_model(buffer, *shader); + render_as_batched_model(buffer, *shader, position_id, normal_id); //shader->set_uniform("emission_factor", 0.0f); } else { @@ -1452,12 +1462,16 @@ void GCodeViewer::_render_calibration_thumbnail_internal(ThumbnailData& thumbnai continue; glsafe(::glBindBuffer(GL_ARRAY_BUFFER, i_buffer.vbo)); - glsafe(::glVertexPointer(buffer.vertices.position_size_floats(), GL_FLOAT, buffer.vertices.vertex_size_bytes(), (const void*)buffer.vertices.position_offset_bytes())); - glsafe(::glEnableClientState(GL_VERTEX_ARRAY)); + if (position_id != -1) { + glsafe(::glVertexAttribPointer(position_id, buffer.vertices.position_size_floats(), GL_FLOAT, GL_FALSE, buffer.vertices.vertex_size_bytes(), (const void*)buffer.vertices.position_offset_bytes())); + glsafe(::glEnableVertexAttribArray(position_id)); + } bool has_normals = false;// buffer.vertices.normal_size_floats() > 0; if (has_normals) { - glsafe(::glNormalPointer(GL_FLOAT, buffer.vertices.vertex_size_bytes(), (const void*)buffer.vertices.normal_offset_bytes())); - glsafe(::glEnableClientState(GL_NORMAL_ARRAY)); + if (normal_id != -1) { + glsafe(::glVertexAttribPointer(normal_id, buffer.vertices.normal_size_floats(), GL_FLOAT, GL_FALSE, buffer.vertices.vertex_size_bytes(), (const void*)buffer.vertices.normal_offset_bytes())); + glsafe(::glEnableVertexAttribArray(normal_id)); + } } glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, i_buffer.ibo)); @@ -1473,11 +1487,12 @@ void GCodeViewer::_render_calibration_thumbnail_internal(ThumbnailData& thumbnai } glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0)); + + if (normal_id != -1) + glsafe(::glDisableVertexAttribArray(normal_id)); + if (position_id != -1) + glsafe(::glDisableVertexAttribArray(position_id)); - if (has_normals) - glsafe(::glDisableClientState(GL_NORMAL_ARRAY)); - - glsafe(::glDisableClientState(GL_VERTEX_ARRAY)); glsafe(::glBindBuffer(GL_ARRAY_BUFFER, 0)); } } @@ -2032,15 +2047,11 @@ void GCodeViewer::load_toolpaths(const GCodeProcessorResult& gcode_result, const // format data into the buffers to be rendered as lines auto add_vertices_as_line = [](const GCodeProcessorResult::MoveVertex& prev, const GCodeProcessorResult::MoveVertex& curr, VertexBuffer& vertices) { - auto add_vertex = [&vertices](const Vec3f& position, const Vec3f& normal) { + auto add_vertex = [&vertices](const Vec3f& position) { // add position vertices.push_back(position.x()); vertices.push_back(position.y()); vertices.push_back(position.z()); - // add normal - vertices.push_back(normal.x()); - vertices.push_back(normal.y()); - vertices.push_back(normal.z()); }; // x component of the normal to the current segment (the normal is parallel to the XY plane) //BBS: Has modified a lot for this function to support arc move @@ -2048,13 +2059,10 @@ void GCodeViewer::load_toolpaths(const GCodeProcessorResult& gcode_result, const for (size_t i = 0; i < loop_num + 1; i++) { const Vec3f &previous = (i == 0? prev.position : curr.interpolation_points[i-1]); const Vec3f ¤t = (i == loop_num? curr.position : curr.interpolation_points[i]); - const Vec3f dir = (current - previous).normalized(); - Vec3f normal(dir.y(), -dir.x(), 0.0); - normal.normalize(); // add previous vertex - add_vertex(previous, normal); + add_vertex(previous); // add current vertex - add_vertex(current, normal); + add_vertex(current); } }; //BBS: modify a lot to support arc travel @@ -2325,7 +2333,7 @@ void GCodeViewer::load_toolpaths(const GCodeProcessorResult& gcode_result, const auto add_indices_as_model_batch = [](const GLModel::Geometry& data, IndexBuffer& indices, IBufferType base_index) { const size_t indices_count = data.indices_count(); for (size_t i = 0; i < indices_count; ++i) { - indices.push_back(static_cast(data.extract_ushort_index(i) + base_index)); + indices.push_back(static_cast(data.extract_index(i) + base_index)); } }; @@ -3765,15 +3773,14 @@ m_no_render_path = false; void GCodeViewer::render_toolpaths() { #if ENABLE_FIXED_SCREEN_SIZE_POINT_MARKERS - float point_size = 20.0f; + const float point_size = 20.0f; #else - float point_size = 0.8f; + const float point_size = 0.8f; #endif // ENABLE_FIXED_SCREEN_SIZE_POINT_MARKERS - std::array light_intensity = { 0.25f, 0.70f, 0.75f, 0.75f }; const Camera& camera = wxGetApp().plater()->get_camera(); - double zoom = camera.get_zoom(); + const double zoom = camera.get_zoom(); const std::array& viewport = camera.get_viewport(); - float near_plane_height = camera.get_type() == Camera::EType::Perspective ? static_cast(viewport[3]) / (2.0f * static_cast(2.0 * std::tan(0.5 * Geometry::deg2rad(camera.get_fov())))) : + const float near_plane_height = camera.get_type() == Camera::EType::Perspective ? static_cast(viewport[3]) / (2.0f * static_cast(2.0 * std::tan(0.5 * Geometry::deg2rad(camera.get_fov())))) : static_cast(viewport[3]) * 0.0005; auto shader_init_as_points = [zoom, point_size, near_plane_height](GLShaderProgram& shader) { @@ -3793,7 +3800,7 @@ void GCodeViewer::render_toolpaths() #if ENABLE_GCODE_VIEWER_STATISTICS this #endif // ENABLE_GCODE_VIEWER_STATISTICS - ](std::vector::reverse_iterator it_path, std::vector::reverse_iterator it_end, GLShaderProgram& shader, int uniform_color) { + ](std::vector::iterator it_path, std::vector::iterator it_end, GLShaderProgram& shader, int uniform_color) { glsafe(::glEnable(GL_VERTEX_PROGRAM_POINT_SIZE)); glsafe(::glEnable(GL_POINT_SPRITE)); @@ -3802,7 +3809,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; @@ -3813,20 +3820,17 @@ void GCodeViewer::render_toolpaths() glsafe(::glDisable(GL_VERTEX_PROGRAM_POINT_SIZE)); }; - auto shader_init_as_lines = [light_intensity](GLShaderProgram &shader) { - shader.set_uniform("light_intensity", light_intensity); - }; auto render_as_lines = [ #if ENABLE_GCODE_VIEWER_STATISTICS this #endif // ENABLE_GCODE_VIEWER_STATISTICS - ](std::vector::reverse_iterator it_path, std::vector::reverse_iterator it_end, GLShaderProgram& shader, int uniform_color) { + ](std::vector::iterator it_path, std::vector::iterator it_end, GLShaderProgram& shader, int uniform_color) { for (auto it = it_path; it != it_end && it_path->ibuffer_id == it->ibuffer_id; ++it) { const RenderPath& path = *it; // 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; @@ -3838,13 +3842,13 @@ void GCodeViewer::render_toolpaths() #if ENABLE_GCODE_VIEWER_STATISTICS this #endif // ENABLE_GCODE_VIEWER_STATISTICS - ](std::vector::reverse_iterator it_path, std::vector::reverse_iterator it_end, GLShaderProgram& shader, int uniform_color) { + ](std::vector::iterator it_path, std::vector::iterator it_end, GLShaderProgram& shader, int uniform_color) { for (auto it = it_path; it != it_end && it_path->ibuffer_id == it->ibuffer_id; ++it) { const RenderPath& path = *it; // 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; @@ -3877,9 +3881,9 @@ void GCodeViewer::render_toolpaths() }; #if ENABLE_GCODE_VIEWER_STATISTICS - auto render_as_batched_model = [this](TBuffer& buffer, GLShaderProgram& shader) { + auto render_as_batched_model = [this](TBuffer& buffer, GLShaderProgram& shader, int position_id, int normal_id) { #else - auto render_as_batched_model = [](TBuffer& buffer, GLShaderProgram& shader) { + auto render_as_batched_model = [](TBuffer& buffer, GLShaderProgram& shader, int position_id, int normal_id) { #endif // ENABLE_GCODE_VIEWER_STATISTICS struct Range @@ -3889,30 +3893,34 @@ void GCodeViewer::render_toolpaths() bool intersects(const Range& other) const { return (other.last < first || other.first > last) ? false : true; } }; Range buffer_range = { 0, 0 }; - size_t indices_per_instance = buffer.model.data.indices_count(); + const size_t indices_per_instance = buffer.model.data.indices_count(); for (size_t j = 0; j < buffer.indices.size(); ++j) { const IBuffer& i_buffer = buffer.indices[j]; buffer_range.last = buffer_range.first + i_buffer.count / indices_per_instance; glsafe(::glBindBuffer(GL_ARRAY_BUFFER, i_buffer.vbo)); - glsafe(::glVertexPointer(buffer.vertices.position_size_floats(), GL_FLOAT, buffer.vertices.vertex_size_bytes(), (const void*)buffer.vertices.position_offset_bytes())); - glsafe(::glEnableClientState(GL_VERTEX_ARRAY)); - bool has_normals = buffer.vertices.normal_size_floats() > 0; + if (position_id != -1) { + glsafe(::glVertexAttribPointer(position_id, buffer.vertices.position_size_floats(), GL_FLOAT, GL_FALSE, buffer.vertices.vertex_size_bytes(), (const void*)buffer.vertices.position_offset_bytes())); + glsafe(::glEnableVertexAttribArray(position_id)); + } + const bool has_normals = buffer.vertices.normal_size_floats() > 0; if (has_normals) { - glsafe(::glNormalPointer(GL_FLOAT, buffer.vertices.vertex_size_bytes(), (const void*)buffer.vertices.normal_offset_bytes())); - glsafe(::glEnableClientState(GL_NORMAL_ARRAY)); + if (normal_id != -1) { + glsafe(::glVertexAttribPointer(normal_id, buffer.vertices.normal_size_floats(), GL_FLOAT, GL_FALSE, buffer.vertices.vertex_size_bytes(), (const void*)buffer.vertices.normal_offset_bytes())); + glsafe(::glEnableVertexAttribArray(normal_id)); + } } glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, i_buffer.ibo)); for (auto& range : buffer.model.instances.render_ranges.ranges) { - Range range_range = { range.offset, range.offset + range.count }; + const Range range_range = { range.offset, range.offset + range.count }; if (range_range.intersects(buffer_range)) { shader.set_uniform("uniform_color", range.color); - unsigned int offset = (range_range.first > buffer_range.first) ? range_range.first - buffer_range.first : 0; - size_t offset_bytes = static_cast(offset) * indices_per_instance * sizeof(IBufferType); - Range render_range = { std::max(range_range.first, buffer_range.first), std::min(range_range.last, buffer_range.last) }; - size_t count = static_cast(render_range.last - render_range.first) * indices_per_instance; + const unsigned int offset = (range_range.first > buffer_range.first) ? range_range.first - buffer_range.first : 0; + const size_t offset_bytes = static_cast(offset) * indices_per_instance * sizeof(IBufferType); + const Range render_range = { std::max(range_range.first, buffer_range.first), std::min(range_range.last, buffer_range.last) }; + const size_t count = static_cast(render_range.last - render_range.first) * indices_per_instance; if (count > 0) { glsafe(::glDrawElements(GL_TRIANGLES, (GLsizei)count, GL_UNSIGNED_SHORT, (const void*)offset_bytes)); #if ENABLE_GCODE_VIEWER_STATISTICS @@ -3924,10 +3932,10 @@ void GCodeViewer::render_toolpaths() glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0)); - if (has_normals) - glsafe(::glDisableClientState(GL_NORMAL_ARRAY)); - - glsafe(::glDisableClientState(GL_VERTEX_ARRAY)); + if (normal_id != -1) + glsafe(::glDisableVertexAttribArray(normal_id)); + if (position_id != -1) + glsafe(::glDisableVertexAttribArray(position_id)); glsafe(::glBindBuffer(GL_ARRAY_BUFFER, 0)); buffer_range.first = buffer_range.last; @@ -3938,9 +3946,8 @@ void GCodeViewer::render_toolpaths() return (zoom < 5.0) ? 1.0 : (1.0 + 5.0 * (zoom - 5.0) / (100.0 - 5.0)); }; - unsigned char begin_id = buffer_id(EMoveType::Retract); - unsigned char end_id = buffer_id(EMoveType::Count); - //BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(":begin_id %1%, end_id %2% ")%(int)begin_id %(int)end_id; + const unsigned char begin_id = buffer_id(EMoveType::Retract); + const unsigned char end_id = buffer_id(EMoveType::Count); for (unsigned char i = begin_id; i < end_id; ++i) { TBuffer& buffer = m_buffers[i]; @@ -3948,80 +3955,90 @@ void GCodeViewer::render_toolpaths() continue; GLShaderProgram* shader = wxGetApp().get_shader(buffer.shader.c_str()); - if (shader != nullptr) { - shader->start_using(); + if (shader == nullptr) + continue; - if (buffer.render_primitive_type == TBuffer::ERenderPrimitiveType::InstancedModel) { - shader->set_uniform("emission_factor", 0.25f); - render_as_instanced_model(buffer, *shader); - shader->set_uniform("emission_factor", 0.0f); - } - else if (buffer.render_primitive_type == TBuffer::ERenderPrimitiveType::BatchedModel) { - shader->set_uniform("emission_factor", 0.25f); - render_as_batched_model(buffer, *shader); - shader->set_uniform("emission_factor", 0.0f); - } - else { - switch (buffer.render_primitive_type) { - case TBuffer::ERenderPrimitiveType::Point: shader_init_as_points(*shader); break; - case TBuffer::ERenderPrimitiveType::Line: shader_init_as_lines(*shader); break; - default: break; - } - int uniform_color = shader->get_uniform_location("uniform_color"); - auto it_path = buffer.render_paths.rbegin(); - //BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(":buffer indices size %1%, render_path size %2% ")%buffer.indices.size() %buffer.render_paths.size(); - unsigned int indices_count = static_cast(buffer.indices.size()); - for (unsigned int index = 0; index < indices_count; ++index) { - unsigned int ibuffer_id = indices_count - index - 1; - const IBuffer& i_buffer = buffer.indices[ibuffer_id]; - // Skip all paths with ibuffer_id < ibuffer_id. - for (; it_path != buffer.render_paths.rend() && it_path->ibuffer_id > ibuffer_id; ++ it_path) ; - if (it_path == buffer.render_paths.rend() || it_path->ibuffer_id < ibuffer_id) - // Not found. This shall not happen. - continue; + shader->start_using(); - glsafe(::glBindBuffer(GL_ARRAY_BUFFER, i_buffer.vbo)); - glsafe(::glVertexPointer(buffer.vertices.position_size_floats(), GL_FLOAT, buffer.vertices.vertex_size_bytes(), (const void*)buffer.vertices.position_offset_bytes())); - glsafe(::glEnableClientState(GL_VERTEX_ARRAY)); - bool has_normals = buffer.vertices.normal_size_floats() > 0; - if (has_normals) { - glsafe(::glNormalPointer(GL_FLOAT, buffer.vertices.vertex_size_bytes(), (const void*)buffer.vertices.normal_offset_bytes())); - glsafe(::glEnableClientState(GL_NORMAL_ARRAY)); - } + int position_id = -1; + int normal_id = -1; + const Transform3d& view_matrix = camera.get_view_matrix(); + shader->set_uniform("view_model_matrix", view_matrix); + shader->set_uniform("projection_matrix", camera.get_projection_matrix()); + shader->set_uniform("normal_matrix", (Matrix3d)view_matrix.matrix().block(0, 0, 3, 3).inverse().transpose()); - glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, i_buffer.ibo)); + position_id = shader->get_attrib_location("v_position"); + normal_id = shader->get_attrib_location("v_normal"); - // Render all elements with it_path->ibuffer_id == ibuffer_id, possible with varying colors. - switch (buffer.render_primitive_type) - { - case TBuffer::ERenderPrimitiveType::Point: { - render_as_points(it_path, buffer.render_paths.rend(), *shader, uniform_color); - break; - } - case TBuffer::ERenderPrimitiveType::Line: { - glsafe(::glLineWidth(static_cast(line_width(zoom)))); - render_as_lines(it_path, buffer.render_paths.rend(), *shader, uniform_color); - break; - } - case TBuffer::ERenderPrimitiveType::Triangle: { - render_as_triangles(it_path, buffer.render_paths.rend(), *shader, uniform_color); - break; - } - default: { break; } - } + if (buffer.render_primitive_type == TBuffer::ERenderPrimitiveType::InstancedModel) { + shader->set_uniform("emission_factor", 0.25f); + render_as_instanced_model(buffer, *shader); + shader->set_uniform("emission_factor", 0.0f); + } + else if (buffer.render_primitive_type == TBuffer::ERenderPrimitiveType::BatchedModel) { + shader->set_uniform("emission_factor", 0.25f); + render_as_batched_model(buffer, *shader, position_id, normal_id); + shader->set_uniform("emission_factor", 0.0f); + } + else { + if (buffer.render_primitive_type == TBuffer::ERenderPrimitiveType::Point) + shader_init_as_points(*shader); + const int uniform_color = shader->get_uniform_location("uniform_color"); - glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0)); + auto it_path = buffer.render_paths.begin(); + for (unsigned int ibuffer_id = 0; ibuffer_id < static_cast(buffer.indices.size()); ++ibuffer_id) { + const IBuffer& i_buffer = buffer.indices[ibuffer_id]; + // Skip all paths with ibuffer_id < ibuffer_id. + for (; it_path != buffer.render_paths.end() && it_path->ibuffer_id < ibuffer_id; ++it_path); + if (it_path == buffer.render_paths.end() || it_path->ibuffer_id > ibuffer_id) + // Not found. This shall not happen. + continue; + + glsafe(::glBindBuffer(GL_ARRAY_BUFFER, i_buffer.vbo)); + if (position_id != -1) { + glsafe(::glVertexAttribPointer(position_id, buffer.vertices.position_size_floats(), GL_FLOAT, GL_FALSE, buffer.vertices.vertex_size_bytes(), (const void*)buffer.vertices.position_offset_bytes())); + glsafe(::glEnableVertexAttribArray(position_id)); + } + const bool has_normals = buffer.vertices.normal_size_floats() > 0; + if (has_normals) { + if (normal_id != -1) { + glsafe(::glVertexAttribPointer(normal_id, buffer.vertices.normal_size_floats(), GL_FLOAT, GL_FALSE, buffer.vertices.vertex_size_bytes(), (const void*)buffer.vertices.normal_offset_bytes())); + glsafe(::glEnableVertexAttribArray(normal_id)); + } + } - if (has_normals) - glsafe(::glDisableClientState(GL_NORMAL_ARRAY)); + glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, i_buffer.ibo)); - glsafe(::glDisableClientState(GL_VERTEX_ARRAY)); - glsafe(::glBindBuffer(GL_ARRAY_BUFFER, 0)); + // Render all elements with it_path->ibuffer_id == ibuffer_id, possible with varying colors. + switch (buffer.render_primitive_type) + { + case TBuffer::ERenderPrimitiveType::Point: { + render_as_points(it_path, buffer.render_paths.end(), *shader, uniform_color); + break; + } + case TBuffer::ERenderPrimitiveType::Line: { + glsafe(::glLineWidth(static_cast(line_width(zoom)))); + render_as_lines(it_path, buffer.render_paths.end(), *shader, uniform_color); + break; + } + case TBuffer::ERenderPrimitiveType::Triangle: { + render_as_triangles(it_path, buffer.render_paths.end(), *shader, uniform_color); + break; + } + default: { break; } } - } - shader->stop_using(); + glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0)); + + if (normal_id != -1) + glsafe(::glDisableVertexAttribArray(normal_id)); + if (position_id != -1) + glsafe(::glDisableVertexAttribArray(position_id)); + glsafe(::glBindBuffer(GL_ARRAY_BUFFER, 0)); + } } + + shader->stop_using(); } #if ENABLE_GCODE_VIEWER_STATISTICS @@ -4030,37 +4047,55 @@ void GCodeViewer::render_toolpaths() auto render_sequential_range_cap = [] #endif // ENABLE_GCODE_VIEWER_STATISTICS (const SequentialRangeCap& cap) { - GLShaderProgram* shader = wxGetApp().get_shader(cap.buffer->shader.c_str()); - if (shader != nullptr) { - shader->start_using(); + const TBuffer* buffer = cap.buffer; + GLShaderProgram* shader = wxGetApp().get_shader(buffer->shader.c_str()); + if (shader == nullptr) + return; - glsafe(::glBindBuffer(GL_ARRAY_BUFFER, cap.vbo)); - glsafe(::glVertexPointer(cap.buffer->vertices.position_size_floats(), GL_FLOAT, cap.buffer->vertices.vertex_size_bytes(), (const void*)cap.buffer->vertices.position_offset_bytes())); - glsafe(::glEnableClientState(GL_VERTEX_ARRAY)); - bool has_normals = cap.buffer->vertices.normal_size_floats() > 0; - if (has_normals) { - glsafe(::glNormalPointer(GL_FLOAT, cap.buffer->vertices.vertex_size_bytes(), (const void*)cap.buffer->vertices.normal_offset_bytes())); - glsafe(::glEnableClientState(GL_NORMAL_ARRAY)); + shader->start_using(); + + int position_id = -1; + int normal_id = -1; + const Camera& camera = wxGetApp().plater()->get_camera(); + const Transform3d& view_matrix = camera.get_view_matrix(); + shader->set_uniform("view_model_matrix", view_matrix); + shader->set_uniform("projection_matrix", camera.get_projection_matrix()); + shader->set_uniform("normal_matrix", (Matrix3d)view_matrix.matrix().block(0, 0, 3, 3).inverse().transpose()); + + position_id = shader->get_attrib_location("v_position"); + normal_id = shader->get_attrib_location("v_normal"); + + glsafe(::glBindBuffer(GL_ARRAY_BUFFER, cap.vbo)); + if (position_id != -1) { + glsafe(::glVertexAttribPointer(position_id, buffer->vertices.position_size_floats(), GL_FLOAT, GL_FALSE, buffer->vertices.vertex_size_bytes(), (const void*)buffer->vertices.position_offset_bytes())); + glsafe(::glEnableVertexAttribArray(position_id)); + } + const bool has_normals = buffer->vertices.normal_size_floats() > 0; + if (has_normals) { + if (normal_id != -1) { + glsafe(::glVertexAttribPointer(normal_id, buffer->vertices.normal_size_floats(), GL_FLOAT, GL_FALSE, buffer->vertices.vertex_size_bytes(), (const void*)buffer->vertices.normal_offset_bytes())); + glsafe(::glEnableVertexAttribArray(normal_id)); } + } - shader->set_uniform("uniform_color", cap.color); + shader->set_uniform("uniform_color", cap.color); - glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, cap.ibo)); - glsafe(::glDrawElements(GL_TRIANGLES, (GLsizei)cap.indices_count(), GL_UNSIGNED_SHORT, nullptr)); - glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0)); + glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, cap.ibo)); + glsafe(::glDrawElements(GL_TRIANGLES, (GLsizei)cap.indices_count(), GL_UNSIGNED_SHORT, nullptr)); + glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0)); #if ENABLE_GCODE_VIEWER_STATISTICS ++m_statistics.gl_triangles_calls_count; #endif // ENABLE_GCODE_VIEWER_STATISTICS - if (has_normals) - glsafe(::glDisableClientState(GL_NORMAL_ARRAY)); + if (normal_id != -1) + glsafe(::glDisableVertexAttribArray(normal_id)); + if (position_id != -1) + glsafe(::glDisableVertexAttribArray(position_id)); - glsafe(::glDisableClientState(GL_VERTEX_ARRAY)); - glsafe(::glBindBuffer(GL_ARRAY_BUFFER, 0)); + glsafe(::glBindBuffer(GL_ARRAY_BUFFER, 0)); - shader->stop_using(); - } + shader->stop_using(); }; for (unsigned int i = 0; i < 2; ++i) { @@ -4076,7 +4111,7 @@ void GCodeViewer::render_shells() //if (!m_shells.visible || m_shells.volumes.empty()) return; - GLShaderProgram* shader = wxGetApp().get_shader("gouraud_light"); + GLShaderProgram* shader = wxGetApp().get_shader("gouraud_light_attr"); if (shader == nullptr) return; @@ -4084,8 +4119,9 @@ void GCodeViewer::render_shells() // glsafe(::glDepthMask(GL_FALSE)); shader->start_using(); + const Camera& camera = wxGetApp().plater()->get_camera(); //BBS: reopen cul faces - m_shells.volumes.render(GLVolumeCollection::ERenderType::Transparent, false, wxGetApp().plater()->get_camera().get_view_matrix()); + m_shells.volumes.render(GLVolumeCollection::ERenderType::Transparent, false, camera.get_view_matrix(), camera.get_projection_matrix()); shader->stop_using(); // glsafe(::glDepthMask(GL_TRUE)); diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index f66a59fb120..81db1388715 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -14,22 +14,16 @@ #include "libslic3r/Technologies.hpp" #include "libslic3r/Tesselate.hpp" #include "libslic3r/PresetBundle.hpp" -#include "slic3r/GUI/3DBed.hpp" -#include "slic3r/GUI/3DScene.hpp" -#include "slic3r/GUI/BackgroundSlicingProcess.hpp" -#include "slic3r/GUI/GLCanvas3D.hpp" -#include "slic3r/GUI/GLShader.hpp" -#include "slic3r/GUI/GUI.hpp" -#include "slic3r/GUI/Tab.hpp" -#include "slic3r/GUI/GUI_Preview.hpp" -#include "slic3r/GUI/OpenGLManager.hpp" -#include "slic3r/GUI/Plater.hpp" -#include "slic3r/GUI/MainFrame.hpp" -#include "slic3r/Utils/UndoRedo.hpp" -#include "slic3r/GUI/Gizmos/GLGizmoPainterBase.hpp" -#include "slic3r/GUI/BitmapCache.hpp" -#include "slic3r/Utils/MacDarkMode.hpp" - +#include "3DBed.hpp" +#include "3DScene.hpp" +#include "BackgroundSlicingProcess.hpp" +#include "GLShader.hpp" +#include "GUI.hpp" +#include "Tab.hpp" +#include "GUI_Preview.hpp" +#include "OpenGLManager.hpp" +#include "Plater.hpp" +#include "MainFrame.hpp" #include "GUI_App.hpp" #include "GUI_ObjectList.hpp" #include "GUI_Colors.hpp" @@ -38,6 +32,9 @@ #include "NotificationManager.hpp" #include "format.hpp" +#include "slic3r/GUI/Gizmos/GLGizmoPainterBase.hpp" +#include "slic3r/Utils/UndoRedo.hpp" + #include #if ENABLE_RETINA_GL @@ -166,7 +163,7 @@ void GLCanvas3D::LayersEditing::select_object(const Model& model, int object_id) bool GLCanvas3D::LayersEditing::is_allowed() const { - return wxGetApp().get_shader("variable_layer_height") != nullptr && m_z_texture_id > 0; + return wxGetApp().get_shader("variable_layer_height_attr") != nullptr && m_z_texture_id > 0; } bool GLCanvas3D::LayersEditing::is_enabled() const @@ -220,9 +217,8 @@ void GLCanvas3D::LayersEditing::render_variable_layer_height_dialog(const GLCanv ImGuiWrapper& imgui = *wxGetApp().imgui(); const Size& cnv_size = canvas.get_canvas_size(); - float zoom = (float)wxGetApp().plater()->get_camera().get_zoom(); float left_pos = canvas.m_main_toolbar.get_item("layersediting")->render_left_pos; - const float x = 0.5 * cnv_size.get_width() + left_pos * zoom; + const float x = (1 + left_pos) * cnv_size.get_width() / 2; imgui.set_next_window_pos(x, canvas.m_main_toolbar.get_height(), ImGuiCond_Always, 0.0f, 0.0f); imgui.push_toolbar_style(canvas.get_scale()); @@ -322,12 +318,8 @@ void GLCanvas3D::LayersEditing::render_variable_layer_height_dialog(const GLCanv void GLCanvas3D::LayersEditing::render_overlay(const GLCanvas3D& canvas) { render_variable_layer_height_dialog(canvas); - const Rect& bar_rect = get_bar_rect_viewport(canvas); - m_profile.dirty = m_profile.old_bar_rect != bar_rect; - render_active_object_annotations(canvas, bar_rect); - render_profile(bar_rect); - m_profile.old_bar_rect = bar_rect; - m_profile.dirty = false; + render_active_object_annotations(canvas); + render_profile(canvas); } float GLCanvas3D::LayersEditing::get_cursor_z_relative(const GLCanvas3D& canvas) @@ -361,18 +353,9 @@ Rect GLCanvas3D::LayersEditing::get_bar_rect_screen(const GLCanvas3D& canvas) return { w - thickness_bar_width(canvas), 0.0f, w, h }; } -Rect GLCanvas3D::LayersEditing::get_bar_rect_viewport(const GLCanvas3D& canvas) -{ - const Size& cnv_size = canvas.get_canvas_size(); - float half_w = 0.5f * (float)cnv_size.get_width(); - float half_h = 0.5f * (float)cnv_size.get_height(); - float inv_zoom = (float)wxGetApp().plater()->get_camera().get_inv_zoom(); - return { (half_w - thickness_bar_width(canvas)) * inv_zoom, half_h * inv_zoom, half_w * inv_zoom, -half_h * inv_zoom }; -} - bool GLCanvas3D::LayersEditing::is_initialized() const { - return wxGetApp().get_shader("variable_layer_height") != nullptr; + return wxGetApp().get_shader("variable_layer_height_attr") != nullptr; } std::string GLCanvas3D::LayersEditing::get_tooltip(const GLCanvas3D& canvas) const @@ -401,12 +384,20 @@ std::string GLCanvas3D::LayersEditing::get_tooltip(const GLCanvas3D& canvas) con return ret; } -void GLCanvas3D::LayersEditing::render_active_object_annotations(const GLCanvas3D& canvas, const Rect& bar_rect) +void GLCanvas3D::LayersEditing::render_active_object_annotations(const GLCanvas3D& canvas) { if (!m_enabled) return; - GLShaderProgram* shader = wxGetApp().get_shader("variable_layer_height"); + const Size cnv_size = canvas.get_canvas_size(); + const float cnv_width = (float)cnv_size.get_width(); + const float cnv_height = (float)cnv_size.get_height(); + if (cnv_width == 0.0f || cnv_height == 0.0f) + return; + + const float cnv_inv_width = 1.0f / cnv_width; + + GLShaderProgram* shader = wxGetApp().get_shader("variable_layer_height_attr"); if (shader == nullptr) return; @@ -417,32 +408,36 @@ void GLCanvas3D::LayersEditing::render_active_object_annotations(const GLCanvas3 shader->set_uniform("z_cursor", m_object_max_z * this->get_cursor_z_relative(canvas)); shader->set_uniform("z_cursor_band_width", band_width); shader->set_uniform("object_max_z", m_object_max_z); + shader->set_uniform("view_model_matrix", Transform3d::Identity()); + shader->set_uniform("projection_matrix", Transform3d::Identity()); + shader->set_uniform("normal_matrix", (Matrix3d)Eigen::Matrix3d::Identity()); glsafe(::glPixelStorei(GL_UNPACK_ALIGNMENT, 1)); glsafe(::glBindTexture(GL_TEXTURE_2D, m_z_texture_id)); // Render the color bar - if (!m_profile.background.is_initialized() || m_profile.dirty) { + if (!m_profile.background.is_initialized() || m_profile.old_canvas_width != cnv_width) { + m_profile.old_canvas_width = cnv_width; m_profile.background.reset(); GLModel::Geometry init_data; - init_data.format = { GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P2T2, GLModel::Geometry::EIndexType::USHORT }; + init_data.format = { GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P2T2 }; init_data.reserve_vertices(4); init_data.reserve_indices(6); // vertices - const float l = bar_rect.get_left(); - const float r = bar_rect.get_right(); - const float t = bar_rect.get_top(); - const float b = bar_rect.get_bottom(); + const float l = 1.0f - 2.0f * THICKNESS_BAR_WIDTH * cnv_inv_width; + const float r = 1.0f; + const float t = 1.0f; + const float b = -1.0f; init_data.add_vertex(Vec2f(l, b), Vec2f(0.0f, 0.0f)); init_data.add_vertex(Vec2f(r, b), Vec2f(1.0f, 0.0f)); init_data.add_vertex(Vec2f(r, t), Vec2f(1.0f, 1.0f)); init_data.add_vertex(Vec2f(l, t), Vec2f(0.0f, 1.0f)); // indices - init_data.add_ushort_triangle(0, 1, 2); - init_data.add_ushort_triangle(2, 3, 0); + init_data.add_triangle(0, 1, 2); + init_data.add_triangle(2, 3, 0); m_profile.background.init_from(std::move(init_data)); } @@ -454,73 +449,82 @@ void GLCanvas3D::LayersEditing::render_active_object_annotations(const GLCanvas3 shader->stop_using(); } -void GLCanvas3D::LayersEditing::render_profile(const Rect& bar_rect) +void GLCanvas3D::LayersEditing::render_profile(const GLCanvas3D& canvas) { if (!m_enabled) return; //FIXME show some kind of legend. + if (!m_slicing_parameters) return; + const Size cnv_size = canvas.get_canvas_size(); + const float cnv_width = (float)cnv_size.get_width(); + const float cnv_height = (float)cnv_size.get_height(); + if (cnv_width == 0.0f || cnv_height == 0.0f) + return; + // Make the vertical bar a bit wider so the layer height curve does not touch the edge of the bar region. - const float scale_x = bar_rect.get_width() / float(1.12 * m_slicing_parameters->max_layer_height); - const float scale_y = bar_rect.get_height() / m_object_max_z; + const float scale_x = THICKNESS_BAR_WIDTH / float(1.12 * m_slicing_parameters->max_layer_height); + const float scale_y = cnv_height / m_object_max_z; + + const float cnv_inv_width = 1.0f / cnv_width; + const float cnv_inv_height = 1.0f / cnv_height; // Baseline - if (!m_profile.baseline.is_initialized() || m_profile.dirty) { + if (!m_profile.baseline.is_initialized() || m_profile.old_layer_height_profile != m_layer_height_profile) { m_profile.baseline.reset(); GLModel::Geometry init_data; - init_data.format = { GLModel::Geometry::EPrimitiveType::Lines, GLModel::Geometry::EVertexLayout::P2, GLModel::Geometry::EIndexType::USHORT }; + init_data.format = { GLModel::Geometry::EPrimitiveType::Lines, GLModel::Geometry::EVertexLayout::P2}; init_data.color = ColorRGBA::BLACK(); init_data.reserve_vertices(2); init_data.reserve_indices(2); // vertices - const float x = bar_rect.get_left() + float(m_slicing_parameters->layer_height) * scale_x; - init_data.add_vertex(Vec2f(x, bar_rect.get_bottom())); - init_data.add_vertex(Vec2f(x, bar_rect.get_top())); + const float axis_x = 2.0f * ((cnv_width - THICKNESS_BAR_WIDTH + float(m_slicing_parameters->layer_height) * scale_x) * cnv_inv_width - 0.5f); + init_data.add_vertex(Vec2f(axis_x, -1.0f)); + init_data.add_vertex(Vec2f(axis_x, 1.0f)); // indices - init_data.add_ushort_line(0, 1); + init_data.add_line(0, 1); m_profile.baseline.init_from(std::move(init_data)); } - if (!m_profile.profile.is_initialized() || m_profile.dirty || m_profile.old_layer_height_profile != m_layer_height_profile) { + if (!m_profile.profile.is_initialized() || m_profile.old_layer_height_profile != m_layer_height_profile) { m_profile.old_layer_height_profile = m_layer_height_profile; m_profile.profile.reset(); GLModel::Geometry init_data; - init_data.format = { GLModel::Geometry::EPrimitiveType::LineStrip, GLModel::Geometry::EVertexLayout::P2, GLModel::Geometry::index_type(m_layer_height_profile.size() / 2) }; + init_data.format = { GLModel::Geometry::EPrimitiveType::LineStrip, GLModel::Geometry::EVertexLayout::P2 }; init_data.color = ColorRGBA::BLUE(); init_data.reserve_vertices(m_layer_height_profile.size() / 2); init_data.reserve_indices(m_layer_height_profile.size() / 2); // vertices + indices for (unsigned int i = 0; i < (unsigned int)m_layer_height_profile.size(); i += 2) { - init_data.add_vertex(Vec2f(bar_rect.get_left() + float(m_layer_height_profile[i + 1]) * scale_x, - bar_rect.get_bottom() + float(m_layer_height_profile[i]) * scale_y)); - if (init_data.format.index_type == GLModel::Geometry::EIndexType::USHORT) - init_data.add_ushort_index((unsigned short)i / 2); - else - init_data.add_uint_index(i / 2); + init_data.add_vertex(Vec2f(2.0f * ((cnv_width - THICKNESS_BAR_WIDTH + float(m_layer_height_profile[i + 1]) * scale_x) * cnv_inv_width - 0.5f), + 2.0f * (float(m_layer_height_profile[i]) * scale_y * cnv_inv_height - 0.5))); + init_data.add_index(i / 2); } m_profile.profile.init_from(std::move(init_data)); } - GLShaderProgram* shader = wxGetApp().get_shader("flat"); + GLShaderProgram* shader = wxGetApp().get_shader("flat_attr"); if (shader != nullptr) { shader->start_using(); + shader->set_uniform("view_model_matrix", Transform3d::Identity()); + shader->set_uniform("projection_matrix", Transform3d::Identity()); m_profile.baseline.render(); m_profile.profile.render(); shader->stop_using(); } } -void GLCanvas3D::LayersEditing::render_volumes(const GLCanvas3D & canvas, const GLVolumeCollection & volumes)//render volume and layer height texture (has mapping relation with each other) +void GLCanvas3D::LayersEditing::render_volumes(const GLCanvas3D& canvas, const GLVolumeCollection& volumes) { assert(this->is_allowed()); assert(this->last_object_id != -1); @@ -530,7 +534,7 @@ void GLCanvas3D::LayersEditing::render_volumes(const GLCanvas3D & canvas, const if (current_shader != nullptr) current_shader->stop_using(); - GLShaderProgram* shader = wxGetApp().get_shader("variable_layer_height"); + GLShaderProgram* shader = wxGetApp().get_shader("variable_layer_height_attr"); if (shader == nullptr) return; @@ -544,6 +548,9 @@ void GLCanvas3D::LayersEditing::render_volumes(const GLCanvas3D & canvas, const shader->set_uniform("z_cursor", float(m_object_max_z) * float(this->get_cursor_z_relative(canvas))); shader->set_uniform("z_cursor_band_width", float(this->band_width)); + const Camera& camera = wxGetApp().plater()->get_camera(); + shader->set_uniform("projection_matrix", camera.get_projection_matrix()); + // Initialize the layer height texture mapping. const GLsizei w = (GLsizei)m_layers_texture.width; const GLsizei h = (GLsizei)m_layers_texture.height; @@ -562,6 +569,9 @@ void GLCanvas3D::LayersEditing::render_volumes(const GLCanvas3D & canvas, const shader->set_uniform("volume_world_matrix", glvolume->world_matrix()); shader->set_uniform("object_max_z", 0.0f); + const Transform3d view_model_matrix = camera.get_view_matrix() * glvolume->world_matrix(); + shader->set_uniform("view_model_matrix", view_model_matrix); + shader->set_uniform("normal_matrix", (Matrix3d)view_model_matrix.matrix().block(0, 0, 3, 3).inverse().transpose()); glvolume->render(); } @@ -883,7 +893,7 @@ void GLCanvas3D::SequentialPrintClearance::set_polygons(const Polygons& polygons if (!polygons.empty()) { if (m_render_fill) { GLModel::Geometry fill_data; - fill_data.format = { GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3, GLModel::Geometry::EIndexType::UINT }; + fill_data.format = { GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3 }; fill_data.color = { 0.8f, 0.8f, 1.0f, 0.5f }; // vertices + indices @@ -897,7 +907,7 @@ void GLCanvas3D::SequentialPrintClearance::set_polygons(const Polygons& polygons fill_data.add_vertex((Vec3f)(v.cast() + 0.0125f * Vec3f::UnitZ())); // add a small positive z to avoid z-fighting ++vertices_counter; if (vertices_counter % 3 == 0) - fill_data.add_uint_triangle(vertices_counter - 3, vertices_counter - 2, vertices_counter - 1); + fill_data.add_triangle(vertices_counter - 3, vertices_counter - 2, vertices_counter - 1); } } @@ -910,7 +920,7 @@ void GLCanvas3D::SequentialPrintClearance::set_polygons(const Polygons& polygons //BBS: add the height limit compute logic if (!height_polygons.empty()) { GLModel::Geometry height_fill_data; - height_fill_data.format = { GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3, GLModel::Geometry::EIndexType::UINT }; + height_fill_data.format = { GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3 }; height_fill_data.color = {0.8f, 0.8f, 1.0f, 0.5f}; // vertices + indices @@ -923,7 +933,7 @@ void GLCanvas3D::SequentialPrintClearance::set_polygons(const Polygons& polygons height_fill_data.add_vertex(point); ++vertices_counter; if (vertices_counter % 3 == 0) - height_fill_data.add_uint_triangle(vertices_counter - 3, vertices_counter - 2, vertices_counter - 1); + height_fill_data.add_triangle(vertices_counter - 3, vertices_counter - 2, vertices_counter - 1); } } @@ -936,12 +946,16 @@ void GLCanvas3D::SequentialPrintClearance::render() const ColorRGBA FILL_COLOR = { 0.7f, 0.7f, 1.0f, 0.5f }; const ColorRGBA NO_FILL_COLOR = { 0.75f, 0.75f, 0.75f, 0.75f }; - GLShaderProgram* shader = wxGetApp().get_shader("flat"); + GLShaderProgram* shader = wxGetApp().get_shader("flat_attr"); if (shader == nullptr) return; shader->start_using(); + const Camera& camera = wxGetApp().plater()->get_camera(); + shader->set_uniform("view_model_matrix", camera.get_view_matrix()); + shader->set_uniform("projection_matrix", camera.get_projection_matrix()); + glsafe(::glEnable(GL_DEPTH_TEST)); glsafe(::glDisable(GL_CULL_FACE)); glsafe(::glEnable(GL_BLEND)); @@ -1839,9 +1853,9 @@ void GLCanvas3D::render(bool only_init) _render_sla_slices(); _render_selection(); if (!no_partplate) - _render_bed(!camera.is_looking_downward(), show_axes); + _render_bed(camera.get_view_matrix(), camera.get_projection_matrix(), !camera.is_looking_downward(), show_axes); if (!no_partplate) //BBS: add outline logic - _render_platelist(!camera.is_looking_downward(), only_current, only_body, hover_id, true); + _render_platelist(camera.get_view_matrix(), camera.get_projection_matrix(), !camera.is_looking_downward(), only_current, only_body, hover_id, true); _render_objects(GLVolumeCollection::ERenderType::Transparent, !m_gizmos.is_running()); } /* preview render */ @@ -1849,8 +1863,8 @@ void GLCanvas3D::render(bool only_init) _render_objects(GLVolumeCollection::ERenderType::Opaque, !m_gizmos.is_running()); _render_sla_slices(); _render_selection(); - _render_bed(!camera.is_looking_downward(), show_axes); - _render_platelist(!camera.is_looking_downward(), only_current, true, hover_id); + _render_bed(camera.get_view_matrix(), camera.get_projection_matrix(), !camera.is_looking_downward(), show_axes); + _render_platelist(camera.get_view_matrix(), camera.get_projection_matrix(), !camera.is_looking_downward(), only_current, true, hover_id); // BBS: GUI refactor: add canvas size as parameters _render_gcode(cnv_size.get_width(), cnv_size.get_height()); } @@ -1858,7 +1872,7 @@ void GLCanvas3D::render(bool only_init) else if (m_canvas_type == ECanvasType::CanvasAssembleView) { //BBS: add outline logic _render_objects(GLVolumeCollection::ERenderType::Opaque, !m_gizmos.is_running()); - //_render_bed(!camera.is_looking_downward(), show_axes); + //_render_bed(camera.get_view_matrix(), camera.get_projection_matrix(), !camera.is_looking_downward(), show_axes); _render_plane(); //BBS: add outline logic insteadof selection under assemble view //_render_selection(); @@ -1992,7 +2006,7 @@ void GLCanvas3D::render_thumbnail(ThumbnailData& thumbnail_data, unsigned int w, void GLCanvas3D::render_thumbnail(ThumbnailData& thumbnail_data, unsigned int w, unsigned int h, const ThumbnailsParams& thumbnail_params, const GLVolumeCollection& volumes, Camera::EType camera_type, bool use_top_view, bool for_picking) { - GLShaderProgram* shader = wxGetApp().get_shader("thumbnail"); + GLShaderProgram* shader = wxGetApp().get_shader("thumbnail_attr"); ModelObjectPtrs& model_objects = GUI::wxGetApp().model().objects; std::vector colors = ::get_extruders_colors(); switch (OpenGLManager::get_framebuffers_type()) @@ -5180,7 +5194,7 @@ bool GLCanvas3D::_render_orient_menu(float left, float right, float bottom, floa //original use center as {0.0}, and top is (canvas_h/2), bottom is (-canvas_h/2), also plus inv_camera //now change to left_up as {0,0}, and top is 0, bottom is canvas_h #if BBS_TOOLBAR_ON_TOP - const float x = left * float(wxGetApp().plater()->get_camera().get_zoom()) + 0.5f * canvas_w; + const float x = (1 + left) * canvas_w / 2; ImGuiWrapper::push_toolbar_style(get_scale()); imgui->set_next_window_pos(x, m_main_toolbar.get_height(), ImGuiCond_Always, 0.5f, 0.0f); #else @@ -5265,9 +5279,8 @@ bool GLCanvas3D::_render_arrange_menu(float left, float right, float bottom, flo //original use center as {0.0}, and top is (canvas_h/2), bottom is (-canvas_h/2), also plus inv_camera //now change to left_up as {0,0}, and top is 0, bottom is canvas_h #if BBS_TOOLBAR_ON_TOP - float zoom = (float)wxGetApp().plater()->get_camera().get_zoom(); float left_pos = m_main_toolbar.get_item("arrange")->render_left_pos; - const float x = 0.5 * canvas_w + left_pos * zoom; + const float x = (1 + left_pos) * canvas_w / 2; imgui->set_next_window_pos(x, m_main_toolbar.get_height(), ImGuiCond_Always, 0.0f, 0.0f); #else @@ -5536,19 +5549,15 @@ void GLCanvas3D::render_thumbnail_internal(ThumbnailData& thumbnail_data, const } else { camera.zoom_to_box(volumes_box); - const Vec3d& target = camera.get_target(); - double distance = camera.get_distance(); camera.select_view("iso"); - camera.apply_view_matrix(); - - camera.apply_projection(plate_build_volume); } - camera.apply_view_matrix(); + const Transform3d &view_matrix = camera.get_view_matrix(); + camera.apply_projection(plate_build_volume); - //GLShaderProgram* shader = wxGetApp().get_shader("gouraud_light"); + //GLShaderProgram* shader = wxGetApp().get_shader("gouraud_light_attr"); if (!for_picking && (shader == nullptr)) { BOOST_LOG_TRIVIAL(info) << boost::format("render_thumbnail with no picking: shader is null, return directly"); return; @@ -5561,6 +5570,8 @@ void GLCanvas3D::render_thumbnail_internal(ThumbnailData& thumbnail_data, const glsafe(::glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)); glsafe(::glEnable(GL_DEPTH_TEST)); + const Transform3d &projection_matrix = camera.get_projection_matrix(); + if (for_picking) { //if (OpenGLManager::can_multisample()) // This flag is often ignored by NVIDIA drivers if rendering into a screen buffer. @@ -5573,9 +5584,6 @@ void GLCanvas3D::render_thumbnail_internal(ThumbnailData& thumbnail_data, const // do not cull backfaces to show broken geometry, if any glsafe(::glDisable(GL_CULL_FACE)); - //glsafe(::glEnableClientState(GL_VERTEX_ARRAY)); - //glsafe(::glEnableClientState(GL_NORMAL_ARRAY)); - for (GLVolume* vol : visible_volumes) { // Object picking mode. Render the object with a color encoding the object index. // we reserve color = (0,0,0) for occluders (as the printbed) @@ -5587,15 +5595,19 @@ void GLCanvas3D::render_thumbnail_internal(ThumbnailData& thumbnail_data, const unsigned int g = (id & (0x000000FF << 8)) >> 8; unsigned int b = (id & (0x000000FF << 16)) >> 16; unsigned int a = 0xFF; - glsafe(::glColor4f((GLfloat)r * INV_255, (GLfloat)g * INV_255, (GLfloat)b * INV_255, (GLfloat)a * INV_255)); + vol->model.set_color({(GLfloat)r * INV_255, (GLfloat)g * INV_255, (GLfloat)b * INV_255, (GLfloat)a * INV_255}); /*curr_color[0] = (GLfloat)r * INV_255; curr_color[1] = (GLfloat)g * INV_255; curr_color[2] = (GLfloat)b * INV_255; curr_color[3] = (GLfloat)a * INV_255; shader->set_uniform("uniform_color", curr_color);*/ - bool is_active = vol->is_active; + const bool is_active = vol->is_active; vol->is_active = true; + const Transform3d matrix = view_matrix * vol->world_matrix(); + shader->set_uniform("view_model_matrix", matrix); + shader->set_uniform("projection_matrix", projection_matrix); + shader->set_uniform("normal_matrix", (Matrix3d) matrix.matrix().block(0, 0, 3, 3).inverse().transpose()); vol->simple_render(nullptr, model_objects, extruder_colors); vol->is_active = is_active; } @@ -5627,8 +5639,12 @@ void GLCanvas3D::render_thumbnail_internal(ThumbnailData& thumbnail_data, const shader->set_uniform("uniform_color", (vol->printable && !vol->is_outside) ? orange : gray); }*/ // the volume may have been deactivated by an active gizmo - bool is_active = vol->is_active; + const bool is_active = vol->is_active; vol->is_active = true; + const Transform3d matrix = view_matrix * vol->world_matrix(); + shader->set_uniform("view_model_matrix", matrix); + shader->set_uniform("projection_matrix", projection_matrix); + shader->set_uniform("normal_matrix", (Matrix3d) matrix.matrix().block(0, 0, 3, 3).inverse().transpose()); vol->simple_render(shader, model_objects, extruder_colors); vol->is_active = is_active; } @@ -6404,7 +6420,8 @@ void GLCanvas3D::_picking_pass() //BBS: only render plate in view 3D if (m_canvas_type == ECanvasType::CanvasView3D) { - _render_plates_for_picking(); + const Camera &camera = wxGetApp().plater()->get_camera(); + _render_plates_for_picking(camera.get_view_matrix(), camera.get_projection_matrix()); } m_camera_clipping_plane = m_gizmos.get_clipping_plane(); @@ -6574,12 +6591,6 @@ void GLCanvas3D::_render_background() } } - glsafe(::glPushMatrix()); - glsafe(::glLoadIdentity()); - glsafe(::glMatrixMode(GL_PROJECTION)); - glsafe(::glPushMatrix()); - glsafe(::glLoadIdentity()); - // Draws a bottom to top gradient over the complete screen. glsafe(::glDisable(GL_DEPTH_TEST)); @@ -6591,7 +6602,7 @@ void GLCanvas3D::_render_background() m_background.reset(); GLModel::Geometry init_data; - init_data.format = { GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P2T2, GLModel::Geometry::EIndexType::USHORT }; + init_data.format = { GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P2T2 }; init_data.reserve_vertices(4); init_data.reserve_indices(6); @@ -6602,30 +6613,25 @@ void GLCanvas3D::_render_background() init_data.add_vertex(Vec2f(-1.0f, 1.0f), Vec2f(0.0f, 1.0f)); // indices - init_data.add_ushort_triangle(0, 1, 2); - init_data.add_ushort_triangle(2, 3, 0); + init_data.add_triangle(0, 1, 2); + init_data.add_triangle(2, 3, 0); m_background.init_from(std::move(init_data)); } - GLShaderProgram* shader = wxGetApp().get_shader("background"); + GLShaderProgram* shader = wxGetApp().get_shader("background_attr"); if (shader != nullptr) { shader->start_using(); shader->set_uniform("top_color", use_error_color ? ERROR_BG_LIGHT_COLOR : DEFAULT_BG_LIGHT_COLOR); shader->set_uniform("bottom_color", bottom_color); - m_background.render(); shader->stop_using(); } glsafe(::glEnable(GL_DEPTH_TEST)); - - glsafe(::glPopMatrix()); - glsafe(::glMatrixMode(GL_MODELVIEW)); - glsafe(::glPopMatrix()); } -void GLCanvas3D::_render_bed(bool bottom, bool show_axes) +void GLCanvas3D::_render_bed(const Transform3d& view_matrix, const Transform3d& projection_matrix, bool bottom, bool show_axes) { float scale_factor = 1.0; #if ENABLE_RETINA_GL @@ -6643,27 +6649,27 @@ void GLCanvas3D::_render_bed(bool bottom, bool show_axes) //bool show_texture = true; //BBS set axes mode m_bed.set_axes_mode(m_main_toolbar.is_enabled()); - m_bed.render(*this, bottom, scale_factor, show_axes); + m_bed.render(*this, view_matrix, projection_matrix, bottom, scale_factor, show_axes); } -void GLCanvas3D::_render_bed_for_picking(bool bottom) +void GLCanvas3D::_render_bed_for_picking(const Transform3d& view_matrix, const Transform3d& projection_matrix, bool bottom) { float scale_factor = 1.0; #if ENABLE_RETINA_GL scale_factor = m_retina_helper->get_scale_factor(); #endif // ENABLE_RETINA_GL - //m_bed.render_for_picking(*this, bottom, scale_factor); + //m_bed.render_for_picking(*this, view_matrix, projection_matrix, bottom, scale_factor); } -void GLCanvas3D::_render_platelist(bool bottom, bool only_current, bool only_body, int hover_id, bool render_cali) const +void GLCanvas3D::_render_platelist(const Transform3d& view_matrix, const Transform3d& projection_matrix, bool bottom, bool only_current, bool only_body, int hover_id, bool render_cali) { - wxGetApp().plater()->get_partplate_list().render(bottom, only_current, only_body, hover_id, render_cali); + wxGetApp().plater()->get_partplate_list().render(view_matrix, projection_matrix, bottom, only_current, only_body, hover_id, render_cali); } -void GLCanvas3D::_render_plates_for_picking() const +void GLCanvas3D::_render_plates_for_picking(const Transform3d &view_matrix, const Transform3d &projection_matrix) { - wxGetApp().plater()->get_partplate_list().render_for_picking_pass(); + wxGetApp().plater()->get_partplate_list().render_for_picking_pass(view_matrix, projection_matrix); } void GLCanvas3D::_render_plane() const @@ -6736,7 +6742,7 @@ void GLCanvas3D::_render_objects(GLVolumeCollection::ERenderType type, bool with else m_volumes.set_show_sinking_contours(!m_gizmos.is_hiding_instances()); - GLShaderProgram* shader = wxGetApp().get_shader("gouraud"); + GLShaderProgram* shader = wxGetApp().get_shader("gouraud_attr"); ECanvasType canvas_type = this->m_canvas_type; if (shader != nullptr) { shader->start_using(); @@ -6751,10 +6757,11 @@ void GLCanvas3D::_render_objects(GLVolumeCollection::ERenderType type, bool with { if (m_picking_enabled && m_layers_editing.is_enabled() && (m_layers_editing.last_object_id != -1) && (m_layers_editing.object_max_z() > 0.0f)) { int object_id = m_layers_editing.last_object_id; - m_volumes.render(type, false, wxGetApp().plater()->get_camera().get_view_matrix(), [object_id](const GLVolume& volume) { - // Which volume to paint without the layer height profile shader? - return volume.is_active && (volume.is_modifier || volume.composite_id.object_id != object_id); - }); + const Camera& camera = wxGetApp().plater()->get_camera(); + m_volumes.render(type, false, camera.get_view_matrix(), camera.get_projection_matrix(), [object_id](const GLVolume& volume) { + // Which volume to paint without the layer height profile shader? + return volume.is_active && (volume.is_modifier || volume.composite_id.object_id != object_id); + }); m_layers_editing.render_volumes(*this, m_volumes); } else { @@ -6766,7 +6773,8 @@ void GLCanvas3D::_render_objects(GLVolumeCollection::ERenderType type, bool with }*/ //BBS:add assemble view related logic // do not cull backfaces to show broken geometry, if any - m_volumes.render(type, m_picking_enabled, wxGetApp().plater()->get_camera().get_view_matrix(), [this, canvas_type](const GLVolume& volume) { + const Camera& camera = wxGetApp().plater()->get_camera(); + m_volumes.render(type, m_picking_enabled, camera.get_view_matrix(), camera.get_projection_matrix(), [this, canvas_type](const GLVolume& volume) { if (canvas_type == ECanvasType::CanvasAssembleView) { return !volume.is_modifier && !volume.is_wipe_tower; } @@ -6798,8 +6806,9 @@ void GLCanvas3D::_render_objects(GLVolumeCollection::ERenderType type, bool with else shader->set_uniform("show_wireframe", false); }*/ + const Camera& camera = wxGetApp().plater()->get_camera(); //BBS:add assemble view related logic - m_volumes.render(type, false, wxGetApp().plater()->get_camera().get_view_matrix(), [this, canvas_type](const GLVolume& volume) { + m_volumes.render(type, false, camera.get_view_matrix(), camera.get_projection_matrix(), [this, canvas_type](const GLVolume& volume) { if (canvas_type == ECanvasType::CanvasAssembleView) { return !volume.is_modifier; } @@ -7171,16 +7180,13 @@ void GLCanvas3D::_render_style_editor() void GLCanvas3D::_render_volumes_for_picking() const { - GLShaderProgram* shader = wxGetApp().get_shader("flat"); + GLShaderProgram* shader = wxGetApp().get_shader("flat_attr"); if (shader == nullptr) return; // do not cull backfaces to show broken geometry, if any glsafe(::glDisable(GL_CULL_FACE)); - glsafe(::glEnableClientState(GL_VERTEX_ARRAY)); - glsafe(::glEnableClientState(GL_NORMAL_ARRAY)); - const Transform3d& view_matrix = wxGetApp().plater()->get_camera().get_view_matrix(); for (size_t type = 0; type < 2; ++ type) { GLVolumeWithIdAndZList to_render = volumes_to_render(m_volumes.volumes, (type == 0) ? GLVolumeCollection::ERenderType::Opaque : GLVolumeCollection::ERenderType::Transparent, view_matrix); @@ -7194,14 +7200,14 @@ void GLCanvas3D::_render_volumes_for_picking() const //const unsigned int id = 1 + volume.second.first; volume.first->model.set_color(picking_decode(id)); shader->start_using(); + const Camera& camera = wxGetApp().plater()->get_camera(); + shader->set_uniform("view_model_matrix", camera.get_view_matrix() * volume.first->world_matrix()); + shader->set_uniform("projection_matrix", camera.get_projection_matrix()); volume.first->render(); shader->stop_using(); } } - glsafe(::glDisableClientState(GL_NORMAL_ARRAY)); - glsafe(::glDisableClientState(GL_VERTEX_ARRAY)); - glsafe(::glEnable(GL_CULL_FACE)); } @@ -7241,32 +7247,19 @@ void GLCanvas3D::_render_main_toolbar() if (!m_main_toolbar.is_enabled()) return; - Size cnv_size = get_canvas_size(); - float inv_zoom = (float)wxGetApp().plater()->get_camera().get_inv_zoom(); + const Size cnv_size = get_canvas_size(); + const float top = 0.5f * (float)cnv_size.get_height(); -#if BBS_TOOLBAR_ON_TOP GLToolbar& collapse_toolbar = wxGetApp().plater()->get_collapse_toolbar(); - float collapse_toolbar_width = collapse_toolbar.is_enabled() ? collapse_toolbar.get_width() : 0.0f; - float gizmo_width = m_gizmos.get_scaled_total_width(); - float assemble_width = m_assemble_view_toolbar.get_width(); - float separator_width = m_separator_toolbar.get_width(); - float top = 0.5f * (float)cnv_size.get_height() * inv_zoom; - float left = std::max(-0.5f * cnv_size.get_width(), -0.5f * (m_main_toolbar.get_width() + separator_width + gizmo_width + assemble_width - collapse_toolbar_width)) * inv_zoom; -#else - float gizmo_height = m_gizmos.get_scaled_total_height(); - float space_height = GLGizmosManager::Default_Icons_Size * wxGetApp().toolbar_icon_scale(); - float main_toolbar_height = (float)m_main_toolbar.get_height(); - float assemble_height = m_assemble_view_toolbar.get_height(); - float top = 0.5f * (main_toolbar_height + gizmo_height + assemble_height) * inv_zoom; - float left = (0.5f * (float)cnv_size.get_width() - m_main_toolbar.get_width()) * inv_zoom; - //BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(": top %1%, main_toolbar_height %2%, space_height %3% gizmo_height %4%") % top % main_toolbar_height % space_height % gizmo_height; -#endif + const float collapse_toolbar_width = collapse_toolbar.is_enabled() ? collapse_toolbar.get_width() : 0.0f; + const float gizmo_width = m_gizmos.get_scaled_total_width(); + const float assemble_width = m_assemble_view_toolbar.get_width(); + const float separator_width = m_separator_toolbar.get_width(); + const float left = std::max(-0.5f * cnv_size.get_width(), -0.5f * (m_main_toolbar.get_width() + separator_width + gizmo_width + assemble_width - collapse_toolbar_width)); m_main_toolbar.set_position(top, left); m_main_toolbar.render(*this); if (m_toolbar_highlighter.m_render_arrow) - { m_main_toolbar.render_arrow(*this, m_toolbar_highlighter.m_toolbar_item); - } } //BBS: GUI refactor: GLToolbar adjust @@ -7591,28 +7584,16 @@ void GLCanvas3D::_render_assemble_view_toolbar() const if (!m_assemble_view_toolbar.is_enabled()) return; - Size cnv_size = get_canvas_size(); - float inv_zoom = (float)wxGetApp().plater()->get_camera().get_inv_zoom(); - -#if BBS_TOOLBAR_ON_TOP + const Size cnv_size = get_canvas_size(); GLToolbar& collapse_toolbar = wxGetApp().plater()->get_collapse_toolbar(); - float collapse_toolbar_width = collapse_toolbar.is_enabled() ? collapse_toolbar.get_width() : 0.0f; - float gizmo_width = m_gizmos.get_scaled_total_width(); - float assemble_width = m_assemble_view_toolbar.get_width(); - float separator_width = m_separator_toolbar.get_width(); - float top = 0.5f * (float)cnv_size.get_height() * inv_zoom; - float main_toolbar_left = std::max(-0.5f * cnv_size.get_width(), -0.5f * (m_main_toolbar.get_width() + gizmo_width + assemble_width - separator_width - collapse_toolbar_width)) * inv_zoom; - float left = main_toolbar_left + (m_main_toolbar.get_width() + gizmo_width) * inv_zoom; - //float left = 0.5f * (m_main_toolbar.get_width() + gizmo_width - m_assemble_view_toolbar.get_width() + collapse_toolbar_width) * inv_zoom; -#else - float gizmo_height = m_gizmos.get_scaled_total_height(); - //float space_height = GLGizmosManager::Default_Icons_Size * wxGetApp().toolbar_icon_scale(); - float main_toolbar_height = (float)m_main_toolbar.get_height(); - float assemble_height = (float)m_assemble_view_toolbar.get_height(); - float top = 0.5f * (assemble_height - main_toolbar_height - gizmo_height) * inv_zoom; - float left = (0.5f * (float)cnv_size.get_width() - m_assemble_view_toolbar.get_width()) * inv_zoom; - //BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(": top %1%, main_toolbar_height %2%, space_height %3% gizmo_height %4%") % top % main_toolbar_height % space_height % gizmo_height; -#endif + const float collapse_toolbar_width = collapse_toolbar.is_enabled() ? collapse_toolbar.get_width() : 0.0f; + const float gizmo_width = m_gizmos.get_scaled_total_width(); + const float assemble_width = m_assemble_view_toolbar.get_width(); + const float separator_width = m_separator_toolbar.get_width(); + const float top = 0.5f * (float)cnv_size.get_height(); + const float main_toolbar_left = std::max(-0.5f * cnv_size.get_width(), -0.5f * (m_main_toolbar.get_width() + gizmo_width + assemble_width + separator_width - collapse_toolbar_width)); + const float left = main_toolbar_left + (m_main_toolbar.get_width() + gizmo_width + separator_width); + m_assemble_view_toolbar.set_position(top, left); m_assemble_view_toolbar.render(*this); } @@ -7677,17 +7658,15 @@ void GLCanvas3D::_render_separator_toolbar_right() const if (!m_separator_toolbar.is_enabled()) return; - Size cnv_size = get_canvas_size(); - float inv_zoom = (float)wxGetApp().plater()->get_camera().get_inv_zoom(); - + const Size cnv_size = get_canvas_size(); GLToolbar& collapse_toolbar = wxGetApp().plater()->get_collapse_toolbar(); - float collapse_toolbar_width = collapse_toolbar.is_enabled() ? collapse_toolbar.get_width() : 0.0f; - float gizmo_width = m_gizmos.get_scaled_total_width(); - float assemble_width = m_assemble_view_toolbar.get_width(); - float separator_width = m_separator_toolbar.get_width(); - float top = 0.5f * (float)cnv_size.get_height() * inv_zoom; - float main_toolbar_left = std::max(-0.5f * cnv_size.get_width(), -0.5f * (m_main_toolbar.get_width() + gizmo_width + assemble_width - collapse_toolbar_width)) * inv_zoom; - float left = main_toolbar_left + (m_main_toolbar.get_width() + gizmo_width) * inv_zoom; + const float collapse_toolbar_width = collapse_toolbar.is_enabled() ? collapse_toolbar.get_width() : 0.0f; + const float gizmo_width = m_gizmos.get_scaled_total_width(); + const float assemble_width = m_assemble_view_toolbar.get_width(); + const float separator_width = m_separator_toolbar.get_width(); + const float top = 0.5f * (float)cnv_size.get_height(); + const float main_toolbar_left = std::max(-0.5f * cnv_size.get_width(), -0.5f * (m_main_toolbar.get_width() + gizmo_width + assemble_width + separator_width - collapse_toolbar_width)); + const float left = main_toolbar_left + (m_main_toolbar.get_width() + gizmo_width + separator_width / 2); m_separator_toolbar.set_position(top, left); m_separator_toolbar.render(*this,GLToolbarItem::SeparatorLine); @@ -7698,17 +7677,15 @@ void GLCanvas3D::_render_separator_toolbar_left() const if (!m_separator_toolbar.is_enabled()) return; - Size cnv_size = get_canvas_size(); - float inv_zoom = (float)wxGetApp().plater()->get_camera().get_inv_zoom(); - + const Size cnv_size = get_canvas_size(); GLToolbar& collapse_toolbar = wxGetApp().plater()->get_collapse_toolbar(); - float collapse_toolbar_width = collapse_toolbar.is_enabled() ? collapse_toolbar.get_width() : 0.0f; - float gizmo_width = m_gizmos.get_scaled_total_width(); - float assemble_width = m_assemble_view_toolbar.get_width(); - float separator_width = m_separator_toolbar.get_width(); - float top = 0.5f * (float)cnv_size.get_height() * inv_zoom; - float main_toolbar_left = std::max(-0.5f * cnv_size.get_width(), -0.5f * (m_main_toolbar.get_width() + gizmo_width + assemble_width + separator_width - collapse_toolbar_width)) * inv_zoom; - float left = main_toolbar_left + (m_main_toolbar.get_width()) * inv_zoom; + const float collapse_toolbar_width = collapse_toolbar.is_enabled() ? collapse_toolbar.get_width() : 0.0f; + const float gizmo_width = m_gizmos.get_scaled_total_width(); + const float assemble_width = m_assemble_view_toolbar.get_width(); + const float separator_width = m_separator_toolbar.get_width(); + const float top = 0.5f * (float)cnv_size.get_height(); + const float main_toolbar_left = std::max(-0.5f * cnv_size.get_width(), -0.5f * (m_main_toolbar.get_width() + gizmo_width + assemble_width + separator_width - collapse_toolbar_width)); + const float left = main_toolbar_left + (m_main_toolbar.get_width()); m_separator_toolbar.set_position(top, left); m_separator_toolbar.render(*this,GLToolbarItem::SeparatorLine); @@ -7718,12 +7695,10 @@ void GLCanvas3D::_render_collapse_toolbar() const { GLToolbar& collapse_toolbar = wxGetApp().plater()->get_collapse_toolbar(); - Size cnv_size = get_canvas_size(); - float inv_zoom = (float)wxGetApp().plater()->get_camera().get_inv_zoom(); - - float top = 0.5f * (float)cnv_size.get_height() * inv_zoom; - //float left = (0.5f * (float)cnv_size.get_width() - (float)collapse_toolbar.get_width() - band) * inv_zoom; - float left = -0.5f * (float)cnv_size.get_width() * inv_zoom; + const Size cnv_size = get_canvas_size(); + const float top = 0.5f * (float)cnv_size.get_height(); + //const float left = (0.5f * (float)cnv_size.get_width() - (float)collapse_toolbar.get_width() - band); + const float left = -0.5f * (float)cnv_size.get_width(); collapse_toolbar.set_position(top, left); collapse_toolbar.render(*this); @@ -8002,52 +7977,51 @@ void GLCanvas3D::_render_assemble_info() const #if ENABLE_SHOW_CAMERA_TARGET void GLCanvas3D::_render_camera_target() { - static const double half_length = 5.0; + static const float half_length = 5.0f; glsafe(::glDisable(GL_DEPTH_TEST)); glsafe(::glLineWidth(2.0f)); - const Vec3d& target = wxGetApp().plater()->get_camera().get_target(); - bool target_changed = !m_camera_target.target.isApprox(target); - m_camera_target.target = target; + const Vec3f& target = wxGetApp().plater()->get_camera().get_target().cast(); + bool target_changed = !m_camera_target.target.isApprox(target.cast()); + m_camera_target.target = target.cast(); for (int i = 0; i < 3; ++i) { if (!m_camera_target.axis[i].is_initialized() || target_changed) { m_camera_target.axis[i].reset(); - GLModel::InitializationData init_data; - GLModel::InitializationData::Entity entity; - entity.type = GLModel::PrimitiveType::Lines; - entity.positions.reserve(2); + GLModel::Geometry init_data; + init_data.format = { GLModel::Geometry::EPrimitiveType::Lines, GLModel::Geometry::EVertexLayout::P3, GLModel::Geometry::EIndexType::USHORT }; + init_data.color = (i == X) ? ColorRGBA::X() : ((i == Y) ? ColorRGBA::Y() : ColorRGBA::Z()); + init_data.reserve_vertices(2); + init_data.reserve_indices(2); + + // vertices if (i == X) { - entity.positions.emplace_back(target.x() - half_length, target.y(), target.z()); - entity.positions.emplace_back(target.x() + half_length, target.y(), target.z()); + init_data.add_vertex(Vec3f(target.x() - half_length, target.y(), target.z())); + init_data.add_vertex(Vec3f(target.x() + half_length, target.y(), target.z())); } else if (i == Y) { - entity.positions.emplace_back(target.x(), target.y() - half_length, target.z()); - entity.positions.emplace_back(target.x(), target.y() + half_length, target.z()); + init_data.add_vertex(Vec3f(target.x(), target.y() - half_length, target.z())); + init_data.add_vertex(Vec3f(target.x(), target.y() + half_length, target.z())); } else { - entity.positions.emplace_back(target.x(), target.y(), target.z() - half_length); - entity.positions.emplace_back(target.x(), target.y(), target.z() + half_length); - } - entity.normals.reserve(2); - for (size_t j = 0; j < 2; ++j) { - entity.normals.emplace_back(Vec3f::UnitZ()); + init_data.add_vertex(Vec3f(target.x(), target.y(), target.z() - half_length)); + init_data.add_vertex(Vec3f(target.x(), target.y(), target.z() + half_length)); } - entity.indices.reserve(2); - entity.indices.emplace_back(0); - entity.indices.emplace_back(1); + // indices + init_data.add_line(0, 1); - init_data.entities.emplace_back(entity); - m_camera_target.axis[i].init_from(init_data); - m_camera_target.axis[i].set_color(-1, (i == X) ? ColorRGBA::X() : (i == Y) ? ColorRGBA::Y() : ColorRGBA::Z()); + m_camera_target.axis[i].init_from(std::move(init_data)); } } - GLShaderProgram* shader = wxGetApp().get_shader("flat"); + GLShaderProgram* shader = wxGetApp().get_shader("flat_attr"); if (shader != nullptr) { shader->start_using(); + const Camera& camera = wxGetApp().plater()->get_camera(); + shader->set_uniform("view_model_matrix", camera.get_view_matrix()); + shader->set_uniform("projection_matrix", camera.get_projection_matrix()); for (int i = 0; i < 3; ++i) { m_camera_target.axis[i].render(); } @@ -8100,7 +8074,7 @@ void GLCanvas3D::_render_sla_slices() auto init_model = [](GLModel& model, const Pointf3s& triangles, const ColorRGBA& color) { GLModel::Geometry init_data; - init_data.format = { GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3, GLModel::Geometry::index_type(triangles.size()) }; + init_data.format = { GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3 }; init_data.reserve_vertices(triangles.size()); init_data.reserve_indices(triangles.size() / 3); init_data.color = color; @@ -8110,10 +8084,7 @@ void GLCanvas3D::_render_sla_slices() init_data.add_vertex((Vec3f)v.cast()); ++vertices_count; if (vertices_count % 3 == 0) { - if (init_data.format.index_type == GLModel::Geometry::EIndexType::USHORT) - init_data.add_ushort_triangle((unsigned short)vertices_count - 3, (unsigned short)vertices_count - 2, (unsigned short)vertices_count - 1); - else - init_data.add_uint_triangle(vertices_count - 3, vertices_count - 2, vertices_count - 1); + init_data.add_triangle(vertices_count - 3, vertices_count - 2, vertices_count - 1); } } @@ -8164,24 +8135,25 @@ void GLCanvas3D::_render_sla_slices() } } - GLShaderProgram* shader = wxGetApp().get_shader("flat"); + GLShaderProgram* shader = wxGetApp().get_shader("flat_attr"); if (shader != nullptr) { shader->start_using(); for (const SLAPrintObject::Instance& inst : obj->instances()) { - glsafe(::glPushMatrix()); - glsafe(::glTranslated(unscale(inst.shift.x()), unscale(inst.shift.y()), 0.0)); - glsafe(::glRotatef(Geometry::rad2deg(inst.rotation), 0.0f, 0.0f, 1.0f)); - if (obj->is_left_handed()) - // The polygons are mirrored by X. - glsafe(::glScalef(-1.0f, 1.0f, 1.0f)); + const Camera& camera = wxGetApp().plater()->get_camera(); + const Transform3d view_model_matrix = camera.get_view_matrix() * + Geometry::assemble_transform(Vec3d(unscale(inst.shift.x()), unscale(inst.shift.y()), 0.0), + inst.rotation * Vec3d::UnitZ(), Vec3d::Ones(), + obj->is_left_handed() ? Vec3d(-1.0f, 1.0f, 1.0f) : Vec3d::Ones()); + + shader->set_uniform("view_model_matrix", view_model_matrix); + shader->set_uniform("projection_matrix", camera.get_projection_matrix()); bottom_obj_triangles.render(); top_obj_triangles.render(); bottom_sup_triangles.render(); top_sup_triangles.render(); - glsafe(::glPopMatrix()); } shader->stop_using(); @@ -8371,7 +8343,7 @@ void GLCanvas3D::_load_print_toolpaths(const BuildVolume &build_volume) GLVolume* volume = m_volumes.new_toolpath_volume(color); GLModel::Geometry init_data; - init_data.format = { GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3N3, GLModel::Geometry::EIndexType::UINT }; + init_data.format = { GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3N3 }; for (size_t i = 0; i < skirt_height; ++ i) { volume->print_zs.emplace_back(print_zs[i]); volume->offsets.emplace_back(init_data.indices_count()); @@ -8594,7 +8566,7 @@ void GLCanvas3D::_load_print_object_toolpaths(const PrintObject& print_object, c assert(vols.size() == geometries.size()); for (GLModel::Geometry& g : geometries) { - g.format = { GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3N3, GLModel::Geometry::EIndexType::UINT }; + g.format = { GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3N3 }; } for (size_t idx_layer = range.begin(); idx_layer < range.end(); ++ idx_layer) { const Layer *layer = ctxt.layers[idx_layer]; @@ -8793,7 +8765,7 @@ void GLCanvas3D::_load_wipe_tower_toolpaths(const BuildVolume& build_volume, con assert(vols.size() == geometries.size()); for (GLModel::Geometry& g : geometries) { - g.format = { GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3N3, GLModel::Geometry::EIndexType::UINT }; + g.format = { GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3N3 }; } for (size_t idx_layer = range.begin(); idx_layer < range.end(); ++idx_layer) { const std::vector &layer = ctxt.tool_change(idx_layer); diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp index f9103c75cd8..77ad6739474 100644 --- a/src/slic3r/GUI/GLCanvas3D.hpp +++ b/src/slic3r/GUI/GLCanvas3D.hpp @@ -261,9 +261,8 @@ class GLCanvas3D GLModel baseline; GLModel profile; GLModel background; - Rect old_bar_rect; + float old_canvas_width{ 0.0f }; std::vector old_layer_height_profile; - bool dirty{ false }; }; Profile m_profile; @@ -294,7 +293,6 @@ class GLCanvas3D static float get_cursor_z_relative(const GLCanvas3D& canvas); static bool bar_rect_contains(const GLCanvas3D& canvas, float x, float y); static Rect get_bar_rect_screen(const GLCanvas3D& canvas); - static Rect get_bar_rect_viewport(const GLCanvas3D& canvas); static float get_overlay_window_width() { return LayersEditing::s_overlay_window_width; } float object_max_z() const { return m_object_max_z; } @@ -304,8 +302,8 @@ class GLCanvas3D private: bool is_initialized() const; void generate_layer_height_texture(); - void render_active_object_annotations(const GLCanvas3D& canvas, const Rect& bar_rect); - void render_profile(const Rect& bar_rect); + void render_active_object_annotations(const GLCanvas3D& canvas); + void render_profile(const GLCanvas3D& canvas); void update_slicing_parameters(); static float thickness_bar_width(const GLCanvas3D& canvas); @@ -1117,11 +1115,11 @@ class GLCanvas3D void _picking_pass(); void _rectangular_selection_picking_pass(); void _render_background(); - void _render_bed(bool bottom, bool show_axes); - void _render_bed_for_picking(bool bottom); + void _render_bed(const Transform3d& view_matrix, const Transform3d& projection_matrix, bool bottom, bool show_axes); + void _render_bed_for_picking(const Transform3d& view_matrix, const Transform3d& projection_matrix, bool bottom); //BBS: add part plate related logic - void _render_platelist(bool bottom, bool only_current, bool only_body = false, int hover_id = -1, bool render_cali = false) const; - void _render_plates_for_picking() const; + void _render_platelist(const Transform3d& view_matrix, const Transform3d& projection_matrix, bool bottom, bool only_current, bool only_body = false, int hover_id = -1, bool render_cali = false); + void _render_plates_for_picking(const Transform3d& view_matrix, const Transform3d& projection_matrix); //BBS: add outline drawing logic void _render_objects(GLVolumeCollection::ERenderType type, bool with_outline = true); //BBS: GUI refactor: add canvas size as parameters diff --git a/src/slic3r/GUI/GLModel.cpp b/src/slic3r/GUI/GLModel.cpp index 1d2337bc602..94a431f1c81 100644 --- a/src/slic3r/GUI/GLModel.cpp +++ b/src/slic3r/GUI/GLModel.cpp @@ -52,16 +52,6 @@ static void smooth_normals_corner(const TriangleMesh& mesh, std::vector::iterator it = vertices.begin() + id * stride; + const size_t stride = vertex_stride_floats(format); + std::vector::const_iterator it = vertices.begin() + id * stride; vertices.erase(it, it + stride); } } @@ -391,21 +302,17 @@ size_t GLModel::Geometry::tex_coord_offset_floats(const Format& format) }; } -size_t GLModel::Geometry::index_stride_bytes(const Format& format) +size_t GLModel::Geometry::index_stride_bytes(const Geometry& data) { - switch (format.index_type) + switch (data.index_type) { case EIndexType::UINT: { return sizeof(unsigned int); } case EIndexType::USHORT: { return sizeof(unsigned short); } + case EIndexType::UBYTE: { return sizeof(unsigned char); } default: { assert(false); return 0; } }; } -GLModel::Geometry::EIndexType GLModel::Geometry::index_type(size_t vertices_count) -{ - return (vertices_count < 65536) ? EIndexType::USHORT : EIndexType::UINT; -} - bool GLModel::Geometry::has_position(const Format& format) { switch (format.vertex_layout) @@ -491,7 +398,7 @@ void GLModel::init_from(const indexed_triangle_set& its) } Geometry& data = m_render_data.geometry; - data.format = { Geometry::EPrimitiveType::Triangles, Geometry::EVertexLayout::P3N3, GLModel::Geometry::index_type(3 * its.indices.size()) }; + data.format = { Geometry::EPrimitiveType::Triangles, Geometry::EVertexLayout::P3N3 }; data.reserve_vertices(3 * its.indices.size()); data.reserve_indices(3 * its.indices.size()); @@ -505,10 +412,7 @@ void GLModel::init_from(const indexed_triangle_set& its) data.add_vertex(vertex[j], n); } vertices_counter += 3; - if (data.format.index_type == GLModel::Geometry::EIndexType::USHORT) - data.add_ushort_triangle((unsigned short)vertices_counter - 3, (unsigned short)vertices_counter - 2, (unsigned short)vertices_counter - 1); - else - data.add_uint_triangle(vertices_counter - 3, vertices_counter - 2, vertices_counter - 1); + data.add_triangle(vertices_counter - 3, vertices_counter - 2, vertices_counter - 1); } // update bounding box @@ -531,7 +435,7 @@ void GLModel::init_from(const Polygons& polygons, float z) } Geometry& data = m_render_data.geometry; - data.format = { Geometry::EPrimitiveType::Lines, Geometry::EVertexLayout::P3, Geometry::EIndexType::UINT }; + data.format = { Geometry::EPrimitiveType::Lines, Geometry::EVertexLayout::P3 }; size_t segments_count = 0; for (const Polygon& polygon : polygons) { @@ -550,7 +454,7 @@ void GLModel::init_from(const Polygons& polygons, float z) data.add_vertex(Vec3f(unscale(p0.x()), unscale(p0.y()), z)); data.add_vertex(Vec3f(unscale(p1.x()), unscale(p1.y()), z)); vertices_counter += 2; - data.add_uint_line(vertices_counter - 2, vertices_counter - 1); + data.add_line(vertices_counter - 2, vertices_counter - 1); } } @@ -598,7 +502,7 @@ void GLModel::reset() m_render_data.vertices_count = 0; m_render_data.indices_count = 0; m_render_data.geometry.vertices = std::vector(); - m_render_data.geometry.indices = std::vector(); + m_render_data.geometry.indices = std::vector(); m_bounding_box = BoundingBoxf3(); m_filename = std::string(); } @@ -618,13 +522,14 @@ static GLenum get_primitive_mode(const GLModel::Geometry::Format& format) } } -static GLenum get_index_type(const GLModel::Geometry::Format& format) +static GLenum get_index_type(const GLModel::Geometry& data) { - switch (format.index_type) + switch (data.index_type) { default: case GLModel::Geometry::EIndexType::UINT: { return GL_UNSIGNED_INT; } case GLModel::Geometry::EIndexType::USHORT: { return GL_UNSIGNED_SHORT; } + case GLModel::Geometry::EIndexType::UBYTE: { return GL_UNSIGNED_BYTE; } } } @@ -642,7 +547,6 @@ void GLModel::render(const std::pair& range) return; GLShaderProgram* shader = wxGetApp().get_current_shader(); - if (shader == nullptr) return; @@ -655,7 +559,7 @@ void GLModel::render(const std::pair& range) const Geometry& data = m_render_data.geometry; const GLenum mode = get_primitive_mode(data.format); - const GLenum index_type = get_index_type(data.format); + const GLenum index_type = get_index_type(data); const size_t vertex_stride_bytes = Geometry::vertex_stride_bytes(data.format); const bool position = Geometry::has_position(data.format); @@ -664,74 +568,44 @@ void GLModel::render(const std::pair& range) glsafe(::glBindBuffer(GL_ARRAY_BUFFER, m_render_data.vbo_id)); - bool use_attributes = boost::algorithm::iends_with(shader->get_name(), "_attr"); - int position_id = -1; int normal_id = -1; int tex_coord_id = -1; if (position) { - if (use_attributes) { - position_id = shader->get_attrib_location("v_position"); - if (position_id != -1) { - glsafe(::glVertexAttribPointer(position_id, Geometry::position_stride_floats(data.format), GL_FLOAT, GL_FALSE, vertex_stride_bytes, (GLvoid*)Geometry::position_offset_bytes(data.format))); - glsafe(::glEnableVertexAttribArray(position_id)); - } - } - else { - glsafe(::glVertexPointer(Geometry::position_stride_floats(data.format), GL_FLOAT, vertex_stride_bytes, (const void*)Geometry::position_offset_bytes(data.format))); - glsafe(::glEnableClientState(GL_VERTEX_ARRAY)); + position_id = shader->get_attrib_location("v_position"); + if (position_id != -1) { + glsafe(::glVertexAttribPointer(position_id, Geometry::position_stride_floats(data.format), GL_FLOAT, GL_FALSE, vertex_stride_bytes, (GLvoid*)Geometry::position_offset_bytes(data.format))); + glsafe(::glEnableVertexAttribArray(position_id)); } } if (normal) { - if (use_attributes) { - normal_id = shader->get_attrib_location("v_normal"); - if (normal_id != -1) { - glsafe(::glVertexAttribPointer(normal_id, Geometry::normal_stride_floats(data.format), GL_FLOAT, GL_FALSE, vertex_stride_bytes, (GLvoid*)Geometry::normal_offset_bytes(data.format))); - glsafe(::glEnableVertexAttribArray(normal_id)); - } - } - else { - glsafe(::glNormalPointer(GL_FLOAT, vertex_stride_bytes, (const void*)Geometry::normal_offset_bytes(data.format))); - glsafe(::glEnableClientState(GL_NORMAL_ARRAY)); + normal_id = shader->get_attrib_location("v_normal"); + if (normal_id != -1) { + glsafe(::glVertexAttribPointer(normal_id, Geometry::normal_stride_floats(data.format), GL_FLOAT, GL_FALSE, vertex_stride_bytes, (GLvoid*)Geometry::normal_offset_bytes(data.format))); + glsafe(::glEnableVertexAttribArray(normal_id)); } } if (tex_coord) { - if (use_attributes) { - tex_coord_id = shader->get_attrib_location("v_tex_coord"); - if (tex_coord_id != -1) { - glsafe(::glVertexAttribPointer(tex_coord_id, Geometry::tex_coord_stride_floats(data.format), GL_FLOAT, GL_FALSE, vertex_stride_bytes, (GLvoid*)Geometry::tex_coord_offset_bytes(data.format))); - glsafe(::glEnableVertexAttribArray(tex_coord_id)); - } - } - else { - glsafe(::glTexCoordPointer(Geometry::tex_coord_stride_floats(data.format), GL_FLOAT, vertex_stride_bytes, (const void*)Geometry::tex_coord_offset_bytes(data.format))); - glsafe(::glEnableClientState(GL_TEXTURE_COORD_ARRAY)); + tex_coord_id = shader->get_attrib_location("v_tex_coord"); + if (tex_coord_id != -1) { + glsafe(::glVertexAttribPointer(tex_coord_id, Geometry::tex_coord_stride_floats(data.format), GL_FLOAT, GL_FALSE, vertex_stride_bytes, (GLvoid*)Geometry::tex_coord_offset_bytes(data.format))); + glsafe(::glEnableVertexAttribArray(tex_coord_id)); } } shader->set_uniform("uniform_color", data.color); glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_render_data.ibo_id)); - glsafe(::glDrawElements(mode, range.second - range.first, index_type, (const void*)(range.first * Geometry::index_stride_bytes(data.format)))); + glsafe(::glDrawElements(mode, range.second - range.first, index_type, (const void*)(range.first * Geometry::index_stride_bytes(data)))); glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0)); - if (use_attributes) { - if (tex_coord_id != -1) - glsafe(::glDisableVertexAttribArray(tex_coord_id)); - if (normal_id != -1) - glsafe(::glDisableVertexAttribArray(normal_id)); - if (position_id != -1) - glsafe(::glDisableVertexAttribArray(position_id)); - } - else { - if (tex_coord) - glsafe(::glDisableClientState(GL_TEXTURE_COORD_ARRAY)); - if (normal) - glsafe(::glDisableClientState(GL_NORMAL_ARRAY)); - if (position) - glsafe(::glDisableClientState(GL_VERTEX_ARRAY)); - } + if (tex_coord_id != -1) + glsafe(::glDisableVertexAttribArray(tex_coord_id)); + if (normal_id != -1) + glsafe(::glDisableVertexAttribArray(normal_id)); + if (position_id != -1) + glsafe(::glDisableVertexAttribArray(position_id)); glsafe(::glBindBuffer(GL_ARRAY_BUFFER, 0)); } @@ -742,18 +616,18 @@ void GLModel::render_instanced(unsigned int instances_vbo, unsigned int instance return; GLShaderProgram* shader = wxGetApp().get_current_shader(); - if (shader == nullptr || !boost::algorithm::iends_with(shader->get_name(), "_instanced")) + if (shader == nullptr || !boost::algorithm::iends_with(shader->get_name(), "_instanced_attr")) return; // vertex attributes - GLint position_id = shader->get_attrib_location("v_position"); - GLint normal_id = shader->get_attrib_location("v_normal"); + const GLint position_id = shader->get_attrib_location("v_position"); + const GLint normal_id = shader->get_attrib_location("v_normal"); if (position_id == -1 || normal_id == -1) return; // instance attributes - GLint offset_id = shader->get_attrib_location("i_offset"); - GLint scales_id = shader->get_attrib_location("i_scales"); + const GLint offset_id = shader->get_attrib_location("i_offset"); + const GLint scales_id = shader->get_attrib_location("i_scales"); if (offset_id == -1 || scales_id == -1) return; @@ -773,8 +647,8 @@ void GLModel::render_instanced(unsigned int instances_vbo, unsigned int instance const Geometry& data = m_render_data.geometry; - GLenum mode = get_primitive_mode(data.format); - GLenum index_type = get_index_type(data.format); + const GLenum mode = get_primitive_mode(data.format); + const GLenum index_type = get_index_type(data); shader->set_uniform("uniform_color", data.color); @@ -833,26 +707,36 @@ bool GLModel::send_to_gpu() // indices glsafe(::glGenBuffers(1, &m_render_data.ibo_id)); glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_render_data.ibo_id)); - glsafe(::glBufferData(GL_ELEMENT_ARRAY_BUFFER, data.indices_size_bytes(), data.indices.data(), GL_STATIC_DRAW)); - glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0)); + if (m_render_data.vertices_count <= 256) { + // convert indices to unsigned char to save gpu memory + std::vector reduced_indices(data.indices.size()); + for (size_t i = 0; i < data.indices.size(); ++i) { + reduced_indices[i] = (unsigned char)data.indices[i]; + } + data.index_type = Geometry::EIndexType::UBYTE; + glsafe(::glBufferData(GL_ELEMENT_ARRAY_BUFFER, reduced_indices.size() * sizeof(unsigned char), reduced_indices.data(), GL_STATIC_DRAW)); + glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0)); + } + else if (m_render_data.vertices_count <= 65536) { + // convert indices to unsigned short to save gpu memory + std::vector reduced_indices(data.indices.size()); + for (size_t i = 0; i < data.indices.size(); ++i) { + reduced_indices[i] = (unsigned short)data.indices[i]; + } + data.index_type = Geometry::EIndexType::USHORT; + glsafe(::glBufferData(GL_ELEMENT_ARRAY_BUFFER, reduced_indices.size() * sizeof(unsigned short), reduced_indices.data(), GL_STATIC_DRAW)); + glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0)); + } + else { + glsafe(::glBufferData(GL_ELEMENT_ARRAY_BUFFER, data.indices_size_bytes(), data.indices.data(), GL_STATIC_DRAW)); + glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0)); + } m_render_data.indices_count = indices_count(); - data.indices = std::vector(); + data.indices = std::vector(); return true; } -static void append_vertex(GLModel::Geometry& data, const Vec3f& position, const Vec3f& normal) -{ - data.add_vertex(position, normal); -} - -static void append_triangle(GLModel::Geometry& data, unsigned short v1, unsigned short v2, unsigned short v3) -{ - data.add_ushort_index(v1); - data.add_ushort_index(v2); - data.add_ushort_index(v3); -} - template inline bool all_vertices_inside(const GLModel::Geometry& geometry, Fn fn) { @@ -907,13 +791,12 @@ bool contains(const BuildVolume& volume, const GLModel& model, bool ignore_botto } } -GLModel::Geometry stilized_arrow(unsigned short resolution, float tip_radius, float tip_height, float stem_radius, float stem_height) +GLModel::Geometry stilized_arrow(unsigned int resolution, float tip_radius, float tip_height, float stem_radius, float stem_height) { - resolution = std::max(4, resolution); - resolution = std::min(10922, resolution); // ensure no unsigned short overflow of indices + resolution = std::max(4, resolution); GLModel::Geometry data; - data.format = { GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3N3, GLModel::Geometry::EIndexType::USHORT }; + data.format = { GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3N3 }; data.reserve_vertices(6 * resolution + 2); data.reserve_indices(6 * resolution * 3); @@ -921,7 +804,7 @@ GLModel::Geometry stilized_arrow(unsigned short resolution, float tip_radius, fl std::vector cosines(resolution); std::vector sines(resolution); - for (unsigned short i = 0; i < resolution; ++i) { + for (unsigned int i = 0; i < resolution; ++i) { const float angle = angle_step * float(i); cosines[i] = ::cos(angle); sines[i] = -::sin(angle); @@ -930,75 +813,74 @@ GLModel::Geometry stilized_arrow(unsigned short resolution, float tip_radius, fl const float total_height = tip_height + stem_height; // tip vertices/normals - append_vertex(data, { 0.0f, 0.0f, total_height }, Vec3f::UnitZ()); - for (unsigned short i = 0; i < resolution; ++i) { - append_vertex(data, { tip_radius * sines[i], tip_radius * cosines[i], stem_height }, { sines[i], cosines[i], 0.0f }); + data.add_vertex(Vec3f(0.0f, 0.0f, total_height), (Vec3f)Vec3f::UnitZ()); + for (unsigned int i = 0; i < resolution; ++i) { + data.add_vertex(Vec3f(tip_radius * sines[i], tip_radius * cosines[i], stem_height), Vec3f(sines[i], cosines[i], 0.0f)); } // tip triangles - for (unsigned short i = 0; i < resolution; ++i) { - const unsigned short v3 = (i < resolution - 1) ? i + 2 : 1; - append_triangle(data, 0, i + 1, v3); + for (unsigned int i = 0; i < resolution; ++i) { + const unsigned int v3 = (i < resolution - 1) ? i + 2 : 1; + data.add_triangle(0, i + 1, v3); } // tip cap outer perimeter vertices - for (unsigned short i = 0; i < resolution; ++i) { - append_vertex(data, { tip_radius * sines[i], tip_radius * cosines[i], stem_height }, -Vec3f::UnitZ()); + for (unsigned int i = 0; i < resolution; ++i) { + data.add_vertex(Vec3f(tip_radius * sines[i], tip_radius * cosines[i], stem_height), (Vec3f)(-Vec3f::UnitZ())); } // tip cap inner perimeter vertices - for (unsigned short i = 0; i < resolution; ++i) { - append_vertex(data, { stem_radius * sines[i], stem_radius * cosines[i], stem_height }, -Vec3f::UnitZ()); + for (unsigned int i = 0; i < resolution; ++i) { + data.add_vertex(Vec3f(stem_radius * sines[i], stem_radius * cosines[i], stem_height), (Vec3f)(-Vec3f::UnitZ())); } // tip cap triangles - for (unsigned short i = 0; i < resolution; ++i) { - const unsigned short v2 = (i < resolution - 1) ? i + resolution + 2 : resolution + 1; - const unsigned short v3 = (i < resolution - 1) ? i + 2 * resolution + 2 : 2 * resolution + 1; - append_triangle(data, i + resolution + 1, v3, v2); - append_triangle(data, i + resolution + 1, i + 2 * resolution + 1, v3); + for (unsigned int i = 0; i < resolution; ++i) { + const unsigned int v2 = (i < resolution - 1) ? i + resolution + 2 : resolution + 1; + const unsigned int v3 = (i < resolution - 1) ? i + 2 * resolution + 2 : 2 * resolution + 1; + data.add_triangle(i + resolution + 1, v3, v2); + data.add_triangle(i + resolution + 1, i + 2 * resolution + 1, v3); } // stem bottom vertices - for (unsigned short i = 0; i < resolution; ++i) { - append_vertex(data, { stem_radius * sines[i], stem_radius * cosines[i], stem_height }, { sines[i], cosines[i], 0.0f }); + for (unsigned int i = 0; i < resolution; ++i) { + data.add_vertex(Vec3f(stem_radius * sines[i], stem_radius * cosines[i], stem_height), Vec3f(sines[i], cosines[i], 0.0f)); } // stem top vertices - for (unsigned short i = 0; i < resolution; ++i) { - append_vertex(data, { stem_radius * sines[i], stem_radius * cosines[i], 0.0f }, { sines[i], cosines[i], 0.0f }); + for (unsigned int i = 0; i < resolution; ++i) { + data.add_vertex(Vec3f(stem_radius * sines[i], stem_radius * cosines[i], 0.0f), Vec3f(sines[i], cosines[i], 0.0f)); } // stem triangles - for (unsigned short i = 0; i < resolution; ++i) { - const unsigned short v2 = (i < resolution - 1) ? i + 3 * resolution + 2 : 3 * resolution + 1; - const unsigned short v3 = (i < resolution - 1) ? i + 4 * resolution + 2 : 4 * resolution + 1; - append_triangle(data, i + 3 * resolution + 1, v3, v2); - append_triangle(data, i + 3 * resolution + 1, i + 4 * resolution + 1, v3); + for (unsigned int i = 0; i < resolution; ++i) { + const unsigned int v2 = (i < resolution - 1) ? i + 3 * resolution + 2 : 3 * resolution + 1; + const unsigned int v3 = (i < resolution - 1) ? i + 4 * resolution + 2 : 4 * resolution + 1; + data.add_triangle(i + 3 * resolution + 1, v3, v2); + data.add_triangle(i + 3 * resolution + 1, i + 4 * resolution + 1, v3); } // stem cap vertices - append_vertex(data, Vec3f::Zero(), -Vec3f::UnitZ()); - for (unsigned short i = 0; i < resolution; ++i) { - append_vertex(data, { stem_radius * sines[i], stem_radius * cosines[i], 0.0f }, -Vec3f::UnitZ()); + data.add_vertex((Vec3f)Vec3f::Zero(), (Vec3f)(-Vec3f::UnitZ())); + for (unsigned int i = 0; i < resolution; ++i) { + data.add_vertex(Vec3f(stem_radius * sines[i], stem_radius * cosines[i], 0.0f), (Vec3f)(-Vec3f::UnitZ())); } // stem cap triangles - for (unsigned short i = 0; i < resolution; ++i) { - const unsigned short v3 = (i < resolution - 1) ? i + 5 * resolution + 3 : 5 * resolution + 2; - append_triangle(data, 5 * resolution + 1, v3, i + 5 * resolution + 2); + for (unsigned int i = 0; i < resolution; ++i) { + const unsigned int v3 = (i < resolution - 1) ? i + 5 * resolution + 3 : 5 * resolution + 2; + data.add_triangle(5 * resolution + 1, v3, i + 5 * resolution + 2); } return data; } -GLModel::Geometry circular_arrow(unsigned short resolution, float radius, float tip_height, float tip_width, float stem_width, float thickness) +GLModel::Geometry circular_arrow(unsigned int resolution, float radius, float tip_height, float tip_width, float stem_width, float thickness) { - resolution = std::max(2, resolution); - resolution = std::min(8188, resolution); // ensure no unsigned short overflow of indices + resolution = std::max(2, resolution); GLModel::Geometry data; - data.format = { GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3N3, GLModel::Geometry::EIndexType::USHORT }; + data.format = { GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3N3 }; data.reserve_vertices(8 * (resolution + 1) + 30); data.reserve_indices((8 * resolution + 16) * 3); @@ -1012,146 +894,146 @@ GLModel::Geometry circular_arrow(unsigned short resolution, float radius, float // tip // top face vertices - append_vertex(data, { 0.0f, outer_radius, half_thickness }, Vec3f::UnitZ()); - append_vertex(data, { 0.0f, radius + half_tip_width, half_thickness }, Vec3f::UnitZ()); - append_vertex(data, { -tip_height, radius, half_thickness }, Vec3f::UnitZ()); - append_vertex(data, { 0.0f, radius - half_tip_width, half_thickness }, Vec3f::UnitZ()); - append_vertex(data, { 0.0f, inner_radius, half_thickness }, Vec3f::UnitZ()); + data.add_vertex(Vec3f(0.0f, outer_radius, half_thickness), (Vec3f)Vec3f::UnitZ()); + data.add_vertex(Vec3f(0.0f, radius + half_tip_width, half_thickness), (Vec3f)Vec3f::UnitZ()); + data.add_vertex(Vec3f(-tip_height, radius, half_thickness), (Vec3f)Vec3f::UnitZ()); + data.add_vertex(Vec3f(0.0f, radius - half_tip_width, half_thickness), (Vec3f)Vec3f::UnitZ()); + data.add_vertex(Vec3f(0.0f, inner_radius, half_thickness), (Vec3f)Vec3f::UnitZ()); // top face triangles - append_triangle(data, 0, 1, 2); - append_triangle(data, 0, 2, 4); - append_triangle(data, 4, 2, 3); + data.add_triangle(0, 1, 2); + data.add_triangle(0, 2, 4); + data.add_triangle(4, 2, 3); // bottom face vertices - append_vertex(data, { 0.0f, outer_radius, -half_thickness }, -Vec3f::UnitZ()); - append_vertex(data, { 0.0f, radius + half_tip_width, -half_thickness }, -Vec3f::UnitZ()); - append_vertex(data, { -tip_height, radius, -half_thickness }, -Vec3f::UnitZ()); - append_vertex(data, { 0.0f, radius - half_tip_width, -half_thickness }, -Vec3f::UnitZ()); - append_vertex(data, { 0.0f, inner_radius, -half_thickness }, -Vec3f::UnitZ()); + data.add_vertex(Vec3f(0.0f, outer_radius, -half_thickness), (Vec3f)(-Vec3f::UnitZ())); + data.add_vertex(Vec3f(0.0f, radius + half_tip_width, -half_thickness), (Vec3f)(-Vec3f::UnitZ())); + data.add_vertex(Vec3f(-tip_height, radius, -half_thickness), (Vec3f)(-Vec3f::UnitZ())); + data.add_vertex(Vec3f(0.0f, radius - half_tip_width, -half_thickness), (Vec3f)(-Vec3f::UnitZ())); + data.add_vertex(Vec3f(0.0f, inner_radius, -half_thickness), (Vec3f)(-Vec3f::UnitZ())); // bottom face triangles - append_triangle(data, 5, 7, 6); - append_triangle(data, 5, 9, 7); - append_triangle(data, 9, 8, 7); + data.add_triangle(5, 7, 6); + data.add_triangle(5, 9, 7); + data.add_triangle(9, 8, 7); // side faces vertices - append_vertex(data, { 0.0f, outer_radius, -half_thickness }, Vec3f::UnitX()); - append_vertex(data, { 0.0f, radius + half_tip_width, -half_thickness }, Vec3f::UnitX()); - append_vertex(data, { 0.0f, outer_radius, half_thickness }, Vec3f::UnitX()); - append_vertex(data, { 0.0f, radius + half_tip_width, half_thickness }, Vec3f::UnitX()); + data.add_vertex(Vec3f(0.0f, outer_radius, -half_thickness), (Vec3f)Vec3f::UnitX()); + data.add_vertex(Vec3f(0.0f, radius + half_tip_width, -half_thickness), (Vec3f)Vec3f::UnitX()); + data.add_vertex(Vec3f(0.0f, outer_radius, half_thickness), (Vec3f)Vec3f::UnitX()); + data.add_vertex(Vec3f(0.0f, radius + half_tip_width, half_thickness), (Vec3f)Vec3f::UnitX()); Vec3f normal(-half_tip_width, tip_height, 0.0f); normal.normalize(); - append_vertex(data, { 0.0f, radius + half_tip_width, -half_thickness }, normal); - append_vertex(data, { -tip_height, radius, -half_thickness }, normal); - append_vertex(data, { 0.0f, radius + half_tip_width, half_thickness }, normal); - append_vertex(data, { -tip_height, radius, half_thickness }, normal); + data.add_vertex(Vec3f(0.0f, radius + half_tip_width, -half_thickness), normal); + data.add_vertex(Vec3f(-tip_height, radius, -half_thickness), normal); + data.add_vertex(Vec3f(0.0f, radius + half_tip_width, half_thickness), normal); + data.add_vertex(Vec3f(-tip_height, radius, half_thickness), normal); normal = { -half_tip_width, -tip_height, 0.0f }; normal.normalize(); - append_vertex(data, { -tip_height, radius, -half_thickness }, normal); - append_vertex(data, { 0.0f, radius - half_tip_width, -half_thickness }, normal); - append_vertex(data, { -tip_height, radius, half_thickness }, normal); - append_vertex(data, { 0.0f, radius - half_tip_width, half_thickness }, normal); + data.add_vertex(Vec3f(-tip_height, radius, -half_thickness), normal); + data.add_vertex(Vec3f(0.0f, radius - half_tip_width, -half_thickness), normal); + data.add_vertex(Vec3f(-tip_height, radius, half_thickness), normal); + data.add_vertex(Vec3f(0.0f, radius - half_tip_width, half_thickness), normal); - append_vertex(data, { 0.0f, radius - half_tip_width, -half_thickness }, Vec3f::UnitX()); - append_vertex(data, { 0.0f, inner_radius, -half_thickness }, Vec3f::UnitX()); - append_vertex(data, { 0.0f, radius - half_tip_width, half_thickness }, Vec3f::UnitX()); - append_vertex(data, { 0.0f, inner_radius, half_thickness }, Vec3f::UnitX()); + data.add_vertex(Vec3f(0.0f, radius - half_tip_width, -half_thickness), (Vec3f)Vec3f::UnitX()); + data.add_vertex(Vec3f(0.0f, inner_radius, -half_thickness), (Vec3f)Vec3f::UnitX()); + data.add_vertex(Vec3f(0.0f, radius - half_tip_width, half_thickness), (Vec3f)Vec3f::UnitX()); + data.add_vertex(Vec3f(0.0f, inner_radius, half_thickness), (Vec3f)Vec3f::UnitX()); // side face triangles - for (unsigned short i = 0; i < 4; ++i) { - const unsigned short ii = i * 4; - append_triangle(data, 10 + ii, 11 + ii, 13 + ii); - append_triangle(data, 10 + ii, 13 + ii, 12 + ii); + for (unsigned int i = 0; i < 4; ++i) { + const unsigned int ii = i * 4; + data.add_triangle(10 + ii, 11 + ii, 13 + ii); + data.add_triangle(10 + ii, 13 + ii, 12 + ii); } // stem // top face vertices - for (unsigned short i = 0; i <= resolution; ++i) { + for (unsigned int i = 0; i <= resolution; ++i) { const float angle = float(i) * step_angle; - append_vertex(data, { inner_radius * ::sin(angle), inner_radius * ::cos(angle), half_thickness }, Vec3f::UnitZ()); + data.add_vertex(Vec3f(inner_radius * ::sin(angle), inner_radius * ::cos(angle), half_thickness), (Vec3f)Vec3f::UnitZ()); } - for (unsigned short i = 0; i <= resolution; ++i) { + for (unsigned int i = 0; i <= resolution; ++i) { const float angle = float(i) * step_angle; - append_vertex(data, { outer_radius * ::sin(angle), outer_radius * ::cos(angle), half_thickness }, Vec3f::UnitZ()); + data.add_vertex(Vec3f(outer_radius * ::sin(angle), outer_radius * ::cos(angle), half_thickness), (Vec3f)Vec3f::UnitZ()); } // top face triangles - for (unsigned short i = 0; i < resolution; ++i) { - append_triangle(data, 26 + i, 27 + i, 27 + resolution + i); - append_triangle(data, 27 + i, 28 + resolution + i, 27 + resolution + i); + for (unsigned int i = 0; i < resolution; ++i) { + data.add_triangle(26 + i, 27 + i, 27 + resolution + i); + data.add_triangle(27 + i, 28 + resolution + i, 27 + resolution + i); } // bottom face vertices - for (unsigned short i = 0; i <= resolution; ++i) { + for (unsigned int i = 0; i <= resolution; ++i) { const float angle = float(i) * step_angle; - append_vertex(data, { inner_radius * ::sin(angle), inner_radius * ::cos(angle), -half_thickness }, -Vec3f::UnitZ()); + data.add_vertex(Vec3f(inner_radius * ::sin(angle), inner_radius * ::cos(angle), -half_thickness), (Vec3f)(-Vec3f::UnitZ())); } - for (unsigned short i = 0; i <= resolution; ++i) { + for (unsigned int i = 0; i <= resolution; ++i) { const float angle = float(i) * step_angle; - append_vertex(data, { outer_radius * ::sin(angle), outer_radius * ::cos(angle), -half_thickness }, -Vec3f::UnitZ()); + data.add_vertex(Vec3f(outer_radius * ::sin(angle), outer_radius * ::cos(angle), -half_thickness), (Vec3f)(-Vec3f::UnitZ())); } // bottom face triangles - for (unsigned short i = 0; i < resolution; ++i) { - append_triangle(data, 28 + 2 * resolution + i, 29 + 3 * resolution + i, 29 + 2 * resolution + i); - append_triangle(data, 29 + 2 * resolution + i, 29 + 3 * resolution + i, 30 + 3 * resolution + i); + for (unsigned int i = 0; i < resolution; ++i) { + data.add_triangle(28 + 2 * resolution + i, 29 + 3 * resolution + i, 29 + 2 * resolution + i); + data.add_triangle(29 + 2 * resolution + i, 29 + 3 * resolution + i, 30 + 3 * resolution + i); } // side faces vertices and triangles - for (unsigned short i = 0; i <= resolution; ++i) { + for (unsigned int i = 0; i <= resolution; ++i) { const float angle = float(i) * step_angle; const float c = ::cos(angle); const float s = ::sin(angle); - append_vertex(data, { inner_radius * s, inner_radius * c, -half_thickness }, { -s, -c, 0.0f }); + data.add_vertex(Vec3f(inner_radius * s, inner_radius * c, -half_thickness), Vec3f(-s, -c, 0.0f)); } - for (unsigned short i = 0; i <= resolution; ++i) { + for (unsigned int i = 0; i <= resolution; ++i) { const float angle = float(i) * step_angle; const float c = ::cos(angle); const float s = ::sin(angle); - append_vertex(data, { inner_radius * s, inner_radius * c, half_thickness }, { -s, -c, 0.0f }); + data.add_vertex(Vec3f(inner_radius * s, inner_radius * c, half_thickness), Vec3f(-s, -c, 0.0f)); } - unsigned short first_id = 26 + 4 * (resolution + 1); - for (unsigned short i = 0; i < resolution; ++i) { - const unsigned short ii = first_id + i; - append_triangle(data, ii, ii + 1, ii + resolution + 2); - append_triangle(data, ii, ii + resolution + 2, ii + resolution + 1); + unsigned int first_id = 26 + 4 * (resolution + 1); + for (unsigned int i = 0; i < resolution; ++i) { + const unsigned int ii = first_id + i; + data.add_triangle(ii, ii + 1, ii + resolution + 2); + data.add_triangle(ii, ii + resolution + 2, ii + resolution + 1); } - append_vertex(data, { inner_radius, 0.0f, -half_thickness }, -Vec3f::UnitY()); - append_vertex(data, { outer_radius, 0.0f, -half_thickness }, -Vec3f::UnitY()); - append_vertex(data, { inner_radius, 0.0f, half_thickness }, -Vec3f::UnitY()); - append_vertex(data, { outer_radius, 0.0f, half_thickness }, -Vec3f::UnitY()); + data.add_vertex(Vec3f(inner_radius, 0.0f, -half_thickness), (Vec3f)(-Vec3f::UnitY())); + data.add_vertex(Vec3f(outer_radius, 0.0f, -half_thickness), (Vec3f)(-Vec3f::UnitY())); + data.add_vertex(Vec3f(inner_radius, 0.0f, half_thickness), (Vec3f)(-Vec3f::UnitY())); + data.add_vertex(Vec3f(outer_radius, 0.0f, half_thickness), (Vec3f)(-Vec3f::UnitY())); first_id = 26 + 6 * (resolution + 1); - append_triangle(data, first_id, first_id + 1, first_id + 3); - append_triangle(data, first_id, first_id + 3, first_id + 2); + data.add_triangle(first_id, first_id + 1, first_id + 3); + data.add_triangle(first_id, first_id + 3, first_id + 2); - for (short i = resolution; i >= 0; --i) { + for (int i = resolution; i >= 0; --i) { const float angle = float(i) * step_angle; const float c = ::cos(angle); const float s = ::sin(angle); - append_vertex(data, { outer_radius * s, outer_radius * c, -half_thickness }, { s, c, 0.0f }); + data.add_vertex(Vec3f(outer_radius * s, outer_radius * c, -half_thickness), Vec3f(s, c, 0.0f)); } - for (short i = resolution; i >= 0; --i) { + for (int i = resolution; i >= 0; --i) { const float angle = float(i) * step_angle; const float c = ::cos(angle); const float s = ::sin(angle); - append_vertex(data, { outer_radius * s, outer_radius * c, +half_thickness }, { s, c, 0.0f }); + data.add_vertex(Vec3f(outer_radius * s, outer_radius * c, +half_thickness), Vec3f(s, c, 0.0f)); } first_id = 30 + 6 * (resolution + 1); - for (unsigned short i = 0; i < resolution; ++i) { - const unsigned short ii = first_id + i; - append_triangle(data, ii, ii + 1, ii + resolution + 2); - append_triangle(data, ii, ii + resolution + 2, ii + resolution + 1); + for (unsigned int i = 0; i < resolution; ++i) { + const unsigned int ii = first_id + i; + data.add_triangle(ii, ii + 1, ii + resolution + 2); + data.add_triangle(ii, ii + resolution + 2, ii + resolution + 1); } return data; @@ -1160,7 +1042,7 @@ GLModel::Geometry circular_arrow(unsigned short resolution, float radius, float GLModel::Geometry straight_arrow(float tip_width, float tip_height, float stem_width, float stem_height, float thickness) { GLModel::Geometry data; - data.format = { GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3N3, GLModel::Geometry::EIndexType::USHORT }; + data.format = { GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3N3 }; data.reserve_vertices(42); data.reserve_indices(72); @@ -1170,122 +1052,121 @@ GLModel::Geometry straight_arrow(float tip_width, float tip_height, float stem_w const float total_height = tip_height + stem_height; // top face vertices - append_vertex(data, { half_stem_width, 0.0, half_thickness }, Vec3f::UnitZ()); - append_vertex(data, { half_stem_width, stem_height, half_thickness }, Vec3f::UnitZ()); - append_vertex(data, { half_tip_width, stem_height, half_thickness }, Vec3f::UnitZ()); - append_vertex(data, { 0.0, total_height, half_thickness }, Vec3f::UnitZ()); - append_vertex(data, { -half_tip_width, stem_height, half_thickness }, Vec3f::UnitZ()); - append_vertex(data, { -half_stem_width, stem_height, half_thickness }, Vec3f::UnitZ()); - append_vertex(data, { -half_stem_width, 0.0, half_thickness }, Vec3f::UnitZ()); + data.add_vertex(Vec3f(half_stem_width, 0.0f, half_thickness), (Vec3f)Vec3f::UnitZ()); + data.add_vertex(Vec3f(half_stem_width, stem_height, half_thickness), (Vec3f)Vec3f::UnitZ()); + data.add_vertex(Vec3f(half_tip_width, stem_height, half_thickness), (Vec3f)Vec3f::UnitZ()); + data.add_vertex(Vec3f(0.0f, total_height, half_thickness), (Vec3f)Vec3f::UnitZ()); + data.add_vertex(Vec3f(-half_tip_width, stem_height, half_thickness), (Vec3f)Vec3f::UnitZ()); + data.add_vertex(Vec3f(-half_stem_width, stem_height, half_thickness), (Vec3f)Vec3f::UnitZ()); + data.add_vertex(Vec3f(-half_stem_width, 0.0f, half_thickness), (Vec3f)Vec3f::UnitZ()); // top face triangles - append_triangle(data, 0, 1, 6); - append_triangle(data, 6, 1, 5); - append_triangle(data, 4, 5, 3); - append_triangle(data, 5, 1, 3); - append_triangle(data, 1, 2, 3); + data.add_triangle(0, 1, 6); + data.add_triangle(6, 1, 5); + data.add_triangle(4, 5, 3); + data.add_triangle(5, 1, 3); + data.add_triangle(1, 2, 3); // bottom face vertices - append_vertex(data, { half_stem_width, 0.0, -half_thickness }, -Vec3f::UnitZ()); - append_vertex(data, { half_stem_width, stem_height, -half_thickness }, -Vec3f::UnitZ()); - append_vertex(data, { half_tip_width, stem_height, -half_thickness }, -Vec3f::UnitZ()); - append_vertex(data, { 0.0, total_height, -half_thickness }, -Vec3f::UnitZ()); - append_vertex(data, { -half_tip_width, stem_height, -half_thickness }, -Vec3f::UnitZ()); - append_vertex(data, { -half_stem_width, stem_height, -half_thickness }, -Vec3f::UnitZ()); - append_vertex(data, { -half_stem_width, 0.0, -half_thickness }, -Vec3f::UnitZ()); + data.add_vertex(Vec3f(half_stem_width, 0.0f, -half_thickness), (Vec3f)(-Vec3f::UnitZ())); + data.add_vertex(Vec3f(half_stem_width, stem_height, -half_thickness), (Vec3f)(-Vec3f::UnitZ())); + data.add_vertex(Vec3f(half_tip_width, stem_height, -half_thickness), (Vec3f)(-Vec3f::UnitZ())); + data.add_vertex(Vec3f(0.0f, total_height, -half_thickness), (Vec3f)(-Vec3f::UnitZ())); + data.add_vertex(Vec3f(-half_tip_width, stem_height, -half_thickness), (Vec3f)(-Vec3f::UnitZ())); + data.add_vertex(Vec3f(-half_stem_width, stem_height, -half_thickness), (Vec3f)(-Vec3f::UnitZ())); + data.add_vertex(Vec3f(-half_stem_width, 0.0f, -half_thickness), (Vec3f)(-Vec3f::UnitZ())); // bottom face triangles - append_triangle(data, 7, 13, 8); - append_triangle(data, 13, 12, 8); - append_triangle(data, 12, 11, 10); - append_triangle(data, 8, 12, 10); - append_triangle(data, 9, 8, 10); + data.add_triangle(7, 13, 8); + data.add_triangle(13, 12, 8); + data.add_triangle(12, 11, 10); + data.add_triangle(8, 12, 10); + data.add_triangle(9, 8, 10); // side faces vertices - append_vertex(data, { half_stem_width, 0.0, -half_thickness }, Vec3f::UnitX()); - append_vertex(data, { half_stem_width, stem_height, -half_thickness }, Vec3f::UnitX()); - append_vertex(data, { half_stem_width, 0.0, half_thickness }, Vec3f::UnitX()); - append_vertex(data, { half_stem_width, stem_height, half_thickness }, Vec3f::UnitX()); + data.add_vertex(Vec3f(half_stem_width, 0.0f, -half_thickness), (Vec3f)Vec3f::UnitX()); + data.add_vertex(Vec3f(half_stem_width, stem_height, -half_thickness), (Vec3f)Vec3f::UnitX()); + data.add_vertex(Vec3f(half_stem_width, 0.0f, half_thickness), (Vec3f)Vec3f::UnitX()); + data.add_vertex(Vec3f(half_stem_width, stem_height, half_thickness), (Vec3f)Vec3f::UnitX()); - append_vertex(data, { half_stem_width, stem_height, -half_thickness }, -Vec3f::UnitY()); - append_vertex(data, { half_tip_width, stem_height, -half_thickness }, -Vec3f::UnitY()); - append_vertex(data, { half_stem_width, stem_height, half_thickness }, -Vec3f::UnitY()); - append_vertex(data, { half_tip_width, stem_height, half_thickness }, -Vec3f::UnitY()); + data.add_vertex(Vec3f(half_stem_width, stem_height, -half_thickness), (Vec3f)(-Vec3f::UnitY())); + data.add_vertex(Vec3f(half_tip_width, stem_height, -half_thickness), (Vec3f)(-Vec3f::UnitY())); + data.add_vertex(Vec3f(half_stem_width, stem_height, half_thickness), (Vec3f)(-Vec3f::UnitY())); + data.add_vertex(Vec3f(half_tip_width, stem_height, half_thickness), (Vec3f)(-Vec3f::UnitY())); Vec3f normal(tip_height, half_tip_width, 0.0f); normal.normalize(); - append_vertex(data, { half_tip_width, stem_height, -half_thickness }, normal); - append_vertex(data, { 0.0, total_height, -half_thickness }, normal); - append_vertex(data, { half_tip_width, stem_height, half_thickness }, normal); - append_vertex(data, { 0.0, total_height, half_thickness }, normal); + data.add_vertex(Vec3f(half_tip_width, stem_height, -half_thickness), normal); + data.add_vertex(Vec3f(0.0f, total_height, -half_thickness), normal); + data.add_vertex(Vec3f(half_tip_width, stem_height, half_thickness), normal); + data.add_vertex(Vec3f(0.0f, total_height, half_thickness), normal); normal = { -tip_height, half_tip_width, 0.0f }; normal.normalize(); - append_vertex(data, { 0.0, total_height, -half_thickness }, normal); - append_vertex(data, { -half_tip_width, stem_height, -half_thickness }, normal); - append_vertex(data, { 0.0, total_height, half_thickness }, normal); - append_vertex(data, { -half_tip_width, stem_height, half_thickness }, normal); - - append_vertex(data, { -half_tip_width, stem_height, -half_thickness }, -Vec3f::UnitY()); - append_vertex(data, { -half_stem_width, stem_height, -half_thickness }, -Vec3f::UnitY()); - append_vertex(data, { -half_tip_width, stem_height, half_thickness }, -Vec3f::UnitY()); - append_vertex(data, { -half_stem_width, stem_height, half_thickness }, -Vec3f::UnitY()); - - append_vertex(data, { -half_stem_width, stem_height, -half_thickness }, -Vec3f::UnitX()); - append_vertex(data, { -half_stem_width, 0.0, -half_thickness }, -Vec3f::UnitX()); - append_vertex(data, { -half_stem_width, stem_height, half_thickness }, -Vec3f::UnitX()); - append_vertex(data, { -half_stem_width, 0.0, half_thickness }, -Vec3f::UnitX()); - - append_vertex(data, { -half_stem_width, 0.0, -half_thickness }, -Vec3f::UnitY()); - append_vertex(data, { half_stem_width, 0.0, -half_thickness }, -Vec3f::UnitY()); - append_vertex(data, { -half_stem_width, 0.0, half_thickness }, -Vec3f::UnitY()); - append_vertex(data, { half_stem_width, 0.0, half_thickness }, -Vec3f::UnitY()); + data.add_vertex(Vec3f(0.0f, total_height, -half_thickness), normal); + data.add_vertex(Vec3f(-half_tip_width, stem_height, -half_thickness), normal); + data.add_vertex(Vec3f(0.0f, total_height, half_thickness), normal); + data.add_vertex(Vec3f(-half_tip_width, stem_height, half_thickness), normal); + + data.add_vertex(Vec3f(-half_tip_width, stem_height, -half_thickness), (Vec3f)(-Vec3f::UnitY())); + data.add_vertex(Vec3f(-half_stem_width, stem_height, -half_thickness), (Vec3f)(-Vec3f::UnitY())); + data.add_vertex(Vec3f(-half_tip_width, stem_height, half_thickness), (Vec3f)(-Vec3f::UnitY())); + data.add_vertex(Vec3f(-half_stem_width, stem_height, half_thickness), (Vec3f)(-Vec3f::UnitY())); + + data.add_vertex(Vec3f(-half_stem_width, stem_height, -half_thickness), (Vec3f)(-Vec3f::UnitX())); + data.add_vertex(Vec3f(-half_stem_width, 0.0f, -half_thickness), (Vec3f)(-Vec3f::UnitX())); + data.add_vertex(Vec3f(-half_stem_width, stem_height, half_thickness), (Vec3f)(-Vec3f::UnitX())); + data.add_vertex(Vec3f(-half_stem_width, 0.0f, half_thickness), (Vec3f)(-Vec3f::UnitX())); + + data.add_vertex(Vec3f(-half_stem_width, 0.0f, -half_thickness), (Vec3f)(-Vec3f::UnitY())); + data.add_vertex(Vec3f(half_stem_width, 0.0f, -half_thickness), (Vec3f)(-Vec3f::UnitY())); + data.add_vertex(Vec3f(-half_stem_width, 0.0f, half_thickness), (Vec3f)(-Vec3f::UnitY())); + data.add_vertex(Vec3f(half_stem_width, 0.0f, half_thickness), (Vec3f)(-Vec3f::UnitY())); // side face triangles - for (unsigned short i = 0; i < 7; ++i) { - const unsigned short ii = i * 4; - append_triangle(data, 14 + ii, 15 + ii, 17 + ii); - append_triangle(data, 14 + ii, 17 + ii, 16 + ii); + for (unsigned int i = 0; i < 7; ++i) { + const unsigned int ii = i * 4; + data.add_triangle(14 + ii, 15 + ii, 17 + ii); + data.add_triangle(14 + ii, 17 + ii, 16 + ii); } return data; } -GLModel::Geometry diamond(unsigned short resolution) +GLModel::Geometry diamond(unsigned int resolution) { - resolution = std::max(4, resolution); - resolution = std::min(65534, resolution); // ensure no unsigned short overflow of indices + resolution = std::max(4, resolution); GLModel::Geometry data; - data.format = { GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3N3, GLModel::Geometry::EIndexType::USHORT }; + data.format = { GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3N3 }; data.reserve_vertices(resolution + 2); data.reserve_indices((2 * (resolution + 1)) * 3); const float step = 2.0f * float(PI) / float(resolution); // vertices - for (unsigned short i = 0; i < resolution; ++i) { - float ii = float(i) * step; + for (unsigned int i = 0; i < resolution; ++i) { + const float ii = float(i) * step; const Vec3f p = { 0.5f * ::cos(ii), 0.5f * ::sin(ii), 0.0f }; - append_vertex(data, p, p.normalized()); + data.add_vertex(p, (Vec3f)p.normalized()); } Vec3f p = { 0.0f, 0.0f, 0.5f }; - append_vertex(data, p, p.normalized()); + data.add_vertex(p, (Vec3f)p.normalized()); p = { 0.0f, 0.0f, -0.5f }; - append_vertex(data, p, p.normalized()); + data.add_vertex(p, (Vec3f)p.normalized()); // triangles // top - for (unsigned short i = 0; i < resolution; ++i) { - append_triangle(data, i + 0, i + 1, resolution); + for (unsigned int i = 0; i < resolution; ++i) { + data.add_triangle(i + 0, i + 1, resolution); } - append_triangle(data, resolution - 1, 0, resolution); + data.add_triangle(resolution - 1, 0, resolution); // bottom - for (unsigned short i = 0; i < resolution; ++i) { - append_triangle(data, i + 0, resolution + 1, i + 1); + for (unsigned int i = 0; i < resolution; ++i) { + data.add_triangle(i + 0, resolution + 1, i + 1); } - append_triangle(data, resolution - 1, resolution + 1, 0); + data.add_triangle(resolution - 1, resolution + 1, 0); return data; } diff --git a/src/slic3r/GUI/GLModel.hpp b/src/slic3r/GUI/GLModel.hpp index 79c615f31c6..28485cd40ee 100644 --- a/src/slic3r/GUI/GLModel.hpp +++ b/src/slic3r/GUI/GLModel.hpp @@ -46,23 +46,25 @@ namespace GUI { enum class EIndexType : unsigned char { UINT, // unsigned int - USHORT // unsigned short + USHORT, // unsigned short + UBYTE // unsigned byte }; struct Format { EPrimitiveType type{ EPrimitiveType::Triangles }; EVertexLayout vertex_layout{ EVertexLayout::P3N3 }; - EIndexType index_type{ EIndexType::UINT }; }; Format format; std::vector vertices; - std::vector indices; + std::vector indices; + EIndexType index_type{ EIndexType::UINT }; ColorRGBA color{ ColorRGBA::BLACK() }; - void reserve_vertices(size_t vertices_count); - void reserve_indices(size_t indices_count); + void reserve_vertices(size_t vertices_count) { vertices.reserve(vertices_count * vertex_stride_floats(format)); } + void reserve_indices(size_t indices_count) { indices.reserve(indices_count * index_stride_bytes(*this)); } + void add_vertex(const Vec2f& position); // EVertexLayout::P2 void add_vertex(const Vec2f& position, const Vec2f& tex_coord); // EVertexLayout::P2T2 @@ -72,36 +74,29 @@ namespace GUI { void set_vertex(size_t id, const Vec3f& position, const Vec3f& normal); // EVertexLayout::P3N3 - void set_ushort_index(size_t id, unsigned short index); - void set_uint_index(size_t id, unsigned int index); - - void add_ushort_index(unsigned short id); - void add_uint_index(unsigned int id); - - void add_ushort_line(unsigned short id1, unsigned short id2); - void add_uint_line(unsigned int id1, unsigned int id2); + void set_index(size_t id, unsigned int index); - void add_ushort_triangle(unsigned short id1, unsigned short id2, unsigned short id3); - void add_uint_triangle(unsigned int id1, unsigned int id2, unsigned int id3); + void add_index(unsigned int id); + void add_line(unsigned int id1, unsigned int id2); + void add_triangle(unsigned int id1, unsigned int id2, unsigned int id3); Vec2f extract_position_2(size_t id) const; Vec3f extract_position_3(size_t id) const; Vec3f extract_normal_3(size_t id) const; Vec2f extract_tex_coord_2(size_t id) const; - unsigned int extract_uint_index(size_t id) const; - unsigned short extract_ushort_index(size_t id) const; + unsigned int extract_index(size_t id) const; void remove_vertex(size_t id); bool is_empty() const { return vertices_count() == 0 || indices_count() == 0; } size_t vertices_count() const { return vertices.size() / vertex_stride_floats(format); } - size_t indices_count() const { return indices.size() / index_stride_bytes(format); } + size_t indices_count() const { return indices.size(); } size_t vertices_size_floats() const { return vertices.size(); } size_t vertices_size_bytes() const { return vertices_size_floats() * sizeof(float); } - size_t indices_size_bytes() const { return indices.size(); } + size_t indices_size_bytes() const { return indices.size() * index_stride_bytes(*this); } static size_t vertex_stride_floats(const Format& format); static size_t vertex_stride_bytes(const Format& format) { return vertex_stride_floats(format) * sizeof(float); } @@ -121,9 +116,7 @@ namespace GUI { static size_t tex_coord_offset_floats(const Format& format); static size_t tex_coord_offset_bytes(const Format& format) { return tex_coord_offset_floats(format) * sizeof(float); } - static size_t index_stride_bytes(const Format& format); - - static EIndexType index_type(size_t vertices_count); + static size_t index_stride_bytes(const Geometry& data); static bool has_position(const Format& format); static bool has_normal(const Format& format); @@ -164,9 +157,10 @@ namespace GUI { size_t vertices_size_floats() const { return vertices_count() * Geometry::vertex_stride_floats(m_render_data.geometry.format); } size_t vertices_size_bytes() const { return vertices_size_floats() * sizeof(float); } - size_t indices_size_bytes() const { return indices_count() * Geometry::index_stride_bytes(m_render_data.geometry.format); } + size_t indices_size_bytes() const { return indices_count() * Geometry::index_stride_bytes(m_render_data.geometry); } const Geometry& get_geometry() const { return m_render_data.geometry; } + void init_from(Geometry&& data); void init_from(const TriangleMesh& mesh); void init_from(const indexed_triangle_set& its); @@ -217,13 +211,13 @@ namespace GUI { // the origin of the arrow is in the center of the stem cap // the arrow has its axis of symmetry along the Z axis and is pointing upward // used to render bed axes and sequential marker - GLModel::Geometry stilized_arrow(unsigned short resolution, float tip_radius, float tip_height, float stem_radius, float stem_height); + GLModel::Geometry stilized_arrow(unsigned int resolution, float tip_radius, float tip_height, float stem_radius, float stem_height); // create an arrow whose stem is a quarter of circle, with the given dimensions and resolution // the origin of the arrow is in the center of the circle // the arrow is contained in the 1st quadrant of the XY plane and is pointing counterclockwise // used to render sidebar hints for rotations - GLModel::Geometry circular_arrow(unsigned short resolution, float radius, float tip_height, float tip_width, float stem_width, float thickness); + GLModel::Geometry circular_arrow(unsigned int resolution, float radius, float tip_height, float tip_width, float stem_width, float thickness); // create an arrow with the given dimensions // the origin of the arrow is in the center of the stem cap @@ -234,7 +228,7 @@ namespace GUI { // create a diamond with the given resolution // the origin of the diamond is in its center // the diamond is contained into a box with size [1, 1, 1] - GLModel::Geometry diamond(unsigned short resolution); + GLModel::Geometry diamond(unsigned int resolution); } // namespace GUI } // namespace Slic3r diff --git a/src/slic3r/GUI/GLSelectionRectangle.cpp b/src/slic3r/GUI/GLSelectionRectangle.cpp index e06f0876999..3f0e7cf66bb 100644 --- a/src/slic3r/GUI/GLSelectionRectangle.cpp +++ b/src/slic3r/GUI/GLSelectionRectangle.cpp @@ -74,40 +74,28 @@ namespace GUI { if (!is_dragging()) return; - const Camera& camera = wxGetApp().plater()->get_camera(); - float inv_zoom = (float)camera.get_inv_zoom(); - - Size cnv_size = canvas.get_canvas_size(); - float cnv_half_width = 0.5f * (float)cnv_size.get_width(); - float cnv_half_height = 0.5f * (float)cnv_size.get_height(); - if (cnv_half_width == 0.0f || cnv_half_height == 0.0f) + const Size cnv_size = canvas.get_canvas_size(); + const float cnv_width = (float)cnv_size.get_width(); + const float cnv_height = (float)cnv_size.get_height(); + if (cnv_width == 0.0f || cnv_height == 0.0f) return; - Vec2d start(m_start_corner(0) - cnv_half_width, cnv_half_height - m_start_corner(1)); - Vec2d end(m_end_corner(0) - cnv_half_width, cnv_half_height - m_end_corner(1)); - - const float left = (float)std::min(start(0), end(0)) * inv_zoom; - const float top = (float)std::max(start(1), end(1)) * inv_zoom; - const float right = (float)std::max(start(0), end(0)) * inv_zoom; - const float bottom = (float)std::min(start(1), end(1)) * inv_zoom; + const float cnv_inv_width = 1.0f / cnv_width; + const float cnv_inv_height = 1.0f / cnv_height; + const float left = 2.0f * (get_left() * cnv_inv_width - 0.5f); + const float right = 2.0f * (get_right() * cnv_inv_width - 0.5f); + const float top = -2.0f * (get_top() * cnv_inv_height - 0.5f); + const float bottom = -2.0f * (get_bottom() * cnv_inv_height - 0.5f); glsafe(::glLineWidth(1.5f)); glsafe(::glDisable(GL_DEPTH_TEST)); - glsafe(::glPushMatrix()); - glsafe(::glLoadIdentity()); - // ensure that the rectangle is renderered inside the frustrum - glsafe(::glTranslated(0.0, 0.0, -(camera.get_near_z() + 0.5))); - // ensure that the overlay fits the frustrum near z plane - const double gui_scale = camera.get_gui_scale(); - glsafe(::glScaled(gui_scale, gui_scale, 1.0)); - glsafe(::glPushAttrib(GL_ENABLE_BIT)); glsafe(::glLineStipple(4, 0xAAAA)); glsafe(::glEnable(GL_LINE_STIPPLE)); - GLShaderProgram* shader = wxGetApp().get_shader("flat"); + GLShaderProgram* shader = wxGetApp().get_shader("flat_attr"); if (shader != nullptr) { shader->start_using(); @@ -117,7 +105,7 @@ namespace GUI { m_rectangle.reset(); GLModel::Geometry init_data; - init_data.format = { GLModel::Geometry::EPrimitiveType::LineLoop, GLModel::Geometry::EVertexLayout::P2, GLModel::Geometry::EIndexType::USHORT }; + init_data.format = { GLModel::Geometry::EPrimitiveType::LineLoop, GLModel::Geometry::EVertexLayout::P2 }; init_data.reserve_vertices(4); init_data.reserve_indices(4); @@ -128,23 +116,23 @@ namespace GUI { init_data.add_vertex(Vec2f(left, top)); // indices - init_data.add_ushort_index(0); - init_data.add_ushort_index(1); - init_data.add_ushort_index(2); - init_data.add_ushort_index(3); + init_data.add_index(0); + init_data.add_index(1); + init_data.add_index(2); + init_data.add_index(3); m_rectangle.init_from(std::move(init_data)); } - const ColorRGBA color(0.0f, 1.0f, 0.38f, 1.0f); - m_rectangle.set_color(color); + shader->set_uniform("view_model_matrix", Transform3d::Identity()); + shader->set_uniform("projection_matrix", Transform3d::Identity()); + + m_rectangle.set_color({0.0f, 1.0f, 0.38f, 1.0f}); m_rectangle.render(); shader->stop_using(); } glsafe(::glPopAttrib()); - - glsafe(::glPopMatrix()); } } // namespace GUI diff --git a/src/slic3r/GUI/GLSelectionRectangle.hpp b/src/slic3r/GUI/GLSelectionRectangle.hpp index ad0360e0ccb..5ec56a60a0e 100644 --- a/src/slic3r/GUI/GLSelectionRectangle.hpp +++ b/src/slic3r/GUI/GLSelectionRectangle.hpp @@ -36,12 +36,12 @@ class GLSelectionRectangle { bool is_dragging() const { return m_state != Off; } EState get_state() const { return m_state; } - float get_width() const { return std::abs(m_start_corner(0) - m_end_corner(0)); } - float get_height() const { return std::abs(m_start_corner(1) - m_end_corner(1)); } - float get_left() const { return std::min(m_start_corner(0), m_end_corner(0)); } - float get_right() const { return std::max(m_start_corner(0), m_end_corner(0)); } - float get_top() const { return std::max(m_start_corner(1), m_end_corner(1)); } - float get_bottom() const { return std::min(m_start_corner(1), m_end_corner(1)); } + float get_width() const { return std::abs(m_start_corner.x() - m_end_corner.x()); } + float get_height() const { return std::abs(m_start_corner.y() - m_end_corner.y()); } + float get_left() const { return std::min(m_start_corner.x(), m_end_corner.x()); } + float get_right() const { return std::max(m_start_corner.x(), m_end_corner.x()); } + float get_top() const { return std::max(m_start_corner.y(), m_end_corner.y()); } + float get_bottom() const { return std::min(m_start_corner.y(), m_end_corner.y()); } private: EState m_state{ Off }; diff --git a/src/slic3r/GUI/GLShader.cpp b/src/slic3r/GUI/GLShader.cpp index 32b3d596014..174cfec590a 100644 --- a/src/slic3r/GUI/GLShader.cpp +++ b/src/slic3r/GUI/GLShader.cpp @@ -296,6 +296,11 @@ void GLShaderProgram::set_uniform(int id, const Matrix3f& value) const glsafe(::glUniformMatrix3fv(id, 1, GL_FALSE, static_cast(value.data()))); } +void GLShaderProgram::set_uniform(int id, const Matrix3d& value) const +{ + set_uniform(id, (Matrix3f)value.cast()); +} + void GLShaderProgram::set_uniform(int id, const Vec3f& value) const { if (id >= 0) diff --git a/src/slic3r/GUI/GLShader.hpp b/src/slic3r/GUI/GLShader.hpp index 975c12c24ad..76697fa594d 100644 --- a/src/slic3r/GUI/GLShader.hpp +++ b/src/slic3r/GUI/GLShader.hpp @@ -60,6 +60,7 @@ class GLShaderProgram void set_uniform(const char* name, const Transform3f& value) const { set_uniform(get_uniform_location(name), value); } void set_uniform(const char* name, const Transform3d& value) const { set_uniform(get_uniform_location(name), value); } void set_uniform(const char* name, const Matrix3f& value) const { set_uniform(get_uniform_location(name), value); } + void set_uniform(const char* name, const Matrix3d& value) const { set_uniform(get_uniform_location(name), value); } void set_uniform(const char* name, const Vec3f& value) const { set_uniform(get_uniform_location(name), value); } void set_uniform(const char* name, const Vec3d& value) const { set_uniform(get_uniform_location(name), value); } void set_uniform(const char* name, const ColorRGB& value) const { set_uniform(get_uniform_location(name), value); } @@ -79,6 +80,7 @@ class GLShaderProgram void set_uniform(int id, const Transform3f& value) const; void set_uniform(int id, const Transform3d& value) const; void set_uniform(int id, const Matrix3f& value) const; + void set_uniform(int id, const Matrix3d& value) const; void set_uniform(int id, const Vec3f& value) const; void set_uniform(int id, const Vec3d& value) const; void set_uniform(int id, const ColorRGB& value) const; diff --git a/src/slic3r/GUI/GLShadersManager.cpp b/src/slic3r/GUI/GLShadersManager.cpp index c00599805cd..2048b561054 100644 --- a/src/slic3r/GUI/GLShadersManager.cpp +++ b/src/slic3r/GUI/GLShadersManager.cpp @@ -34,25 +34,22 @@ std::pair GLShadersManager::init() bool valid = true; // basic shader, used to render all what was previously rendered using the immediate mode - valid &= append_shader("flat", { "flat.vs", "flat.fs" }); valid &= append_shader("flat_attr", { "flat_attr.vs", "flat.fs" }); // basic shader for textures, used to render textures - valid &= append_shader("flat_texture", { "flat_texture.vs", "flat_texture.fs" }); + valid &= append_shader("flat_texture_attr", { "flat_texture_attr.vs", "flat_texture.fs" }); // used to render 3D scene background - valid &= append_shader("background", { "background.vs", "background.fs" }); + valid &= append_shader("background_attr", { "background_attr.vs", "background.fs" }); // used to render bed axes and model, selection hints, gcode sequential view marker model, preview shells, options in gcode preview - valid &= append_shader("gouraud_light", { "gouraud_light.vs", "gouraud_light.fs" }); + valid &= append_shader("gouraud_light_attr", { "gouraud_light_attr.vs", "gouraud_light.fs" }); //used to render thumbnail - valid &= append_shader("thumbnail", { "thumbnail.vs", "thumbnail.fs" }); - // used to render first layer for calibration - valid &= append_shader("cali", { "cali.vs", "cali.fs"}); + valid &= append_shader("thumbnail_attr", {"thumbnail_attr.vs", "thumbnail.fs"}); + valid &= append_shader("thumbnail", {"thumbnail.vs", "thumbnail.fs"}); // used to render printbed - valid &= append_shader("printbed", { "printbed.vs", "printbed.fs" }); + valid &= append_shader("printbed_attr", { "printbed_attr.vs", "printbed.fs" }); // used to render options in gcode preview - if (GUI::wxGetApp().is_gl_version_greater_or_equal_to(3, 3)) - valid &= append_shader("gouraud_light_instanced", { "gouraud_light_instanced.vs", "gouraud_light_instanced.fs" }); - // used to render extrusion and travel paths as lines in gcode preview - valid &= append_shader("toolpaths_lines", { "toolpaths_lines.vs", "toolpaths_lines.fs" }); + if (GUI::wxGetApp().is_gl_version_greater_or_equal_to(3, 3)) { + valid &= append_shader("gouraud_light_instanced_attr", { "gouraud_light_instanced_attr.vs", "gouraud_light_instanced.fs" }); + } // used to render objects in 3d editor //if (GUI::wxGetApp().is_gl_version_greater_or_equal_to(3, 0)) { @@ -64,34 +61,26 @@ std::pair GLShadersManager::init() ); } else { - valid &= append_shader("gouraud", { "gouraud.vs", "gouraud.fs" } + valid &= append_shader("gouraud_attr", { "gouraud_attr.vs", "gouraud.fs" } #if ENABLE_ENVIRONMENT_MAP , { "ENABLE_ENVIRONMENT_MAP"sv } #endif // ENABLE_ENVIRONMENT_MAP ); } // used to render variable layers heights in 3d editor - valid &= append_shader("variable_layer_height", { "variable_layer_height.vs", "variable_layer_height.fs" }); + valid &= append_shader("variable_layer_height_attr", { "variable_layer_height_attr.vs", "variable_layer_height.fs" }); // used to render highlight contour around selected triangles inside the multi-material gizmo - valid &= append_shader("mm_contour", { "mm_contour.vs", "mm_contour.fs" }); + valid &= append_shader("mm_contour_attr", { "mm_contour_attr.vs", "mm_contour_attr.fs" }); // Used to render painted triangles inside the multi-material gizmo. Triangle normals are computed inside fragment shader. // For Apple's on Arm CPU computed triangle normals inside fragment shader using dFdx and dFdy has the opposite direction. // Because of this, objects had darker colors inside the multi-material gizmo. // Based on https://stackoverflow.com/a/66206648, the similar behavior was also spotted on some other devices with Arm CPU. // Since macOS 12 (Monterey), this issue with the opposite direction on Apple's Arm CPU seems to be fixed, and computed // triangle normals inside fragment shader have the right direction. - if (platform_flavor() == PlatformFlavor::OSXOnArm && wxPlatformInfo::Get().GetOSMajorVersion() < 12) { - //if (GUI::wxGetApp().plater() && GUI::wxGetApp().plater()->is_wireframe_enabled()) - // valid &= append_shader("mm_gouraud", {"mm_gouraud_wireframe.vs", "mm_gouraud_wireframe.fs"}, {"FLIP_TRIANGLE_NORMALS"sv}); - //else - valid &= append_shader("mm_gouraud", {"mm_gouraud.vs", "mm_gouraud.fs"}, {"FLIP_TRIANGLE_NORMALS"sv}); - } - else { - //if (GUI::wxGetApp().plater() && GUI::wxGetApp().plater()->is_wireframe_enabled()) - // valid &= append_shader("mm_gouraud", {"mm_gouraud_wireframe.vs", "mm_gouraud_wireframe.fs"}); - //else - valid &= append_shader("mm_gouraud", {"mm_gouraud.vs", "mm_gouraud.fs"}); - } + if (platform_flavor() == PlatformFlavor::OSXOnArm && wxPlatformInfo::Get().GetOSMajorVersion() < 12) + valid &= append_shader("mm_gouraud_attr", { "mm_gouraud_attr.vs", "mm_gouraud_attr.fs" }, { "FLIP_TRIANGLE_NORMALS"sv }); + else + valid &= append_shader("mm_gouraud_attr", { "mm_gouraud_attr.vs", "mm_gouraud_attr.fs" }); //BBS: add shader for outline valid &= append_shader("outline", { "outline.vs", "outline.fs" }); diff --git a/src/slic3r/GUI/GLTexture.cpp b/src/slic3r/GUI/GLTexture.cpp index 69ed23e2ffe..041653a6c47 100644 --- a/src/slic3r/GUI/GLTexture.cpp +++ b/src/slic3r/GUI/GLTexture.cpp @@ -663,7 +663,7 @@ void GLTexture::render_sub_texture(unsigned int tex_id, float left, float right, glsafe(::glBindTexture(GL_TEXTURE_2D, (GLuint)tex_id)); GLModel::Geometry init_data; - init_data.format = { GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P2T2, GLModel::Geometry::EIndexType::USHORT }; + init_data.format = { GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P2T2 }; init_data.reserve_vertices(4); init_data.reserve_indices(6); @@ -674,15 +674,17 @@ void GLTexture::render_sub_texture(unsigned int tex_id, float left, float right, init_data.add_vertex(Vec2f(left, top), Vec2f(uvs.left_top.u, uvs.left_top.v)); // indices - init_data.add_ushort_triangle(0, 1, 2); - init_data.add_ushort_triangle(2, 3, 0); + init_data.add_triangle(0, 1, 2); + init_data.add_triangle(2, 3, 0); GLModel model; model.init_from(std::move(init_data)); - GLShaderProgram* shader = wxGetApp().get_shader("flat_texture"); + GLShaderProgram* shader = wxGetApp().get_shader("flat_texture_attr"); if (shader != nullptr) { shader->start_using(); + shader->set_uniform("view_model_matrix", Transform3d::Identity()); + shader->set_uniform("projection_matrix", Transform3d::Identity()); model.render(); shader->stop_using(); } diff --git a/src/slic3r/GUI/GLToolbar.cpp b/src/slic3r/GUI/GLToolbar.cpp index 6a78edd907d..a10177ba9c0 100644 --- a/src/slic3r/GUI/GLToolbar.cpp +++ b/src/slic3r/GUI/GLToolbar.cpp @@ -551,18 +551,16 @@ void GLToolbar::render(const GLCanvas3D& parent,GLToolbarItem::EType type) { default: case Layout::Horizontal: { render_horizontal(parent,type); break; } - case Layout::Vertical: { render_vertical(parent); break; } + case Layout::Vertical: { render_vertical(parent); break; } } } - - bool GLToolbar::on_mouse(wxMouseEvent& evt, GLCanvas3D& parent) { if (!m_enabled) return false; - Vec2d mouse_pos((double)evt.GetX(), (double)evt.GetY()); + const Vec2d mouse_pos((double)evt.GetX(), (double)evt.GetY()); bool processed = false; // mouse anywhere @@ -610,7 +608,7 @@ bool GLToolbar::on_mouse(wxMouseEvent& evt, GLCanvas3D& parent) return false; } - int item_id = contains_mouse(mouse_pos, parent); + const int item_id = contains_mouse(mouse_pos, parent); if (item_id != -1) { // mouse inside toolbar if (evt.LeftDown() || evt.LeftDClick()) { @@ -757,16 +755,12 @@ int GLToolbar::get_visible_items_cnt() const void GLToolbar::do_action(GLToolbarItem::EActionType type, int item_id, GLCanvas3D& parent, bool check_hover) { - if ((m_pressed_toggable_id == -1) || (m_pressed_toggable_id == item_id)) - { - if ((0 <= item_id) && (item_id < (int)m_items.size())) - { + if (m_pressed_toggable_id == -1 || m_pressed_toggable_id == item_id) { + if (0 <= item_id && item_id < (int)m_items.size()) { GLToolbarItem* item = m_items[item_id]; - if ((item != nullptr) && !item->is_separator() && !item->is_disabled() && (!check_hover || item->is_hovered())) - { - if (((type == GLToolbarItem::Right) && item->is_right_toggable()) || - ((type == GLToolbarItem::Left) && item->is_left_toggable())) - { + if (item != nullptr && !item->is_separator() && !item->is_disabled() && (!check_hover || item->is_hovered())) { + if ((type == GLToolbarItem::Right && item->is_right_toggable()) || + (type == GLToolbarItem::Left && item->is_left_toggable())) { GLToolbarItem::EState state = item->get_state(); if (state == GLToolbarItem::Hover) item->set_state(GLToolbarItem::HoverPressed); @@ -784,12 +778,11 @@ void GLToolbar::do_action(GLToolbarItem::EActionType type, int item_id, GLCanvas switch (type) { default: - case GLToolbarItem::Left: { item->do_left_action(); break; } + case GLToolbarItem::Left: { item->do_left_action(); break; } case GLToolbarItem::Right: { item->do_right_action(); break; } } } - else - { + else { if (m_type == Radio) select_item(item->get_name()); else @@ -804,8 +797,7 @@ void GLToolbar::do_action(GLToolbarItem::EActionType type, int item_id, GLCanvas case GLToolbarItem::Right: { item->do_right_action(); break; } } - if ((m_type == Normal) && (item->get_state() != GLToolbarItem::Disabled)) - { + if (m_type == Normal && item->get_state() != GLToolbarItem::Disabled) { // the item may get disabled during the action, if not, set it back to normal state item->set_state(GLToolbarItem::Normal); parent.render(); @@ -825,55 +817,51 @@ void GLToolbar::update_hover_state(const Vec2d& mouse_pos, GLCanvas3D& parent) { default: case Layout::Horizontal: { update_hover_state_horizontal(mouse_pos, parent); break; } - case Layout::Vertical: { update_hover_state_vertical(mouse_pos, parent); break; } + case Layout::Vertical: { update_hover_state_vertical(mouse_pos, parent); break; } } } void GLToolbar::update_hover_state_horizontal(const Vec2d& mouse_pos, GLCanvas3D& parent) { - // NB: mouse_pos is already scaled appropriately - - float inv_zoom = (float)wxGetApp().plater()->get_camera().get_inv_zoom(); - float factor = m_layout.scale * inv_zoom; + const Size cnv_size = parent.get_canvas_size(); + const Vec2d scaled_mouse_pos((mouse_pos.x() - 0.5 * (double)cnv_size.get_width()), (0.5 * (double)cnv_size.get_height() - mouse_pos.y())); - Size cnv_size = parent.get_canvas_size(); - Vec2d scaled_mouse_pos((mouse_pos(0) - 0.5 * (double)cnv_size.get_width()) * inv_zoom, (0.5 * (double)cnv_size.get_height() - mouse_pos(1)) * inv_zoom); - - float scaled_icons_size = m_layout.icons_size * factor; - float scaled_separator_size = m_layout.separator_size * factor; - float scaled_gap_size = m_layout.gap_size * factor; - float scaled_border = m_layout.border * factor; + const float icons_size = m_layout.icons_size * m_layout.scale; + const float separator_size = m_layout.separator_size * m_layout.scale; + const float gap_size = m_layout.gap_size * m_layout.scale; + const float border = m_layout.border * m_layout.scale; - float separator_stride = scaled_separator_size + scaled_gap_size; - float icon_stride = scaled_icons_size + scaled_gap_size; + const float separator_stride = separator_size + gap_size; + const float icon_stride = icons_size + gap_size; - float left = m_layout.left + scaled_border; - float top = m_layout.top - scaled_border; + float left = m_layout.left + border; + float top = m_layout.top - border; - for (GLToolbarItem* item : m_items) - { + for (GLToolbarItem* item : m_items) { if (!item->is_visible()) continue; if (item->is_separator()) left += separator_stride; - else - { - float right = left + scaled_icons_size; - float bottom = top - scaled_icons_size; + else { + float right = left + icons_size; + const float bottom = top - icons_size; //BBS: GUI refactor: GLToolbar if (item->is_action_with_text()) - right += scaled_icons_size * item->get_extra_size_ratio(); - GLToolbarItem::EState state = item->get_state(); - bool inside = (left <= (float)scaled_mouse_pos(0)) && ((float)scaled_mouse_pos(0) <= right) && (bottom <= (float)scaled_mouse_pos(1)) && ((float)scaled_mouse_pos(1) <= top); + right += icons_size * item->get_extra_size_ratio(); + + const GLToolbarItem::EState state = item->get_state(); + bool inside = (left <= (float)scaled_mouse_pos.x()) && + ((float)scaled_mouse_pos.x() <= right) && + (bottom <= (float)scaled_mouse_pos.y()) && + ((float)scaled_mouse_pos.y() <= top); switch (state) { case GLToolbarItem::Normal: { - if (inside) - { + if (inside) { item->set_state(GLToolbarItem::Hover); parent.set_as_dirty(); } @@ -882,8 +870,7 @@ void GLToolbar::update_hover_state_horizontal(const Vec2d& mouse_pos, GLCanvas3D } case GLToolbarItem::Hover: { - if (!inside) - { + if (!inside) { item->set_state(GLToolbarItem::Normal); parent.set_as_dirty(); } @@ -892,8 +879,7 @@ void GLToolbar::update_hover_state_horizontal(const Vec2d& mouse_pos, GLCanvas3D } case GLToolbarItem::Pressed: { - if (inside) - { + if (inside) { item->set_state(GLToolbarItem::HoverPressed); parent.set_as_dirty(); } @@ -902,8 +888,7 @@ void GLToolbar::update_hover_state_horizontal(const Vec2d& mouse_pos, GLCanvas3D } case GLToolbarItem::HoverPressed: { - if (!inside) - { + if (!inside) { item->set_state(GLToolbarItem::Pressed); parent.set_as_dirty(); } @@ -912,8 +897,7 @@ void GLToolbar::update_hover_state_horizontal(const Vec2d& mouse_pos, GLCanvas3D } case GLToolbarItem::Disabled: { - if (inside) - { + if (inside) { item->set_state(GLToolbarItem::HoverDisabled); parent.set_as_dirty(); } @@ -922,8 +906,7 @@ void GLToolbar::update_hover_state_horizontal(const Vec2d& mouse_pos, GLCanvas3D } case GLToolbarItem::HoverDisabled: { - if (!inside) - { + if (!inside) { item->set_state(GLToolbarItem::Disabled); parent.set_as_dirty(); } @@ -939,59 +922,55 @@ void GLToolbar::update_hover_state_horizontal(const Vec2d& mouse_pos, GLCanvas3D left += icon_stride; //BBS: GUI refactor: GLToolbar if (item->is_action_with_text()) - left += scaled_icons_size * item->get_extra_size_ratio(); + left += icons_size * item->get_extra_size_ratio(); } } } void GLToolbar::update_hover_state_vertical(const Vec2d& mouse_pos, GLCanvas3D& parent) { - // NB: mouse_pos is already scaled appropriately - - float inv_zoom = (float)wxGetApp().plater()->get_camera().get_inv_zoom(); - float factor = m_layout.scale * inv_zoom; + const Size cnv_size = parent.get_canvas_size(); + const Vec2d scaled_mouse_pos((mouse_pos.x() - 0.5 * (double)cnv_size.get_width()), (0.5 * (double)cnv_size.get_height() - mouse_pos.y())); - Size cnv_size = parent.get_canvas_size(); - Vec2d scaled_mouse_pos((mouse_pos(0) - 0.5 * (double)cnv_size.get_width()) * inv_zoom, (0.5 * (double)cnv_size.get_height() - mouse_pos(1)) * inv_zoom); + const float icons_size = m_layout.icons_size * m_layout.scale; + const float separator_size = m_layout.separator_size * m_layout.scale; + const float gap_size = m_layout.gap_size * m_layout.scale; + const float border = m_layout.border * m_layout.scale; - float scaled_icons_size = m_layout.icons_size * factor; - float scaled_separator_size = m_layout.separator_size * factor; - float scaled_gap_size = m_layout.gap_size * factor; - float scaled_border = m_layout.border * factor; - float separator_stride = scaled_separator_size + scaled_gap_size; - float icon_stride = scaled_icons_size + scaled_gap_size; + const float separator_stride = separator_size + gap_size; + const float icon_stride = icons_size + gap_size; - float left = m_layout.left + scaled_border; - float top = m_layout.top - scaled_border; + float left = m_layout.left + border; + float top = m_layout.top - border; - for (GLToolbarItem* item : m_items) - { + for (GLToolbarItem* item : m_items) { if (!item->is_visible()) continue; if (item->is_separator()) top -= separator_stride; - else - { - float right = left + scaled_icons_size; - float bottom = top - scaled_icons_size; + else { + float right = left + icons_size; + const float bottom = top - icons_size; if (item->is_action_with_text_image()) - right += m_layout.text_size * factor; + right += m_layout.text_size * m_layout.scale; //BBS: GUI refactor: GLToolbar if (item->is_action_with_text()) - right += scaled_icons_size * item->get_extra_size_ratio(); + right += icons_size * item->get_extra_size_ratio(); GLToolbarItem::EState state = item->get_state(); - bool inside = (left <= (float)scaled_mouse_pos(0)) && ((float)scaled_mouse_pos(0) <= right) && (bottom <= (float)scaled_mouse_pos(1)) && ((float)scaled_mouse_pos(1) <= top); + const bool inside = (left <= (float)scaled_mouse_pos.x()) && + ((float)scaled_mouse_pos.x() <= right) && + (bottom <= (float)scaled_mouse_pos.y()) && + ((float)scaled_mouse_pos.y() <= top); switch (state) { case GLToolbarItem::Normal: { - if (inside) - { + if (inside) { item->set_state(GLToolbarItem::Hover); parent.set_as_dirty(); } @@ -1000,8 +979,7 @@ void GLToolbar::update_hover_state_vertical(const Vec2d& mouse_pos, GLCanvas3D& } case GLToolbarItem::Hover: { - if (!inside) - { + if (!inside) { item->set_state(GLToolbarItem::Normal); parent.set_as_dirty(); } @@ -1010,8 +988,7 @@ void GLToolbar::update_hover_state_vertical(const Vec2d& mouse_pos, GLCanvas3D& } case GLToolbarItem::Pressed: { - if (inside) - { + if (inside) { item->set_state(GLToolbarItem::HoverPressed); parent.set_as_dirty(); } @@ -1020,8 +997,7 @@ void GLToolbar::update_hover_state_vertical(const Vec2d& mouse_pos, GLCanvas3D& } case GLToolbarItem::HoverPressed: { - if (!inside) - { + if (!inside) { item->set_state(GLToolbarItem::Pressed); parent.set_as_dirty(); } @@ -1030,8 +1006,7 @@ void GLToolbar::update_hover_state_vertical(const Vec2d& mouse_pos, GLCanvas3D& } case GLToolbarItem::Disabled: { - if (inside) - { + if (inside) { item->set_state(GLToolbarItem::HoverDisabled); parent.set_as_dirty(); } @@ -1040,8 +1015,7 @@ void GLToolbar::update_hover_state_vertical(const Vec2d& mouse_pos, GLCanvas3D& } case GLToolbarItem::HoverDisabled: { - if (!inside) - { + if (!inside) { item->set_state(GLToolbarItem::Disabled); parent.set_as_dirty(); } @@ -1083,77 +1057,78 @@ int GLToolbar::contains_mouse(const Vec2d& mouse_pos, const GLCanvas3D& parent) { default: case Layout::Horizontal: { return contains_mouse_horizontal(mouse_pos, parent); } - case Layout::Vertical: { return contains_mouse_vertical(mouse_pos, parent); } + case Layout::Vertical: { return contains_mouse_vertical(mouse_pos, parent); } } } int GLToolbar::contains_mouse_horizontal(const Vec2d& mouse_pos, const GLCanvas3D& parent) const { - // NB: mouse_pos is already scaled appropriately + const Size cnv_size = parent.get_canvas_size(); + const Vec2d scaled_mouse_pos((mouse_pos.x() - 0.5 * (double)cnv_size.get_width()), (0.5 * (double)cnv_size.get_height() - mouse_pos.y())); - float inv_zoom = (float)wxGetApp().plater()->get_camera().get_inv_zoom(); - float factor = m_layout.scale * inv_zoom; - - Size cnv_size = parent.get_canvas_size(); - Vec2d scaled_mouse_pos((mouse_pos(0) - 0.5 * (double)cnv_size.get_width()) * inv_zoom, (0.5 * (double)cnv_size.get_height() - mouse_pos(1)) * inv_zoom); - - float scaled_icons_size = m_layout.icons_size * factor; - float scaled_separator_size = m_layout.separator_size * factor; - float scaled_gap_size = m_layout.gap_size * factor; - float scaled_border = m_layout.border * factor; + const float icons_size = m_layout.icons_size * m_layout.scale; + const float separator_size = m_layout.separator_size * m_layout.scale; + const float gap_size = m_layout.gap_size * m_layout.scale; + const float border = m_layout.border * m_layout.scale; - float left = m_layout.left + scaled_border; - float top = m_layout.top - scaled_border; + float left = m_layout.left + border; + const float top = m_layout.top - border; - - for (size_t id=0; idis_visible()) continue; - if (item->is_separator()) - { - float right = left + scaled_separator_size; - float bottom = top - scaled_icons_size; + if (item->is_separator()) { + float right = left + separator_size; + const float bottom = top - icons_size; // mouse inside the separator - if ((left <= (float)scaled_mouse_pos(0)) && ((float)scaled_mouse_pos(0) <= right) && (bottom <= (float)scaled_mouse_pos(1)) && ((float)scaled_mouse_pos(1) <= top)) + if (left <= (float)scaled_mouse_pos.x() && + (float)scaled_mouse_pos.x() <= right && + bottom <= (float)scaled_mouse_pos.y() && + (float)scaled_mouse_pos.y() <= top) return id; left = right; - right += scaled_gap_size; + right += gap_size; - if (id < m_items.size() - 1) - { + if (id < m_items.size() - 1) { // mouse inside the gap - if ((left <= (float)scaled_mouse_pos(0)) && ((float)scaled_mouse_pos(0) <= right) && (bottom <= (float)scaled_mouse_pos(1)) && ((float)scaled_mouse_pos(1) <= top)) + if (left <= (float)scaled_mouse_pos.x() && + (float)scaled_mouse_pos.x() <= right && + bottom <= (float)scaled_mouse_pos.y() && + (float)scaled_mouse_pos.y() <= top) return -2; } left = right; } - else - { - float right = left + scaled_icons_size; - float bottom = top - scaled_icons_size; + else { + float right = left + icons_size; + const float bottom = top - icons_size; //BBS: GUI refactor: GLToolbar if (item->is_action_with_text()) - right += scaled_icons_size * item->get_extra_size_ratio(); + right += icons_size * item->get_extra_size_ratio(); // mouse inside the icon - if ((left <= (float)scaled_mouse_pos(0)) && ((float)scaled_mouse_pos(0) <= right) && (bottom <= (float)scaled_mouse_pos(1)) && ((float)scaled_mouse_pos(1) <= top)) + if (left <= (float)scaled_mouse_pos.x() && + (float)scaled_mouse_pos.x() <= right && + bottom <= (float)scaled_mouse_pos.y() && + (float)scaled_mouse_pos.y() <= top) return id; left = right; - right += scaled_gap_size; + right += gap_size; - if (id < m_items.size() - 1) - { + if (id < m_items.size() - 1) { // mouse inside the gap - if ((left <= (float)scaled_mouse_pos(0)) && ((float)scaled_mouse_pos(0) <= right) && (bottom <= (float)scaled_mouse_pos(1)) && ((float)scaled_mouse_pos(1) <= top)) + if (left <= (float)scaled_mouse_pos.x() && + (float)scaled_mouse_pos.x() <= right && + bottom <= (float)scaled_mouse_pos.y() && + (float)scaled_mouse_pos.y() <= top) return -2; } @@ -1166,73 +1141,75 @@ int GLToolbar::contains_mouse_horizontal(const Vec2d& mouse_pos, const GLCanvas3 int GLToolbar::contains_mouse_vertical(const Vec2d& mouse_pos, const GLCanvas3D& parent) const { - // NB: mouse_pos is already scaled appropriately - - float inv_zoom = (float)wxGetApp().plater()->get_camera().get_inv_zoom(); - float factor = m_layout.scale * inv_zoom; - - Size cnv_size = parent.get_canvas_size(); - Vec2d scaled_mouse_pos((mouse_pos(0) - 0.5 * (double)cnv_size.get_width()) * inv_zoom, (0.5 * (double)cnv_size.get_height() - mouse_pos(1)) * inv_zoom); + const Size cnv_size = parent.get_canvas_size(); + const Vec2d scaled_mouse_pos((mouse_pos.x() - 0.5 * (double)cnv_size.get_width()), (0.5 * (double)cnv_size.get_height() - mouse_pos.y())); - float scaled_icons_size = m_layout.icons_size * factor; - float scaled_separator_size = m_layout.separator_size * factor; - float scaled_gap_size = m_layout.gap_size * factor; - float scaled_border = m_layout.border * factor; + const float icons_size = m_layout.icons_size * m_layout.scale; + const float separator_size = m_layout.separator_size * m_layout.scale; + const float gap_size = m_layout.gap_size * m_layout.scale; + const float border = m_layout.border * m_layout.scale; - float left = m_layout.left + scaled_border; - float top = m_layout.top - scaled_border; + const float left = m_layout.left + border; + float top = m_layout.top - border; - for (size_t id=0; idis_visible()) continue; - if (item->is_separator()) - { - float right = left + scaled_icons_size; - float bottom = top - scaled_separator_size; + if (item->is_separator()) { + const float right = left + icons_size; + float bottom = top - separator_size; // mouse inside the separator - if ((left <= (float)scaled_mouse_pos(0)) && ((float)scaled_mouse_pos(0) <= right) && (bottom <= (float)scaled_mouse_pos(1)) && ((float)scaled_mouse_pos(1) <= top)) + if (left <= (float)scaled_mouse_pos.x() && + (float)scaled_mouse_pos.x() <= right && + bottom <= (float)scaled_mouse_pos.y() && + (float)scaled_mouse_pos.y() <= top) return id; top = bottom; - bottom -= scaled_gap_size; + bottom -= gap_size; - if (id < m_items.size() - 1) - { + if (id < m_items.size() - 1) { // mouse inside the gap - if ((left <= (float)scaled_mouse_pos(0)) && ((float)scaled_mouse_pos(0) <= right) && (bottom <= (float)scaled_mouse_pos(1)) && ((float)scaled_mouse_pos(1) <= top)) + if (left <= (float)scaled_mouse_pos.x() && + (float)scaled_mouse_pos.x() <= right && + bottom <= (float)scaled_mouse_pos.y() && + (float)scaled_mouse_pos.y() <= top) return -2; } top = bottom; } - else - { - float right = left + scaled_icons_size; - float bottom = top - scaled_icons_size; + else { + float right = left + icons_size; + float bottom = top - icons_size; if (item->is_action_with_text_image()) - right += m_layout.text_size * factor; + right += m_layout.text_size * m_layout.scale; //BBS: GUI refactor: GLToolbar if (item->is_action_with_text()) - right += scaled_icons_size * item->get_extra_size_ratio(); + right += icons_size * item->get_extra_size_ratio(); // mouse inside the icon - if ((left <= (float)scaled_mouse_pos(0)) && ((float)scaled_mouse_pos(0) <= right) && (bottom <= (float)scaled_mouse_pos(1)) && ((float)scaled_mouse_pos(1) <= top)) + if (left <= (float)scaled_mouse_pos.x() && + (float)scaled_mouse_pos.x() <= right && + bottom <= (float)scaled_mouse_pos.y() && + (float)scaled_mouse_pos.y() <= top) return id; top = bottom; - bottom -= scaled_gap_size; + bottom -= gap_size; - if (id < m_items.size() - 1) - { + if (id < m_items.size() - 1) { // mouse inside the gap - if ((left <= (float)scaled_mouse_pos(0)) && ((float)scaled_mouse_pos(0) <= right) && (bottom <= (float)scaled_mouse_pos(1)) && ((float)scaled_mouse_pos(1) <= top)) + if (left <= (float)scaled_mouse_pos.x() && + (float)scaled_mouse_pos.x() <= right && + bottom <= (float)scaled_mouse_pos.y() && + (float)scaled_mouse_pos.y() <= top) return -2; } @@ -1243,33 +1220,32 @@ int GLToolbar::contains_mouse_vertical(const Vec2d& mouse_pos, const GLCanvas3D& return -1; } -void GLToolbar::render_background(float left, float top, float right, float bottom, float border) const +void GLToolbar::render_background(float left, float top, float right, float bottom, float border_w, float border_h) const { - unsigned int tex_id = m_background_texture.texture.get_id(); - float tex_width = (float)m_background_texture.texture.get_width(); - float tex_height = (float)m_background_texture.texture.get_height(); - if ((tex_id != 0) && (tex_width > 0) && (tex_height > 0)) - { - float inv_tex_width = (tex_width != 0.0f) ? 1.0f / tex_width : 0.0f; - float inv_tex_height = (tex_height != 0.0f) ? 1.0f / tex_height : 0.0f; + const unsigned int tex_id = m_background_texture.texture.get_id(); + const float tex_width = (float)m_background_texture.texture.get_width(); + const float tex_height = (float)m_background_texture.texture.get_height(); + if (tex_id != 0 && tex_width > 0.0f && tex_height > 0.0f) { + const float inv_tex_width = 1.0f / tex_width; + const float inv_tex_height = 1.0f / tex_height; - float internal_left = left + border; - float internal_right = right - border; - float internal_top = top - border; - float internal_bottom = bottom + border; + const float internal_left = left + border_w; + const float internal_right = right - border_w; + const float internal_top = top - border_h; + const float internal_bottom = bottom + border_w; - float left_uv = 0.0f; - float right_uv = 1.0f; - float top_uv = 1.0f; - float bottom_uv = 0.0f; + const float left_uv = 0.0f; + const float right_uv = 1.0f; + const float top_uv = 1.0f; + const float bottom_uv = 0.0f; - float internal_left_uv = (float)m_background_texture.metadata.left * inv_tex_width; - float internal_right_uv = 1.0f - (float)m_background_texture.metadata.right * inv_tex_width; - float internal_top_uv = 1.0f - (float)m_background_texture.metadata.top * inv_tex_height; - float internal_bottom_uv = (float)m_background_texture.metadata.bottom * inv_tex_height; + const float internal_left_uv = (float)m_background_texture.metadata.left * inv_tex_width; + const float internal_right_uv = 1.0f - (float)m_background_texture.metadata.right * inv_tex_width; + const float internal_top_uv = 1.0f - (float)m_background_texture.metadata.top * inv_tex_height; + const float internal_bottom_uv = (float)m_background_texture.metadata.bottom * inv_tex_height; // top-left corner - if ((m_layout.horizontal_orientation == Layout::HO_Left) || (m_layout.vertical_orientation == Layout::VO_Top)) + if (m_layout.horizontal_orientation == Layout::HO_Left || m_layout.vertical_orientation == Layout::VO_Top) GLTexture::render_sub_texture(tex_id, left, internal_left, internal_top, top, { { internal_left_uv, internal_bottom_uv }, { internal_right_uv, internal_bottom_uv }, { internal_right_uv, internal_top_uv }, { internal_left_uv, internal_top_uv } }); else GLTexture::render_sub_texture(tex_id, left, internal_left, internal_top, top, { { left_uv, internal_top_uv }, { internal_left_uv, internal_top_uv }, { internal_left_uv, top_uv }, { left_uv, top_uv } }); @@ -1281,7 +1257,7 @@ void GLToolbar::render_background(float left, float top, float right, float bott GLTexture::render_sub_texture(tex_id, internal_left, internal_right, internal_top, top, { { internal_left_uv, internal_top_uv }, { internal_right_uv, internal_top_uv }, { internal_right_uv, top_uv }, { internal_left_uv, top_uv } }); // top-right corner - if ((m_layout.horizontal_orientation == Layout::HO_Right) || (m_layout.vertical_orientation == Layout::VO_Top)) + if (m_layout.horizontal_orientation == Layout::HO_Right || m_layout.vertical_orientation == Layout::VO_Top) GLTexture::render_sub_texture(tex_id, internal_right, right, internal_top, top, { { internal_left_uv, internal_bottom_uv }, { internal_right_uv, internal_bottom_uv }, { internal_right_uv, internal_top_uv }, { internal_left_uv, internal_top_uv } }); else GLTexture::render_sub_texture(tex_id, internal_right, right, internal_top, top, { { internal_right_uv, internal_top_uv }, { right_uv, internal_top_uv }, { right_uv, top_uv }, { internal_right_uv, top_uv } }); @@ -1302,7 +1278,7 @@ void GLToolbar::render_background(float left, float top, float right, float bott GLTexture::render_sub_texture(tex_id, internal_right, right, internal_bottom, internal_top, { { internal_right_uv, internal_bottom_uv }, { right_uv, internal_bottom_uv }, { right_uv, internal_top_uv }, { internal_right_uv, internal_top_uv } }); // bottom-left corner - if ((m_layout.horizontal_orientation == Layout::HO_Left) || (m_layout.vertical_orientation == Layout::VO_Bottom)) + if (m_layout.horizontal_orientation == Layout::HO_Left || m_layout.vertical_orientation == Layout::VO_Bottom) GLTexture::render_sub_texture(tex_id, left, internal_left, bottom, internal_bottom, { { internal_left_uv, internal_bottom_uv }, { internal_right_uv, internal_bottom_uv }, { internal_right_uv, internal_top_uv }, { internal_left_uv, internal_top_uv } }); else GLTexture::render_sub_texture(tex_id, left, internal_left, bottom, internal_bottom, { { left_uv, bottom_uv }, { internal_left_uv, bottom_uv }, { internal_left_uv, internal_bottom_uv }, { left_uv, internal_bottom_uv } }); @@ -1314,7 +1290,7 @@ void GLToolbar::render_background(float left, float top, float right, float bott GLTexture::render_sub_texture(tex_id, internal_left, internal_right, bottom, internal_bottom, { { internal_left_uv, bottom_uv }, { internal_right_uv, bottom_uv }, { internal_right_uv, internal_bottom_uv }, { internal_left_uv, internal_bottom_uv } }); // bottom-right corner - if ((m_layout.horizontal_orientation == Layout::HO_Right) || (m_layout.vertical_orientation == Layout::VO_Bottom)) + if (m_layout.horizontal_orientation == Layout::HO_Right || m_layout.vertical_orientation == Layout::VO_Bottom) GLTexture::render_sub_texture(tex_id, internal_right, right, bottom, internal_bottom, { { internal_left_uv, internal_bottom_uv }, { internal_right_uv, internal_bottom_uv }, { internal_right_uv, internal_top_uv }, { internal_left_uv, internal_top_uv } }); else GLTexture::render_sub_texture(tex_id, internal_right, right, bottom, internal_bottom, { { internal_right_uv, bottom_uv }, { right_uv, bottom_uv }, { right_uv, internal_bottom_uv }, { internal_right_uv, internal_bottom_uv } }); @@ -1389,41 +1365,48 @@ void GLToolbar::render_arrow(const GLCanvas3D& parent, GLToolbarItem* highlighte void GLToolbar::render_horizontal(const GLCanvas3D& parent,GLToolbarItem::EType type) { - float inv_zoom = (float)wxGetApp().plater()->get_camera().get_inv_zoom(); - float factor = inv_zoom * m_layout.scale; + const Size cnv_size = parent.get_canvas_size(); + const float cnv_w = (float)cnv_size.get_width(); + const float cnv_h = (float)cnv_size.get_height(); - float scaled_icons_size = m_layout.icons_size * factor; - float scaled_separator_size = m_layout.separator_size * factor; - float scaled_gap_size = m_layout.gap_size * factor; - float scaled_border = m_layout.border * factor; - float scaled_width = get_width() * inv_zoom; - float scaled_height = get_height() * inv_zoom; + if (cnv_w == 0 || cnv_h == 0) + return; - float separator_stride = scaled_separator_size + scaled_gap_size; - float icon_stride = scaled_icons_size + scaled_gap_size; + const float inv_cnv_w = 1.0f / cnv_w; + const float inv_cnv_h = 1.0f / cnv_h; - float left = m_layout.left; - float top = m_layout.top; - float right = left + scaled_width; + const float icons_size_x = 2.0f * m_layout.icons_size * m_layout.scale * inv_cnv_w; + const float icons_size_y = 2.0f * m_layout.icons_size * m_layout.scale * inv_cnv_h; + const float separator_size = 2.0f * m_layout.separator_size * m_layout.scale * inv_cnv_w; + const float gap_size = 2.0f * m_layout.gap_size * m_layout.scale * inv_cnv_w; + const float border_w = 2.0f * m_layout.border * m_layout.scale * inv_cnv_w; + const float border_h = 2.0f * m_layout.border * m_layout.scale * inv_cnv_h; + const float width = 2.0f * get_width() * inv_cnv_w; + const float height = 2.0f * get_height() * inv_cnv_h; + + const float separator_stride = separator_size + gap_size; + const float icon_stride = icons_size_x + gap_size; + + float left = 2.0f * m_layout.left * inv_cnv_w; + float top = 2.0f * m_layout.top * inv_cnv_h; + float right = left + width; if (type == GLToolbarItem::SeparatorLine) - right = left + scaled_width * 0.5; - float bottom = top - scaled_height; + right = left + width * 0.5; + const float bottom = top - height; - render_background(left, top, right, bottom, scaled_border); + render_background(left, top, right, bottom, border_w, border_h); - left += scaled_border; - top -= scaled_border; + left += border_w; + top -= border_h; // renders icons - for (const GLToolbarItem* item : m_items) - { + for (const GLToolbarItem* item : m_items) { if (!item->is_visible()) continue; if (item->is_separator()) left += separator_stride; - else - { + else { //BBS GUI refactor item->render_left_pos = left; if (!item->is_action_with_text_image()) { @@ -1432,13 +1415,13 @@ void GLToolbar::render_horizontal(const GLCanvas3D& parent,GLToolbarItem::EType int tex_height = m_icons_texture.get_height(); if ((tex_id == 0) || (tex_width <= 0) || (tex_height <= 0)) return; - item->render(tex_id, left, left + scaled_icons_size, top - scaled_icons_size, top, (unsigned int)tex_width, (unsigned int)tex_height, (unsigned int)(m_layout.icons_size * m_layout.scale)); + item->render(tex_id, left, left + icons_size_x, top - icons_size_y, top, (unsigned int)tex_width, (unsigned int)tex_height, (unsigned int)(m_layout.icons_size * m_layout.scale)); } //BBS: GUI refactor: GLToolbar if (item->is_action_with_text()) { - float scaled_text_size = item->get_extra_size_ratio() * scaled_icons_size; - item->render_text(left + scaled_icons_size, left + scaled_icons_size + scaled_text_size, top - scaled_icons_size, top); + float scaled_text_size = item->get_extra_size_ratio() * icons_size_x; + item->render_text(left + icons_size_x, left + icons_size_x + scaled_text_size, top - icons_size_y, top); left += scaled_text_size; } left += icon_stride; @@ -1448,28 +1431,37 @@ void GLToolbar::render_horizontal(const GLCanvas3D& parent,GLToolbarItem::EType void GLToolbar::render_vertical(const GLCanvas3D& parent) { - float inv_zoom = (float)wxGetApp().plater()->get_camera().get_inv_zoom(); - float factor = inv_zoom * m_layout.scale; + const Size cnv_size = parent.get_canvas_size(); + const float cnv_w = (float)cnv_size.get_width(); + const float cnv_h = (float)cnv_size.get_height(); - float scaled_icons_size = m_layout.icons_size * factor; - float scaled_separator_size = m_layout.separator_size * factor; - float scaled_gap_size = m_layout.gap_size * factor; - float scaled_border = m_layout.border * factor; - float scaled_width = get_width() * inv_zoom; - float scaled_height = get_height() * inv_zoom; + if (cnv_w == 0 || cnv_h == 0) + return; - float separator_stride = scaled_separator_size + scaled_gap_size; - float icon_stride = scaled_icons_size + scaled_gap_size; + const float inv_cnv_w = 1.0f / cnv_w; + const float inv_cnv_h = 1.0f / cnv_h; - float left = m_layout.left; - float top = m_layout.top; - float right = left + scaled_width; - float bottom = top - scaled_height; + const float icons_size_x = 2.0f * m_layout.icons_size * m_layout.scale * inv_cnv_w; + const float icons_size_y = 2.0f * m_layout.icons_size * m_layout.scale * inv_cnv_h; + const float separator_size = 2.0f * m_layout.separator_size * m_layout.scale * inv_cnv_h; + const float gap_size = 2.0f * m_layout.gap_size * m_layout.scale * inv_cnv_h; + const float border_w = 2.0f * m_layout.border * m_layout.scale * inv_cnv_w; + const float border_h = 2.0f * m_layout.border * m_layout.scale * inv_cnv_h; + const float width = 2.0f * get_width() * inv_cnv_w; + const float height = 2.0f * get_height() * inv_cnv_h; + + const float separator_stride = separator_size + gap_size; + const float icon_stride = icons_size_y + gap_size; + + float left = 2.0f * m_layout.left * inv_cnv_w; + float top = 2.0f * m_layout.top * inv_cnv_h; + const float right = left + width; + const float bottom = top - height; - render_background(left, top, right, bottom, scaled_border); + render_background(left, top, right, bottom, border_w, border_h); - left += scaled_border; - top -= scaled_border; + left += border_w; + top -= border_h; // renders icons for (const GLToolbarItem* item : m_items) { @@ -1482,10 +1474,10 @@ void GLToolbar::render_vertical(const GLCanvas3D& parent) unsigned int tex_id; int tex_width, tex_height; if (item->is_action_with_text_image()) { - float scaled_text_size = m_layout.text_size * factor; - float scaled_text_width = item->get_extra_size_ratio() * scaled_icons_size; - float scaled_text_border = 2.5 * factor; - float scaled_text_height = scaled_icons_size / 2.0f; + float scaled_text_size = m_layout.text_size * m_layout.scale * inv_cnv_w; + float scaled_text_width = item->get_extra_size_ratio() * icons_size_x; + float scaled_text_border = 2.5 * m_layout.scale * inv_cnv_h; + float scaled_text_height = icons_size_y / 2.0f; item->render_text(left, left + scaled_text_size, top - scaled_text_border - scaled_text_height, top - scaled_text_border); float image_left = left + scaled_text_size; @@ -1494,7 +1486,7 @@ void GLToolbar::render_vertical(const GLCanvas3D& parent) tex_height = item->m_data.image_texture.get_height(); if ((tex_id == 0) || (tex_width <= 0) || (tex_height <= 0)) return; - item->render_image(tex_id, image_left, image_left + scaled_icons_size, top - scaled_icons_size, top, (unsigned int)tex_width, (unsigned int)tex_height, (unsigned int)(m_layout.icons_size * m_layout.scale)); + item->render_image(tex_id, image_left, image_left + icons_size_x, top - icons_size_y, top, (unsigned int)tex_width, (unsigned int)tex_height, (unsigned int)(m_layout.icons_size * m_layout.scale)); } else { tex_id = m_icons_texture.get_id(); @@ -1502,14 +1494,14 @@ void GLToolbar::render_vertical(const GLCanvas3D& parent) tex_height = m_icons_texture.get_height(); if ((tex_id == 0) || (tex_width <= 0) || (tex_height <= 0)) return; - item->render(tex_id, left, left + scaled_icons_size, top - scaled_icons_size, top, (unsigned int)tex_width, (unsigned int)tex_height, (unsigned int)(m_layout.icons_size * m_layout.scale)); + item->render(tex_id, left, left + icons_size_x, top - icons_size_y, top, (unsigned int)tex_width, (unsigned int)tex_height, (unsigned int)(m_layout.icons_size * m_layout.scale)); //BBS: GUI refactor: GLToolbar } if (item->is_action_with_text()) { - float scaled_text_width = item->get_extra_size_ratio() * scaled_icons_size; - float scaled_text_height = scaled_icons_size; - item->render_text(left + scaled_icons_size, left + scaled_icons_size + scaled_text_width, top - scaled_text_height, top); + float scaled_text_width = item->get_extra_size_ratio() * icons_size_x; + float scaled_text_height = icons_size_y; + item->render_text(left + icons_size_x, left + icons_size_x + scaled_text_width, top - scaled_text_height, top); } top -= icon_stride; } diff --git a/src/slic3r/GUI/GLToolbar.hpp b/src/slic3r/GUI/GLToolbar.hpp index 09da22d3cd1..43f81b5abb2 100644 --- a/src/slic3r/GUI/GLToolbar.hpp +++ b/src/slic3r/GUI/GLToolbar.hpp @@ -436,8 +436,8 @@ class GLToolbar int contains_mouse_horizontal(const Vec2d& mouse_pos, const GLCanvas3D& parent) const; int contains_mouse_vertical(const Vec2d& mouse_pos, const GLCanvas3D& parent) const; - void render_background(float left, float top, float right, float bottom, float border) const; - void render_horizontal(const GLCanvas3D& parent,GLToolbarItem::EType type); + void render_background(float left, float top, float right, float bottom, float border_w, float border_h) const; + void render_horizontal(const GLCanvas3D &parent, GLToolbarItem::EType type); void render_vertical(const GLCanvas3D& parent); bool generate_icons_texture(); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoAdvancedCut.cpp b/src/slic3r/GUI/Gizmos/GLGizmoAdvancedCut.cpp index 9bae84b0349..fc132f57bc8 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoAdvancedCut.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoAdvancedCut.cpp @@ -492,8 +492,6 @@ void GLGizmoAdvancedCut::on_render_for_picking() glsafe(::glDisable(GL_DEPTH_TEST)); - glsafe(::glPushMatrix()); - BoundingBoxf3 box = m_parent.get_selection().get_bounding_box(); #if ENABLE_FIXED_GRABBER float mean_size = (float)(GLGizmoBase::Grabber::FixedGrabberSize); @@ -502,17 +500,17 @@ void GLGizmoAdvancedCut::on_render_for_picking() #endif m_move_grabber.color = picking_color_component(0); - GLShaderProgram *shader = wxGetApp().get_shader("flat"); + GLShaderProgram *shader = wxGetApp().get_shader("flat_attr"); if (shader != nullptr) { shader->start_using(); - + const Camera &camera = wxGetApp().plater()->get_camera(); + shader->set_uniform("view_model_matrix", camera.get_view_matrix()); + shader->set_uniform("projection_matrix", camera.get_projection_matrix()); m_move_grabber.render_for_picking(mean_size); shader->stop_using(); } - glsafe(::glPopMatrix()); - glsafe(::glEnable(GL_DEPTH_TEST)); auto inst_id = m_c->selection_info()->get_active_instance(); if (inst_id < 0) @@ -868,7 +866,7 @@ void GLGizmoAdvancedCut::render_cut_plane_and_grabbers() glsafe(::glEnable(GL_BLEND)); glsafe(::glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)); - GLShaderProgram *shader = wxGetApp().get_shader("flat"); + GLShaderProgram *shader = wxGetApp().get_shader("flat_attr"); if (shader != nullptr) { shader->start_using(); @@ -877,7 +875,7 @@ void GLGizmoAdvancedCut::render_cut_plane_and_grabbers() m_plane.reset(); GLModel::Geometry init_data; - init_data.format = { GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3, GLModel::Geometry::EIndexType::USHORT }; + init_data.format = { GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3 }; init_data.color = { 0.8f, 0.8f, 0.8f, 0.5f }; init_data.reserve_vertices(4); init_data.reserve_vertices(6); @@ -888,11 +886,14 @@ void GLGizmoAdvancedCut::render_cut_plane_and_grabbers() } // indices - init_data.add_ushort_triangle(0, 1, 2); - init_data.add_ushort_triangle(2, 3, 0); + init_data.add_triangle(0, 1, 2); + init_data.add_triangle(2, 3, 0); m_plane.init_from(std::move(init_data)); } + const Camera &camera = wxGetApp().plater()->get_camera(); + shader->set_uniform("view_model_matrix", camera.get_view_matrix()); + shader->set_uniform("projection_matrix", camera.get_projection_matrix()); m_plane.render(); glsafe(::glEnable(GL_CULL_FACE)); @@ -907,17 +908,17 @@ void GLGizmoAdvancedCut::render_cut_plane_and_grabbers() m_grabber_connection.reset(); GLModel::Geometry init_data; - init_data.format = { GLModel::Geometry::EPrimitiveType::Lines, GLModel::Geometry::EVertexLayout::P3, GLModel::Geometry::EIndexType::USHORT }; + init_data.format = { GLModel::Geometry::EPrimitiveType::Lines, GLModel::Geometry::EVertexLayout::P3 }; init_data.color = ColorRGBA::YELLOW(); - init_data.vertices.reserve(2 * GLModel::Geometry::vertex_stride_floats(init_data.format)); - init_data.indices.reserve(2 * GLModel::Geometry::index_stride_bytes(init_data.format)); + init_data.reserve_vertices(2); + init_data.reserve_vertices(2); // vertices init_data.add_vertex((Vec3f)plane_center_rot.cast()); init_data.add_vertex((Vec3f)m_move_grabber.center.cast()); // indices - init_data.add_ushort_line(0, 1); + init_data.add_line(0, 1); m_grabber_connection.init_from(std::move(init_data)); } @@ -933,7 +934,7 @@ void GLGizmoAdvancedCut::render_cut_plane_and_grabbers() } { - GLShaderProgram *shader = wxGetApp().get_shader("gouraud_light"); + GLShaderProgram *shader = wxGetApp().get_shader("gouraud_light_attr"); if (shader == nullptr) return; shader->start_using(); @@ -960,13 +961,15 @@ void GLGizmoAdvancedCut::render_cut_plane_and_grabbers() cube.set_color(render_color); - glsafe(::glPushMatrix()); - glsafe(::glTranslated(m_move_grabber.center.x(), m_move_grabber.center.y(), m_move_grabber.center.z())); - glsafe(::glMultMatrixd(m_rotate_matrix.data())); - - glsafe(::glScaled(fullsize, fullsize, fullsize)); + const Camera& camera = wxGetApp().plater()->get_camera(); + const Transform3d view_model_matrix = camera.get_view_matrix() * Geometry::assemble_transform(m_move_grabber.center) * + m_rotate_matrix * + Geometry::assemble_transform(Vec3d::Zero(), Vec3d::Zero(), fullsize * Vec3d::Ones()); + const Transform3d& projection_matrix = camera.get_projection_matrix(); + shader->set_uniform("view_model_matrix", view_model_matrix); + shader->set_uniform("projection_matrix", projection_matrix); + shader->set_uniform("normal_matrix", (Matrix3d) view_model_matrix.matrix().block(0, 0, 3, 3).inverse().transpose()); cube.render(); - glsafe(::glPopMatrix()); shader->stop_using(); } @@ -1064,23 +1067,26 @@ void GLGizmoAdvancedCut::render_cut_line() void GLGizmoAdvancedCut::render_connector_model(GLModel &model, const ColorRGBA &color, Transform3d view_model_matrix, bool for_picking) { - glPushMatrix(); GLShaderProgram *shader = nullptr; if (for_picking) - shader = wxGetApp().get_shader("cali"); + shader = wxGetApp().get_shader("flat_attr"); else - shader = wxGetApp().get_shader("gouraud_light"); + shader = wxGetApp().get_shader("gouraud_light_attr"); if (shader) { shader->start_using(); - glsafe(::glMultMatrixd(view_model_matrix.data())); + const Camera& camera = wxGetApp().plater()->get_camera(); + view_model_matrix = camera.get_view_matrix() * view_model_matrix; + const Transform3d &projection_matrix = camera.get_projection_matrix(); + shader->set_uniform("view_model_matrix", view_model_matrix); + shader->set_uniform("projection_matrix", projection_matrix); + shader->set_uniform("normal_matrix", (Matrix3d) view_model_matrix.matrix().block(0, 0, 3, 3).inverse().transpose()); model.set_color(color); model.render(); shader->stop_using(); } - glPopMatrix(); } void GLGizmoAdvancedCut::clear_selection() diff --git a/src/slic3r/GUI/Gizmos/GLGizmoBase.cpp b/src/slic3r/GUI/Gizmos/GLGizmoBase.cpp index 849470f3817..5dc0cc38e74 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoBase.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoBase.cpp @@ -4,6 +4,7 @@ #include #include "slic3r/GUI/GUI_App.hpp" +#include "slic3r/GUI/Plater.hpp" #include "slic3r/GUI/GUI_Colors.hpp" // TODO: Display tooltips quicker on Linux @@ -97,11 +98,15 @@ GLModel& GLGizmoBase::Grabber::get_cube() void GLGizmoBase::Grabber::render(float size, const ColorRGBA& render_color, bool picking) { + GLShaderProgram* shader = wxGetApp().get_current_shader(); + if (shader == nullptr) + return; + if (!m_cube.is_initialized()) { // This cannot be done in constructor, OpenGL is not yet // initialized at that point (on Linux at least). indexed_triangle_set its = its_make_cube(1., 1., 1.); - its_translate(its, Vec3f(-0.5, -0.5, -0.5)); + its_translate(its, -0.5f * Vec3f::Ones()); m_cube.init_from(its); } @@ -115,14 +120,14 @@ void GLGizmoBase::Grabber::render(float size, const ColorRGBA& render_color, boo m_cube.set_color(render_color); - glsafe(::glPushMatrix()); - glsafe(::glTranslated(center.x(), center.y(), center.z())); - glsafe(::glRotated(Geometry::rad2deg(angles.z()), 0.0, 0.0, 1.0)); - glsafe(::glRotated(Geometry::rad2deg(angles.y()), 0.0, 1.0, 0.0)); - glsafe(::glRotated(Geometry::rad2deg(angles.x()), 1.0, 0.0, 0.0)); - glsafe(::glScaled(fullsize, fullsize, fullsize)); + const Camera& camera = wxGetApp().plater()->get_camera(); + const Transform3d view_model_matrix = camera.get_view_matrix() * matrix * Geometry::assemble_transform(center, angles, fullsize * Vec3d::Ones()); + const Transform3d& projection_matrix = camera.get_projection_matrix(); + + shader->set_uniform("view_model_matrix", view_model_matrix); + shader->set_uniform("projection_matrix", projection_matrix); + shader->set_uniform("normal_matrix", (Matrix3d)view_model_matrix.matrix().block(0, 0, 3, 3).inverse().transpose()); m_cube.render(); - glsafe(::glPopMatrix()); } GLGizmoBase::GLGizmoBase(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id) @@ -257,7 +262,7 @@ void GLGizmoBase::render_grabbers(const BoundingBoxf3& box) const void GLGizmoBase::render_grabbers(float size) const { - GLShaderProgram* shader = wxGetApp().get_shader("gouraud_light"); + GLShaderProgram* shader = wxGetApp().get_shader("gouraud_light_attr"); if (shader == nullptr) return; shader->start_using(); @@ -271,7 +276,7 @@ void GLGizmoBase::render_grabbers(float size) const void GLGizmoBase::render_grabbers_for_picking(const BoundingBoxf3& box) const { - GLShaderProgram* shader = wxGetApp().get_shader("flat"); + GLShaderProgram* shader = wxGetApp().get_shader("flat_attr"); if (shader != nullptr) { shader->start_using(); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoBase.hpp b/src/slic3r/GUI/Gizmos/GLGizmoBase.hpp index b2b8c4626e8..4e8a6dc1d04 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoBase.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoBase.hpp @@ -68,6 +68,7 @@ class GLGizmoBase bool dragging{ false }; Vec3d center{ Vec3d::Zero() }; Vec3d angles{ Vec3d::Zero() }; + Transform3d matrix{ Transform3d::Identity() }; ColorRGBA color{GRABBER_NORMAL_COL}; ColorRGBA hover_color{GRABBER_HOVER_COL}; diff --git a/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp b/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp index 86aa18f8944..c6a635ccd50 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp @@ -155,7 +155,7 @@ bool GLGizmoFdmSupports::on_key_down_select_tool_type(int keyCode) { void GLGizmoFdmSupports::render_triangles(const Selection& selection) const { ClippingPlaneDataWrapper clp_data = this->get_clipping_plane_data(); - auto* shader = wxGetApp().get_shader("mm_gouraud"); + auto* shader = wxGetApp().get_shader("mm_gouraud_attr"); if (!shader) return; shader->start_using(); @@ -177,8 +177,11 @@ void GLGizmoFdmSupports::render_triangles(const Selection& selection) const if (is_left_handed) glsafe(::glFrontFace(GL_CW)); - glsafe(::glPushMatrix()); - glsafe(::glMultMatrixd(trafo_matrix.data())); + const Camera& camera = wxGetApp().plater()->get_camera(); + const Transform3d matrix = camera.get_view_matrix() * trafo_matrix; + shader->set_uniform("view_model_matrix", matrix); + shader->set_uniform("projection_matrix", camera.get_projection_matrix()); + shader->set_uniform("normal_matrix", (Matrix3d)matrix.matrix().block(0, 0, 3, 3).inverse().transpose()); float normal_z = -::cos(Geometry::deg2rad(m_highlight_by_angle_threshold_deg)); Matrix3f normal_matrix = static_cast(trafo_matrix.matrix().block(0, 0, 3, 3).inverse().transpose().cast()); @@ -188,9 +191,8 @@ void GLGizmoFdmSupports::render_triangles(const Selection& selection) const shader->set_uniform("slope.actived", m_parent.is_using_slope()); shader->set_uniform("slope.volume_world_normal_matrix", normal_matrix); shader->set_uniform("slope.normal_z", normal_z); - m_triangle_selectors[mesh_id]->render(m_imgui); + m_triangle_selectors[mesh_id]->render(m_imgui, trafo_matrix); - glsafe(::glPopMatrix()); if (is_left_handed) glsafe(::glFrontFace(GL_CCW)); } @@ -895,7 +897,7 @@ void GLGizmoFdmSupports::run_thread() goto _finished; } GLModel::Geometry init_data; - init_data.format = { GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3N3, GLModel::Geometry::EIndexType::UINT }; + init_data.format = { GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3N3 }; for (const SupportLayer *support_layer : m_print_instance.print_object->support_layers()) { for (const ExtrusionEntity *extrusion_entity : support_layer->support_fills.entities) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoFlatten.cpp b/src/slic3r/GUI/Gizmos/GLGizmoFlatten.cpp index 71ce1097949..c47e1225d82 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoFlatten.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoFlatten.cpp @@ -2,6 +2,7 @@ #include "GLGizmoFlatten.hpp" #include "slic3r/GUI/GLCanvas3D.hpp" #include "slic3r/GUI/GUI_App.hpp" +#include "slic3r/GUI/Plater.hpp" #include "slic3r/GUI/Gizmos/GLGizmosCommon.hpp" #include "libslic3r/Geometry/ConvexHull.hpp" @@ -63,7 +64,7 @@ void GLGizmoFlatten::on_render() { const Selection& selection = m_parent.get_selection(); - GLShaderProgram* shader = wxGetApp().get_shader("flat"); + GLShaderProgram* shader = wxGetApp().get_shader("flat_attr"); if (shader == nullptr) return; @@ -75,16 +76,18 @@ void GLGizmoFlatten::on_render() if (selection.is_single_full_instance()) { const Transform3d& m = selection.get_volume(*selection.get_volume_idxs().begin())->get_instance_transformation().get_matrix(); - glsafe(::glPushMatrix()); - glsafe(::glTranslatef(0.f, 0.f, selection.get_volume(*selection.get_volume_idxs().begin())->get_sla_shift_z())); - glsafe(::glMultMatrixd(m.data())); + const Camera& camera = wxGetApp().plater()->get_camera(); + const Transform3d view_model_matrix = camera.get_view_matrix() * + Geometry::assemble_transform(selection.get_volume(*selection.get_volume_idxs().begin())->get_sla_shift_z() * Vec3d::UnitZ()) * m; + + shader->set_uniform("view_model_matrix", view_model_matrix); + shader->set_uniform("projection_matrix", camera.get_projection_matrix()); if (this->is_plane_update_necessary()) update_planes(); for (int i = 0; i < (int)m_planes.size(); ++i) { m_planes[i].vbo.set_color(i == m_hover_id ? GLGizmoBase::FLATTEN_HOVER_COLOR : GLGizmoBase::FLATTEN_COLOR); m_planes[i].vbo.render(); } - glsafe(::glPopMatrix()); } glsafe(::glEnable(GL_CULL_FACE)); @@ -95,7 +98,7 @@ void GLGizmoFlatten::on_render() void GLGizmoFlatten::on_render_for_picking() { const Selection& selection = m_parent.get_selection(); - GLShaderProgram* shader = wxGetApp().get_shader("flat"); + GLShaderProgram* shader = wxGetApp().get_shader("flat_attr"); if (shader == nullptr) return; @@ -106,16 +109,18 @@ void GLGizmoFlatten::on_render_for_picking() if (selection.is_single_full_instance() && !wxGetKeyState(WXK_CONTROL)) { const Transform3d& m = selection.get_volume(*selection.get_volume_idxs().begin())->get_instance_transformation().get_matrix(); - glsafe(::glPushMatrix()); - glsafe(::glTranslatef(0.f, 0.f, selection.get_volume(*selection.get_volume_idxs().begin())->get_sla_shift_z())); - glsafe(::glMultMatrixd(m.data())); + const Camera& camera = wxGetApp().plater()->get_camera(); + const Transform3d view_model_matrix = camera.get_view_matrix() * + Geometry::assemble_transform(selection.get_volume(*selection.get_volume_idxs().begin())->get_sla_shift_z() * Vec3d::UnitZ()) * m; + + shader->set_uniform("view_model_matrix", view_model_matrix); + shader->set_uniform("projection_matrix", camera.get_projection_matrix()); if (this->is_plane_update_necessary()) update_planes(); for (int i = 0; i < (int)m_planes.size(); ++i) { m_planes[i].vbo.set_color(picking_color_component(i)); m_planes[i].vbo.render(); } - glsafe(::glPopMatrix()); } glsafe(::glEnable(GL_CULL_FACE)); @@ -337,16 +342,13 @@ void GLGizmoFlatten::update_planes() // the vertices in order, so triangulation is trivial. for (auto& plane : m_planes) { GLModel::Geometry init_data; - init_data.format = { GLModel::Geometry::EPrimitiveType::TriangleFan, GLModel::Geometry::EVertexLayout::P3N3, GLModel::Geometry::index_type(plane.vertices.size()) }; + init_data.format = { GLModel::Geometry::EPrimitiveType::TriangleFan, GLModel::Geometry::EVertexLayout::P3N3 }; init_data.reserve_vertices(plane.vertices.size()); init_data.reserve_indices(plane.vertices.size()); // vertices + indices for (size_t i = 0; i < plane.vertices.size(); ++i) { init_data.add_vertex((Vec3f)plane.vertices[i].cast(), (Vec3f)plane.normal.cast()); - if (init_data.format.index_type == GLModel::Geometry::EIndexType::USHORT) - init_data.add_ushort_index((unsigned short)i); - else - init_data.add_uint_index((unsigned int)i); + init_data.add_index((unsigned int)i); } plane.vbo.init_from(std::move(init_data)); // FIXME: vertices should really be local, they need not diff --git a/src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp b/src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp index 113ea049928..59026be85eb 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp @@ -103,28 +103,30 @@ void GLGizmoHollow::on_render_for_picking() void GLGizmoHollow::render_points(const Selection& selection, bool picking) { - GLShaderProgram* shader = picking ? wxGetApp().get_shader("flat") : wxGetApp().get_shader("gouraud_light"); + GLShaderProgram* shader = picking ? wxGetApp().get_shader("flat_attr") : wxGetApp().get_shader("gouraud_light_attr"); if (shader == nullptr) return; - + shader->start_using(); ScopeGuard guard([shader]() { shader->stop_using(); }); const GLVolume* vol = selection.get_volume(*selection.get_volume_idxs().begin()); - const Transform3d& instance_scaling_matrix_inverse = vol->get_instance_transformation().get_matrix(true, true, false, true).inverse(); - const Transform3d& instance_matrix = vol->get_instance_transformation().get_matrix(); + const Transform3d instance_scaling_matrix_inverse = vol->get_instance_transformation().get_matrix(true, true, false, true).inverse(); + const Transform3d instance_matrix = Geometry::assemble_transform(m_c->selection_info()->get_sla_shift() * Vec3d::UnitZ()) * vol->get_instance_transformation().get_matrix(); + + const Camera& camera = wxGetApp().plater()->get_camera(); + const Transform3d& view_matrix = camera.get_view_matrix(); + const Transform3d& projection_matrix = camera.get_projection_matrix(); - glsafe(::glPushMatrix()); - glsafe(::glTranslated(0.0, 0.0, m_c->selection_info()->get_sla_shift())); - glsafe(::glMultMatrixd(instance_matrix.data())); + shader->set_uniform("projection_matrix", projection_matrix); ColorRGBA render_color; const sla::DrainHoles& drain_holes = m_c->selection_info()->model_object()->sla_drain_holes; - size_t cache_size = drain_holes.size(); + const size_t cache_size = drain_holes.size(); for (size_t i = 0; i < cache_size; ++i) { const sla::DrainHole& drain_hole = drain_holes[i]; - const bool& point_selected = m_selected[i]; + const bool point_selected = m_selected[i]; if (is_mesh_point_clipped(drain_hole.pos.cast())) continue; @@ -147,9 +149,7 @@ void GLGizmoHollow::render_points(const Selection& selection, bool picking) m_cylinder.set_color(render_color); // Inverse matrix of the instance scaling is applied so that the mark does not scale with the object. - glsafe(::glPushMatrix()); - glsafe(::glTranslatef(drain_hole.pos.x(), drain_hole.pos.y(), drain_hole.pos.z())); - glsafe(::glMultMatrixd(instance_scaling_matrix_inverse.data())); + const Transform3d hole_matrix = Geometry::assemble_transform(drain_hole.pos.cast()) * instance_scaling_matrix_inverse; if (vol->is_left_handed()) glFrontFace(GL_CW); @@ -157,18 +157,17 @@ void GLGizmoHollow::render_points(const Selection& selection, bool picking) // Matrices set, we can render the point mark now. Eigen::Quaterniond q; q.setFromTwoVectors(Vec3d::UnitZ(), instance_scaling_matrix_inverse * (-drain_hole.normal).cast()); - Eigen::AngleAxisd aa(q); - glsafe(::glRotated(aa.angle() * (180. / M_PI), aa.axis().x(), aa.axis().y(), aa.axis().z())); - glsafe(::glTranslated(0., 0., -drain_hole.height)); - glsafe(::glScaled(drain_hole.radius, drain_hole.radius, drain_hole.height + sla::HoleStickOutLength)); + const Eigen::AngleAxisd aa(q); + const Transform3d view_model_matrix = view_matrix * instance_matrix * hole_matrix * Transform3d(aa.toRotationMatrix()) * + Geometry::assemble_transform(-drain_hole.height * Vec3d::UnitZ(), Vec3d::Zero(), Vec3d(drain_hole.radius, drain_hole.radius, drain_hole.height + sla::HoleStickOutLength)); + + shader->set_uniform("view_model_matrix", view_model_matrix); + shader->set_uniform("normal_matrix", (Matrix3d)view_model_matrix.matrix().block(0, 0, 3, 3).inverse().transpose()); m_cylinder.render(); if (vol->is_left_handed()) glFrontFace(GL_CCW); - glsafe(::glPopMatrix()); } - - glsafe(::glPopMatrix()); } bool GLGizmoHollow::is_mesh_point_clipped(const Vec3d& point) const diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp index 30bc71f8e61..e52267841ed 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp @@ -192,7 +192,7 @@ void GLGizmoMmuSegmentation::set_painter_gizmo_data(const Selection &selection) void GLGizmoMmuSegmentation::render_triangles(const Selection &selection) const { ClippingPlaneDataWrapper clp_data = this->get_clipping_plane_data(); - auto *shader = wxGetApp().get_shader("mm_gouraud"); + auto* shader = wxGetApp().get_shader("mm_gouraud_attr"); if (!shader) return; shader->start_using(); @@ -221,18 +221,20 @@ void GLGizmoMmuSegmentation::render_triangles(const Selection &selection) const trafo_matrix = mo->instances[selection.get_instance_idx()]->get_transformation().get_matrix()* mv->get_matrix(); } - bool is_left_handed = trafo_matrix.matrix().determinant() < 0.; + const bool is_left_handed = trafo_matrix.matrix().determinant() < 0.0; if (is_left_handed) glsafe(::glFrontFace(GL_CW)); - glsafe(::glPushMatrix()); - glsafe(::glMultMatrixd(trafo_matrix.data())); + const Camera& camera = wxGetApp().plater()->get_camera(); + const Transform3d matrix = camera.get_view_matrix() * trafo_matrix; + shader->set_uniform("view_model_matrix", matrix); + shader->set_uniform("projection_matrix", camera.get_projection_matrix()); + shader->set_uniform("normal_matrix", (Matrix3d)matrix.matrix().block(0, 0, 3, 3).inverse().transpose()); shader->set_uniform("volume_world_matrix", trafo_matrix); shader->set_uniform("volume_mirrored", is_left_handed); - m_triangle_selectors[mesh_id]->render(m_imgui); + m_triangle_selectors[mesh_id]->render(m_imgui, trafo_matrix); - glsafe(::glPopMatrix()); if (is_left_handed) glsafe(::glFrontFace(GL_CCW)); } diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMove.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMove.cpp index 469dff42f60..ebdf6ec390a 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMove.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMove.cpp @@ -140,7 +140,7 @@ void GLGizmoMove3D::on_render() m_grabber_connections[id].model.reset(); GLModel::Geometry init_data; - init_data.format = { GLModel::Geometry::EPrimitiveType::Lines, GLModel::Geometry::EVertexLayout::P3, GLModel::Geometry::EIndexType::USHORT }; + init_data.format = { GLModel::Geometry::EPrimitiveType::Lines, GLModel::Geometry::EVertexLayout::P3 }; init_data.color = AXES_COLOR[id]; init_data.reserve_vertices(2); init_data.reserve_indices(2); @@ -150,7 +150,7 @@ void GLGizmoMove3D::on_render() init_data.add_vertex((Vec3f)m_grabbers[id].center.cast()); // indices - init_data.add_ushort_line(0, 1); + init_data.add_line(0, 1); m_grabber_connections[id].model.init_from(std::move(init_data)); //} @@ -162,11 +162,13 @@ void GLGizmoMove3D::on_render() } }; - GLShaderProgram* shader = wxGetApp().get_shader("flat"); + GLShaderProgram* shader = wxGetApp().get_shader("flat_attr"); if (shader != nullptr) { shader->start_using(); - - // draw axes line + const Camera& camera = wxGetApp().plater()->get_camera(); + shader->set_uniform("view_model_matrix", camera.get_view_matrix()); + shader->set_uniform("projection_matrix", camera.get_projection_matrix()); + // draw axes for (unsigned int i = 0; i < 3; ++i) { render_grabber_connection(i); @@ -240,12 +242,12 @@ double GLGizmoMove3D::calc_projection(const UpdateData& data) const void GLGizmoMove3D::render_grabber_extension(Axis axis, const BoundingBoxf3& box, bool picking) { #if ENABLE_FIXED_GRABBER - float mean_size = (float)(GLGizmoBase::Grabber::FixedGrabberSize); + const float mean_size = (float)(GLGizmoBase::Grabber::FixedGrabberSize); #else - float mean_size = (float)((box.size().x() + box.size().y() + box.size().z()) / 3.0); + const float mean_size = (float)((box.size().x() + box.size().y() + box.size().z()) / 3.0); #endif - double size = 0.75 * GLGizmoBase::Grabber::FixedGrabberSize * GLGizmoBase::INV_ZOOM; + const double size = 0.75 * GLGizmoBase::Grabber::FixedGrabberSize * GLGizmoBase::INV_ZOOM; ColorRGBA color = m_grabbers[axis].color; if (!picking && m_hover_id != -1) { @@ -254,7 +256,7 @@ void GLGizmoMove3D::render_grabber_extension(Axis axis, const BoundingBoxf3& box } } - GLShaderProgram* shader = wxGetApp().get_shader(picking ? "flat" : "gouraud_light"); + GLShaderProgram* shader = wxGetApp().get_shader(picking ? "flat_attr" : "gouraud_light_attr"); if (shader == nullptr) return; @@ -262,22 +264,21 @@ void GLGizmoMove3D::render_grabber_extension(Axis axis, const BoundingBoxf3& box shader->start_using(); shader->set_uniform("emission_factor", 0.1f); - glsafe(::glPushMatrix()); - glsafe(::glTranslated(m_grabbers[axis].center.x(), m_grabbers[axis].center.y(), m_grabbers[axis].center.z())); + const Camera& camera = wxGetApp().plater()->get_camera(); + Transform3d view_model_matrix = camera.get_view_matrix() * Geometry::assemble_transform(m_grabbers[axis].center); if (axis == X) - glsafe(::glRotated(90.0, 0.0, 1.0, 0.0)); + view_model_matrix = view_model_matrix * Geometry::assemble_transform(Vec3d::Zero(), 0.5 * PI * Vec3d::UnitY()); else if (axis == Y) - glsafe(::glRotated(-90.0, 1.0, 0.0, 0.0)); + view_model_matrix = view_model_matrix * Geometry::assemble_transform(Vec3d::Zero(), -0.5 * PI * Vec3d::UnitX()); + view_model_matrix = view_model_matrix * Geometry::assemble_transform(Vec3d::Zero(), Vec3d::Zero(), Vec3d(0.75 * size, 0.75 * size, 2.0 * size)); - //glsafe(::glTranslated(0.0, 0.0, 2.0 * size)); - glsafe(::glScaled(0.75 * size, 0.75 * size, 2.0 * size)); + shader->set_uniform("view_model_matrix", view_model_matrix); + shader->set_uniform("projection_matrix", camera.get_projection_matrix()); + shader->set_uniform("normal_matrix", (Matrix3d)view_model_matrix.matrix().block(0, 0, 3, 3).inverse().transpose()); m_cone.render(); - glsafe(::glPopMatrix()); shader->stop_using(); } - - } // namespace GUI } // namespace Slic3r diff --git a/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp b/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp index fbc2f25ffaf..7d83f38cce4 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp @@ -75,7 +75,7 @@ GLGizmoPainterBase::ClippingPlaneDataWrapper GLGizmoPainterBase::get_clipping_pl void GLGizmoPainterBase::render_triangles(const Selection& selection) const { - auto* shader = wxGetApp().get_shader("gouraud"); + auto* shader = wxGetApp().get_shader("gouraud_attr"); if (! shader) return; shader->start_using(); @@ -105,8 +105,11 @@ void GLGizmoPainterBase::render_triangles(const Selection& selection) const if (is_left_handed) glsafe(::glFrontFace(GL_CW)); - glsafe(::glPushMatrix()); - glsafe(::glMultMatrixd(trafo_matrix.data())); + const Camera& camera = wxGetApp().plater()->get_camera(); + const Transform3d matrix = camera.get_view_matrix() * trafo_matrix; + shader->set_uniform("view_model_matrix", matrix); + shader->set_uniform("projection_matrix", camera.get_projection_matrix()); + shader->set_uniform("normal_matrix", (Matrix3d)matrix.matrix().block(0, 0, 3, 3).inverse().transpose()); // For printers with multiple extruders, it is necessary to pass trafo_matrix // to the shader input variable print_box.volume_world_matrix before @@ -114,9 +117,8 @@ void GLGizmoPainterBase::render_triangles(const Selection& selection) const // wrong transformation matrix is used for "Clipping of view". shader->set_uniform("volume_world_matrix", trafo_matrix); - m_triangle_selectors[mesh_id]->render(m_imgui); + m_triangle_selectors[mesh_id]->render(m_imgui, trafo_matrix); - glsafe(::glPopMatrix()); if (is_left_handed) glsafe(::glFrontFace(GL_CCW)); } @@ -165,43 +167,34 @@ void GLGizmoPainterBase::render_cursor() void GLGizmoPainterBase::render_cursor_circle() { - const Camera &camera = wxGetApp().plater()->get_camera(); - const float zoom = float(camera.get_zoom()); - const float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f; - const Size cnv_size = m_parent.get_canvas_size(); - const float cnv_half_width = 0.5f * float(cnv_size.get_width()); - const float cnv_half_height = 0.5f * float(cnv_size.get_height()); - if (cnv_half_width == 0.0f || cnv_half_height == 0.0f) + const float cnv_width = float(cnv_size.get_width()); + const float cnv_height = float(cnv_size.get_height()); + if (cnv_width == 0.0f || cnv_height == 0.0f) return; - const Vec2d mouse_pos(m_parent.get_local_mouse_position().x(), m_parent.get_local_mouse_position().y()); - Vec2d center(mouse_pos.x() - cnv_half_width, cnv_half_height - mouse_pos.y()); - center = center * inv_zoom; + + const float cnv_inv_width = 1.0f / cnv_width; + const float cnv_inv_height = 1.0f / cnv_height; + + const Vec2d center = m_parent.get_local_mouse_position(); + const float radius = m_cursor_radius * float(wxGetApp().plater()->get_camera().get_zoom()); glsafe(::glLineWidth(1.5f)); glsafe(::glDisable(GL_DEPTH_TEST)); - glsafe(::glPushMatrix()); - glsafe(::glLoadIdentity()); - // ensure that the circle is renderered inside the frustrum - glsafe(::glTranslated(0.0, 0.0, -(camera.get_near_z() + 0.5))); - // ensure that the overlay fits the frustrum near z plane - const double gui_scale = camera.get_gui_scale(); - glsafe(::glScaled(gui_scale, gui_scale, 1.0)); - glsafe(::glPushAttrib(GL_ENABLE_BIT)); glsafe(::glLineStipple(4, 0xAAAA)); glsafe(::glEnable(GL_LINE_STIPPLE)); - if (!m_circle.is_initialized() || !m_old_center.isApprox(center) || std::abs(m_old_cursor_radius - m_cursor_radius) > EPSILON) { + if (!m_circle.is_initialized() || !m_old_center.isApprox(center) || std::abs(m_old_cursor_radius - radius) > EPSILON) { + m_old_cursor_radius = radius; m_old_center = center; - m_old_cursor_radius = m_cursor_radius; m_circle.reset(); GLModel::Geometry init_data; static const unsigned int StepsCount = 32; static const float StepSize = 2.0f * float(PI) / float(StepsCount); - init_data.format = { GLModel::Geometry::EPrimitiveType::LineLoop, GLModel::Geometry::EVertexLayout::P2, GLModel::Geometry::EIndexType::USHORT }; + init_data.format = { GLModel::Geometry::EPrimitiveType::LineLoop, GLModel::Geometry::EVertexLayout::P2 }; init_data.color = { 0.0f, 1.0f, 0.3f, 1.0f }; init_data.reserve_vertices(StepsCount); init_data.reserve_indices(StepsCount); @@ -209,8 +202,9 @@ void GLGizmoPainterBase::render_cursor_circle() // vertices + indices for (unsigned short i = 0; i < StepsCount; ++i) { const float angle = float(i * StepSize); - init_data.add_vertex(Vec2f(center.x() + ::cos(angle) * m_cursor_radius, center.y() + ::sin(angle) * m_cursor_radius)); - init_data.add_ushort_index(i); + init_data.add_vertex(Vec2f(2.0f * ((center.x() + ::cos(angle) * radius) * cnv_inv_width - 0.5f), + -2.0f * ((center.y() + ::sin(angle) * radius) * cnv_inv_height - 0.5f))); + init_data.add_index(i); } m_circle.init_from(std::move(init_data)); @@ -225,15 +219,16 @@ void GLGizmoPainterBase::render_cursor_circle() m_circle.set_color(render_color); - GLShaderProgram* shader = GUI::wxGetApp().get_shader("flat"); + GLShaderProgram* shader = wxGetApp().get_shader("flat_attr"); if (shader != nullptr) { shader->start_using(); + shader->set_uniform("view_model_matrix", Transform3d::Identity()); + shader->set_uniform("projection_matrix", Transform3d::Identity()); m_circle.render(); shader->stop_using(); } glsafe(::glPopAttrib()); - glsafe(::glPopMatrix()); glsafe(::glEnable(GL_DEPTH_TEST)); } @@ -245,20 +240,13 @@ void GLGizmoPainterBase::render_cursor_sphere(const Transform3d& trafo) const s_sphere->init_from(its_make_sphere(1.0, double(PI) / 12.0)); } - GLShaderProgram* shader = wxGetApp().get_shader("flat"); + GLShaderProgram* shader = wxGetApp().get_shader("flat_attr"); if (shader == nullptr) return; const Transform3d complete_scaling_matrix_inverse = Geometry::Transformation(trafo).get_matrix(true, true, false, true).inverse(); const bool is_left_handed = Geometry::Transformation(trafo).is_left_handed(); - glsafe(::glPushMatrix()); - glsafe(::glMultMatrixd(trafo.data())); - // Inverse matrix of the instance scaling is applied so that the mark does not scale with the object. - glsafe(::glTranslatef(m_rr.hit.x(), m_rr.hit.y(), m_rr.hit.z())); - glsafe(::glMultMatrixd(complete_scaling_matrix_inverse.data())); - glsafe(::glScaled(m_cursor_radius, m_cursor_radius, m_cursor_radius)); - if (is_left_handed) glFrontFace(GL_CW); @@ -270,6 +258,14 @@ void GLGizmoPainterBase::render_cursor_sphere(const Transform3d& trafo) const render_color = this->get_cursor_sphere_right_button_color(); shader->start_using(); + const Camera& camera = wxGetApp().plater()->get_camera(); + Transform3d view_model_matrix = camera.get_view_matrix() * trafo * + Geometry::assemble_transform(m_rr.hit.cast()) * complete_scaling_matrix_inverse * + Geometry::assemble_transform(Vec3d::Zero(), Vec3d::Zero(), m_cursor_radius * Vec3d::Ones()); + + shader->set_uniform("view_model_matrix", view_model_matrix); + shader->set_uniform("projection_matrix", camera.get_projection_matrix()); + assert(s_sphere != nullptr); s_sphere->set_color(render_color); s_sphere->render(); @@ -277,13 +273,17 @@ void GLGizmoPainterBase::render_cursor_sphere(const Transform3d& trafo) const shader->stop_using(); if (is_left_handed) glFrontFace(GL_CCW); - - glsafe(::glPopMatrix()); } // BBS void GLGizmoPainterBase::render_cursor_height_range(const Transform3d& trafo) const { + GLShaderProgram *shader = wxGetApp().get_shader("flat_attr"); + if (shader == nullptr) + return; + + shader->start_using(); + const BoundingBoxf3 box = bounding_box(); Vec3d hit_world = trafo * Vec3d(m_rr.hit(0), m_rr.hit(1), m_rr.hit(2)); float max_z = (float)box.max.z(); @@ -309,14 +309,18 @@ void GLGizmoPainterBase::render_cursor_height_range(const Transform3d& trafo) co for (int i = 0; i < zs.size(); i++) { update_contours(vol_mesh, zs[i], max_z, min_z); - glsafe(::glPushMatrix()); - glsafe(::glTranslated(m_cut_contours.shift.x(), m_cut_contours.shift.y(), m_cut_contours.shift.z())); + const Camera& camera = wxGetApp().plater()->get_camera(); + Transform3d view_model_matrix = camera.get_view_matrix() * Geometry::assemble_transform(m_cut_contours.shift); + + shader->set_uniform("view_model_matrix", view_model_matrix); + shader->set_uniform("projection_matrix", camera.get_projection_matrix()); glsafe(::glLineWidth(2.0f)); m_cut_contours.contours.render(); - glsafe(::glPopMatrix()); } } + + shader->stop_using(); } BoundingBoxf3 GLGizmoPainterBase::bounding_box() const @@ -1056,7 +1060,7 @@ ColorRGBA TriangleSelectorGUI::get_seed_fill_color(const ColorRGBA& base_color) 1.f}; } -void TriangleSelectorGUI::render(ImGuiWrapper* imgui) +void TriangleSelectorGUI::render(ImGuiWrapper* imgui, const Transform3d& matrix) { if (m_update_render_data) { update_render_data(); @@ -1066,7 +1070,7 @@ void TriangleSelectorGUI::render(ImGuiWrapper* imgui) auto* shader = wxGetApp().get_current_shader(); if (! shader) return; - assert(shader->get_name() == "gouraud"); + assert(shader->get_name() == "gouraud_attr" || shader->get_name() == "mm_gouraud_attr"); ScopeGuard guard([shader]() { if (shader) shader->set_uniform("offset_depth_buffer", false);}); shader->set_uniform("offset_depth_buffer", true); for (auto iva : {std::make_pair(&m_iva_enforcers, enforcers_color), @@ -1084,7 +1088,7 @@ void TriangleSelectorGUI::render(ImGuiWrapper* imgui) iva.render(); } - render_paint_contour(); + render_paint_contour(matrix); #ifdef PRUSASLICER_TRIANGLE_SELECTOR_DEBUG if (imgui) @@ -1109,12 +1113,12 @@ void TriangleSelectorGUI::update_render_data() } GLModel::Geometry iva_enforcers_data; - iva_enforcers_data.format = { GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3N3, GLModel::Geometry::EIndexType::UINT }; + iva_enforcers_data.format = { GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3N3 }; GLModel::Geometry iva_blockers_data; - iva_blockers_data.format = { GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3N3, GLModel::Geometry::EIndexType::UINT }; + iva_blockers_data.format = { GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3N3 }; std::array iva_seed_fills_data; for (auto& data : iva_seed_fills_data) - data.format = { GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3N3, GLModel::Geometry::EIndexType::UINT }; + data.format = { GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3N3 }; for (const Triangle &tr : m_triangles) { bool is_valid = tr.valid(); @@ -1140,7 +1144,7 @@ void TriangleSelectorGUI::update_render_data() iva.add_vertex(v0, n); iva.add_vertex(v1, n); iva.add_vertex(v2, n); - iva.add_uint_triangle((unsigned int)cnt, (unsigned int)cnt + 1, (unsigned int)cnt + 2); + iva.add_triangle((unsigned int)cnt, (unsigned int)cnt + 1, (unsigned int)cnt + 2); cnt += 3; } @@ -1164,7 +1168,7 @@ bool TrianglePatch::is_fragment() const float TriangleSelectorPatch::gap_area = TriangleSelectorPatch::GapAreaMin; -void TriangleSelectorPatch::render(ImGuiWrapper* imgui) +void TriangleSelectorPatch::render(ImGuiWrapper* imgui, const Transform3d& matrix) { if (m_update_render_data) { update_render_data(); @@ -1174,8 +1178,8 @@ void TriangleSelectorPatch::render(ImGuiWrapper* imgui) auto* shader = wxGetApp().get_current_shader(); if (!shader) return; - assert(shader->get_name() == "mm_gouraud"); - GLint position_id = -1; + assert(shader->get_name() == "gouraud_attr" || shader->get_name() == "mm_gouraud_attr"); + GLint position_id = -1; GLint barycentric_id = -1; if (wxGetApp().plater()->is_wireframe_enabled()) { position_id = shader->get_attrib_location("v_position"); @@ -1212,7 +1216,7 @@ void TriangleSelectorPatch::render(ImGuiWrapper* imgui) } } - render_paint_contour(); + render_paint_contour(matrix); } void TriangleSelectorPatch::update_triangles_per_type() @@ -1631,10 +1635,14 @@ void TriangleSelectorGUI::render_debug(ImGuiWrapper* imgui) if (curr_shader != nullptr) curr_shader->stop_using(); - GLShaderProgram* shader = wxGetApp().get_shader("flat"); + GLShaderProgram* shader = wxGetApp().get_shader("flat_attr"); if (shader != nullptr) { shader->start_using(); + const Camera& camera = wxGetApp().plater()->get_camera(); + shader->set_uniform("view_model_matrix", camera.get_view_matrix()); + shader->set_uniform("projection_matrix", camera.get_projection_matrix()); + ::glPolygonMode( GL_FRONT_AND_BACK, GL_LINE ); for (vtype i : {ORIGINAL, SPLIT, INVALID}) { GLModel& va = m_varrays[i]; @@ -1661,35 +1669,37 @@ void TriangleSelectorGUI::update_paint_contour() GLModel::Geometry init_data; const std::vector contour_edges = this->get_seed_fill_contour(); - init_data.format = { GLModel::Geometry::EPrimitiveType::Lines, GLModel::Geometry::EVertexLayout::P3, GLModel::Geometry::index_type(2 * contour_edges.size()) }; + init_data.format = { GLModel::Geometry::EPrimitiveType::Lines, GLModel::Geometry::EVertexLayout::P3 }; init_data.reserve_vertices(2 * contour_edges.size()); init_data.reserve_indices(2 * contour_edges.size()); + init_data.color = ColorRGBA::WHITE(); // vertices + indices unsigned int vertices_count = 0; for (const Vec2i& edge : contour_edges) { init_data.add_vertex(m_vertices[edge(0)].v); init_data.add_vertex(m_vertices[edge(1)].v); vertices_count += 2; - if (init_data.format.index_type == GLModel::Geometry::EIndexType::USHORT) - init_data.add_ushort_line((unsigned short)vertices_count - 2, (unsigned short)vertices_count - 1); - else - init_data.add_uint_line(vertices_count - 2, vertices_count - 1); + init_data.add_line(vertices_count - 2, vertices_count - 1); } if (!init_data.is_empty()) m_paint_contour.init_from(std::move(init_data)); } -void TriangleSelectorGUI::render_paint_contour() +void TriangleSelectorGUI::render_paint_contour(const Transform3d& matrix) { auto* curr_shader = wxGetApp().get_current_shader(); if (curr_shader != nullptr) curr_shader->stop_using(); - auto* contour_shader = wxGetApp().get_shader("mm_contour"); + auto* contour_shader = wxGetApp().get_shader("mm_contour_attr"); if (contour_shader != nullptr) { contour_shader->start_using(); + const Camera& camera = wxGetApp().plater()->get_camera(); + contour_shader->set_uniform("view_model_matrix", camera.get_view_matrix() * matrix); + contour_shader->set_uniform("projection_matrix", camera.get_projection_matrix()); + glsafe(::glDepthFunc(GL_LEQUAL)); m_paint_contour.render(); glsafe(::glDepthFunc(GL_LESS)); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.hpp b/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.hpp index c4f2cb5e29c..0582e7aa778 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.hpp @@ -34,10 +34,8 @@ class TriangleSelectorGUI : public TriangleSelector { : TriangleSelector(mesh, edge_limit) {} virtual ~TriangleSelectorGUI() = default; - // Render current selection. Transformation matrices are supposed - // to be already set. - virtual void render(ImGuiWrapper *imgui); - void render() { this->render(nullptr); } + virtual void render(ImGuiWrapper* imgui, const Transform3d& matrix); + void render(const Transform3d& matrix) { this->render(nullptr, matrix); } void set_wireframe_needed(bool need_wireframe) { m_need_wireframe = need_wireframe; } bool get_wireframe_needed() { return m_need_wireframe; } @@ -79,7 +77,7 @@ class TriangleSelectorGUI : public TriangleSelector { GLModel m_paint_contour; void update_paint_contour(); - void render_paint_contour(); + void render_paint_contour(const Transform3d& matrix); bool m_need_wireframe {false}; }; @@ -105,7 +103,7 @@ class TriangleSelectorPatch : public TriangleSelectorGUI { // Render current selection. Transformation matrices are supposed // to be already set. - void render(ImGuiWrapper* imgui) override; + void render(ImGuiWrapper* imgui, const Transform3d& matrix) override; // TriangleSelector.m_triangles => m_gizmo_scene.triangle_patches void update_triangles_per_type(); // m_gizmo_scene.triangle_patches => TriangleSelector.m_triangles diff --git a/src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp b/src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp index a660d87dcc0..ab3196364e9 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp @@ -126,14 +126,19 @@ void GLGizmoRotate::on_render() glsafe(::glEnable(GL_DEPTH_TEST)); - glsafe(::glPushMatrix()); - transform_to_local(selection); + m_grabbers.front().matrix = local_transform(selection); glsafe(::glLineWidth((m_hover_id != -1) ? 2.0f : 1.5f)); - GLShaderProgram* shader = wxGetApp().get_shader("flat"); + GLShaderProgram* shader = wxGetApp().get_shader("flat_attr"); if (shader != nullptr) { shader->start_using(); + const Camera& camera = wxGetApp().plater()->get_camera(); + Transform3d view_model_matrix = camera.get_view_matrix() * m_grabbers.front().matrix; + + shader->set_uniform("view_model_matrix", view_model_matrix); + shader->set_uniform("projection_matrix", camera.get_projection_matrix()); + const bool radius_changed = std::abs(m_old_radius - m_radius) > EPSILON; m_old_radius = m_radius; @@ -152,6 +157,8 @@ void GLGizmoRotate::on_render() render_grabber_connection(color, radius_changed); shader->stop_using(); } + glsafe(::glPushMatrix()); + transform_to_local(selection); render_grabber(box); render_grabber_extension(box, false); @@ -165,15 +172,11 @@ void GLGizmoRotate::on_render_for_picking() glsafe(::glDisable(GL_DEPTH_TEST)); - glsafe(::glPushMatrix()); - - transform_to_local(selection); + m_grabbers.front().matrix = local_transform(selection); const BoundingBoxf3& box = selection.get_bounding_box(); render_grabbers_for_picking(box); render_grabber_extension(box, true); - - glsafe(::glPopMatrix()); } //BBS: add input window for move @@ -214,7 +217,7 @@ void GLGizmoRotate::render_circle(const ColorRGBA& color, bool radius_changed) m_circle.reset(); GLModel::Geometry init_data; - init_data.format = { GLModel::Geometry::EPrimitiveType::LineLoop, GLModel::Geometry::EVertexLayout::P3, GLModel::Geometry::EIndexType::USHORT }; + init_data.format = { GLModel::Geometry::EPrimitiveType::LineLoop, GLModel::Geometry::EVertexLayout::P3 }; init_data.reserve_vertices(ScaleStepsCount); init_data.reserve_indices(ScaleStepsCount); @@ -222,7 +225,7 @@ void GLGizmoRotate::render_circle(const ColorRGBA& color, bool radius_changed) for (unsigned short i = 0; i < ScaleStepsCount; ++i) { const float angle = float(i * ScaleStepRad); init_data.add_vertex(Vec3f(::cos(angle) * m_radius, ::sin(angle) * m_radius, 0.0f)); - init_data.add_ushort_index(i); + init_data.add_index(i); } m_circle.init_from(std::move(init_data)); @@ -241,7 +244,7 @@ void GLGizmoRotate::render_scale(const ColorRGBA& color, bool radius_changed) m_scale.reset(); GLModel::Geometry init_data; - init_data.format = { GLModel::Geometry::EPrimitiveType::Lines, GLModel::Geometry::EVertexLayout::P3, GLModel::Geometry::EIndexType::USHORT }; + init_data.format = { GLModel::Geometry::EPrimitiveType::Lines, GLModel::Geometry::EVertexLayout::P3 }; init_data.reserve_vertices(2 * ScaleStepsCount); init_data.reserve_indices(2 * ScaleStepsCount); @@ -257,8 +260,8 @@ void GLGizmoRotate::render_scale(const ColorRGBA& color, bool radius_changed) init_data.add_vertex(Vec3f(in_x, in_y, 0.0f)); init_data.add_vertex(Vec3f(out_x, out_y, 0.0f)); - init_data.add_ushort_index(i * 2); - init_data.add_ushort_index(i * 2 + 1); + init_data.add_index(i * 2); + init_data.add_index(i * 2 + 1); } m_scale.init_from(std::move(init_data)); @@ -278,7 +281,7 @@ void GLGizmoRotate::render_snap_radii(const ColorRGBA& color, bool radius_change m_snap_radii.reset(); GLModel::Geometry init_data; - init_data.format = { GLModel::Geometry::EPrimitiveType::Lines, GLModel::Geometry::EVertexLayout::P3, GLModel::Geometry::EIndexType::USHORT }; + init_data.format = { GLModel::Geometry::EPrimitiveType::Lines, GLModel::Geometry::EVertexLayout::P3 }; init_data.reserve_vertices(2 * ScaleStepsCount); init_data.reserve_indices(2 * ScaleStepsCount); @@ -294,8 +297,8 @@ void GLGizmoRotate::render_snap_radii(const ColorRGBA& color, bool radius_change init_data.add_vertex(Vec3f(in_x, in_y, 0.0f)); init_data.add_vertex(Vec3f(out_x, out_y, 0.0f)); - init_data.add_ushort_index(i * 2); - init_data.add_ushort_index(i * 2 + 1); + init_data.add_index(i * 2); + init_data.add_index(i * 2 + 1); } m_snap_radii.init_from(std::move(init_data)); @@ -311,7 +314,7 @@ void GLGizmoRotate::render_reference_radius(const ColorRGBA& color, bool radius_ m_reference_radius.reset(); GLModel::Geometry init_data; - init_data.format = { GLModel::Geometry::EPrimitiveType::Lines, GLModel::Geometry::EVertexLayout::P3, GLModel::Geometry::EIndexType::USHORT }; + init_data.format = { GLModel::Geometry::EPrimitiveType::Lines, GLModel::Geometry::EVertexLayout::P3 }; init_data.reserve_vertices(2); init_data.reserve_indices(2); @@ -320,7 +323,7 @@ void GLGizmoRotate::render_reference_radius(const ColorRGBA& color, bool radius_ init_data.add_vertex(Vec3f(m_radius * (1.0f + GrabberOffset), 0.0f, 0.0f)); // indices - init_data.add_ushort_line(0, 1); + init_data.add_line(0, 1); m_reference_radius.init_from(std::move(init_data)); } @@ -341,7 +344,7 @@ void GLGizmoRotate::render_angle_arc(const ColorRGBA& color, bool radius_changed m_angle_arc.reset(); if (m_angle > 0.0f) { GLModel::Geometry init_data; - init_data.format = { GLModel::Geometry::EPrimitiveType::LineStrip, GLModel::Geometry::EVertexLayout::P3, GLModel::Geometry::EIndexType::USHORT }; + init_data.format = { GLModel::Geometry::EPrimitiveType::LineStrip, GLModel::Geometry::EVertexLayout::P3 }; init_data.reserve_vertices(1 + AngleResolution); init_data.reserve_indices(1 + AngleResolution); @@ -349,7 +352,7 @@ void GLGizmoRotate::render_angle_arc(const ColorRGBA& color, bool radius_changed for (unsigned short i = 0; i <= AngleResolution; ++i) { const float angle = float(i) * step_angle; init_data.add_vertex(Vec3f(::cos(angle) * ex_radius, ::sin(angle) * ex_radius, 0.0f)); - init_data.add_ushort_index(i); + init_data.add_index(i); } m_angle_arc.init_from(std::move(init_data)); @@ -367,7 +370,7 @@ void GLGizmoRotate::render_grabber_connection(const ColorRGBA& color, bool radiu m_grabber_connection.old_center = m_grabbers.front().center; GLModel::Geometry init_data; - init_data.format = { GLModel::Geometry::EPrimitiveType::Lines, GLModel::Geometry::EVertexLayout::P3, GLModel::Geometry::EIndexType::USHORT }; + init_data.format = { GLModel::Geometry::EPrimitiveType::Lines, GLModel::Geometry::EVertexLayout::P3 }; init_data.reserve_vertices(2); init_data.reserve_indices(2); @@ -376,7 +379,7 @@ void GLGizmoRotate::render_grabber_connection(const ColorRGBA& color, bool radiu init_data.add_vertex((Vec3f)m_grabbers.front().center.cast()); // indices - init_data.add_ushort_line(0, 1); + init_data.add_line(0, 1); m_grabber_connection.model.init_from(std::move(init_data)); } @@ -401,36 +404,69 @@ void GLGizmoRotate::render_grabber_extension(const BoundingBoxf3& box, bool pick if (!picking && m_hover_id != -1) color = m_grabbers.front().hover_color; - GLShaderProgram* shader = wxGetApp().get_shader(picking ? "flat" : "gouraud_light"); + GLShaderProgram* shader = wxGetApp().get_shader(picking ? "flat_attr" : "gouraud_light_attr"); if (shader == nullptr) return; m_cone.set_color(color); + shader->start_using(); shader->set_uniform("emission_factor", 0.1f); const Vec3d& center = m_grabbers.front().center; - glsafe(::glPushMatrix()); - glsafe(::glTranslated(center.x(), center.y(), center.z())); - glsafe(::glRotated(Geometry::rad2deg(m_angle), 0.0, 0.0, 1.0)); - glsafe(::glRotated(90.0, 1.0, 0.0, 0.0)); - glsafe(::glTranslated(0.0, 0.0, 1.5 * size)); - glsafe(::glScaled(0.75 * size, 0.75 * size, 3.0 * size)); + const Camera& camera = wxGetApp().plater()->get_camera(); + const Transform3d& view_matrix = camera.get_view_matrix(); + shader->set_uniform("projection_matrix", camera.get_projection_matrix()); + + Transform3d view_model_matrix = view_matrix * m_grabbers.front().matrix * + Geometry::assemble_transform(center, Vec3d(0.5 * PI, 0.0, m_angle)) * + Geometry::assemble_transform(1.5 * size * Vec3d::UnitZ(), Vec3d::Zero(), Vec3d(0.75 * size, 0.75 * size, 3.0 * size)); + + shader->set_uniform("view_model_matrix", view_model_matrix); + shader->set_uniform("normal_matrix", (Matrix3d)view_model_matrix.matrix().block(0, 0, 3, 3).inverse().transpose()); m_cone.render(); - glsafe(::glPopMatrix()); - glsafe(::glPushMatrix()); - glsafe(::glTranslated(center.x(), center.y(), center.z())); - glsafe(::glRotated(Geometry::rad2deg(m_angle), 0.0, 0.0, 1.0)); - glsafe(::glRotated(-90.0, 1.0, 0.0, 0.0)); - glsafe(::glTranslated(0.0, 0.0, 1.5 * size)); - glsafe(::glScaled(0.75 * size, 0.75 * size, 3.0 * size)); + view_model_matrix = view_matrix * m_grabbers.front().matrix * + Geometry::assemble_transform(center, Vec3d(-0.5 * PI, 0.0, m_angle)) * + Geometry::assemble_transform(1.5 * size * Vec3d::UnitZ(), Vec3d::Zero(), Vec3d(0.75 * size, 0.75 * size, 3.0 * size)); + + shader->set_uniform("view_model_matrix", view_model_matrix); + shader->set_uniform("normal_matrix", (Matrix3d)view_model_matrix.matrix().block(0, 0, 3, 3).inverse().transpose()); m_cone.render(); - glsafe(::glPopMatrix()); shader->stop_using(); } +Transform3d GLGizmoRotate::local_transform(const Selection& selection) const +{ + Transform3d ret; + + switch (m_axis) + { + case X: + { + ret = Geometry::assemble_transform(Vec3d::Zero(), Vec3d(0.0, 0.5 * PI, 0.0)) * Geometry::assemble_transform(Vec3d::Zero(), Vec3d(0.0, 0.0, -0.5 * PI)); + break; + } + case Y: + { + ret = Geometry::assemble_transform(Vec3d::Zero(), Vec3d(0.0, 0.0, -0.5 * PI)) * Geometry::assemble_transform(Vec3d::Zero(), Vec3d(0.0, -0.5 * PI, 0.0)); + break; + } + default: + case Z: + { + ret = Transform3d::Identity(); + break; + } + } + + if (selection.is_single_volume() || selection.is_single_modifier() || selection.requires_local_axes()) + ret = selection.get_volume(*selection.get_volume_idxs().begin())->get_instance_transformation().get_matrix(true, false, true, true) * ret; + + return Geometry::assemble_transform(m_center) * ret; +} + void GLGizmoRotate::transform_to_local(const Selection& selection) const { glsafe(::glTranslated(m_center.x(), m_center.y(), m_center.z())); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoRotate.hpp b/src/slic3r/GUI/Gizmos/GLGizmoRotate.hpp index aa4a773b47c..b3cb7078080 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoRotate.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoRotate.hpp @@ -85,6 +85,8 @@ class GLGizmoRotate : public GLGizmoBase void render_grabber(const BoundingBoxf3& box); void render_grabber_extension(const BoundingBoxf3& box, bool picking); + Transform3d local_transform(const Selection& selection) const; + void transform_to_local(const Selection& selection) const; // returns the intersection of the mouse ray with the plane perpendicular to the gizmo axis, in local coordinate Vec3d mouse_position_in_local_plane(const Linef3& mouse_ray, const Selection& selection) const; diff --git a/src/slic3r/GUI/Gizmos/GLGizmoScale.cpp b/src/slic3r/GUI/Gizmos/GLGizmoScale.cpp index 0db0b4ab4b9..aa3abff9bc0 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoScale.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoScale.cpp @@ -2,6 +2,7 @@ #include "GLGizmoScale.hpp" #include "slic3r/GUI/GLCanvas3D.hpp" #include "slic3r/GUI/GUI_App.hpp" +#include "slic3r/GUI/Plater.hpp" #include @@ -185,11 +186,11 @@ void GLGizmoScale3D::on_render() m_box = selection.get_bounding_box(); const Vec3d& center = m_box.center(); - Vec3d offset_x = offsets_transform * Vec3d((double)Offset, 0.0, 0.0); - Vec3d offset_y = offsets_transform * Vec3d(0.0, (double)Offset, 0.0); - Vec3d offset_z = offsets_transform * Vec3d(0.0, 0.0, (double)Offset); + const Vec3d offset_x = offsets_transform * Vec3d((double)Offset, 0.0, 0.0); + const Vec3d offset_y = offsets_transform * Vec3d(0.0, (double)Offset, 0.0); + const Vec3d offset_z = offsets_transform * Vec3d(0.0, 0.0, (double)Offset); - bool ctrl_down = (m_dragging && m_starting.ctrl_down) || (!m_dragging && wxGetKeyState(WXK_CONTROL)); + const bool ctrl_down = (m_dragging && m_starting.ctrl_down) || (!m_dragging && wxGetKeyState(WXK_CONTROL)); // x axis m_grabbers[0].center = m_transform * Vec3d(m_box.min.x(), center.y(), m_box.min.z()); @@ -230,14 +231,17 @@ void GLGizmoScale3D::on_render() const BoundingBoxf3& selection_box = selection.get_bounding_box(); - float grabber_mean_size = (float)((selection_box.size().x() + selection_box.size().y() + selection_box.size().z()) / 3.0); + const float grabber_mean_size = (float)((selection_box.size().x() + selection_box.size().y() + selection_box.size().z()) / 3.0); //draw connections - GLShaderProgram* shader = wxGetApp().get_shader("flat"); + GLShaderProgram* shader = wxGetApp().get_shader("flat_attr"); if (shader != nullptr) { shader->start_using(); // BBS: when select multiple objects, uniform scale can be deselected, display the connection(4,5) //if (single_instance || single_volume) { + const Camera& camera = wxGetApp().plater()->get_camera(); + shader->set_uniform("view_model_matrix", camera.get_view_matrix()); + shader->set_uniform("projection_matrix", camera.get_projection_matrix()); if (m_grabbers[4].enabled && m_grabbers[5].enabled) render_grabbers_connection(4, 5, m_grabbers[4].color); render_grabbers_connection(6, 7, m_grabbers[2].color); @@ -279,7 +283,7 @@ void GLGizmoScale3D::render_grabbers_connection(unsigned int id_1, unsigned int m_grabber_connections[id].model.reset(); GLModel::Geometry init_data; - init_data.format = { GLModel::Geometry::EPrimitiveType::Lines, GLModel::Geometry::EVertexLayout::P3, GLModel::Geometry::EIndexType::USHORT }; + init_data.format = { GLModel::Geometry::EPrimitiveType::Lines, GLModel::Geometry::EVertexLayout::P3 }; init_data.reserve_vertices(2); init_data.reserve_indices(2); @@ -288,7 +292,7 @@ void GLGizmoScale3D::render_grabbers_connection(unsigned int id_1, unsigned int init_data.add_vertex((Vec3f)m_grabbers[id_2].center.cast()); // indices - init_data.add_ushort_line(0, 1); + init_data.add_line(0, 1); m_grabber_connections[id].model.init_from(std::move(init_data)); } diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSeam.cpp b/src/slic3r/GUI/Gizmos/GLGizmoSeam.cpp index 04e32898d6d..57019b951dc 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSeam.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSeam.cpp @@ -98,7 +98,7 @@ bool GLGizmoSeam::on_key_down_select_tool_type(int keyCode) { void GLGizmoSeam::render_triangles(const Selection& selection) const { ClippingPlaneDataWrapper clp_data = this->get_clipping_plane_data(); - auto* shader = wxGetApp().get_shader("mm_gouraud"); + auto* shader = wxGetApp().get_shader("mm_gouraud_attr"); if (!shader) return; shader->start_using(); @@ -120,8 +120,11 @@ void GLGizmoSeam::render_triangles(const Selection& selection) const if (is_left_handed) glsafe(::glFrontFace(GL_CW)); - glsafe(::glPushMatrix()); - glsafe(::glMultMatrixd(trafo_matrix.data())); + const Camera& camera = wxGetApp().plater()->get_camera(); + const Transform3d matrix = camera.get_view_matrix() * trafo_matrix; + shader->set_uniform("view_model_matrix", matrix); + shader->set_uniform("projection_matrix", camera.get_projection_matrix()); + shader->set_uniform("normal_matrix", (Matrix3d)matrix.matrix().block(0, 0, 3, 3).inverse().transpose()); float normal_z = -::cos(Geometry::deg2rad(m_highlight_by_angle_threshold_deg)); Matrix3f normal_matrix = static_cast(trafo_matrix.matrix().block(0, 0, 3, 3).inverse().transpose().cast()); @@ -129,11 +132,10 @@ void GLGizmoSeam::render_triangles(const Selection& selection) const shader->set_uniform("volume_world_matrix", trafo_matrix); shader->set_uniform("volume_mirrored", is_left_handed); shader->set_uniform("slope.actived", m_parent.is_using_slope()); - shader->set_uniform("slope.volume_world_normal_matrix", static_cast(trafo_matrix.matrix().block(0, 0, 3, 3).inverse().transpose().cast())); + shader->set_uniform("slope.volume_world_normal_matrix", normal_matrix); shader->set_uniform("slope.normal_z", normal_z); - m_triangle_selectors[mesh_id]->render(m_imgui); + m_triangle_selectors[mesh_id]->render(m_imgui, trafo_matrix); - glsafe(::glPopMatrix()); if (is_left_handed) glsafe(::glFrontFace(GL_CCW)); } diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSimplify.cpp b/src/slic3r/GUI/Gizmos/GLGizmoSimplify.cpp index aca431750d0..3beb4f0a989 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSimplify.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSimplify.cpp @@ -641,19 +641,25 @@ void GLGizmoSimplify::on_render() return; const Transform3d trafo_matrix = selected_volume->world_matrix(); - glsafe(::glPushMatrix()); - glsafe(::glMultMatrixd(trafo_matrix.data())); - - auto *gouraud_shader = wxGetApp().get_shader("gouraud_light"); + auto* gouraud_shader = wxGetApp().get_shader("gouraud_light_attr"); glsafe(::glPushAttrib(GL_DEPTH_TEST)); glsafe(::glEnable(GL_DEPTH_TEST)); gouraud_shader->start_using(); + const Camera& camera = wxGetApp().plater()->get_camera(); + const Transform3d view_model_matrix = camera.get_view_matrix() * trafo_matrix; + gouraud_shader->set_uniform("view_model_matrix", view_model_matrix); + gouraud_shader->set_uniform("projection_matrix", camera.get_projection_matrix()); + gouraud_shader->set_uniform("normal_matrix", (Matrix3d)view_model_matrix.matrix().block(0, 0, 3, 3).inverse().transpose()); m_glmodel.render(); gouraud_shader->stop_using(); if (m_show_wireframe) { - auto* contour_shader = wxGetApp().get_shader("mm_contour"); + auto* contour_shader = wxGetApp().get_shader("mm_contour_attr"); contour_shader->start_using(); + contour_shader->set_uniform("view_model_matrix", view_model_matrix); + contour_shader->set_uniform("projection_matrix", camera.get_projection_matrix()); + const ColorRGBA color = m_glmodel.get_color(); + m_glmodel.set_color(ColorRGBA::WHITE()); glsafe(::glLineWidth(1.0f)); glsafe(::glPolygonMode(GL_FRONT_AND_BACK, GL_LINE)); //ScopeGuard offset_fill_guard([]() { glsafe(::glDisable(GL_POLYGON_OFFSET_FILL)); }); @@ -661,11 +667,11 @@ void GLGizmoSimplify::on_render() //glsafe(::glPolygonOffset(5.0, 5.0)); m_glmodel.render(); glsafe(::glPolygonMode(GL_FRONT_AND_BACK, GL_FILL)); + m_glmodel.set_color(color); contour_shader->stop_using(); } glsafe(::glPopAttrib()); - glsafe(::glPopMatrix()); } diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp index a981d15c725..820c6769037 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp @@ -127,7 +127,7 @@ void GLGizmoSlaSupports::render_points(const Selection& selection, bool picking) if (! has_points && ! has_holes) return; - GLShaderProgram* shader = wxGetApp().get_shader(picking ? "flat" : "gouraud_light"); + GLShaderProgram* shader = picking ? wxGetApp().get_shader("flat_attr") : wxGetApp().get_shader("gouraud_light_attr"); if (shader == nullptr) return; @@ -136,12 +136,13 @@ void GLGizmoSlaSupports::render_points(const Selection& selection, bool picking) const GLVolume* vol = selection.get_volume(*selection.get_volume_idxs().begin()); const Transform3d instance_scaling_matrix_inverse = vol->get_instance_transformation().get_matrix(true, true, false, true).inverse(); - const Transform3d& instance_matrix = vol->get_instance_transformation().get_matrix(); - const float z_shift = m_c->selection_info()->get_sla_shift(); + const Transform3d instance_matrix = Geometry::assemble_transform(m_c->selection_info()->get_sla_shift() * Vec3d::UnitZ()) * vol->get_instance_transformation().get_matrix(); - glsafe(::glPushMatrix()); - glsafe(::glTranslated(0.0, 0.0, z_shift)); - glsafe(::glMultMatrixd(instance_matrix.data())); + const Camera& camera = wxGetApp().plater()->get_camera(); + const Transform3d& view_matrix = camera.get_view_matrix(); + const Transform3d& projection_matrix = camera.get_projection_matrix(); + + shader->set_uniform("projection_matrix", projection_matrix); ColorRGBA render_color; for (size_t i = 0; i < cache_size; ++i) { @@ -179,9 +180,7 @@ void GLGizmoSlaSupports::render_points(const Selection& selection, bool picking) shader->set_uniform("emission_factor", 0.5f); // Inverse matrix of the instance scaling is applied so that the mark does not scale with the object. - glsafe(::glPushMatrix()); - glsafe(::glTranslatef(support_point.pos.x(), support_point.pos.y(), support_point.pos.z())); - glsafe(::glMultMatrixd(instance_scaling_matrix_inverse.data())); + const Transform3d support_matrix = Geometry::assemble_transform(support_point.pos.cast()) * instance_scaling_matrix_inverse; if (vol->is_left_handed()) glFrontFace(GL_CW); @@ -194,27 +193,29 @@ void GLGizmoSlaSupports::render_points(const Selection& selection, bool picking) m_c->raycaster()->raycaster()->get_closest_point(m_editing_cache[i].support_point.pos, &m_editing_cache[i].normal); Eigen::Quaterniond q; - q.setFromTwoVectors(Vec3d{0., 0., 1.}, instance_scaling_matrix_inverse * m_editing_cache[i].normal.cast()); + q.setFromTwoVectors(Vec3d::UnitZ(), instance_scaling_matrix_inverse * m_editing_cache[i].normal.cast()); const Eigen::AngleAxisd aa(q); - glsafe(::glPushMatrix()); - glsafe(::glRotated(aa.angle() * (180. / M_PI), aa.axis().x(), aa.axis().y(), aa.axis().z())); const double cone_radius = 0.25; // mm const double cone_height = 0.75; - glsafe(::glTranslatef(0.f, 0.f, cone_height + support_point.head_front_radius * RenderPointScale)); - glsafe(::glRotated(180., 1., 0., 0.)); - glsafe(::glScaled(cone_radius, cone_radius, cone_height)); + const Transform3d view_model_matrix = view_matrix * instance_matrix * support_matrix * Transform3d(aa.toRotationMatrix()) * + Geometry::assemble_transform((cone_height + support_point.head_front_radius * RenderPointScale) * Vec3d::UnitZ(), + Vec3d(PI, 0.0, 0.0), Vec3d(cone_radius, cone_radius, cone_height)); + + shader->set_uniform("view_model_matrix", view_model_matrix); + shader->set_uniform("normal_matrix", (Matrix3d)view_model_matrix.matrix().block(0, 0, 3, 3).inverse().transpose()); m_cone.render(); - glsafe(::glPopMatrix()); } const double radius = (double)support_point.head_front_radius * RenderPointScale; - glsafe(::glScaled(radius, radius, radius)); + const Transform3d view_model_matrix = view_matrix * instance_matrix * support_matrix * + Geometry::assemble_transform(Vec3d::Zero(), Vec3d::Zero(), radius * Vec3d::Ones()); + + shader->set_uniform("view_model_matrix", view_model_matrix); + shader->set_uniform("normal_matrix", (Matrix3d)view_model_matrix.matrix().block(0, 0, 3, 3).inverse().transpose()); m_sphere.render(); if (vol->is_left_handed()) glFrontFace(GL_CCW); - - glsafe(::glPopMatrix()); } // Now render the drain holes: @@ -226,31 +227,26 @@ void GLGizmoSlaSupports::render_points(const Selection& selection, bool picking) if (is_mesh_point_clipped(drain_hole.pos.cast())) continue; - // Inverse matrix of the instance scaling is applied so that the mark does not scale with the object. - glsafe(::glPushMatrix()); - glsafe(::glTranslatef(drain_hole.pos.x(), drain_hole.pos.y(), drain_hole.pos.z())); - glsafe(::glMultMatrixd(instance_scaling_matrix_inverse.data())); + const Transform3d hole_matrix = Geometry::assemble_transform(drain_hole.pos.cast()) * instance_scaling_matrix_inverse; if (vol->is_left_handed()) glFrontFace(GL_CW); // Matrices set, we can render the point mark now. - Eigen::Quaterniond q; - q.setFromTwoVectors(Vec3d{0., 0., 1.}, instance_scaling_matrix_inverse * (-drain_hole.normal).cast()); + q.setFromTwoVectors(Vec3d::UnitZ(), instance_scaling_matrix_inverse * (-drain_hole.normal).cast()); const Eigen::AngleAxisd aa(q); - glsafe(::glRotated(aa.angle() * (180. / M_PI), aa.axis().x(), aa.axis().y(), aa.axis().z())); - glsafe(::glTranslated(0., 0., -drain_hole.height)); - glsafe(::glScaled(drain_hole.radius, drain_hole.radius, drain_hole.height + sla::HoleStickOutLength)); + const Transform3d view_model_matrix = view_matrix * instance_matrix * hole_matrix * Transform3d(aa.toRotationMatrix()) * + Geometry::assemble_transform(-drain_hole.height * Vec3d::UnitZ(), Vec3d::Zero(), Vec3d(drain_hole.radius, drain_hole.radius, drain_hole.height + sla::HoleStickOutLength)); + + shader->set_uniform("view_model_matrix", view_model_matrix); + shader->set_uniform("normal_matrix", (Matrix3d)view_model_matrix.matrix().block(0, 0, 3, 3).inverse().transpose()); m_cylinder.render(); if (vol->is_left_handed()) glFrontFace(GL_CCW); - glsafe(::glPopMatrix()); } } - - glsafe(::glPopMatrix()); } diff --git a/src/slic3r/GUI/Gizmos/GLGizmoText.cpp b/src/slic3r/GUI/Gizmos/GLGizmoText.cpp index facfa464ede..6d31534d4ab 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoText.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoText.cpp @@ -448,7 +448,7 @@ void GLGizmoText::on_render() ColorRGBA color = picking_color_component(0); m_grabbers[0].color = color; - GLShaderProgram *shader = wxGetApp().get_shader("gouraud_light"); + GLShaderProgram *shader = wxGetApp().get_shader("gouraud_light_attr"); if (shader != nullptr) { shader->start_using(); m_grabbers[0].render_for_picking(mean_size); @@ -500,14 +500,12 @@ void GLGizmoText::on_render_for_picking() ColorRGBA color = picking_color_component(0); m_grabbers[0].color = color; - GLShaderProgram *shader = wxGetApp().get_shader("flat"); + GLShaderProgram *shader = wxGetApp().get_shader("flat_attr"); if (shader != nullptr) { - glsafe(::glPushMatrix()); shader->start_using(); m_grabbers[0].render_for_picking(mean_size); shader->stop_using(); - glsafe(::glPopMatrix()); } } } diff --git a/src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp b/src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp index 3f65a188ef7..5a7d4c0f500 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp @@ -214,15 +214,14 @@ void InstancesHider::render_cut() const ClippingPlane clp = *get_pool()->object_clipper()->get_clipping_plane(); clp.set_normal(-clp.get_normal()); clipper->set_limiting_plane(clp); - } else + } + else clipper->set_limiting_plane(ClippingPlane::ClipsNothing()); - glsafe(::glPushMatrix()); glsafe(::glPushAttrib(GL_DEPTH_TEST)); glsafe(::glDisable(GL_DEPTH_TEST)); clipper->render_cut(mv->is_model_part() ? ColorRGBA(0.8f, 0.3f, 0.0f, 1.0f) : color_from_model_volume(*mv)); glsafe(::glPopAttrib()); - glsafe(::glPopMatrix()); ++clipper_id; } @@ -412,7 +411,7 @@ void ObjectClipper::render_cut() const size_t clipper_id = 0; for (const ModelVolume* mv : mo->volumes) { - Geometry::Transformation vol_trafo = mv->get_transformation(); + const Geometry::Transformation vol_trafo = mv->get_transformation(); Geometry::Transformation trafo = inst_trafo * vol_trafo; if (is_assem_cnv) { trafo.set_offset(trafo.get_offset() + offset_to_assembly * (GLVolume::explosion_ratio - 1.0) + vol_trafo.get_offset() * (GLVolume::explosion_ratio - 1.0)); @@ -427,10 +426,8 @@ void ObjectClipper::render_cut() const clipper->set_limiting_plane(ClippingPlane(Vec3d::UnitZ(), std::numeric_limits::max())); else clipper->set_limiting_plane(ClippingPlane(Vec3d::UnitZ(), -SINKING_Z_THRESHOLD)); - glsafe(::glPushMatrix()); // BBS clipper->render_cut({ 0.25f, 0.25f, 0.25f, 1.0f }); - glsafe(::glPopMatrix()); ++clipper_id; } @@ -557,7 +554,7 @@ void SupportsClipper::render_cut() const const SelectionInfo* sel_info = get_pool()->selection_info(); const ModelObject* mo = sel_info->model_object(); - Geometry::Transformation inst_trafo = mo->instances[sel_info->get_active_instance()]->get_transformation(); + const Geometry::Transformation inst_trafo = mo->instances[sel_info->get_active_instance()]->get_transformation(); //Geometry::Transformation vol_trafo = mo->volumes.front()->get_transformation(); Geometry::Transformation trafo = inst_trafo;// * vol_trafo; trafo.set_offset(trafo.get_offset() + Vec3d(0., 0., sel_info->get_sla_shift())); @@ -576,9 +573,7 @@ void SupportsClipper::render_cut() const m_clipper->set_plane(*ocl->get_clipping_plane()); m_clipper->set_transformation(supports_trafo); - glsafe(::glPushMatrix()); m_clipper->render_cut({ 1.0f, 0.f, 0.37f, 1.0f }); - glsafe(::glPopMatrix()); } diff --git a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp index 1e500ff4067..7f13c25c778 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp @@ -85,7 +85,9 @@ size_t GLGizmosManager::get_gizmo_idx_from_mouse(const Vec2d& mouse_pos) const float width = get_scaled_total_width(); #if BBS_TOOLBAR_ON_TOP //float space_width = GLGizmosManager::Default_Icons_Size * wxGetApp().toolbar_icon_scale();; - float top_x = std::max(m_parent.get_main_toolbar_width() + border, 0.5f * (cnv_w - width + m_parent.get_main_toolbar_width() + m_parent.get_collapse_toolbar_width() - m_parent.get_assemble_view_toolbar_width()) + border); + const float separator_width = m_parent.get_separator_toolbar_width(); + float top_x = std::max(0.0f, 0.5f * (cnv_w - (width + separator_width + m_parent.get_main_toolbar_width() - m_parent.get_collapse_toolbar_width() + m_parent.get_assemble_view_toolbar_width()))); + top_x += m_parent.get_main_toolbar_width() + separator_width / 2 + border; if (m_parent.get_canvas_type() == GLCanvas3D::CanvasAssembleView) top_x = 0.5f * cnv_w + 0.5f * (m_parent.get_assembly_paint_toolbar_width()); float top_y = 0; @@ -1277,37 +1279,37 @@ void GLGizmosManager::update_after_undo_redo(const UndoRedo::Snapshot& snapshot) dynamic_cast(m_gizmos[SlaSupports].get())->reslice_SLA_supports(true); } -void GLGizmosManager::render_background(float left, float top, float right, float bottom, float border) const +void GLGizmosManager::render_background(float left, float top, float right, float bottom, float border_w, float border_h) const { const unsigned int tex_id = m_background_texture.texture.get_id(); const float tex_width = float(m_background_texture.texture.get_width()); const float tex_height = float(m_background_texture.texture.get_height()); if (tex_id != 0 && tex_width > 0 && tex_height > 0) { //BBS: GUI refactor: remove the corners of gizmo - const float inv_tex_width = (tex_width != 0.0f) ? 1.0f / tex_width : 0.0f; - const float inv_tex_height = (tex_height != 0.0f) ? 1.0f / tex_height : 0.0f; + const float inv_tex_width = 1.0f / tex_width; + const float inv_tex_height = 1.0f / tex_height; - const float internal_left_uv = (float)m_background_texture.metadata.left * inv_tex_width; - const float internal_right_uv = 1.0f - (float)m_background_texture.metadata.right * inv_tex_width; - const float internal_top_uv = 1.0f - (float)m_background_texture.metadata.top * inv_tex_height; - const float internal_bottom_uv = (float)m_background_texture.metadata.bottom * inv_tex_height; + const float internal_left_uv = float(m_background_texture.metadata.left) * inv_tex_width; + const float internal_right_uv = 1.0f - float(m_background_texture.metadata.right) * inv_tex_width; + const float internal_top_uv = 1.0f - float(m_background_texture.metadata.top) * inv_tex_height; + const float internal_bottom_uv = float(m_background_texture.metadata.bottom) * inv_tex_height; GLTexture::render_sub_texture(tex_id, left, right, bottom, top, { { internal_left_uv, internal_bottom_uv }, { internal_right_uv, internal_bottom_uv }, { internal_right_uv, internal_top_uv }, { internal_left_uv, internal_top_uv } }); /* - const float internal_left = left + border; - const float internal_right = right - border; - const float internal_top = top - border; - const float internal_bottom = bottom + border; + const float internal_left = left + border_w; + const float internal_right = right - border_w; + const float internal_top = top - border_h; + const float internal_bottom = bottom + border_h; // float left_uv = 0.0f; const float right_uv = 1.0f; const float top_uv = 1.0f; const float bottom_uv = 0.0f; - const float internal_left_uv = float(m_background_texture.metadata.left) * inv_tex_width; - const float internal_right_uv = 1.0f - float(m_background_texture.metadata.right) * inv_tex_width; - const float internal_top_uv = 1.0f - float(m_background_texture.metadata.top) * inv_tex_height; + const float internal_left_uv = float(m_background_texture.metadata.left) * inv_tex_width; + const float internal_right_uv = 1.0f - float(m_background_texture.metadata.right) * inv_tex_width; + const float internal_top_uv = 1.0f - float(m_background_texture.metadata.top) * inv_tex_height; const float internal_bottom_uv = float(m_background_texture.metadata.bottom) * inv_tex_height; // top-left corner @@ -1383,119 +1385,98 @@ void GLGizmosManager::render_arrow(const GLCanvas3D& parent, EType highlighted_t //when rendering, {0, 0} is at the center, {-0.5, 0.5} at the left-top void GLGizmosManager::do_render_overlay() const { - std::vector selectable_idxs = get_selectable_idxs(); + const std::vector selectable_idxs = get_selectable_idxs(); if (selectable_idxs.empty()) return; - float cnv_w = (float)m_parent.get_canvas_size().get_width(); - float cnv_h = (float)m_parent.get_canvas_size().get_height(); - float zoom = (float)wxGetApp().plater()->get_camera().get_zoom(); - float inv_zoom = (float)wxGetApp().plater()->get_camera().get_inv_zoom(); + const Size cnv_size = m_parent.get_canvas_size(); + const float cnv_w = (float)cnv_size.get_width(); + const float cnv_h = (float)cnv_size.get_height(); - float height = get_scaled_total_height(); - float width = get_scaled_total_width(); - float zoomed_border = m_layout.scaled_border() * inv_zoom; + if (cnv_w == 0 || cnv_h == 0) + return; - float zoomed_top_x; + const float inv_cnv_w = 1.0f / cnv_w; + const float inv_cnv_h = 1.0f / cnv_h; + + const float height = 2.0f * get_scaled_total_height() * inv_cnv_h; + const float width = 2.0f * get_scaled_total_width() * inv_cnv_w; + const float border_h = 2.0f * m_layout.scaled_border() * inv_cnv_h; + const float border_w = 2.0f * m_layout.scaled_border() * inv_cnv_w; + + float top_x; if (m_parent.get_canvas_type() == GLCanvas3D::CanvasAssembleView) { - zoomed_top_x = 0.5f * m_parent.get_assembly_paint_toolbar_width() * inv_zoom; + top_x = m_parent.get_assembly_paint_toolbar_width() * inv_cnv_w; } else { //BBS: GUI refactor: GLToolbar&&Gizmo adjust -#if BBS_TOOLBAR_ON_TOP float main_toolbar_width = (float)m_parent.get_main_toolbar_width(); float assemble_view_width = (float)m_parent.get_assemble_view_toolbar_width(); float collapse_width = (float)m_parent.get_collapse_toolbar_width(); + float separator_width = (float)m_parent.get_separator_toolbar_width(); //float space_width = GLGizmosManager::Default_Icons_Size * wxGetApp().toolbar_icon_scale(); //float zoomed_top_x = 0.5f *(cnv_w + main_toolbar_width - 2 * space_width - width) * inv_zoom; - float main_toolbar_left = std::max(-0.5f * cnv_w, -0.5f * (main_toolbar_width + get_scaled_total_width() + assemble_view_width - collapse_width)) * inv_zoom; + float main_toolbar_left = std::max(-0.5f * cnv_w, -0.5f * (main_toolbar_width + get_scaled_total_width() + assemble_view_width + separator_width - collapse_width)); //float zoomed_top_x = 0.5f *(main_toolbar_width + collapse_width - width - assemble_view_width) * inv_zoom; - zoomed_top_x = main_toolbar_left + (main_toolbar_width)*inv_zoom; + top_x = main_toolbar_left + main_toolbar_width + separator_width / 2; + top_x = top_x * inv_cnv_w * 2; } - float zoomed_top_y = 0.5f * cnv_h * inv_zoom; -#else - //float zoomed_top_x = (-0.5f * cnv_w) * inv_zoom; - //float zoomed_top_y = (0.5f * height) * inv_zoom; - float zoomed_top_x = (0.5f * cnv_w - width) * inv_zoom; - float main_toolbar_height = (float)m_parent.get_main_toolbar_height(); - float assemble_view_height = (float)m_parent.get_assemble_view_toolbar_height(); - //float space_height = GLGizmosManager::Default_Icons_Size * wxGetApp().toolbar_icon_scale(); - float zoomed_top_y = 0.5f * (height + assemble_view_height - main_toolbar_height) * inv_zoom; -#endif - //BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(": zoomed_top_y %1%, space_height %2%, main_toolbar_height %3% zoomed_top_x %4%") % zoomed_top_y % space_height % main_toolbar_height % zoomed_top_x; - - float zoomed_left = zoomed_top_x; - float zoomed_top = zoomed_top_y; - float zoomed_right = zoomed_left + width * inv_zoom; - float zoomed_bottom = zoomed_top - height * inv_zoom; + float top_y = 1.0f; - render_background(zoomed_left, zoomed_top, zoomed_right, zoomed_bottom, zoomed_border); + render_background(top_x, top_y, top_x + width, top_y - height, border_w, border_h); - zoomed_top_x += zoomed_border; - zoomed_top_y -= zoomed_border; + top_x += border_w; + top_y -= border_h; - float icons_size = m_layout.scaled_icons_size(); - float zoomed_icons_size = icons_size * inv_zoom; - float zoomed_stride_y = m_layout.scaled_stride_y() * inv_zoom; + const float icons_size_x = 2.0f * m_layout.scaled_icons_size() * inv_cnv_w; + const float icons_size_y = 2.0f * m_layout.scaled_icons_size() * inv_cnv_h; //BBS: GUI refactor: GLToolbar&&Gizmo adjust - float zoomed_stride_x = m_layout.scaled_stride_x() * inv_zoom; + const float stride_x = 2.0f * m_layout.scaled_stride_x() * inv_cnv_w; - unsigned int icons_texture_id = m_icons_texture.get_id(); - int tex_width = m_icons_texture.get_width(); - int tex_height = m_icons_texture.get_height(); + const unsigned int icons_texture_id = m_icons_texture.get_id(); + const int tex_width = m_icons_texture.get_width(); + const int tex_height = m_icons_texture.get_height(); - if ((icons_texture_id == 0) || (tex_width <= 1) || (tex_height <= 1)) + if (icons_texture_id == 0 || tex_width <= 1 || tex_height <= 1) return; - float du = (float)(tex_width - 1) / (6.0f * (float)tex_width); // 6 is the number of possible states if the icons - float dv = (float)(tex_height - 1) / (float)(m_gizmos.size() * tex_height); + const float du = (float)(tex_width - 1) / (6.0f * (float)tex_width); // 6 is the number of possible states if the icons + const float dv = (float)(tex_height - 1) / (float)(m_gizmos.size() * tex_height); // tiles in the texture are spaced by 1 pixel - float u_offset = 1.0f / (float)tex_width; - float v_offset = 1.0f / (float)tex_height; + const float u_offset = 1.0f / (float)tex_width; + const float v_offset = 1.0f / (float)tex_height; bool is_render_current = false; - for (size_t idx : selectable_idxs) - { + for (size_t idx : selectable_idxs) { GLGizmoBase* gizmo = m_gizmos[idx].get(); - unsigned int sprite_id = gizmo->get_sprite_id(); + const unsigned int sprite_id = gizmo->get_sprite_id(); // higlighted state needs to be decided first so its highlighting in every other state - int icon_idx = (m_highlight.first == idx ? (m_highlight.second ? 4 : 5) : (m_current == idx) ? 2 : ((m_hover == idx) ? 1 : (gizmo->is_activable()? 0 : 3))); - - float v_top = v_offset + sprite_id * dv; - float u_left = u_offset + icon_idx * du; - float v_bottom = v_top + dv - v_offset; - float u_right = u_left + du - u_offset; + const int icon_idx = (m_highlight.first == idx ? (m_highlight.second ? 4 : 5) : (m_current == idx) ? 2 : ((m_hover == idx) ? 1 : (gizmo->is_activable()? 0 : 3))); - GLTexture::render_sub_texture(icons_texture_id, zoomed_top_x, zoomed_top_x + zoomed_icons_size, zoomed_top_y - zoomed_icons_size, zoomed_top_y, { { u_left, v_bottom }, { u_right, v_bottom }, { u_right, v_top }, { u_left, v_top } }); + const float u_left = u_offset + icon_idx * du; + const float u_right = u_left + du - u_offset; + const float v_top = v_offset + sprite_id * dv; + const float v_bottom = v_top + dv - v_offset; + GLTexture::render_sub_texture(icons_texture_id, top_x, top_x + icons_size_x, top_y - icons_size_y, top_y, { { u_left, v_bottom }, { u_right, v_bottom }, { u_right, v_top }, { u_left, v_top } }); if (idx == m_current) { //BBS: GUI refactor: GLToolbar&&Gizmo adjust //render_input_window uses a different coordination(imgui) //1. no need to scale by camera zoom, set {0,0} at left-up corner for imgui -#if BBS_TOOLBAR_ON_TOP //gizmo->render_input_window(width, 0.5f * cnv_h - zoomed_top_y * zoom, toolbar_top); - gizmo->render_input_window(0.5 * cnv_w + zoomed_top_x * zoom, height, cnv_h); + gizmo->render_input_window(0.5 * cnv_w + 0.5f * top_x * cnv_w, get_scaled_total_height(), cnv_h); is_render_current = true; -#else - float toolbar_top = cnv_h - wxGetApp().plater()->get_view_toolbar().get_height(); - //gizmo->render_input_window(width, 0.5f * cnv_h - zoomed_top_y * zoom, toolbar_top); - gizmo->render_input_window(cnv_w - width, 0.5f * cnv_h - zoomed_top_y * zoom, toolbar_top); -#endif } -#if BBS_TOOLBAR_ON_TOP - zoomed_top_x += zoomed_stride_x; -#else - zoomed_top_y -= zoomed_stride_y; -#endif + top_x += stride_x; } // BBS simplify gizmo is not a selected gizmo and need to render input window if (!is_render_current && m_current != Undefined) { - m_gizmos[m_current]->render_input_window(0.5 * cnv_w + zoomed_top_x * zoom, height, cnv_h); + m_gizmos[m_current]->render_input_window(0.5 * cnv_w + 0.5f * top_x * cnv_w, get_scaled_total_height(), cnv_h); } } @@ -1542,14 +1523,12 @@ GLGizmosManager::EType GLGizmosManager::get_gizmo_from_name(const std::string& g return GLGizmosManager::EType::Undefined; } -bool GLGizmosManager::generate_icons_texture() const +bool GLGizmosManager::generate_icons_texture() { std::string path = resources_dir() + "/images/"; std::vector filenames; - for (size_t idx=0; idxget_icon_filename(); if (!icon_filename.empty()) filenames.push_back(path + icon_filename); diff --git a/src/slic3r/GUI/Gizmos/GLGizmosManager.hpp b/src/slic3r/GUI/Gizmos/GLGizmosManager.hpp index 12c97e9ac4d..d95c1693860 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosManager.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosManager.hpp @@ -325,11 +325,11 @@ class GLGizmosManager : public Slic3r::ObjectBase bool get_uniform_scaling() const { return m_object_manipulation.get_uniform_scaling();} private: - void render_background(float left, float top, float right, float bottom, float border) const; + void render_background(float left, float top, float right, float bottom, float border_w, float border_h) const; void do_render_overlay() const; - bool generate_icons_texture() const; + bool generate_icons_texture(); void update_on_off_state(const Vec2d& mouse_pos); std::string update_hover_state(const Vec2d& mouse_pos); diff --git a/src/slic3r/GUI/MeshUtils.cpp b/src/slic3r/GUI/MeshUtils.cpp index 3cdf5b63686..be30f4c732e 100644 --- a/src/slic3r/GUI/MeshUtils.cpp +++ b/src/slic3r/GUI/MeshUtils.cpp @@ -8,6 +8,7 @@ #include "slic3r/GUI/GUI_App.hpp" #include "slic3r/GUI/Camera.hpp" +#include "slic3r/GUI/Plater.hpp" #include @@ -73,13 +74,19 @@ void MeshClipper::render_cut(const ColorRGBA& color) if (! m_triangles_valid) recalculate_triangles(); + if (m_model.vertices_count() == 0 || m_model.indices_count() == 0) + return; + GLShaderProgram* curr_shader = wxGetApp().get_current_shader(); if (curr_shader != nullptr) curr_shader->stop_using(); - GLShaderProgram* shader = wxGetApp().get_shader("flat"); + GLShaderProgram* shader = wxGetApp().get_shader("flat_attr"); if (shader != nullptr) { shader->start_using(); + const Camera& camera = wxGetApp().plater()->get_camera(); + shader->set_uniform("view_model_matrix", camera.get_view_matrix()); + shader->set_uniform("projection_matrix", camera.get_projection_matrix()); m_model.set_color(color); m_model.render(); shader->stop_using(); @@ -205,7 +212,7 @@ void MeshClipper::recalculate_triangles() m_model.reset(); GLModel::Geometry init_data; - init_data.format = { GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3N3, GLModel::Geometry::index_type(m_triangles2d.size()) }; + init_data.format = { GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3N3 }; init_data.reserve_vertices(m_triangles2d.size()); init_data.reserve_indices(m_triangles2d.size()); @@ -215,10 +222,7 @@ void MeshClipper::recalculate_triangles() init_data.add_vertex((Vec3f)(tr * Vec3d((*(it + 1)).x(), (*(it + 1)).y(), height_mesh)).cast(), (Vec3f)up.cast()); init_data.add_vertex((Vec3f)(tr * Vec3d((*(it + 2)).x(), (*(it + 2)).y(), height_mesh)).cast(), (Vec3f)up.cast()); const size_t idx = it - m_triangles2d.cbegin(); - if (init_data.format.index_type == GLModel::Geometry::EIndexType::USHORT) - init_data.add_ushort_triangle((unsigned short)idx, (unsigned short)idx + 1, (unsigned short)idx + 2); - else - init_data.add_uint_triangle((unsigned int)idx, (unsigned int)idx + 1, (unsigned int)idx + 2); + init_data.add_triangle((unsigned int)idx, (unsigned int)idx + 1, (unsigned int)idx + 2); } if (!init_data.is_empty()) diff --git a/src/slic3r/GUI/PartPlate.cpp b/src/slic3r/GUI/PartPlate.cpp index d56b369f380..958fd6d50b2 100644 --- a/src/slic3r/GUI/PartPlate.cpp +++ b/src/slic3r/GUI/PartPlate.cpp @@ -351,7 +351,7 @@ static bool init_model_from_lines(GLModel &model, const Lines &lines, float z) { GLModel::Geometry init_data; - init_data.format = { GLModel::Geometry::EPrimitiveType::Lines, GLModel::Geometry::EVertexLayout::P3, GLModel::Geometry::index_type(2 * lines.size()) }; + init_data.format = { GLModel::Geometry::EPrimitiveType::Lines, GLModel::Geometry::EVertexLayout::P3 }; init_data.reserve_vertices(2 * lines.size()); init_data.reserve_indices(2 * lines.size()); @@ -359,10 +359,7 @@ static bool init_model_from_lines(GLModel &model, const Lines &lines, float z) init_data.add_vertex(Vec3f(unscale(l.a.x()), unscale(l.a.y()), z)); init_data.add_vertex(Vec3f(unscale(l.b.x()), unscale(l.b.y()), z)); const unsigned int vertices_counter = (unsigned int)init_data.vertices_count(); - if (init_data.format.index_type == GLModel::Geometry::EIndexType::USHORT) - init_data.add_ushort_line((unsigned short)vertices_counter - 2, (unsigned short)vertices_counter - 1); - else - init_data.add_uint_line(vertices_counter - 2, vertices_counter - 1); + init_data.add_line(vertices_counter - 2, vertices_counter - 1); } model.init_from(std::move(init_data)); @@ -374,7 +371,7 @@ static bool init_model_from_lines(GLModel &model, const Lines3 &lines) { GLModel::Geometry init_data; - init_data.format = {GLModel::Geometry::EPrimitiveType::Lines, GLModel::Geometry::EVertexLayout::P3, GLModel::Geometry::index_type(2 * lines.size())}; + init_data.format = { GLModel::Geometry::EPrimitiveType::Lines, GLModel::Geometry::EVertexLayout::P3 }; init_data.reserve_vertices(2 * lines.size()); init_data.reserve_indices(2 * lines.size()); @@ -382,10 +379,7 @@ static bool init_model_from_lines(GLModel &model, const Lines3 &lines) init_data.add_vertex(Vec3f(unscale(l.a.x()), unscale(l.a.y()), unscale(l.a.z()))); init_data.add_vertex(Vec3f(unscale(l.b.x()), unscale(l.b.y()), unscale(l.b.z()))); const unsigned int vertices_counter = (unsigned int) init_data.vertices_count(); - if (init_data.format.index_type == GLModel::Geometry::EIndexType::USHORT) - init_data.add_ushort_line((unsigned short) vertices_counter - 2, (unsigned short) vertices_counter - 1); - else - init_data.add_uint_line(vertices_counter - 2, vertices_counter - 1); + init_data.add_line(vertices_counter - 2, vertices_counter - 1); } model.init_from(std::move(init_data)); @@ -583,9 +577,12 @@ void PartPlate::render_logo_texture(GLTexture &logo_texture, GLModel& logo_buffe } if (logo_buffer.is_initialized()) { - GLShaderProgram* shader = wxGetApp().get_shader("printbed"); + GLShaderProgram* shader = wxGetApp().get_shader("printbed_attr"); if (shader != nullptr) { shader->start_using(); + const Camera &camera = wxGetApp().plater()->get_camera(); + shader->set_uniform("view_model_matrix", camera.get_view_matrix()); + shader->set_uniform("projection_matrix", camera.get_projection_matrix()); shader->set_uniform("transparent_background", 0); shader->set_uniform("svg_source", 0); @@ -852,9 +849,12 @@ void PartPlate::show_tooltip(const std::string tooltip) void PartPlate::render_icons(bool bottom, bool only_name, int hover_id) { - GLShaderProgram* shader = wxGetApp().get_shader("printbed"); + GLShaderProgram* shader = wxGetApp().get_shader("printbed_attr"); if (shader != nullptr) { shader->start_using(); + const Camera &camera = wxGetApp().plater()->get_camera(); + shader->set_uniform("view_model_matrix", camera.get_view_matrix()); + shader->set_uniform("projection_matrix", camera.get_projection_matrix()); shader->set_uniform("transparent_background", bottom); //shader->set_uniform("svg_source", boost::algorithm::iends_with(m_partplate_list->m_del_texture.get_source(), ".svg")); shader->set_uniform("svg_source", 0); @@ -940,9 +940,12 @@ void PartPlate::render_icons(bool bottom, bool only_name, int hover_id) void PartPlate::render_only_numbers(bool bottom) { - GLShaderProgram* shader = wxGetApp().get_shader("printbed"); + GLShaderProgram* shader = wxGetApp().get_shader("printbed_attr"); if (shader != nullptr) { shader->start_using(); + const Camera &camera = wxGetApp().plater()->get_camera(); + shader->set_uniform("view_model_matrix", camera.get_view_matrix()); + shader->set_uniform("projection_matrix", camera.get_projection_matrix()); shader->set_uniform("transparent_background", bottom); //shader->set_uniform("svg_source", boost::algorithm::iends_with(m_partplate_list->m_del_texture.get_source(), ".svg")); shader->set_uniform("svg_source", 0); @@ -968,14 +971,17 @@ void PartPlate::render_only_numbers(bool bottom) } } -void PartPlate::render_rectangle_for_picking(GLModel &buffer, const ColorRGBA render_color) +void PartPlate::render_rectangle_for_picking(const Transform3d &view_matrix, const Transform3d &projection_matrix, GLModel &buffer, const ColorRGBA render_color) { glsafe(::glDisable(GL_DEPTH_TEST)); - GLShaderProgram *shader = wxGetApp().get_shader("flat"); + GLShaderProgram *shader = wxGetApp().get_shader("flat_attr"); if (shader != nullptr) { shader->start_using(); + shader->set_uniform("view_model_matrix", view_matrix); + shader->set_uniform("projection_matrix", projection_matrix); + //glsafe(::glDepthMask(GL_FALSE)); buffer.set_color(render_color); buffer.render(); @@ -1203,36 +1209,36 @@ void PartPlate::render_right_arrow(const ColorRGBA render_color, bool use_lighti } */ -void PartPlate::on_render_for_picking() { +void PartPlate::on_render_for_picking(const Transform3d &view_matrix, const Transform3d &projection_matrix) { //glsafe(::glDisable(GL_DEPTH_TEST)); int hover_id = 0; ColorRGBA color = picking_color_component(hover_id); m_grabber_color = color; //render_grabber(m_grabber_color, false); - render_rectangle_for_picking(m_triangles, m_grabber_color); + render_rectangle_for_picking(view_matrix, projection_matrix, m_triangles, m_grabber_color); hover_id = 1; color = picking_color_component(hover_id); m_grabber_color = color; //render_left_arrow(m_grabber_color, false); - render_rectangle_for_picking(m_del_icon, m_grabber_color); + render_rectangle_for_picking(view_matrix, projection_matrix, m_del_icon, m_grabber_color); hover_id = 2; color = picking_color_component(hover_id); m_grabber_color = color; - render_rectangle_for_picking(m_orient_icon, m_grabber_color); + render_rectangle_for_picking(view_matrix, projection_matrix, m_orient_icon, m_grabber_color); hover_id = 3; color = picking_color_component(hover_id); m_grabber_color = color; - render_rectangle_for_picking(m_arrange_icon, m_grabber_color); + render_rectangle_for_picking(view_matrix, projection_matrix, m_arrange_icon, m_grabber_color); hover_id = 4; color = picking_color_component(hover_id); m_grabber_color = color; //render_right_arrow(m_grabber_color, false); - render_rectangle_for_picking(m_lock_icon, m_grabber_color); + render_rectangle_for_picking(view_matrix, projection_matrix, m_lock_icon, m_grabber_color); hover_id = 5; color = picking_color_component(hover_id); m_grabber_color = color; if (m_partplate_list->render_plate_settings) - render_rectangle_for_picking(m_plate_settings_icon, m_grabber_color); + render_rectangle_for_picking(view_matrix, projection_matrix, m_plate_settings_icon, m_grabber_color); } ColorRGBA PartPlate::picking_color_component(int idx) const @@ -2494,7 +2500,7 @@ bool PartPlate::intersects(const BoundingBoxf3& bb) const return print_volume.intersects(bb); } -void PartPlate::render(bool bottom, bool only_body, bool force_background_color, HeightLimitMode mode, int hover_id, bool render_cali) +void PartPlate::render(const Transform3d& view_matrix, const Transform3d& projection_matrix, bool bottom, bool only_body, bool force_background_color, HeightLimitMode mode, int hover_id, bool render_cali) { GLShaderProgram *shader = wxGetApp().get_shader("flat_attr"); if (shader != nullptr) { @@ -2503,8 +2509,8 @@ void PartPlate::render(bool bottom, bool only_body, bool force_background_color, glsafe(::glEnable(GL_BLEND)); glsafe(::glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)); - const Transform3d matrix = wxGetApp().plater()->get_camera().get_projection_view_matrix(); - shader->set_uniform("projection_view_model_matrix", matrix); + shader->set_uniform("view_model_matrix", view_matrix); + shader->set_uniform("projection_matrix", projection_matrix); if (!bottom) { // draw background @@ -4352,7 +4358,7 @@ void PartPlateList::postprocess_arrange_polygon(arrangement::ArrangePolygon& arr /*rendering related functions*/ //render -void PartPlateList::render(bool bottom, bool only_current, bool only_body, int hover_id, bool render_cali) +void PartPlateList::render(const Transform3d& view_matrix, const Transform3d& projection_matrix, bool bottom, bool only_current, bool only_body, int hover_id, bool render_cali) { const std::lock_guard local_lock(m_plates_mutex); std::vector::iterator it = m_plate_list.begin(); @@ -4377,25 +4383,25 @@ void PartPlateList::render(bool bottom, bool only_current, bool only_body, int h if (current_index == m_current_plate) { PartPlate::HeightLimitMode height_mode = (only_current)?PartPlate::HEIGHT_LIMIT_NONE:m_height_limit_mode; if (plate_hover_index == current_index) - (*it)->render(bottom, only_body, false, height_mode, plate_hover_action, render_cali); + (*it)->render(view_matrix, projection_matrix, bottom, only_body, false, height_mode, plate_hover_action, render_cali); else - (*it)->render(bottom, only_body, false, height_mode, -1, render_cali); + (*it)->render(view_matrix, projection_matrix, bottom, only_body, false, height_mode, -1, render_cali); } else { if (plate_hover_index == current_index) - (*it)->render(bottom, only_body, false, PartPlate::HEIGHT_LIMIT_NONE, plate_hover_action, render_cali); + (*it)->render(view_matrix, projection_matrix, bottom, only_body, false, PartPlate::HEIGHT_LIMIT_NONE, plate_hover_action, render_cali); else - (*it)->render(bottom, only_body, false, PartPlate::HEIGHT_LIMIT_NONE, -1, render_cali); + (*it)->render(view_matrix, projection_matrix, bottom, only_body, false, PartPlate::HEIGHT_LIMIT_NONE, -1, render_cali); } } } -void PartPlateList::render_for_picking_pass() +void PartPlateList::render_for_picking_pass(const Transform3d &view_matrix, const Transform3d &projection_matrix) { const std::lock_guard local_lock(m_plates_mutex); std::vector::iterator it = m_plate_list.begin(); for (it = m_plate_list.begin(); it != m_plate_list.end(); it++) { - (*it)->render_for_picking(); + (*it)->render_for_picking(view_matrix, projection_matrix); } } diff --git a/src/slic3r/GUI/PartPlate.hpp b/src/slic3r/GUI/PartPlate.hpp index 9fcadf05980..b93e4f4dfaa 100644 --- a/src/slic3r/GUI/PartPlate.hpp +++ b/src/slic3r/GUI/PartPlate.hpp @@ -181,8 +181,8 @@ class PartPlate : public ObjectBase void render_icons(bool bottom, bool only_name = false, int hover_id = -1); void render_only_numbers(bool bottom); void render_plate_name_texture(); - void render_rectangle_for_picking(GLModel &buffer, const ColorRGBA render_color); - void on_render_for_picking(); + void render_rectangle_for_picking(const Transform3d &view_matrix, const Transform3d &projection_matrix, GLModel &buffer, const ColorRGBA render_color); + void on_render_for_picking(const Transform3d &view_matrix, const Transform3d &projection_matrix); ColorRGBA picking_color_component(int idx) const; public: @@ -341,8 +341,8 @@ class PartPlate : public ObjectBase bool contains(const BoundingBoxf3& bb) const; bool intersects(const BoundingBoxf3& bb) const; - void render(bool bottom, bool only_body = false, bool force_background_color = false, HeightLimitMode mode = HEIGHT_LIMIT_NONE, int hover_id = -1, bool render_cali = false); - void render_for_picking() { on_render_for_picking(); } + void render(const Transform3d& view_matrix, const Transform3d& projection_matrix, bool bottom, bool only_body = false, bool force_background_color = false, HeightLimitMode mode = HEIGHT_LIMIT_NONE, int hover_id = -1, bool render_cali = false); + void render_for_picking(const Transform3d &view_matrix, const Transform3d &projection_matrix) { on_render_for_picking(view_matrix, projection_matrix); } void set_selected(); void set_unselected(); void set_hover_id(int id) { m_hover_id = id; } @@ -740,8 +740,8 @@ class PartPlateList : public ObjectBase /*rendering related functions*/ void on_change_color_mode(bool is_dark) { m_is_dark = is_dark; } - void render(bool bottom, bool only_current = false, bool only_body = false, int hover_id = -1, bool render_cali = false); - void render_for_picking_pass(); + void render(const Transform3d& view_matrix, const Transform3d& projection_matrix, bool bottom, bool only_current = false, bool only_body = false, int hover_id = -1, bool render_cali = false); + void render_for_picking_pass(const Transform3d& view_matrix, const Transform3d& projection_matrix); void set_render_option(bool bedtype_texture, bool plate_settings); void set_render_cali(bool value = true) { render_cali_logo = value; } BoundingBoxf3& get_bounding_box() { return m_bounding_box; } diff --git a/src/slic3r/GUI/Selection.cpp b/src/slic3r/GUI/Selection.cpp index cff214537fd..455616e3f2b 100644 --- a/src/slic3r/GUI/Selection.cpp +++ b/src/slic3r/GUI/Selection.cpp @@ -1570,22 +1570,26 @@ void Selection::render_center(bool gizmo_is_dragging) if (!m_valid || is_empty()) return; + GLShaderProgram* shader = wxGetApp().get_shader("flat_attr"); + if (shader == nullptr) + return; + + shader->start_using(); + const Vec3d center = gizmo_is_dragging ? m_cache.dragging_center : get_bounding_box().center(); glsafe(::glDisable(GL_DEPTH_TEST)); - glsafe(::glPushMatrix()); - glsafe(::glTranslated(center.x(), center.y(), center.z())); - - GLShaderProgram* shader = wxGetApp().get_shader("flat"); - if (shader == nullptr) - return; + const Camera& camera = wxGetApp().plater()->get_camera(); + Transform3d view_model_matrix = camera.get_view_matrix() * Geometry::assemble_transform(center); - shader->start_using(); - m_vbo_sphere.set_color(-1, ColorRGBA::WHITE()); + shader->set_uniform("view_model_matrix", view_model_matrix); + shader->set_uniform("projection_matrix", camera.get_projection_matrix()); + + m_vbo_sphere.set_color(ColorRGBA::WHITE()); m_vbo_sphere.render(); + shader->stop_using(); - glsafe(::glPopMatrix()); } #endif // ENABLE_RENDER_SELECTION_CENTER @@ -1596,7 +1600,7 @@ void Selection::render_sidebar_hints(const std::string& sidebar_field, bool unif if (sidebar_field.empty()) return; - GLShaderProgram* shader = wxGetApp().get_shader(boost::starts_with(sidebar_field, "layer") ? "flat" : "gouraud_light"); + GLShaderProgram* shader = wxGetApp().get_shader(boost::starts_with(sidebar_field, "layer") ? "flat_attr" : "gouraud_light_attr"); if (shader == nullptr) return; @@ -1604,16 +1608,14 @@ void Selection::render_sidebar_hints(const std::string& sidebar_field, bool unif glsafe(::glEnable(GL_DEPTH_TEST)); - glsafe(::glPushMatrix()); + const Transform3d base_matrix = Geometry::assemble_transform(get_bounding_box().center()); + Transform3d orient_matrix = Transform3d::Identity(); if (!boost::starts_with(sidebar_field, "layer")) { - const Vec3d& center = get_bounding_box().center(); - + shader->set_uniform("emission_factor", 0.05f); // BBS if (is_single_full_instance()/* && !wxGetApp().obj_manipul()->get_world_coordinates()*/) { - glsafe(::glTranslated(center.x(), center.y(), center.z())); if (!boost::starts_with(sidebar_field, "position")) { - Transform3d orient_matrix = Transform3d::Identity(); if (boost::starts_with(sidebar_field, "scale")) orient_matrix = (*m_volumes)[*m_list.begin()]->get_instance_transformation().get_matrix(true, false, true, true); else if (boost::starts_with(sidebar_field, "rotation")) { @@ -1621,51 +1623,45 @@ void Selection::render_sidebar_hints(const std::string& sidebar_field, bool unif orient_matrix = (*m_volumes)[*m_list.begin()]->get_instance_transformation().get_matrix(true, false, true, true); else if (boost::ends_with(sidebar_field, "y")) { const Vec3d& rotation = (*m_volumes)[*m_list.begin()]->get_instance_transformation().get_rotation(); - if (rotation(0) == 0.0) + if (rotation.x() == 0.0) orient_matrix = (*m_volumes)[*m_list.begin()]->get_instance_transformation().get_matrix(true, false, true, true); else - orient_matrix.rotate(Eigen::AngleAxisd(rotation(2), Vec3d::UnitZ())); + orient_matrix.rotate(Eigen::AngleAxisd(rotation.z(), Vec3d::UnitZ())); } } - - glsafe(::glMultMatrixd(orient_matrix.data())); } - } else if (is_single_volume() || is_single_modifier()) { - glsafe(::glTranslated(center.x(), center.y(), center.z())); - Transform3d orient_matrix = (*m_volumes)[*m_list.begin()]->get_instance_transformation().get_matrix(true, false, true, true); + } + else if (is_single_volume() || is_single_modifier()) { + orient_matrix = (*m_volumes)[*m_list.begin()]->get_instance_transformation().get_matrix(true, false, true, true); if (!boost::starts_with(sidebar_field, "position")) orient_matrix = orient_matrix * (*m_volumes)[*m_list.begin()]->get_volume_transformation().get_matrix(true, false, true, true); - glsafe(::glMultMatrixd(orient_matrix.data())); - } else { - glsafe(::glTranslated(center(0), center(1), center(2))); - if (requires_local_axes()) { - const Transform3d orient_matrix = (*m_volumes)[*m_list.begin()]->get_instance_transformation().get_matrix(true, false, true, true); - glsafe(::glMultMatrixd(orient_matrix.data())); - } + } + else { + if (requires_local_axes()) + orient_matrix = (*m_volumes)[*m_list.begin()]->get_instance_transformation().get_matrix(true, false, true, true); } } if (!boost::starts_with(sidebar_field, "layer")) glsafe(::glClear(GL_DEPTH_BUFFER_BIT)); if (boost::starts_with(sidebar_field, "position")) - render_sidebar_position_hints(sidebar_field); + render_sidebar_position_hints(sidebar_field, *shader, base_matrix * orient_matrix); else if (boost::starts_with(sidebar_field, "rotation")) - render_sidebar_rotation_hints(sidebar_field); + render_sidebar_rotation_hints(sidebar_field, *shader, base_matrix * orient_matrix); else if (boost::starts_with(sidebar_field, "scale") || boost::starts_with(sidebar_field, "size")) //BBS: GUI refactor: add uniform_scale from gizmo - render_sidebar_scale_hints(sidebar_field, uniform_scale); + render_sidebar_scale_hints(sidebar_field, uniform_scale, *shader, base_matrix * orient_matrix); else if (boost::starts_with(sidebar_field, "layer")) - render_sidebar_layers_hints(sidebar_field); + render_sidebar_layers_hints(sidebar_field, *shader); - glsafe(::glPopMatrix()); shader->stop_using(); } bool Selection::requires_local_axes() const { - return (m_mode == Volume) && is_from_single_instance(); + return m_mode == Volume && is_from_single_instance(); } void Selection::cut_to_clipboard() @@ -1681,8 +1677,7 @@ void Selection::copy_to_clipboard() m_clipboard.reset(); - for (const ObjectIdxsToInstanceIdxsMap::value_type& object : m_cache.content) - { + for (const ObjectIdxsToInstanceIdxsMap::value_type& object : m_cache.content) { ModelObject* src_object = m_model->objects[object.first]; ModelObject* dst_object = m_clipboard.add_object(); dst_object->name = src_object->name; @@ -1695,26 +1690,22 @@ void Selection::copy_to_clipboard() dst_object->layer_height_profile.assign(src_object->layer_height_profile); dst_object->origin_translation = src_object->origin_translation; - for (int i : object.second) - { + for (int i : object.second) { dst_object->add_instance(*src_object->instances[i]); } - for (unsigned int i : m_list) - { + for (unsigned int i : m_list) { // Copy the ModelVolumes only for the selected GLVolumes of the 1st selected instance. const GLVolume* volume = (*m_volumes)[i]; - if ((volume->object_idx() == object.first) && (volume->instance_idx() == *object.second.begin())) - { + if (volume->object_idx() == object.first && volume->instance_idx() == *object.second.begin()) { int volume_idx = volume->volume_idx(); - if ((0 <= volume_idx) && (volume_idx < (int)src_object->volumes.size())) - { + if (0 <= volume_idx && volume_idx < (int)src_object->volumes.size()) { ModelVolume* src_volume = src_object->volumes[volume_idx]; ModelVolume* dst_volume = dst_object->add_volume(*src_volume); dst_volume->set_new_unique_id(); - } else { - assert(false); } + else + assert(false); } } } @@ -2167,7 +2158,7 @@ void Selection::render_bounding_box(const BoundingBoxf3& box, const ColorRGB& co const Vec3f size = 0.2f * box.size().cast(); GLModel::Geometry init_data; - init_data.format = { GLModel::Geometry::EPrimitiveType::Lines, GLModel::Geometry::EVertexLayout::P3, GLModel::Geometry::EIndexType::USHORT }; + init_data.format = { GLModel::Geometry::EPrimitiveType::Lines, GLModel::Geometry::EVertexLayout::P3 }; init_data.reserve_vertices(48); init_data.reserve_indices(48); @@ -2230,7 +2221,7 @@ void Selection::render_bounding_box(const BoundingBoxf3& box, const ColorRGB& co // indices for (unsigned short i = 0; i < 48; ++i) { - init_data.add_ushort_index(i); + init_data.add_index(i); } m_box.init_from(std::move(init_data)); @@ -2240,11 +2231,14 @@ void Selection::render_bounding_box(const BoundingBoxf3& box, const ColorRGB& co glsafe(::glLineWidth(2.0f * m_scale_factor)); - GLShaderProgram* shader = wxGetApp().get_shader("flat"); + GLShaderProgram* shader = wxGetApp().get_shader("flat_attr"); if (shader == nullptr) return; shader->start_using(); + const Camera& camera = wxGetApp().plater()->get_camera(); + shader->set_uniform("view_model_matrix", camera.get_view_matrix()); + shader->set_uniform("projection_matrix", camera.get_projection_matrix()); m_box.set_color(to_rgba(color)); m_box.render(); shader->stop_using(); @@ -2255,91 +2249,103 @@ static ColorRGBA get_color(Axis axis) return GLGizmoBase::AXES_COLOR[axis]; } -void Selection::render_sidebar_position_hints(const std::string& sidebar_field) +void Selection::render_sidebar_position_hints(const std::string& sidebar_field, GLShaderProgram& shader, const Transform3d& matrix) { + const Camera& camera = wxGetApp().plater()->get_camera(); + const Transform3d view_matrix = camera.get_view_matrix() * matrix; + shader.set_uniform("projection_matrix", camera.get_projection_matrix()); + if (boost::ends_with(sidebar_field, "x")) { - glsafe(::glRotated(-90.0, 0.0, 0.0, 1.0)); + const Transform3d view_model_matrix = view_matrix * Geometry::assemble_transform(Vec3d::Zero(), -0.5 * PI * Vec3d::UnitZ()); + shader.set_uniform("view_model_matrix", view_model_matrix); + shader.set_uniform("normal_matrix", (Matrix3d)view_model_matrix.matrix().block(0, 0, 3, 3).inverse().transpose()); m_arrow.set_color(get_color(X)); m_arrow.render(); } else if (boost::ends_with(sidebar_field, "y")) { + shader.set_uniform("view_model_matrix", view_matrix); + shader.set_uniform("normal_matrix", (Matrix3d)view_matrix.matrix().block(0, 0, 3, 3).inverse().transpose()); m_arrow.set_color(get_color(Y)); m_arrow.render(); } else if (boost::ends_with(sidebar_field, "z")) { - glsafe(::glRotated(90.0, 1.0, 0.0, 0.0)); + const Transform3d view_model_matrix = view_matrix * Geometry::assemble_transform(Vec3d::Zero(), 0.5 * PI * Vec3d::UnitX()); + shader.set_uniform("view_model_matrix", view_model_matrix); + shader.set_uniform("normal_matrix", (Matrix3d)view_model_matrix.matrix().block(0, 0, 3, 3).inverse().transpose()); m_arrow.set_color(get_color(Z)); m_arrow.render(); } } -void Selection::render_sidebar_rotation_hints(const std::string& sidebar_field) +void Selection::render_sidebar_rotation_hints(const std::string& sidebar_field, GLShaderProgram& shader, const Transform3d& matrix) { - auto render_sidebar_rotation_hint = [this]() { + auto render_sidebar_rotation_hint = [this](GLShaderProgram& shader, const Transform3d& matrix) { + Transform3d view_model_matrix = matrix; + shader.set_uniform("view_model_matrix", view_model_matrix); + shader.set_uniform("normal_matrix", (Matrix3d)view_model_matrix.matrix().block(0, 0, 3, 3).inverse().transpose()); m_curved_arrow.render(); - glsafe(::glRotated(180.0, 0.0, 0.0, 1.0)); + view_model_matrix = matrix * Geometry::assemble_transform(Vec3d::Zero(), PI * Vec3d::UnitZ()); + shader.set_uniform("view_model_matrix", view_model_matrix); + shader.set_uniform("normal_matrix", (Matrix3d)view_model_matrix.matrix().block(0, 0, 3, 3).inverse().transpose()); m_curved_arrow.render(); }; + const Camera& camera = wxGetApp().plater()->get_camera(); + const Transform3d view_matrix = camera.get_view_matrix() * matrix; + shader.set_uniform("projection_matrix", camera.get_projection_matrix()); + if (boost::ends_with(sidebar_field, "x")) { - glsafe(::glRotated(90.0, 0.0, 1.0, 0.0)); m_curved_arrow.set_color(get_color(X)); - render_sidebar_rotation_hint(); + render_sidebar_rotation_hint(shader, view_matrix * Geometry::assemble_transform(Vec3d::Zero(), 0.5 * PI * Vec3d::UnitY())); } else if (boost::ends_with(sidebar_field, "y")) { - glsafe(::glRotated(-90.0, 1.0, 0.0, 0.0)); m_curved_arrow.set_color(get_color(Y)); - render_sidebar_rotation_hint(); + render_sidebar_rotation_hint(shader, view_matrix * Geometry::assemble_transform(Vec3d::Zero(), -0.5 * PI * Vec3d::UnitX())); } else if (boost::ends_with(sidebar_field, "z")) { m_curved_arrow.set_color(get_color(Z)); - render_sidebar_rotation_hint(); + render_sidebar_rotation_hint(shader, view_matrix); } } //BBS: GUI refactor: add gizmo uniform_scale -void Selection::render_sidebar_scale_hints(const std::string& sidebar_field, bool gizmo_uniform_scale) +void Selection::render_sidebar_scale_hints(const std::string& sidebar_field, bool gizmo_uniform_scale, GLShaderProgram& shader, const Transform3d& matrix) { // BBS //bool uniform_scale = requires_uniform_scale() || wxGetApp().obj_manipul()->get_uniform_scaling(); bool uniform_scale = requires_uniform_scale() || gizmo_uniform_scale; - auto render_sidebar_scale_hint = [this, uniform_scale](Axis axis) { + auto render_sidebar_scale_hint = [this, uniform_scale](Axis axis, GLShaderProgram& shader, const Transform3d& matrix) { m_arrow.set_color(uniform_scale ? UNIFORM_SCALE_COLOR : get_color(axis)); - GLShaderProgram* shader = wxGetApp().get_current_shader(); - if (shader != nullptr) - shader->set_uniform("emission_factor", 0.0f); - - glsafe(::glTranslated(0.0, 5.0, 0.0)); + Transform3d view_model_matrix = matrix * Geometry::assemble_transform(5.0 * Vec3d::UnitY()); + shader.set_uniform("view_model_matrix", view_model_matrix); + shader.set_uniform("normal_matrix", (Matrix3d)view_model_matrix.matrix().block(0, 0, 3, 3).inverse().transpose()); m_arrow.render(); - glsafe(::glTranslated(0.0, -10.0, 0.0)); - glsafe(::glRotated(180.0, 0.0, 0.0, 1.0)); + view_model_matrix = matrix * Geometry::assemble_transform(-5.0 * Vec3d::UnitY(), PI * Vec3d::UnitZ()); + shader.set_uniform("view_model_matrix", view_model_matrix); + shader.set_uniform("normal_matrix", (Matrix3d)view_model_matrix.matrix().block(0, 0, 3, 3).inverse().transpose()); m_arrow.render(); }; + const Camera& camera = wxGetApp().plater()->get_camera(); + const Transform3d view_matrix = camera.get_view_matrix() * matrix; + shader.set_uniform("projection_matrix", camera.get_projection_matrix()); + if (boost::ends_with(sidebar_field, "x") || uniform_scale) { - glsafe(::glPushMatrix()); - glsafe(::glRotated(-90.0, 0.0, 0.0, 1.0)); - render_sidebar_scale_hint(X); - glsafe(::glPopMatrix()); + render_sidebar_scale_hint(X, shader, view_matrix * Geometry::assemble_transform(Vec3d::Zero(), -0.5 * PI * Vec3d::UnitZ())); } if (boost::ends_with(sidebar_field, "y") || uniform_scale) { - glsafe(::glPushMatrix()); - render_sidebar_scale_hint(Y); - glsafe(::glPopMatrix()); + render_sidebar_scale_hint(Y, shader, view_matrix); } if (boost::ends_with(sidebar_field, "z") || uniform_scale) { - glsafe(::glPushMatrix()); - glsafe(::glRotated(90.0, 1.0, 0.0, 0.0)); - render_sidebar_scale_hint(Z); - glsafe(::glPopMatrix()); + render_sidebar_scale_hint(Z, shader, view_matrix * Geometry::assemble_transform(Vec3d::Zero(), 0.5 * PI * Vec3d::UnitX())); } } -void Selection::render_sidebar_layers_hints(const std::string& sidebar_field) +void Selection::render_sidebar_layers_hints(const std::string& sidebar_field, GLShaderProgram& shader) { static const float Margin = 10.0f; @@ -2388,7 +2394,7 @@ void Selection::render_sidebar_layers_hints(const std::string& sidebar_field) m_planes.models[0].reset(); GLModel::Geometry init_data; - init_data.format = { GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3, GLModel::Geometry::EIndexType::USHORT }; + init_data.format = { GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3 }; init_data.reserve_vertices(4); init_data.reserve_indices(6); @@ -2399,8 +2405,8 @@ void Selection::render_sidebar_layers_hints(const std::string& sidebar_field) init_data.add_vertex(Vec3f(p1.x(), p2.y(), z1)); // indices - init_data.add_ushort_triangle(0, 1, 2); - init_data.add_ushort_triangle(2, 3, 0); + init_data.add_triangle(0, 1, 2); + init_data.add_triangle(2, 3, 0); m_planes.models[0].init_from(std::move(init_data)); } @@ -2410,7 +2416,7 @@ void Selection::render_sidebar_layers_hints(const std::string& sidebar_field) m_planes.models[1].reset(); GLModel::Geometry init_data; - init_data.format = { GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3, GLModel::Geometry::EIndexType::USHORT }; + init_data.format = { GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3 }; init_data.reserve_vertices(4); init_data.reserve_indices(6); @@ -2421,12 +2427,16 @@ void Selection::render_sidebar_layers_hints(const std::string& sidebar_field) init_data.add_vertex(Vec3f(p1.x(), p2.y(), z2)); // indices - init_data.add_ushort_triangle(0, 1, 2); - init_data.add_ushort_triangle(2, 3, 0); + init_data.add_triangle(0, 1, 2); + init_data.add_triangle(2, 3, 0); m_planes.models[1].init_from(std::move(init_data)); } + const Camera& camera = wxGetApp().plater()->get_camera(); + shader.set_uniform("view_model_matrix", camera.get_view_matrix()); + shader.set_uniform("projection_matrix", camera.get_projection_matrix()); + m_planes.models[0].set_color((camera_on_top && type == 1) || (!camera_on_top && type == 2) ? SOLID_PLANE_COLOR : TRANSPARENT_PLANE_COLOR); m_planes.models[0].render(); m_planes.models[1].set_color((camera_on_top && type == 2) || (!camera_on_top && type == 1) ? SOLID_PLANE_COLOR : TRANSPARENT_PLANE_COLOR); diff --git a/src/slic3r/GUI/Selection.hpp b/src/slic3r/GUI/Selection.hpp index 254f82a3cf7..71c2cf6a1b6 100644 --- a/src/slic3r/GUI/Selection.hpp +++ b/src/slic3r/GUI/Selection.hpp @@ -408,11 +408,11 @@ class Selection void set_bounding_boxes_dirty() { m_bounding_box.reset(); m_unscaled_instance_bounding_box.reset(); m_scaled_instance_bounding_box.reset(); } void render_synchronized_volumes(); void render_bounding_box(const BoundingBoxf3& box, const ColorRGB& color); - void render_sidebar_position_hints(const std::string& sidebar_field); - void render_sidebar_rotation_hints(const std::string& sidebar_field); + void render_sidebar_position_hints(const std::string& sidebar_field, GLShaderProgram& shader, const Transform3d& matrix); + void render_sidebar_rotation_hints(const std::string& sidebar_field, GLShaderProgram& shader, const Transform3d& matrix); //BBS: GUI refactor: add uniform_scale from gizmo - void render_sidebar_scale_hints(const std::string& sidebar_field, bool gizmo_uniform_scale); - void render_sidebar_layers_hints(const std::string& sidebar_field); + void render_sidebar_scale_hints(const std::string& sidebar_field, bool gizmo_uniform_scale, GLShaderProgram& shader, const Transform3d& matrix); + void render_sidebar_layers_hints(const std::string& sidebar_field, GLShaderProgram& shader); public: enum SyncRotationType { diff --git a/src/slic3r/Utils/CalibUtils.cpp b/src/slic3r/Utils/CalibUtils.cpp index a496d1ff34a..9530a4eb7d6 100644 --- a/src/slic3r/Utils/CalibUtils.cpp +++ b/src/slic3r/Utils/CalibUtils.cpp @@ -917,7 +917,7 @@ void CalibUtils::process_and_store_3mf(Model *model, const DynamicPrintConfig &f ThumbnailData* thumbnail_data = &plate_data_list[0]->plate_thumbnail; unsigned int thumbnail_width = 512, thumbnail_height = 512; const ThumbnailsParams thumbnail_params = {{}, false, true, true, true, 0}; - GLShaderProgram* shader = wxGetApp().get_shader("thumbnail"); + GLShaderProgram* shader = wxGetApp().get_shader("thumbnail_attr"); for (unsigned int obj_idx = 0; obj_idx < (unsigned int)model->objects.size(); ++ obj_idx) { const ModelObject &model_object = *model->objects[obj_idx]; From 03daf61862fb4897860d28dcf18423d110dfea7b Mon Sep 17 00:00:00 2001 From: Noisyfox Date: Thu, 26 Oct 2023 15:06:46 +0800 Subject: [PATCH 35/99] Fix outline rendering --- src/slic3r/GUI/3DScene.cpp | 312 ++++--------------- src/slic3r/GUI/3DScene.hpp | 6 +- src/slic3r/GUI/GLCanvas3D.cpp | 2 +- src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp | 4 +- 4 files changed, 70 insertions(+), 254 deletions(-) diff --git a/src/slic3r/GUI/3DScene.cpp b/src/slic3r/GUI/3DScene.cpp index 354dc76c71e..a3fdcfa8f8e 100644 --- a/src/slic3r/GUI/3DScene.cpp +++ b/src/slic3r/GUI/3DScene.cpp @@ -396,250 +396,65 @@ void GLVolume::set_range(double min_z, double max_z) } } -//BBS: add outline related logic -//static unsigned char stencil_data[1284][2944]; -void GLVolume::render(bool with_outline) +void GLVolume::render() { if (!is_active) return; - GLShaderProgram* shader = GUI::wxGetApp().get_current_shader(); + GLShaderProgram *shader = GUI::wxGetApp().get_current_shader(); if (shader == nullptr) return; - if (this->is_left_handed()) - glFrontFace(GL_CW); - glsafe(::glCullFace(GL_BACK)); - if (with_outline) { - // Error: not supported! - throw Slic3r::InvalidArgument("Render GLVolume with outline is not supported"); - } + ModelObjectPtrs &model_objects = GUI::wxGetApp().model().objects; + std::vector colors = get_extruders_colors(); - // BBS: add logic for mmu segmentation rendering - auto render_body = [&]() { - bool color_volume = false; - ModelObjectPtrs& model_objects = GUI::wxGetApp().model().objects; - do { - if ((!printable) || object_idx() >= model_objects.size()) - break; - - ModelObject* mo = model_objects[object_idx()]; - if (volume_idx() >= mo->volumes.size()) - break; - - ModelVolume* mv = mo->volumes[volume_idx()]; - if (mv->mmu_segmentation_facets.empty()) - break; - - color_volume = true; - if (mv->mmu_segmentation_facets.timestamp() != mmuseg_ts) { - BOOST_LOG_TRIVIAL(debug) << __FUNCTION__<< boost::format(", this %1%, name %2%, current mmuseg_ts %3%, current color size %4%") - %this %this->name %mmuseg_ts %mmuseg_models.size() ; - mmuseg_models.clear(); - std::vector its_per_color; - mv->mmu_segmentation_facets.get_facets(*mv, its_per_color); - mmuseg_models.resize(its_per_color.size()); - for (int idx = 0; idx < its_per_color.size(); idx++) { - mmuseg_models[idx].init_from(its_per_color[idx]); - } - - mmuseg_ts = mv->mmu_segmentation_facets.timestamp(); - BOOST_LOG_TRIVIAL(debug) << __FUNCTION__<< boost::format(", this %1%, name %2%, new mmuseg_ts %3%, new color size %4%") - %this %this->name %mmuseg_ts %mmuseg_models.size(); - } - } while (0); - - if (color_volume) { - GLShaderProgram* shader = GUI::wxGetApp().get_current_shader(); - std::vector colors = get_extruders_colors(); - - //when force_transparent, we need to keep the alpha - if (force_native_color && (render_color.is_transparent())) { - for (int index = 0; index < colors.size(); index++) - colors[index].a(render_color.a()); - } - for (int idx = 0; idx < mmuseg_models.size(); idx++) { - GUI::GLModel &m = mmuseg_models[idx]; - if (m.is_empty()) - continue; - - if (shader) { - if (idx == 0) { - ModelObject* mo = model_objects[object_idx()]; - ModelVolume* mv = mo->volumes[volume_idx()]; - int extruder_id = mv->extruder_id(); - //shader->set_uniform("uniform_color", colors[extruder_id - 1]); - //to make black not too hard too see - ColorRGBA new_color = adjust_color_for_rendering(colors[extruder_id - 1]); - m.set_color(new_color); - } - else { - if (idx <= colors.size()) { - //shader->set_uniform("uniform_color", colors[idx - 1]); - //to make black not too hard too see - ColorRGBA new_color = adjust_color_for_rendering(colors[idx - 1]); - m.set_color(new_color); - } - else { - //shader->set_uniform("uniform_color", colors[0]); - //to make black not too hard too see - ColorRGBA new_color = adjust_color_for_rendering(colors[0]); - m.set_color(new_color); - } - } - } - if (tverts_range == std::make_pair(0, -1)) - m.render(); - else - m.render(this->tverts_range); - /*if (force_native_color && (render_color[3] < 1.0)) { - BOOST_LOG_TRIVIAL(debug) << __FUNCTION__<< boost::format(", this %1%, name %2%, tverts_range {%3,%4}, qverts_range{%5%, %6%}") - %this %this->name %this->tverts_range.first %this->tverts_range.second - % this->qverts_range.first % this->qverts_range.second; - }*/ - } - } - else { - if (tverts_range == std::make_pair(0, -1)) - model.render(); - else - model.render(this->tverts_range); - } - }; + simple_render(shader, model_objects, colors); +} - //BBS: add logic of outline rendering - //BOOST_LOG_TRIVIAL(info) << boost::format(": %1%, with_outline %2%, shader %3%.")%__LINE__ %with_outline %shader; - if (with_outline && shader != nullptr) - { - do - { - glEnable(GL_STENCIL_TEST); - glStencilMask(0xFF); - glStencilOp(GL_KEEP, GL_REPLACE, GL_REPLACE); - glClear(GL_STENCIL_BUFFER_BIT); - glStencilFunc(GL_ALWAYS, 0xff, 0xFF); - //another way use depth buffer - //glsafe(::glEnable(GL_DEPTH_TEST)); - //glsafe(::glDepthFunc(GL_ALWAYS)); - //glsafe(::glDepthMask(GL_FALSE)); - //glsafe(::glEnable(GL_BLEND)); - //glsafe(::glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)); - - /*GLShaderProgram* outline_shader = GUI::wxGetApp().get_shader("outline"); - if (outline_shader == nullptr) - { - glDisable(GL_STENCIL_TEST); - this->indexed_vertex_array.render(this->tverts_range, this->qverts_range); - break; - } - shader->stop_using(); - outline_shader->start_using(); - //float scale_ratio = 1.02f; - ColorRGBA outline_color = { 0.0f, 1.0f, 0.0f, 1.0f }; - - outline_shader->set_uniform("uniform_color", outline_color);*/ -#if 0 //dump stencil buffer - int i = 100, j = 100; - std::string file_name; - FILE* file = NULL; - memset(stencil_data, 0, sizeof(stencil_data)); - glReadPixels(0, 0, 2936, 1083, GL_STENCIL_INDEX, GL_UNSIGNED_BYTE, stencil_data); - for (i = 100; i < 1083; i++) - { - for (j = 100; j < 2936; j++) - { - if (stencil_data[i][j] != 0) - { - file_name = "before_stencil_index_" + std::to_string(i) + "x" + std::to_string(j) + ".a8"; - break; - } - } +//BBS: add outline related logic +void GLVolume::render_with_outline(const Transform3d &view_model_matrix) +{ + if (!is_active) + return; - if (stencil_data[i][j] != 0) - break; - } - file = fopen(file_name.c_str(), "w"); - if (file) - { - fwrite(stencil_data, 2936 * 1083, 1, file); - fclose(file); - } -#endif - render_body(); - //BOOST_LOG_TRIVIAL(info) << boost::format(": %1%, outline render body, shader name %2%")%__LINE__ %shader->get_name(); + GLShaderProgram *shader = GUI::wxGetApp().get_current_shader(); + if (shader == nullptr) + return; -#if 0 //dump stencil buffer after first rendering - memset(stencil_data, 0, sizeof(stencil_data)); - glReadPixels(0, 0, 2936, 1083, GL_STENCIL_INDEX, GL_UNSIGNED_BYTE, stencil_data); - for (i = 100; i < 1083; i++) - { - for (j = 100; j < 2936; j++) - if (stencil_data[i][j] != 0) - { - file_name = "after_stencil_index_" + std::to_string(i) + "x" + std::to_string(j) + ".a8"; - break; - } + ModelObjectPtrs &model_objects = GUI::wxGetApp().model().objects; + std::vector colors = get_extruders_colors(); + + glEnable(GL_STENCIL_TEST); + glStencilMask(0xFF); + glStencilOp(GL_KEEP, GL_REPLACE, GL_REPLACE); + glClear(GL_STENCIL_BUFFER_BIT); + glStencilFunc(GL_ALWAYS, 0xff, 0xFF); + + simple_render(shader, model_objects, colors); + + // 2nd. render pass: now draw slightly scaled versions of the objects, this time disabling stencil writing. + // Because the stencil buffer is now filled with several 1s. The parts of the buffer that are 1 are not drawn, thus only drawing + // the objects' size differences, making it look like borders. + glStencilFunc(GL_NOTEQUAL, 0xff, 0xFF); + glStencilMask(0x00); + float scale = 1.02f; + ColorRGBA body_color = { 1.0f, 1.0f, 1.0f, 1.0f }; //red + + model.set_color(body_color); + shader->set_uniform("is_outline", true); + + Transform3d matrix = view_model_matrix; + matrix.scale(scale); + shader->set_uniform("view_model_matrix", matrix); + if (tverts_range == std::make_pair(0, -1)) + model.render(); + else + model.render(this->tverts_range); - if (stencil_data[i][j] != 0) - break; - } + shader->set_uniform("view_model_matrix", view_model_matrix); + shader->set_uniform("is_outline", false); - file = fopen(file_name.c_str(), "w"); - if (file) - { - fwrite(stencil_data, 2936 * 1083, 1, file); - fclose(file); - } -#endif - // 2nd. render pass: now draw slightly scaled versions of the objects, this time disabling stencil writing. - // Because the stencil buffer is now filled with several 1s. The parts of the buffer that are 1 are not drawn, thus only drawing - // the objects' size differences, making it look like borders. - // ----------------------------------------------------------------------------------------------------------------------------- - /*GLShaderProgram* outline_shader = GUI::wxGetApp().get_shader("outline"); - if (outline_shader == nullptr) - { - glDisable(GL_STENCIL_TEST); - break; - } - shader->stop_using(); - outline_shader->start_using();*/ - //outline_shader->stop_using(); - //shader->start_using(); - - glStencilFunc(GL_NOTEQUAL, 0xff, 0xFF); - glStencilMask(0x00); - float scale = 1.02f; - ColorRGBA body_color = { 1.0f, 1.0f, 1.0f, 1.0f }; //red - - model.set_color(body_color); - shader->set_uniform("is_outline", true); - glsafe(::glPopMatrix()); - glsafe(::glPushMatrix()); - - Transform3d matrix = world_matrix(); - matrix.scale(scale); - glsafe(::glMultMatrixd(matrix.data())); - if (tverts_range == std::make_pair(0, -1)) - model.render(); - else - model.render(this->tverts_range); - //BOOST_LOG_TRIVIAL(info) << boost::format(": %1%, outline render for body, shader name %2%")%__LINE__ %shader->get_name(); - shader->set_uniform("is_outline", false); - - //glStencilMask(0xFF); - //glStencilFunc(GL_ALWAYS, 0, 0xFF); - glDisable(GL_STENCIL_TEST); - //glEnable(GL_DEPTH_TEST); - //outline_shader->stop_using(); - //shader->start_using(); - } while (0); - } - else { - render_body(); - //BOOST_LOG_TRIVIAL(info) << boost::format(": %1%, normal render.")%__LINE__; - } - if (this->is_left_handed()) - glFrontFace(GL_CCW); + glDisable(GL_STENCIL_TEST); } //BBS add render for simple case @@ -684,26 +499,22 @@ void GLVolume::simple_render(GLShaderProgram* shader, ModelObjectPtrs& model_obj if (m.is_empty()) continue; - if (shader) { - if (idx == 0) { - int extruder_id = model_volume->extruder_id(); + if (idx == 0) { + int extruder_id = model_volume->extruder_id(); + //to make black not too hard too see + ColorRGBA new_color = adjust_color_for_rendering(extruder_colors[extruder_id - 1]); + m.set_color(new_color); + } + else { + if (idx <= extruder_colors.size()) { //to make black not too hard too see - ColorRGBA new_color = adjust_color_for_rendering(extruder_colors[extruder_id - 1]); + ColorRGBA new_color = adjust_color_for_rendering(extruder_colors[idx - 1]); m.set_color(new_color); } else { - if (idx <= extruder_colors.size()) { - //shader->set_uniform("uniform_color", extruder_colors[idx - 1]); - //to make black not too hard too see - ColorRGBA new_color = adjust_color_for_rendering(extruder_colors[idx - 1]); - m.set_color(new_color); - } - else { - //shader->set_uniform("uniform_color", extruder_colors[0]); - //to make black not too hard too see - ColorRGBA new_color = adjust_color_for_rendering(extruder_colors[0]); - m.set_color(new_color); - } + //to make black not too hard too see + ColorRGBA new_color = adjust_color_for_rendering(extruder_colors[0]); + m.set_color(new_color); } } if (tverts_range == std::make_pair(0, -1)) @@ -748,7 +559,7 @@ GLWipeTowerVolume::GLWipeTowerVolume(const std::vector& colors) m_colors = colors; } -void GLWipeTowerVolume::render(bool with_outline) +void GLWipeTowerVolume::render() { if (!is_active) return; @@ -1102,7 +913,10 @@ void GLVolumeCollection::render(GLVolumeCollection::ERenderType type, bool disab shader->set_uniform("projection_matrix", projection_matrix); shader->set_uniform("normal_matrix", (Matrix3d)matrix.matrix().block(0, 0, 3, 3).inverse().transpose()); //BBS: add outline related logic - volume.first->render(with_outline && volume.first->selected); + if (with_outline && volume.first->selected) + volume.first->render_with_outline(matrix); + else + volume.first->render(); #if ENABLE_ENVIRONMENT_MAP if (use_environment_texture) diff --git a/src/slic3r/GUI/3DScene.hpp b/src/slic3r/GUI/3DScene.hpp index 79e53320b4e..aefa250b52c 100644 --- a/src/slic3r/GUI/3DScene.hpp +++ b/src/slic3r/GUI/3DScene.hpp @@ -312,8 +312,10 @@ class GLVolume { void set_range(double low, double high); + virtual void render(); + //BBS: add outline related logic and add virtual specifier - virtual void render(bool with_outline = false); + void render_with_outline(const Transform3d &view_model_matrix); //BBS: add simple render function for thumbnail void simple_render(GLShaderProgram* shader, ModelObjectPtrs& model_objects, std::vector& extruder_colors); @@ -345,7 +347,7 @@ class GLVolume { class GLWipeTowerVolume : public GLVolume { public: GLWipeTowerVolume(const std::vector& colors); - virtual void render(bool with_outline = false); + void render() override; std::vector model_per_colors; bool IsTransparent(); diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 81db1388715..e9592292282 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -5608,7 +5608,7 @@ void GLCanvas3D::render_thumbnail_internal(ThumbnailData& thumbnail_data, const shader->set_uniform("view_model_matrix", matrix); shader->set_uniform("projection_matrix", projection_matrix); shader->set_uniform("normal_matrix", (Matrix3d) matrix.matrix().block(0, 0, 3, 3).inverse().transpose()); - vol->simple_render(nullptr, model_objects, extruder_colors); + vol->simple_render(shader, model_objects, extruder_colors); vol->is_active = is_active; } diff --git a/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp b/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp index c6a635ccd50..6aa834ad963 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp @@ -116,8 +116,8 @@ void GLGizmoFdmSupports::render_painter_gizmo() //BBS: draw support volumes if (m_volume_ready && m_support_volume && (m_edit_state != state_generating)) { - //m_support_volume->set_render_color(); - ::glColor4f(0.f, 0.7f, 0.f, 0.7f); + // TODO: FIXME + m_support_volume->set_render_color({0.f, 0.7f, 0.f, 0.7f}); m_support_volume->render(); } From 8f49be40b71d9d05edeb1fd194eca6c6c95642a4 Mon Sep 17 00:00:00 2001 From: Noisyfox Date: Thu, 26 Oct 2023 16:28:10 +0800 Subject: [PATCH 36/99] Fix preview shell rendering --- src/slic3r/GUI/GCodeViewer.cpp | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/src/slic3r/GUI/GCodeViewer.cpp b/src/slic3r/GUI/GCodeViewer.cpp index c106ed01ec0..3737c7021c3 100644 --- a/src/slic3r/GUI/GCodeViewer.cpp +++ b/src/slic3r/GUI/GCodeViewer.cpp @@ -1236,15 +1236,12 @@ void GCodeViewer::render(int canvas_width, int canvas_height, int right_margin) m_statistics.total_instances_gpu_size = 0; #endif // ENABLE_GCODE_VIEWER_STATISTICS - render_shells(); - // Orca: add shell overlay effect - glsafe(::glClear(GL_DEPTH_BUFFER_BIT)); - if (m_roles.empty()) return; - glsafe(::glEnable(GL_DEPTH_TEST)); + glsafe(::glEnable(GL_DEPTH_TEST)); render_toolpaths(); + render_shells(); float legend_height = 0.0f; render_legend(legend_height, canvas_width, canvas_height, right_margin); @@ -4115,16 +4112,16 @@ void GCodeViewer::render_shells() if (shader == nullptr) return; - glsafe(::glEnable(GL_DEPTH_TEST)); // glsafe(::glDepthMask(GL_FALSE)); shader->start_using(); + shader->set_uniform("emission_factor", 0.1f); const Camera& camera = wxGetApp().plater()->get_camera(); - //BBS: reopen cul faces - m_shells.volumes.render(GLVolumeCollection::ERenderType::Transparent, false, camera.get_view_matrix(), camera.get_projection_matrix()); + m_shells.volumes.render(GLVolumeCollection::ERenderType::Transparent, true, camera.get_view_matrix(), camera.get_projection_matrix()); + shader->set_uniform("emission_factor", 0.0f); shader->stop_using(); - // glsafe(::glDepthMask(GL_TRUE)); +// glsafe(::glDepthMask(GL_TRUE)); } //BBS From 511bfa71b6201ff3b05dd3271426818e75573642 Mon Sep 17 00:00:00 2001 From: Noisyfox Date: Thu, 26 Oct 2023 19:21:48 +0800 Subject: [PATCH 37/99] Fix plate texture rendering depth issue --- src/slic3r/GUI/PartPlate.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/slic3r/GUI/PartPlate.cpp b/src/slic3r/GUI/PartPlate.cpp index 958fd6d50b2..b4fa5c3d386 100644 --- a/src/slic3r/GUI/PartPlate.cpp +++ b/src/slic3r/GUI/PartPlate.cpp @@ -2502,10 +2502,11 @@ bool PartPlate::intersects(const BoundingBoxf3& bb) const void PartPlate::render(const Transform3d& view_matrix, const Transform3d& projection_matrix, bool bottom, bool only_body, bool force_background_color, HeightLimitMode mode, int hover_id, bool render_cali) { + glsafe(::glEnable(GL_DEPTH_TEST)); + GLShaderProgram *shader = wxGetApp().get_shader("flat_attr"); if (shader != nullptr) { shader->start_using(); - glsafe(::glEnable(GL_DEPTH_TEST)); glsafe(::glEnable(GL_BLEND)); glsafe(::glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)); @@ -2529,7 +2530,6 @@ void PartPlate::render(const Transform3d& view_matrix, const Transform3d& projec // render_label(canvas); // } - glsafe(::glDisable(GL_DEPTH_TEST)); shader->stop_using(); } @@ -2544,6 +2544,8 @@ void PartPlate::render(const Transform3d& view_matrix, const Transform3d& projec if (!force_background_color) { render_only_numbers(bottom); } + + glsafe(::glDisable(GL_DEPTH_TEST)); } void PartPlate::set_selected() { From e211e7d144c26e959016c57c92eecf856046e915 Mon Sep 17 00:00:00 2001 From: Noisyfox Date: Thu, 26 Oct 2023 20:06:44 +0800 Subject: [PATCH 38/99] Fix mm rendering --- src/slic3r/GUI/3DScene.cpp | 17 ++++++++--------- src/slic3r/GUI/3DScene.hpp | 5 ++++- src/slic3r/GUI/GLCanvas3D.cpp | 2 ++ 3 files changed, 14 insertions(+), 10 deletions(-) diff --git a/src/slic3r/GUI/3DScene.cpp b/src/slic3r/GUI/3DScene.cpp index a3fdcfa8f8e..2be7dd9afc0 100644 --- a/src/slic3r/GUI/3DScene.cpp +++ b/src/slic3r/GUI/3DScene.cpp @@ -492,11 +492,10 @@ void GLVolume::simple_render(GLShaderProgram* shader, ModelObjectPtrs& model_obj } } while (0); - if (color_volume) { - glsafe(::glMultMatrixd(world_matrix().data())); + if (color_volume && !picking) { for (int idx = 0; idx < mmuseg_models.size(); idx++) { GUI::GLModel &m = mmuseg_models[idx]; - if (m.is_empty()) + if (!m.is_initialized()) continue; if (idx == 0) { @@ -570,17 +569,17 @@ void GLWipeTowerVolume::render() if (this->is_left_handed()) glFrontFace(GL_CW); glsafe(::glCullFace(GL_BACK)); - glsafe(::glPushMatrix()); - glsafe(::glMultMatrixd(world_matrix().data())); - GLShaderProgram* shader = GUI::wxGetApp().get_current_shader(); for (int i = 0; i < m_colors.size(); i++) { - ColorRGBA new_color = adjust_color_for_rendering(m_colors[i]); - this->model_per_colors[i].set_color(new_color); + if (!picking) { + ColorRGBA new_color = adjust_color_for_rendering(m_colors[i]); + this->model_per_colors[i].set_color(new_color); + } else { + this->model_per_colors[i].set_color(model.get_color()); + } this->model_per_colors[i].render(); } - glsafe(::glPopMatrix()); if (this->is_left_handed()) glFrontFace(GL_CCW); } diff --git a/src/slic3r/GUI/3DScene.hpp b/src/slic3r/GUI/3DScene.hpp index aefa250b52c..18a8ec279d1 100644 --- a/src/slic3r/GUI/3DScene.hpp +++ b/src/slic3r/GUI/3DScene.hpp @@ -194,6 +194,8 @@ class GLVolume { bool force_neutral_color : 1; // Whether or not to force rendering of sinking contours bool force_sinking_contours : 1; + // Is render for picking + bool picking : 1; }; // Is mouse or rectangle selection over this object to select/deselect it ? @@ -315,7 +317,7 @@ class GLVolume { virtual void render(); //BBS: add outline related logic and add virtual specifier - void render_with_outline(const Transform3d &view_model_matrix); + virtual void render_with_outline(const Transform3d &view_model_matrix); //BBS: add simple render function for thumbnail void simple_render(GLShaderProgram* shader, ModelObjectPtrs& model_objects, std::vector& extruder_colors); @@ -348,6 +350,7 @@ class GLWipeTowerVolume : public GLVolume { public: GLWipeTowerVolume(const std::vector& colors); void render() override; + void render_with_outline(const Transform3d &view_model_matrix) override { render(); } std::vector model_per_colors; bool IsTransparent(); diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index e9592292282..32b828e6fa8 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -7203,7 +7203,9 @@ void GLCanvas3D::_render_volumes_for_picking() const const Camera& camera = wxGetApp().plater()->get_camera(); shader->set_uniform("view_model_matrix", camera.get_view_matrix() * volume.first->world_matrix()); shader->set_uniform("projection_matrix", camera.get_projection_matrix()); + volume.first->picking = true; volume.first->render(); + volume.first->picking = false; shader->stop_using(); } } From ac001f881608248cf0f8cdb4efd1505b4d2f4db8 Mon Sep 17 00:00:00 2001 From: Noisyfox Date: Thu, 26 Oct 2023 22:19:21 +0800 Subject: [PATCH 39/99] Fix pick rendering depth issue --- src/slic3r/GUI/PartPlate.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/slic3r/GUI/PartPlate.cpp b/src/slic3r/GUI/PartPlate.cpp index b4fa5c3d386..ced8d15c59f 100644 --- a/src/slic3r/GUI/PartPlate.cpp +++ b/src/slic3r/GUI/PartPlate.cpp @@ -973,8 +973,6 @@ void PartPlate::render_only_numbers(bool bottom) void PartPlate::render_rectangle_for_picking(const Transform3d &view_matrix, const Transform3d &projection_matrix, GLModel &buffer, const ColorRGBA render_color) { - glsafe(::glDisable(GL_DEPTH_TEST)); - GLShaderProgram *shader = wxGetApp().get_shader("flat_attr"); if (shader != nullptr) { shader->start_using(); From 8dc82e7a8d8905f0394fbe284908796b9bbd7e86 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Thu, 26 Oct 2023 22:45:42 +0800 Subject: [PATCH 40/99] Few small fixes --- src/slic3r/GUI/GCodeViewer.cpp | 6 ++-- src/slic3r/GUI/GLCanvas3D.cpp | 10 ------- src/slic3r/GUI/GLModel.cpp | 17 ++++++----- src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp | 40 ++----------------------- src/slic3r/GUI/Gizmos/GLGizmoRotate.hpp | 1 - 5 files changed, 14 insertions(+), 60 deletions(-) diff --git a/src/slic3r/GUI/GCodeViewer.cpp b/src/slic3r/GUI/GCodeViewer.cpp index 3737c7021c3..667c950f930 100644 --- a/src/slic3r/GUI/GCodeViewer.cpp +++ b/src/slic3r/GUI/GCodeViewer.cpp @@ -5584,13 +5584,13 @@ void GCodeViewer::render_statistics() ImGuiWrapper& imgui = *wxGetApp().imgui(); - auto add_time = [this, &imgui](const std::string& label, int64_t time) { + auto add_time = [&imgui](const std::string& label, int64_t time) { imgui.text_colored(ImGuiWrapper::COL_ORANGE_LIGHT, label); ImGui::SameLine(offset); imgui.text(std::to_string(time) + " ms (" + get_time_dhms(static_cast(time) * 0.001f) + ")"); }; - auto add_memory = [this, &imgui](const std::string& label, int64_t memory) { + auto add_memory = [&imgui](const std::string& label, int64_t memory) { auto format_string = [memory](const std::string& units, float value) { return std::to_string(memory) + " bytes (" + Slic3r::float_to_string_decimal_point(float(memory) * value, 3) @@ -5613,7 +5613,7 @@ void GCodeViewer::render_statistics() imgui.text(format_string("GB", inv_gb)); }; - auto add_counter = [this, &imgui](const std::string& label, int64_t counter) { + auto add_counter = [&imgui](const std::string& label, int64_t counter) { imgui.text_colored(ImGuiWrapper::COL_ORANGE_LIGHT, label); ImGui::SameLine(offset); imgui.text(std::to_string(counter)); diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 32b828e6fa8..a6d32d8d5ff 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -7002,14 +7002,6 @@ void GLCanvas3D::_check_and_update_toolbar_icon_scale() void GLCanvas3D::_render_overlays() { glsafe(::glDisable(GL_DEPTH_TEST)); - glsafe(::glPushMatrix()); - glsafe(::glLoadIdentity()); - // ensure that the textures are renderered inside the frustrum - const Camera& camera = wxGetApp().plater()->get_camera(); - glsafe(::glTranslated(0.0, 0.0, -(camera.get_near_z() + 0.10))); - // ensure that the overlay fits the frustrum near z plane - double gui_scale = camera.get_gui_scale(); - glsafe(::glScaled(gui_scale, gui_scale, 1.0)); _check_and_update_toolbar_icon_scale(); @@ -7081,8 +7073,6 @@ void GLCanvas3D::_render_overlays() }*/ } m_labels.render(sorted_instances); - - glsafe(::glPopMatrix()); } void GLCanvas3D::_render_style_editor() diff --git a/src/slic3r/GUI/GLModel.cpp b/src/slic3r/GUI/GLModel.cpp index 94a431f1c81..eaaf4b4bd38 100644 --- a/src/slic3r/GUI/GLModel.cpp +++ b/src/slic3r/GUI/GLModel.cpp @@ -417,7 +417,7 @@ void GLModel::init_from(const indexed_triangle_set& its) // update bounding box for (size_t i = 0; i < vertices_count(); ++i) { - m_bounding_box.merge(m_render_data.geometry.extract_position_3(i).cast()); + m_bounding_box.merge(data.extract_position_3(i).cast()); } } @@ -460,7 +460,7 @@ void GLModel::init_from(const Polygons& polygons, float z) // update bounding box for (size_t i = 0; i < vertices_count(); ++i) { - m_bounding_box.merge(m_render_data.geometry.extract_position_3(i).cast()); + m_bounding_box.merge(data.extract_position_3(i).cast()); } } @@ -707,31 +707,32 @@ bool GLModel::send_to_gpu() // indices glsafe(::glGenBuffers(1, &m_render_data.ibo_id)); glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_render_data.ibo_id)); + const size_t indices_count = data.indices.size(); if (m_render_data.vertices_count <= 256) { // convert indices to unsigned char to save gpu memory - std::vector reduced_indices(data.indices.size()); - for (size_t i = 0; i < data.indices.size(); ++i) { + std::vector reduced_indices(indices_count); + for (size_t i = 0; i < indices_count; ++i) { reduced_indices[i] = (unsigned char)data.indices[i]; } data.index_type = Geometry::EIndexType::UBYTE; - glsafe(::glBufferData(GL_ELEMENT_ARRAY_BUFFER, reduced_indices.size() * sizeof(unsigned char), reduced_indices.data(), GL_STATIC_DRAW)); + glsafe(::glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices_count * sizeof(unsigned char), reduced_indices.data(), GL_STATIC_DRAW)); glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0)); } else if (m_render_data.vertices_count <= 65536) { // convert indices to unsigned short to save gpu memory - std::vector reduced_indices(data.indices.size()); + std::vector reduced_indices(indices_count); for (size_t i = 0; i < data.indices.size(); ++i) { reduced_indices[i] = (unsigned short)data.indices[i]; } data.index_type = Geometry::EIndexType::USHORT; - glsafe(::glBufferData(GL_ELEMENT_ARRAY_BUFFER, reduced_indices.size() * sizeof(unsigned short), reduced_indices.data(), GL_STATIC_DRAW)); + glsafe(::glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices_count * sizeof(unsigned short), reduced_indices.data(), GL_STATIC_DRAW)); glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0)); } else { glsafe(::glBufferData(GL_ELEMENT_ARRAY_BUFFER, data.indices_size_bytes(), data.indices.data(), GL_STATIC_DRAW)); glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0)); } - m_render_data.indices_count = indices_count(); + m_render_data.indices_count = indices_count; data.indices = std::vector(); return true; diff --git a/src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp b/src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp index ab3196364e9..7924fea1898 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp @@ -157,13 +157,9 @@ void GLGizmoRotate::on_render() render_grabber_connection(color, radius_changed); shader->stop_using(); } - glsafe(::glPushMatrix()); - transform_to_local(selection); render_grabber(box); render_grabber_extension(box, false); - - glsafe(::glPopMatrix()); } void GLGizmoRotate::on_render_for_picking() @@ -445,12 +441,12 @@ Transform3d GLGizmoRotate::local_transform(const Selection& selection) const { case X: { - ret = Geometry::assemble_transform(Vec3d::Zero(), Vec3d(0.0, 0.5 * PI, 0.0)) * Geometry::assemble_transform(Vec3d::Zero(), Vec3d(0.0, 0.0, -0.5 * PI)); + ret = Geometry::assemble_transform(Vec3d::Zero(), 0.5 * PI * Vec3d::UnitY()) * Geometry::assemble_transform(Vec3d::Zero(), -0.5 * PI * Vec3d::UnitZ()); break; } case Y: { - ret = Geometry::assemble_transform(Vec3d::Zero(), Vec3d(0.0, 0.0, -0.5 * PI)) * Geometry::assemble_transform(Vec3d::Zero(), Vec3d(0.0, -0.5 * PI, 0.0)); + ret = Geometry::assemble_transform(Vec3d::Zero(), -0.5 * PI * Vec3d::UnitZ()) * Geometry::assemble_transform(Vec3d::Zero(), -0.5 * PI * Vec3d::UnitY()); break; } default: @@ -467,38 +463,6 @@ Transform3d GLGizmoRotate::local_transform(const Selection& selection) const return Geometry::assemble_transform(m_center) * ret; } -void GLGizmoRotate::transform_to_local(const Selection& selection) const -{ - glsafe(::glTranslated(m_center.x(), m_center.y(), m_center.z())); - - if (selection.is_single_volume() || selection.is_single_modifier() || selection.requires_local_axes()) { - const Transform3d orient_matrix = selection.get_volume(*selection.get_volume_idxs().begin())->get_instance_transformation().get_matrix(true, false, true, true); - glsafe(::glMultMatrixd(orient_matrix.data())); - } - - switch (m_axis) - { - case X: - { - glsafe(::glRotatef(90.0f, 0.0f, 1.0f, 0.0f)); - glsafe(::glRotatef(-90.0f, 0.0f, 0.0f, 1.0f)); - break; - } - case Y: - { - glsafe(::glRotatef(-90.0f, 0.0f, 0.0f, 1.0f)); - glsafe(::glRotatef(-90.0f, 0.0f, 1.0f, 0.0f)); - break; - } - default: - case Z: - { - // no rotation - break; - } - } -} - Vec3d GLGizmoRotate::mouse_position_in_local_plane(const Linef3& mouse_ray, const Selection& selection) const { double half_pi = 0.5 * double(PI); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoRotate.hpp b/src/slic3r/GUI/Gizmos/GLGizmoRotate.hpp index b3cb7078080..80d16172bf9 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoRotate.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoRotate.hpp @@ -87,7 +87,6 @@ class GLGizmoRotate : public GLGizmoBase Transform3d local_transform(const Selection& selection) const; - void transform_to_local(const Selection& selection) const; // returns the intersection of the mouse ray with the plane perpendicular to the gizmo axis, in local coordinate Vec3d mouse_position_in_local_plane(const Linef3& mouse_ray, const Selection& selection) const; }; From 15bad7fc19e934ac7f170467be5f3cbb609269fb Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Fri, 27 Oct 2023 09:05:47 +0800 Subject: [PATCH 41/99] Tech ENABLE_GL_IMGUI_SHADERS - Render imgui using shaders (cherry picked from commit prusa3d/PrusaSlicer@d0d89a4d5bc02a87f417a2f2c73f5f91db0da5d6) --- resources/shaders/imgui.fs | 11 +++ resources/shaders/imgui.vs | 17 ++++ src/slic3r/GUI/GLShader.cpp | 14 ++- src/slic3r/GUI/GLShader.hpp | 5 ++ src/slic3r/GUI/GLShadersManager.cpp | 2 + src/slic3r/GUI/ImGuiWrapper.cpp | 134 +++++++++++++++++++--------- 6 files changed, 141 insertions(+), 42 deletions(-) create mode 100644 resources/shaders/imgui.fs create mode 100644 resources/shaders/imgui.vs diff --git a/resources/shaders/imgui.fs b/resources/shaders/imgui.fs new file mode 100644 index 00000000000..4b0e27ce9da --- /dev/null +++ b/resources/shaders/imgui.fs @@ -0,0 +1,11 @@ +#version 110 + +uniform sampler2D Texture; + +varying vec2 Frag_UV; +varying vec4 Frag_Color; + +void main() +{ + gl_FragColor = Frag_Color * texture2D(Texture, Frag_UV.st); +} \ No newline at end of file diff --git a/resources/shaders/imgui.vs b/resources/shaders/imgui.vs new file mode 100644 index 00000000000..100813e2b5e --- /dev/null +++ b/resources/shaders/imgui.vs @@ -0,0 +1,17 @@ +#version 110 + +uniform mat4 ProjMtx; + +attribute vec2 Position; +attribute vec2 UV; +attribute vec4 Color; + +varying vec2 Frag_UV; +varying vec4 Frag_Color; + +void main() +{ + Frag_UV = UV; + Frag_Color = Color; + gl_Position = ProjMtx * vec4(Position.xy, 0.0, 1.0); +} \ No newline at end of file diff --git a/src/slic3r/GUI/GLShader.cpp b/src/slic3r/GUI/GLShader.cpp index 174cfec590a..d510a81b401 100644 --- a/src/slic3r/GUI/GLShader.cpp +++ b/src/slic3r/GUI/GLShader.cpp @@ -122,8 +122,7 @@ bool GLShaderProgram::init_from_texts(const std::string& name, const ShaderSourc for (size_t i = 0; i < static_cast(EShaderType::Count); ++i) { const std::string& source = sources[i]; - if (!source.empty()) - { + if (!source.empty()) { EShaderType type = static_cast(i); auto [result, id] = create_shader(type); if (result) @@ -301,6 +300,17 @@ void GLShaderProgram::set_uniform(int id, const Matrix3d& value) const set_uniform(id, (Matrix3f)value.cast()); } +void GLShaderProgram::set_uniform(int id, const Matrix4f& value) const +{ + if (id >= 0) + glsafe(::glUniformMatrix4fv(id, 1, GL_FALSE, static_cast(value.data()))); +} + +void GLShaderProgram::set_uniform(int id, const Matrix4d& value) const +{ + set_uniform(id, (Matrix4f)value.cast()); +} + void GLShaderProgram::set_uniform(int id, const Vec3f& value) const { if (id >= 0) diff --git a/src/slic3r/GUI/GLShader.hpp b/src/slic3r/GUI/GLShader.hpp index 76697fa594d..fd30b3750de 100644 --- a/src/slic3r/GUI/GLShader.hpp +++ b/src/slic3r/GUI/GLShader.hpp @@ -11,6 +11,7 @@ namespace Slic3r { class ColorRGB; class ColorRGBA; + class GLShaderProgram { public: @@ -61,6 +62,8 @@ class GLShaderProgram void set_uniform(const char* name, const Transform3d& value) const { set_uniform(get_uniform_location(name), value); } void set_uniform(const char* name, const Matrix3f& value) const { set_uniform(get_uniform_location(name), value); } void set_uniform(const char* name, const Matrix3d& value) const { set_uniform(get_uniform_location(name), value); } + void set_uniform(const char* name, const Matrix4f& value) const { set_uniform(get_uniform_location(name), value); } + void set_uniform(const char* name, const Matrix4d& value) const { set_uniform(get_uniform_location(name), value); } void set_uniform(const char* name, const Vec3f& value) const { set_uniform(get_uniform_location(name), value); } void set_uniform(const char* name, const Vec3d& value) const { set_uniform(get_uniform_location(name), value); } void set_uniform(const char* name, const ColorRGB& value) const { set_uniform(get_uniform_location(name), value); } @@ -81,6 +84,8 @@ class GLShaderProgram void set_uniform(int id, const Transform3d& value) const; void set_uniform(int id, const Matrix3f& value) const; void set_uniform(int id, const Matrix3d& value) const; + void set_uniform(int id, const Matrix4f& value) const; + void set_uniform(int id, const Matrix4d& value) const; void set_uniform(int id, const Vec3f& value) const; void set_uniform(int id, const Vec3d& value) const; void set_uniform(int id, const ColorRGB& value) const; diff --git a/src/slic3r/GUI/GLShadersManager.cpp b/src/slic3r/GUI/GLShadersManager.cpp index 2048b561054..1a03c3f8677 100644 --- a/src/slic3r/GUI/GLShadersManager.cpp +++ b/src/slic3r/GUI/GLShadersManager.cpp @@ -33,6 +33,8 @@ std::pair GLShadersManager::init() bool valid = true; + // imgui shader + valid &= append_shader("imgui", { "imgui.vs", "imgui.fs" }); // basic shader, used to render all what was previously rendered using the immediate mode valid &= append_shader("flat_attr", { "flat_attr.vs", "flat.fs" }); // basic shader for textures, used to render textures diff --git a/src/slic3r/GUI/ImGuiWrapper.cpp b/src/slic3r/GUI/ImGuiWrapper.cpp index bc2e84e9461..a45d8f0d2d9 100644 --- a/src/slic3r/GUI/ImGuiWrapper.cpp +++ b/src/slic3r/GUI/ImGuiWrapper.cpp @@ -29,13 +29,16 @@ #include "libslic3r/Utils.hpp" #include "libslic3r/Color.hpp" #include "libslic3r/Shape/TextShape.hpp" + #include "3DScene.hpp" #include "GUI.hpp" #include "I18N.hpp" #include "Search.hpp" #include "BitmapCache.hpp" +#include "GUI_App.hpp" #include "../Utils/MacDarkMode.hpp" + #include "nanosvg/nanosvg.h" #include "nanosvg/nanosvgrast.h" #include "OpenGLManager.hpp" @@ -2386,13 +2389,25 @@ void ImGuiWrapper::init_style() void ImGuiWrapper::render_draw_data(ImDrawData *draw_data) { + if (draw_data == nullptr || draw_data->CmdListsCount == 0) + return; + + GLShaderProgram* shader = wxGetApp().get_shader("imgui"); + if (shader == nullptr) + return; + // Avoid rendering when minimized, scale coordinates for retina displays (screen coordinates != framebuffer coordinates) ImGuiIO& io = ImGui::GetIO(); - const int fb_width = (int)(draw_data->DisplaySize.x * io.DisplayFramebufferScale.x); + const int fb_width = (int)(draw_data->DisplaySize.x * io.DisplayFramebufferScale.x); const int fb_height = (int)(draw_data->DisplaySize.y * io.DisplayFramebufferScale.y); if (fb_width == 0 || fb_height == 0) return; - draw_data->ScaleClipRects(io.DisplayFramebufferScale); + + GLShaderProgram* curr_shader = wxGetApp().get_current_shader(); + if (curr_shader != nullptr) + curr_shader->stop_using(); + + shader->start_using(); // We are using the OpenGL fixed pipeline to make the example code simpler to read! // Setup render state: alpha-blending enabled, no face culling, no depth testing, scissor enabled, vertex/texcoord/color pointers, polygon fill. @@ -2400,45 +2415,72 @@ void ImGuiWrapper::render_draw_data(ImDrawData *draw_data) GLint last_polygon_mode[2]; glsafe(::glGetIntegerv(GL_POLYGON_MODE, last_polygon_mode)); GLint last_viewport[4]; glsafe(::glGetIntegerv(GL_VIEWPORT, last_viewport)); GLint last_scissor_box[4]; glsafe(::glGetIntegerv(GL_SCISSOR_BOX, last_scissor_box)); + GLint last_texture_env_mode; glsafe(::glGetTexEnviv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, &last_texture_env_mode)); glsafe(::glPushAttrib(GL_ENABLE_BIT | GL_COLOR_BUFFER_BIT | GL_TRANSFORM_BIT)); glsafe(::glEnable(GL_BLEND)); glsafe(::glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)); glsafe(::glDisable(GL_CULL_FACE)); glsafe(::glDisable(GL_DEPTH_TEST)); - glsafe(::glDisable(GL_LIGHTING)); - glsafe(::glDisable(GL_COLOR_MATERIAL)); glsafe(::glEnable(GL_SCISSOR_TEST)); - glsafe(::glEnableClientState(GL_VERTEX_ARRAY)); - glsafe(::glEnableClientState(GL_TEXTURE_COORD_ARRAY)); - glsafe(::glEnableClientState(GL_COLOR_ARRAY)); glsafe(::glEnable(GL_TEXTURE_2D)); glsafe(::glPolygonMode(GL_FRONT_AND_BACK, GL_FILL)); glsafe(::glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE)); - GLint texture_env_mode = GL_MODULATE; - glsafe(::glGetTexEnviv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, &texture_env_mode)); - glsafe(::glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE)); - //glUseProgram(0); // You may want this if using this code in an OpenGL 3+ context where shaders may be bound // Setup viewport, orthographic projection matrix - // Our visible imgui space lies from draw_data->DisplayPps (top left) to draw_data->DisplayPos+data_data->DisplaySize (bottom right). DisplayMin is typically (0,0) for single viewport apps. + // Our visible imgui space lies from draw_data->DisplayPos (top left) to draw_data->DisplayPos+data_data->DisplaySize (bottom right). DisplayPos is (0,0) for single viewport apps. glsafe(::glViewport(0, 0, (GLsizei)fb_width, (GLsizei)fb_height)); - glsafe(::glMatrixMode(GL_PROJECTION)); - glsafe(::glPushMatrix()); - glsafe(::glLoadIdentity()); - glsafe(::glOrtho(draw_data->DisplayPos.x, draw_data->DisplayPos.x + draw_data->DisplaySize.x, draw_data->DisplayPos.y + draw_data->DisplaySize.y, draw_data->DisplayPos.y, -1.0f, +1.0f)); - glsafe(::glMatrixMode(GL_MODELVIEW)); - glsafe(::glPushMatrix()); - glsafe(::glLoadIdentity()); + const float L = draw_data->DisplayPos.x; + const float R = draw_data->DisplayPos.x + draw_data->DisplaySize.x; + const float T = draw_data->DisplayPos.y; + const float B = draw_data->DisplayPos.y + draw_data->DisplaySize.y; + + Matrix4f ortho_projection; + ortho_projection << + 2.0f / (R - L), 0.0f, 0.0f, (R + L) / (L - R), + 0.0f, 2.0f / (T - B), 0.0f, (T + B) / (B - T), + 0.0f, 0.0f, -1.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f; + + shader->set_uniform("Texture", 0); + shader->set_uniform("ProjMtx", ortho_projection); + + // Will project scissor/clipping rectangles into framebuffer space + const ImVec2 clip_off = draw_data->DisplayPos; // (0,0) unless using multi-viewports + const ImVec2 clip_scale = draw_data->FramebufferScale; // (1,1) unless using retina display which are often (2,2) // Render command lists - ImVec2 pos = draw_data->DisplayPos; for (int n = 0; n < draw_data->CmdListsCount; ++n) { const ImDrawList* cmd_list = draw_data->CmdLists[n]; const ImDrawVert* vtx_buffer = cmd_list->VtxBuffer.Data; const ImDrawIdx* idx_buffer = cmd_list->IdxBuffer.Data; - glsafe(::glVertexPointer(2, GL_FLOAT, sizeof(ImDrawVert), (const GLvoid*)((const char*)vtx_buffer + IM_OFFSETOF(ImDrawVert, pos)))); - glsafe(::glTexCoordPointer(2, GL_FLOAT, sizeof(ImDrawVert), (const GLvoid*)((const char*)vtx_buffer + IM_OFFSETOF(ImDrawVert, uv)))); - glsafe(::glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(ImDrawVert), (const GLvoid*)((const char*)vtx_buffer + IM_OFFSETOF(ImDrawVert, col)))); + const GLsizeiptr vtx_buffer_size = (GLsizeiptr)cmd_list->VtxBuffer.Size * (int)sizeof(ImDrawVert); + const GLsizeiptr idx_buffer_size = (GLsizeiptr)cmd_list->IdxBuffer.Size * (int)sizeof(ImDrawIdx); + + GLuint vbo_id; + glsafe(::glGenBuffers(1, &vbo_id)); + glsafe(::glBindBuffer(GL_ARRAY_BUFFER, vbo_id)); + glsafe(::glBufferData(GL_ARRAY_BUFFER, vtx_buffer_size, vtx_buffer, GL_STATIC_DRAW)); + + GLuint ibo_id; + glsafe(::glGenBuffers(1, &ibo_id)); + glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo_id)); + glsafe(::glBufferData(GL_ELEMENT_ARRAY_BUFFER, idx_buffer_size, idx_buffer, GL_STATIC_DRAW)); + + const int position_id = shader->get_attrib_location("Position"); + if (position_id != -1) { + glsafe(::glVertexAttribPointer(position_id, 2, GL_FLOAT, GL_FALSE, sizeof(ImDrawVert), (GLvoid*)IM_OFFSETOF(ImDrawVert, pos))); + glsafe(::glEnableVertexAttribArray(position_id)); + } + const int uv_id = shader->get_attrib_location("UV"); + if (uv_id != -1) { + glsafe(::glVertexAttribPointer(uv_id, 2, GL_FLOAT, GL_FALSE, sizeof(ImDrawVert), (GLvoid*)IM_OFFSETOF(ImDrawVert, uv))); + glsafe(::glEnableVertexAttribArray(uv_id)); + } + const int color_id = shader->get_attrib_location("Color"); + if (color_id != -1) { + glsafe(::glVertexAttribPointer(color_id, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(ImDrawVert), (GLvoid*)IM_OFFSETOF(ImDrawVert, col))); + glsafe(::glEnableVertexAttribArray(color_id)); + } for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; ++cmd_i) { const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i]; @@ -2446,34 +2488,46 @@ void ImGuiWrapper::render_draw_data(ImDrawData *draw_data) // User callback (registered via ImDrawList::AddCallback) pcmd->UserCallback(cmd_list, pcmd); else { - ImVec4 clip_rect = ImVec4(pcmd->ClipRect.x - pos.x, pcmd->ClipRect.y - pos.y, pcmd->ClipRect.z - pos.x, pcmd->ClipRect.w - pos.y); - if (clip_rect.x < fb_width && clip_rect.y < fb_height && clip_rect.z >= 0.0f && clip_rect.w >= 0.0f) { - // Apply scissor/clipping rectangle - glsafe(::glScissor((int)clip_rect.x, (int)(fb_height - clip_rect.w), (int)(clip_rect.z - clip_rect.x), (int)(clip_rect.w - clip_rect.y))); - - // Bind texture, Draw - glsafe(::glBindTexture(GL_TEXTURE_2D, (GLuint)(intptr_t)pcmd->TextureId)); - glsafe(::glDrawElements(GL_TRIANGLES, (GLsizei)pcmd->ElemCount, sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, idx_buffer)); - } + // Project scissor/clipping rectangles into framebuffer space + const ImVec2 clip_min((pcmd->ClipRect.x - clip_off.x) * clip_scale.x, (pcmd->ClipRect.y - clip_off.y) * clip_scale.y); + const ImVec2 clip_max((pcmd->ClipRect.z - clip_off.x) * clip_scale.x, (pcmd->ClipRect.w - clip_off.y) * clip_scale.y); + if (clip_max.x <= clip_min.x || clip_max.y <= clip_min.y) + continue; + + // Apply scissor/clipping rectangle (Y is inverted in OpenGL) + glsafe(::glScissor((int)clip_min.x, (int)(fb_height - clip_max.y), (int)(clip_max.x - clip_min.x), (int)(clip_max.y - clip_min.y))); + + // Bind texture, Draw + glsafe(::glBindTexture(GL_TEXTURE_2D, (GLuint)(intptr_t)pcmd->GetTexID())); + glsafe(::glDrawElements(GL_TRIANGLES, (GLsizei)pcmd->ElemCount, sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, (void*)(intptr_t)(pcmd->IdxOffset * sizeof(ImDrawIdx)))); } idx_buffer += pcmd->ElemCount; } + + if (position_id != -1) + glsafe(::glDisableVertexAttribArray(position_id)); + if (uv_id != -1) + glsafe(::glDisableVertexAttribArray(uv_id)); + if (color_id != -1) + glsafe(::glDisableVertexAttribArray(color_id)); + + glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0)); + glsafe(::glBindBuffer(GL_ARRAY_BUFFER, 0)); + + glsafe(::glDeleteBuffers(1, &ibo_id)); + glsafe(::glDeleteBuffers(1, &vbo_id)); } // Restore modified state - glsafe(::glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, texture_env_mode)); - glsafe(::glDisableClientState(GL_COLOR_ARRAY)); - glsafe(::glDisableClientState(GL_TEXTURE_COORD_ARRAY)); - glsafe(::glDisableClientState(GL_VERTEX_ARRAY)); + glsafe(::glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, last_texture_env_mode)); glsafe(::glBindTexture(GL_TEXTURE_2D, (GLuint)last_texture)); - glsafe(::glMatrixMode(GL_MODELVIEW)); - glsafe(::glPopMatrix()); - glsafe(::glMatrixMode(GL_PROJECTION)); - glsafe(::glPopMatrix()); glsafe(::glPopAttrib()); glsafe(::glPolygonMode(GL_FRONT, (GLenum)last_polygon_mode[0]); glPolygonMode(GL_BACK, (GLenum)last_polygon_mode[1])); glsafe(::glViewport(last_viewport[0], last_viewport[1], (GLsizei)last_viewport[2], (GLsizei)last_viewport[3])); glsafe(::glScissor(last_scissor_box[0], last_scissor_box[1], (GLsizei)last_scissor_box[2], (GLsizei)last_scissor_box[3])); + + if (curr_shader != nullptr) + curr_shader->start_using(); } bool ImGuiWrapper::display_initialized() const From 63272a9df80612480ba84b9486c66329d80903c4 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Fri, 27 Oct 2023 09:30:17 +0800 Subject: [PATCH 42/99] Tech ENABLE_GL_SHADERS_ATTRIBUTES - Use shader's vertex attributes and matrices in GLMmSegmentationGizmo3DScene (cherry picked from commit prusa3d/PrusaSlicer@4eee0d05f3367c9b05f195ec2e4e4ada41ba5b94) --- .../GUI/Gizmos/GLGizmoMmuSegmentation.cpp | 20 +++++-- src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp | 55 ++++--------------- src/slic3r/GUI/Gizmos/GLGizmoPainterBase.hpp | 4 +- 3 files changed, 28 insertions(+), 51 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp index e52267841ed..1313b33bd24 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp @@ -918,19 +918,27 @@ void GLMmSegmentationGizmo3DScene::render(size_t triangle_indices_idx) const assert(this->vertices_VBO_id != 0); assert(this->triangle_indices_VBO_ids[triangle_indices_idx] != 0); - glsafe(::glBindBuffer(GL_ARRAY_BUFFER, this->vertices_VBO_id)); - glsafe(::glVertexPointer(3, GL_FLOAT, 3 * sizeof(float), (const void*)(0 * sizeof(float)))); + GLShaderProgram* shader = wxGetApp().get_current_shader(); + if (shader == nullptr) + return; - glsafe(::glEnableClientState(GL_VERTEX_ARRAY)); + glsafe(::glBindBuffer(GL_ARRAY_BUFFER, this->vertices_VBO_id)); + const GLint position_id = shader->get_attrib_location("v_position"); + if (position_id != -1) { + glsafe(::glVertexAttribPointer(position_id, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (GLvoid*)0)); + glsafe(::glEnableVertexAttribArray(position_id)); + } // Render using the Vertex Buffer Objects. - if (this->triangle_indices_sizes[triangle_indices_idx] > 0) { + if (this->triangle_indices_VBO_ids[triangle_indices_idx] != 0 && + this->triangle_indices_sizes[triangle_indices_idx] > 0) { glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, this->triangle_indices_VBO_ids[triangle_indices_idx])); glsafe(::glDrawElements(GL_TRIANGLES, GLsizei(this->triangle_indices_sizes[triangle_indices_idx]), GL_UNSIGNED_INT, nullptr)); - glsafe(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0)); + glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0)); } - glsafe(::glDisableClientState(GL_VERTEX_ARRAY)); + if (position_id != -1) + glsafe(::glDisableVertexAttribArray(position_id)); glsafe(::glBindBuffer(GL_ARRAY_BUFFER, 0)); } diff --git a/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp b/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp index 7d83f38cce4..296506cad66 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp @@ -1179,20 +1179,6 @@ void TriangleSelectorPatch::render(ImGuiWrapper* imgui, const Transform3d& matri if (!shader) return; assert(shader->get_name() == "gouraud_attr" || shader->get_name() == "mm_gouraud_attr"); - GLint position_id = -1; - GLint barycentric_id = -1; - if (wxGetApp().plater()->is_wireframe_enabled()) { - position_id = shader->get_attrib_location("v_position"); - barycentric_id = shader->get_attrib_location("v_barycentric"); - if (m_need_wireframe && wxGetApp().plater()->is_show_wireframe()) { - //BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(", show_wireframe on"); - shader->set_uniform("show_wireframe", true); - } - else { - //BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(", show_wireframe off"); - shader->set_uniform("show_wireframe", false); - } - } for (size_t buffer_idx = 0; buffer_idx < m_triangle_patches.size(); ++buffer_idx) { if (this->has_VBOs(buffer_idx)) { @@ -1210,9 +1196,7 @@ void TriangleSelectorPatch::render(ImGuiWrapper* imgui, const Transform3d& matri //to make black not too hard too see ColorRGBA new_color = adjust_color_for_rendering(color); shader->set_uniform("uniform_color", new_color); - //shader->set_uniform("uniform_color", color); - //BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(", buffer_idx %1%: new_color[%2%, %3%, %4%, %5%]")%buffer_idx%new_color[0]%new_color[1]%new_color[2]%new_color[3]; - this->render(buffer_idx, (int)position_id, (int)barycentric_id); + this->render(buffer_idx); } } @@ -1443,7 +1427,7 @@ void TriangleSelectorPatch::update_render_data() //BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(", exit"); } -void TriangleSelectorPatch::render(int triangle_indices_idx, int position_id, int barycentric_id) +void TriangleSelectorPatch::render(int triangle_indices_idx) { assert(triangle_indices_idx < this->m_triangle_indices_VBO_ids.size()); assert(this->m_triangle_patches.size() == this->m_triangle_indices_VBO_ids.size()); @@ -1452,28 +1436,17 @@ void TriangleSelectorPatch::render(int triangle_indices_idx, int position_id, in assert(this->m_vertices_VBO_ids[triangle_indices_idx] != 0); assert(this->m_triangle_indices_VBO_ids[triangle_indices_idx] != 0); - //glsafe(::glBindBuffer(GL_ARRAY_BUFFER, this->m_vertices_VBO_id)); - //glsafe(::glVertexPointer(3, GL_FLOAT, 3 * sizeof(float), (const void*)(0 * sizeof(float)))); - if (this->m_triangle_indices_sizes[triangle_indices_idx] > 0) { - glsafe(::glBindBuffer(GL_ARRAY_BUFFER, this->m_vertices_VBO_ids[triangle_indices_idx])); - if (position_id != -1) { - glsafe(::glEnableVertexAttribArray((GLint)position_id)); - glsafe(::glVertexAttribPointer((GLint)position_id, 3, GL_FLOAT, GL_FALSE, 6*sizeof(float), nullptr)); - } - else { - glsafe(::glVertexPointer(3, GL_FLOAT, 3 * sizeof(float), nullptr)); - } + GLShaderProgram *shader = wxGetApp().get_current_shader(); + if (shader == nullptr) + return; - if (barycentric_id != -1) { - glsafe(::glEnableVertexAttribArray((GLint)barycentric_id)); - glsafe(::glVertexAttribPointer((GLint)barycentric_id, 3, GL_FLOAT, GL_FALSE, 6*sizeof(float), (GLvoid*)(intptr_t)(3 * sizeof(float)))); - } - //glsafe(::glVertexPointer(3, GL_FLOAT, 3 * sizeof(float), nullptr)); - //BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(", Line %1%: triangle_indices_idx %2%, bind vertex vbo, buffer id %3%")%__LINE__%triangle_indices_idx%this->m_vertices_VBO_ids[triangle_indices_idx]; + glsafe(::glBindBuffer(GL_ARRAY_BUFFER, this->m_vertices_VBO_ids[triangle_indices_idx])); + const GLint position_id = shader->get_attrib_location("v_position"); + if (position_id != -1) { + glsafe(::glVertexAttribPointer((GLint) position_id, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), nullptr)); + glsafe(::glEnableVertexAttribArray((GLint)position_id)); } - glsafe(::glEnableClientState(GL_VERTEX_ARRAY)); - // Render using the Vertex Buffer Objects. if (this->m_triangle_indices_sizes[triangle_indices_idx] > 0) { glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, this->m_triangle_indices_VBO_ids[triangle_indices_idx])); @@ -1482,14 +1455,10 @@ void TriangleSelectorPatch::render(int triangle_indices_idx, int position_id, in //BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(", Line %1%: triangle_indices_idx %2%, bind indices vbo, buffer id %3%")%__LINE__%triangle_indices_idx%this->m_triangle_indices_VBO_ids[triangle_indices_idx]; } - glsafe(::glDisableClientState(GL_VERTEX_ARRAY)); - if ((this->m_triangle_indices_sizes[triangle_indices_idx] > 0)&&(position_id != -1)) + if (position_id != -1) glsafe(::glDisableVertexAttribArray(position_id)); - if ((this->m_triangle_indices_sizes[triangle_indices_idx] > 0)&&(barycentric_id != -1)) - glsafe(::glDisableVertexAttribArray((GLint)barycentric_id)); - if (this->m_triangle_indices_sizes[triangle_indices_idx] > 0) - glsafe(::glBindBuffer(GL_ARRAY_BUFFER, 0)); + glsafe(::glBindBuffer(GL_ARRAY_BUFFER, 0)); } void TriangleSelectorPatch::release_geometry() diff --git a/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.hpp b/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.hpp index 0582e7aa778..afba98fd7e1 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.hpp @@ -35,7 +35,7 @@ class TriangleSelectorGUI : public TriangleSelector { virtual ~TriangleSelectorGUI() = default; virtual void render(ImGuiWrapper* imgui, const Transform3d& matrix); - void render(const Transform3d& matrix) { this->render(nullptr, matrix); } + //void render(const Transform3d& matrix) { this->render(nullptr, matrix); } void set_wireframe_needed(bool need_wireframe) { m_need_wireframe = need_wireframe; } bool get_wireframe_needed() { return m_need_wireframe; } @@ -170,7 +170,7 @@ class TriangleSelectorPatch : public TriangleSelectorGUI { private: void update_render_data(); - void render(int buffer_idx, int position_id = -1, int barycentric_id = -1); + void render(int buffer_idx); }; From 96c8c110301d82762c5379e10b848228a4c319de Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Fri, 27 Oct 2023 09:40:39 +0800 Subject: [PATCH 43/99] Removed obsolete code from GCodeViewer (cherry picked from commit prusa3d/PrusaSlicer@033bee64311d7645a581020dde77b028aac9dbc2) --- src/slic3r/GUI/GCodeViewer.cpp | 87 ++++------------------------------ src/slic3r/GUI/GCodeViewer.hpp | 7 --- 2 files changed, 8 insertions(+), 86 deletions(-) diff --git a/src/slic3r/GUI/GCodeViewer.cpp b/src/slic3r/GUI/GCodeViewer.cpp index 667c950f930..6fcb27a9608 100644 --- a/src/slic3r/GUI/GCodeViewer.cpp +++ b/src/slic3r/GUI/GCodeViewer.cpp @@ -2030,18 +2030,6 @@ void GCodeViewer::load_toolpaths(const GCodeProcessorResult& gcode_result, const log_memory_used(label, vertices_size + indices_size); }; - // format data into the buffers to be rendered as points - auto add_vertices_as_point = [](const GCodeProcessorResult::MoveVertex& curr, VertexBuffer& vertices) { - vertices.push_back(curr.position.x()); - vertices.push_back(curr.position.y()); - vertices.push_back(curr.position.z()); - }; - auto add_indices_as_point = [](const GCodeProcessorResult::MoveVertex& curr, TBuffer& buffer, - unsigned int ibuffer_id, IndexBuffer& indices, size_t move_id) { - buffer.add_path(curr, ibuffer_id, indices.size(), move_id); - indices.push_back(static_cast(indices.size())); - }; - // format data into the buffers to be rendered as lines auto add_vertices_as_line = [](const GCodeProcessorResult::MoveVertex& prev, const GCodeProcessorResult::MoveVertex& curr, VertexBuffer& vertices) { auto add_vertex = [&vertices](const Vec3f& position) { @@ -2505,7 +2493,6 @@ void GCodeViewer::load_toolpaths(const GCodeProcessorResult& gcode_result, const switch (t_buffer.render_primitive_type) { - case TBuffer::ERenderPrimitiveType::Point: { add_vertices_as_point(curr, v_buffer); break; } case TBuffer::ERenderPrimitiveType::Line: { add_vertices_as_line(prev, curr, v_buffer); break; } case TBuffer::ERenderPrimitiveType::Triangle: { add_vertices_as_solid(prev, curr, t_buffer, static_cast(v_multibuffer.size()) - 1, v_buffer, move_id); break; } case TBuffer::ERenderPrimitiveType::InstancedModel: @@ -2893,8 +2880,7 @@ void GCodeViewer::load_toolpaths(const GCodeProcessorResult& gcode_result, const if (i_multibuffer.back().size() * sizeof(IBufferType) >= IBUFFER_THRESHOLD_BYTES - indiced_size_to_add) { i_multibuffer.push_back(IndexBuffer()); vbo_index_list.push_back(t_buffer.vertices.vbos[curr_vertex_buffer.first]); - if (t_buffer.render_primitive_type != TBuffer::ERenderPrimitiveType::Point && - t_buffer.render_primitive_type != TBuffer::ERenderPrimitiveType::BatchedModel) { + if (t_buffer.render_primitive_type != TBuffer::ERenderPrimitiveType::BatchedModel) { Path& last_path = t_buffer.paths.back(); last_path.add_sub_path(prev, static_cast(i_multibuffer.size()) - 1, 0, move_id - 1); } @@ -2911,8 +2897,7 @@ void GCodeViewer::load_toolpaths(const GCodeProcessorResult& gcode_result, const curr_vertex_buffer.second = 0; vbo_index_list.push_back(t_buffer.vertices.vbos[curr_vertex_buffer.first]); - if (t_buffer.render_primitive_type != TBuffer::ERenderPrimitiveType::Point && - t_buffer.render_primitive_type != TBuffer::ERenderPrimitiveType::BatchedModel) { + if (t_buffer.render_primitive_type != TBuffer::ERenderPrimitiveType::BatchedModel) { Path& last_path = t_buffer.paths.back(); last_path.add_sub_path(prev, static_cast(i_multibuffer.size()) - 1, 0, move_id - 1); } @@ -2922,11 +2907,6 @@ void GCodeViewer::load_toolpaths(const GCodeProcessorResult& gcode_result, const switch (t_buffer.render_primitive_type) { - case TBuffer::ERenderPrimitiveType::Point: { - add_indices_as_point(curr, t_buffer, static_cast(i_multibuffer.size()) - 1, i_buffer, move_id); - curr_vertex_buffer.second += t_buffer.max_vertices_per_segment(); - break; - } case TBuffer::ERenderPrimitiveType::Line: { add_indices_as_line(prev, curr, t_buffer, curr_vertex_buffer.second, static_cast(i_multibuffer.size()) - 1, i_buffer, move_id); break; @@ -3522,10 +3502,6 @@ m_no_render_path = false; unsigned int size_in_indices = 0; switch (buffer.render_primitive_type) { - case TBuffer::ERenderPrimitiveType::Point: { - size_in_indices = buffer.indices_per_segment(); - break; - } case TBuffer::ERenderPrimitiveType::Line: case TBuffer::ERenderPrimitiveType::Triangle: { // BBS: modify to support moves which has internal point @@ -3780,43 +3756,6 @@ void GCodeViewer::render_toolpaths() const float near_plane_height = camera.get_type() == Camera::EType::Perspective ? static_cast(viewport[3]) / (2.0f * static_cast(2.0 * std::tan(0.5 * Geometry::deg2rad(camera.get_fov())))) : static_cast(viewport[3]) * 0.0005; - auto shader_init_as_points = [zoom, point_size, near_plane_height](GLShaderProgram& shader) { -#if ENABLE_FIXED_SCREEN_SIZE_POINT_MARKERS - shader.set_uniform("use_fixed_screen_size", 1); -#else - shader.set_uniform("use_fixed_screen_size", 0); -#endif // ENABLE_FIXED_SCREEN_SIZE_POINT_MARKERS - shader.set_uniform("zoom", zoom); - shader.set_uniform("percent_outline_radius", 0.0f); - shader.set_uniform("percent_center_radius", 0.33f); - shader.set_uniform("point_size", point_size); - shader.set_uniform("near_plane_height", near_plane_height); - }; - - auto render_as_points = [ -#if ENABLE_GCODE_VIEWER_STATISTICS - this -#endif // ENABLE_GCODE_VIEWER_STATISTICS - ](std::vector::iterator it_path, std::vector::iterator it_end, GLShaderProgram& shader, int uniform_color) { - glsafe(::glEnable(GL_VERTEX_PROGRAM_POINT_SIZE)); - glsafe(::glEnable(GL_POINT_SPRITE)); - - for (auto it = it_path; it != it_end && it_path->ibuffer_id == it->ibuffer_id; ++it) { - const RenderPath& path = *it; - // Some OpenGL drivers crash on empty glMultiDrawElements, see GH #7415. - assert(! path.sizes.empty()); - assert(! path.offsets.empty()); - 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; -#endif // ENABLE_GCODE_VIEWER_STATISTICS - } - - glsafe(::glDisable(GL_POINT_SPRITE)); - glsafe(::glDisable(GL_VERTEX_PROGRAM_POINT_SIZE)); - }; - auto render_as_lines = [ #if ENABLE_GCODE_VIEWER_STATISTICS this @@ -3957,16 +3896,11 @@ void GCodeViewer::render_toolpaths() shader->start_using(); - int position_id = -1; - int normal_id = -1; const Transform3d& view_matrix = camera.get_view_matrix(); shader->set_uniform("view_model_matrix", view_matrix); shader->set_uniform("projection_matrix", camera.get_projection_matrix()); shader->set_uniform("normal_matrix", (Matrix3d)view_matrix.matrix().block(0, 0, 3, 3).inverse().transpose()); - position_id = shader->get_attrib_location("v_position"); - normal_id = shader->get_attrib_location("v_normal"); - if (buffer.render_primitive_type == TBuffer::ERenderPrimitiveType::InstancedModel) { shader->set_uniform("emission_factor", 0.25f); render_as_instanced_model(buffer, *shader); @@ -3974,12 +3908,14 @@ void GCodeViewer::render_toolpaths() } else if (buffer.render_primitive_type == TBuffer::ERenderPrimitiveType::BatchedModel) { shader->set_uniform("emission_factor", 0.25f); + const int position_id = shader->get_attrib_location("v_position"); + const int normal_id = shader->get_attrib_location("v_normal"); render_as_batched_model(buffer, *shader, position_id, normal_id); shader->set_uniform("emission_factor", 0.0f); } else { - if (buffer.render_primitive_type == TBuffer::ERenderPrimitiveType::Point) - shader_init_as_points(*shader); + const int position_id = shader->get_attrib_location("v_position"); + const int normal_id = shader->get_attrib_location("v_normal"); const int uniform_color = shader->get_uniform_location("uniform_color"); auto it_path = buffer.render_paths.begin(); @@ -4009,10 +3945,6 @@ void GCodeViewer::render_toolpaths() // Render all elements with it_path->ibuffer_id == ibuffer_id, possible with varying colors. switch (buffer.render_primitive_type) { - case TBuffer::ERenderPrimitiveType::Point: { - render_as_points(it_path, buffer.render_paths.end(), *shader, uniform_color); - break; - } case TBuffer::ERenderPrimitiveType::Line: { glsafe(::glLineWidth(static_cast(line_width(zoom)))); render_as_lines(it_path, buffer.render_paths.end(), *shader, uniform_color); @@ -4051,16 +3983,14 @@ void GCodeViewer::render_toolpaths() shader->start_using(); - int position_id = -1; - int normal_id = -1; const Camera& camera = wxGetApp().plater()->get_camera(); const Transform3d& view_matrix = camera.get_view_matrix(); shader->set_uniform("view_model_matrix", view_matrix); shader->set_uniform("projection_matrix", camera.get_projection_matrix()); shader->set_uniform("normal_matrix", (Matrix3d)view_matrix.matrix().block(0, 0, 3, 3).inverse().transpose()); - position_id = shader->get_attrib_location("v_position"); - normal_id = shader->get_attrib_location("v_normal"); + const int position_id = shader->get_attrib_location("v_position"); + const int normal_id = shader->get_attrib_location("v_normal"); glsafe(::glBindBuffer(GL_ARRAY_BUFFER, cap.vbo)); if (position_id != -1) { @@ -5637,7 +5567,6 @@ void GCodeViewer::render_statistics() } if (ImGui::CollapsingHeader("OpenGL calls")) { - add_counter(std::string("Multi GL_POINTS:"), m_statistics.gl_multi_points_calls_count); add_counter(std::string("Multi GL_LINES:"), m_statistics.gl_multi_lines_calls_count); add_counter(std::string("Multi GL_TRIANGLES:"), m_statistics.gl_multi_triangles_calls_count); add_counter(std::string("GL_TRIANGLES:"), m_statistics.gl_triangles_calls_count); diff --git a/src/slic3r/GUI/GCodeViewer.hpp b/src/slic3r/GUI/GCodeViewer.hpp index fa638f0a081..a91e7b938e9 100644 --- a/src/slic3r/GUI/GCodeViewer.hpp +++ b/src/slic3r/GUI/GCodeViewer.hpp @@ -293,7 +293,6 @@ class GCodeViewer { enum class ERenderPrimitiveType : unsigned char { - Point, Line, Triangle, InstancedModel, @@ -334,7 +333,6 @@ class GCodeViewer unsigned int max_vertices_per_segment() const { switch (render_primitive_type) { - case ERenderPrimitiveType::Point: { return 1; } case ERenderPrimitiveType::Line: { return 2; } case ERenderPrimitiveType::Triangle: { return 8; } default: { return 0; } @@ -346,7 +344,6 @@ class GCodeViewer unsigned int indices_per_segment() const { switch (render_primitive_type) { - case ERenderPrimitiveType::Point: { return 1; } case ERenderPrimitiveType::Line: { return 2; } case ERenderPrimitiveType::Triangle: { return 30; } // 3 indices x 10 triangles default: { return 0; } @@ -356,7 +353,6 @@ class GCodeViewer unsigned int max_indices_per_segment() const { switch (render_primitive_type) { - case ERenderPrimitiveType::Point: { return 1; } case ERenderPrimitiveType::Line: { return 2; } case ERenderPrimitiveType::Triangle: { return 36; } // 3 indices x 12 triangles default: { return 0; } @@ -367,7 +363,6 @@ class GCodeViewer bool has_data() const { switch (render_primitive_type) { - case ERenderPrimitiveType::Point: case ERenderPrimitiveType::Line: case ERenderPrimitiveType::Triangle: { return !vertices.vbos.empty() && vertices.vbos.front() != 0 && !indices.empty() && indices.front().ibo != 0; @@ -536,7 +531,6 @@ Range layer_duration_log; int64_t refresh_time{ 0 }; int64_t refresh_paths_time{ 0 }; // opengl calls - int64_t gl_multi_points_calls_count{ 0 }; int64_t gl_multi_lines_calls_count{ 0 }; int64_t gl_multi_triangles_calls_count{ 0 }; int64_t gl_triangles_calls_count{ 0 }; @@ -579,7 +573,6 @@ Range layer_duration_log; } void reset_opengl() { - gl_multi_points_calls_count = 0; gl_multi_lines_calls_count = 0; gl_multi_triangles_calls_count = 0; gl_triangles_calls_count = 0; From cabb8fcf6e1e2938a01691060d141ed36da6be85 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Fri, 27 Oct 2023 10:08:29 +0800 Subject: [PATCH 44/99] Tech ENABLE_GL_SHADERS_ATTRIBUTES - Fixed rendering of default bed in thumbnails (cherry picked from commit prusa3d/PrusaSlicer@568bd39c5ab3ea4ed43b8f43f14e2c746b289087) --- src/slic3r/GUI/3DBed.cpp | 9 ++++----- src/slic3r/GUI/3DBed.hpp | 2 +- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/src/slic3r/GUI/3DBed.cpp b/src/slic3r/GUI/3DBed.cpp index 7d3867b3982..620a84c171b 100644 --- a/src/slic3r/GUI/3DBed.cpp +++ b/src/slic3r/GUI/3DBed.cpp @@ -688,7 +688,7 @@ void Bed3D::render_model(const Transform3d& view_matrix, const Transform3d& proj void Bed3D::render_custom(GLCanvas3D& canvas, const Transform3d& view_matrix, const Transform3d& projection_matrix, bool bottom) { if (m_model_filename.empty()) { - render_default(bottom); + render_default(bottom, view_matrix, projection_matrix); return; } @@ -699,7 +699,7 @@ void Bed3D::render_custom(GLCanvas3D& canvas, const Transform3d& view_matrix, co render_texture(bottom, canvas);*/ } -void Bed3D::render_default(bool bottom) +void Bed3D::render_default(bool bottom, const Transform3d& view_matrix, const Transform3d& projection_matrix) { bool picking = false; m_texture.reset(); @@ -710,9 +710,8 @@ void Bed3D::render_default(bool bottom) if (shader != nullptr) { shader->start_using(); - const Camera& camera = wxGetApp().plater()->get_camera(); - shader->set_uniform("view_model_matrix", camera.get_view_matrix()); - shader->set_uniform("projection_matrix", camera.get_projection_matrix()); + shader->set_uniform("view_model_matrix", view_matrix); + shader->set_uniform("projection_matrix", projection_matrix); glsafe(::glEnable(GL_DEPTH_TEST)); glsafe(::glEnable(GL_BLEND)); diff --git a/src/slic3r/GUI/3DBed.hpp b/src/slic3r/GUI/3DBed.hpp index e72c6f8af6c..3fa40df084e 100644 --- a/src/slic3r/GUI/3DBed.hpp +++ b/src/slic3r/GUI/3DBed.hpp @@ -166,7 +166,7 @@ class Bed3D //void render_texture(bool bottom, GLCanvas3D& canvas); void render_model(const Transform3d& view_matrix, const Transform3d& projection_matrix); void render_custom(GLCanvas3D& canvas, const Transform3d& view_matrix, const Transform3d& projection_matrix, bool bottom); - void render_default(bool bottom); + void render_default(bool bottom, const Transform3d& view_matrix, const Transform3d& projection_matrix); }; } // GUI From 7081ebddfaa074994fa777b5931d9f8c4d42ab92 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Fri, 27 Oct 2023 10:12:23 +0800 Subject: [PATCH 45/99] Follow-up of 6b2fea5f8bb67a38bdcb7e3fb43c06a12a6d7798 - Fixed warnings (cherry picked from commit prusa3d/PrusaSlicer@9701d3b01d2d64c3e45d7357c645f8664990f6d2) --- src/slic3r/GUI/GCodeViewer.cpp | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/src/slic3r/GUI/GCodeViewer.cpp b/src/slic3r/GUI/GCodeViewer.cpp index 6fcb27a9608..a5eb7412a9f 100644 --- a/src/slic3r/GUI/GCodeViewer.cpp +++ b/src/slic3r/GUI/GCodeViewer.cpp @@ -3745,16 +3745,8 @@ m_no_render_path = false; void GCodeViewer::render_toolpaths() { -#if ENABLE_FIXED_SCREEN_SIZE_POINT_MARKERS - const float point_size = 20.0f; -#else - const float point_size = 0.8f; -#endif // ENABLE_FIXED_SCREEN_SIZE_POINT_MARKERS const Camera& camera = wxGetApp().plater()->get_camera(); const double zoom = camera.get_zoom(); - const std::array& viewport = camera.get_viewport(); - const float near_plane_height = camera.get_type() == Camera::EType::Perspective ? static_cast(viewport[3]) / (2.0f * static_cast(2.0 * std::tan(0.5 * Geometry::deg2rad(camera.get_fov())))) : - static_cast(viewport[3]) * 0.0005; auto render_as_lines = [ #if ENABLE_GCODE_VIEWER_STATISTICS @@ -3971,9 +3963,9 @@ void GCodeViewer::render_toolpaths() } #if ENABLE_GCODE_VIEWER_STATISTICS - auto render_sequential_range_cap = [this] + auto render_sequential_range_cap = [this, &camera] #else - auto render_sequential_range_cap = [] + auto render_sequential_range_cap = [&camera] #endif // ENABLE_GCODE_VIEWER_STATISTICS (const SequentialRangeCap& cap) { const TBuffer* buffer = cap.buffer; @@ -3983,7 +3975,6 @@ void GCodeViewer::render_toolpaths() shader->start_using(); - const Camera& camera = wxGetApp().plater()->get_camera(); const Transform3d& view_matrix = camera.get_view_matrix(); shader->set_uniform("view_model_matrix", view_matrix); shader->set_uniform("projection_matrix", camera.get_projection_matrix()); From bb044754af5e971e16a0cd1a25d9c95dda79e1e7 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Fri, 27 Oct 2023 10:16:55 +0800 Subject: [PATCH 46/99] ENABLE_GL_IMGUI_SHADERS - Fixes in ImGuiWrapper::render_draw_data() (cherry picked from commit prusa3d/PrusaSlicer@4964d6ecd56133237fc9999b677a71ae5fff2817) --- src/slic3r/GUI/ImGuiWrapper.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/slic3r/GUI/ImGuiWrapper.cpp b/src/slic3r/GUI/ImGuiWrapper.cpp index a45d8f0d2d9..22606d1e902 100644 --- a/src/slic3r/GUI/ImGuiWrapper.cpp +++ b/src/slic3r/GUI/ImGuiWrapper.cpp @@ -2445,14 +2445,14 @@ void ImGuiWrapper::render_draw_data(ImDrawData *draw_data) shader->set_uniform("ProjMtx", ortho_projection); // Will project scissor/clipping rectangles into framebuffer space - const ImVec2 clip_off = draw_data->DisplayPos; // (0,0) unless using multi-viewports + const ImVec2 clip_off = draw_data->DisplayPos; // (0,0) unless using multi-viewports const ImVec2 clip_scale = draw_data->FramebufferScale; // (1,1) unless using retina display which are often (2,2) // Render command lists for (int n = 0; n < draw_data->CmdListsCount; ++n) { const ImDrawList* cmd_list = draw_data->CmdLists[n]; const ImDrawVert* vtx_buffer = cmd_list->VtxBuffer.Data; - const ImDrawIdx* idx_buffer = cmd_list->IdxBuffer.Data; + const ImDrawIdx* idx_buffer = cmd_list->IdxBuffer.Data; const GLsizeiptr vtx_buffer_size = (GLsizeiptr)cmd_list->VtxBuffer.Size * (int)sizeof(ImDrawVert); const GLsizeiptr idx_buffer_size = (GLsizeiptr)cmd_list->IdxBuffer.Size * (int)sizeof(ImDrawIdx); @@ -2501,7 +2501,6 @@ void ImGuiWrapper::render_draw_data(ImDrawData *draw_data) glsafe(::glBindTexture(GL_TEXTURE_2D, (GLuint)(intptr_t)pcmd->GetTexID())); glsafe(::glDrawElements(GL_TRIANGLES, (GLsizei)pcmd->ElemCount, sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, (void*)(intptr_t)(pcmd->IdxOffset * sizeof(ImDrawIdx)))); } - idx_buffer += pcmd->ElemCount; } if (position_id != -1) From 1e4f16bd39bd76e2ce89b636b1ec157cd0bbadba Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Fri, 27 Oct 2023 10:51:15 +0800 Subject: [PATCH 47/99] Tech ENABLE_GL_SHADERS_ATTRIBUTES - Added shaders for glsl version 140 (cherry picked from commit prusa3d/PrusaSlicer@76d1d4949bbd0964717f8112aae992a1267c5eb4) --- resources/shaders/110/background.fs | 11 ++ .../{background_attr.vs => 110/background.vs} | 0 resources/shaders/110/flat.fs | 8 ++ .../shaders/{flat_attr.vs => 110/flat.vs} | 4 +- resources/shaders/110/flat_texture.fs | 10 ++ .../flat_texture.vs} | 6 +- resources/shaders/110/gouraud.fs | 105 ++++++++++++++++++ .../{gouraud_attr.vs => 110/gouraud.vs} | 6 +- resources/shaders/110/gouraud_light.fs | 12 ++ .../gouraud_light.vs} | 6 +- .../shaders/110/gouraud_light_instanced.fs | 12 ++ .../gouraud_light_instanced.vs} | 8 +- resources/shaders/{ => 110}/imgui.fs | 0 resources/shaders/{ => 110}/imgui.vs | 0 .../{mm_contour_attr.fs => 110/mm_contour.fs} | 0 .../{mm_contour_attr.vs => 110/mm_contour.vs} | 4 +- .../{mm_gouraud_attr.fs => 110/mm_gouraud.fs} | 0 .../{mm_gouraud_attr.vs => 110/mm_gouraud.vs} | 4 +- resources/shaders/110/printbed.fs | 34 ++++++ .../{printbed_attr.vs => 110/printbed.vs} | 6 +- resources/shaders/110/thumbnail.fs | 16 +++ .../{thumbnail_attr.vs => 110/thumbnail.vs} | 0 .../shaders/110/variable_layer_height.fs | 41 +++++++ .../variable_layer_height.vs} | 8 +- resources/shaders/140/background.fs | 11 ++ resources/shaders/140/background.vs | 12 ++ resources/shaders/140/flat.fs | 8 ++ resources/shaders/140/flat.vs | 11 ++ resources/shaders/140/flat_texture.fs | 10 ++ resources/shaders/140/flat_texture.vs | 15 +++ resources/shaders/140/gouraud.fs | 105 ++++++++++++++++++ resources/shaders/140/gouraud.vs | 77 +++++++++++++ resources/shaders/140/gouraud_light.fs | 12 ++ resources/shaders/140/gouraud_light.vs | 45 ++++++++ .../shaders/140/gouraud_light_instanced.fs | 12 ++ .../shaders/140/gouraud_light_instanced.vs | 50 +++++++++ resources/shaders/140/imgui.fs | 11 ++ resources/shaders/140/imgui.vs | 17 +++ resources/shaders/140/mm_contour.fs | 13 +++ resources/shaders/140/mm_contour.vs | 11 ++ resources/shaders/140/mm_gouraud.fs | 90 +++++++++++++++ resources/shaders/140/mm_gouraud.vs | 35 ++++++ resources/shaders/140/printbed.fs | 35 ++++++ resources/shaders/140/printbed.vs | 15 +++ resources/shaders/140/thumbnail.fs | 16 +++ resources/shaders/140/thumbnail.vs | 51 +++++++++ .../shaders/140/variable_layer_height.fs | 41 +++++++ .../shaders/140/variable_layer_height.vs | 60 ++++++++++ src/OrcaSlicer.cpp | 2 +- src/slic3r/GUI/3DBed.cpp | 8 +- src/slic3r/GUI/3DScene.cpp | 5 +- src/slic3r/GUI/GCodeViewer.cpp | 14 +-- src/slic3r/GUI/GLCanvas3D.cpp | 26 ++--- src/slic3r/GUI/GLModel.cpp | 23 ++-- src/slic3r/GUI/GLSelectionRectangle.cpp | 2 +- src/slic3r/GUI/GLShadersManager.cpp | 41 +++---- src/slic3r/GUI/GLTexture.cpp | 2 +- src/slic3r/GUI/Gizmos/GLGizmoAdvancedCut.cpp | 10 +- src/slic3r/GUI/Gizmos/GLGizmoBase.cpp | 4 +- src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp | 2 +- src/slic3r/GUI/Gizmos/GLGizmoFlatten.cpp | 4 +- src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp | 2 +- .../GUI/Gizmos/GLGizmoMmuSegmentation.cpp | 2 +- src/slic3r/GUI/Gizmos/GLGizmoMove.cpp | 4 +- src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp | 16 +-- src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp | 4 +- src/slic3r/GUI/Gizmos/GLGizmoScale.cpp | 2 +- src/slic3r/GUI/Gizmos/GLGizmoSeam.cpp | 2 +- src/slic3r/GUI/Gizmos/GLGizmoSimplify.cpp | 4 +- src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp | 2 +- src/slic3r/GUI/Gizmos/GLGizmoText.cpp | 4 +- src/slic3r/GUI/ImGuiWrapper.cpp | 19 ++-- src/slic3r/GUI/MeshUtils.cpp | 2 +- src/slic3r/GUI/PartPlate.cpp | 10 +- src/slic3r/GUI/Selection.cpp | 6 +- src/slic3r/Utils/CalibUtils.cpp | 2 +- 76 files changed, 1145 insertions(+), 143 deletions(-) create mode 100644 resources/shaders/110/background.fs rename resources/shaders/{background_attr.vs => 110/background.vs} (100%) create mode 100644 resources/shaders/110/flat.fs rename resources/shaders/{flat_attr.vs => 110/flat.vs} (100%) create mode 100644 resources/shaders/110/flat_texture.fs rename resources/shaders/{flat_texture_attr.vs => 110/flat_texture.vs} (100%) create mode 100644 resources/shaders/110/gouraud.fs rename resources/shaders/{gouraud_attr.vs => 110/gouraud.vs} (100%) create mode 100644 resources/shaders/110/gouraud_light.fs rename resources/shaders/{gouraud_light_attr.vs => 110/gouraud_light.vs} (100%) create mode 100644 resources/shaders/110/gouraud_light_instanced.fs rename resources/shaders/{gouraud_light_instanced_attr.vs => 110/gouraud_light_instanced.vs} (100%) rename resources/shaders/{ => 110}/imgui.fs (100%) rename resources/shaders/{ => 110}/imgui.vs (100%) rename resources/shaders/{mm_contour_attr.fs => 110/mm_contour.fs} (100%) rename resources/shaders/{mm_contour_attr.vs => 110/mm_contour.vs} (100%) rename resources/shaders/{mm_gouraud_attr.fs => 110/mm_gouraud.fs} (100%) rename resources/shaders/{mm_gouraud_attr.vs => 110/mm_gouraud.vs} (100%) create mode 100644 resources/shaders/110/printbed.fs rename resources/shaders/{printbed_attr.vs => 110/printbed.vs} (100%) create mode 100644 resources/shaders/110/thumbnail.fs rename resources/shaders/{thumbnail_attr.vs => 110/thumbnail.vs} (100%) create mode 100644 resources/shaders/110/variable_layer_height.fs rename resources/shaders/{variable_layer_height_attr.vs => 110/variable_layer_height.vs} (100%) create mode 100644 resources/shaders/140/background.fs create mode 100644 resources/shaders/140/background.vs create mode 100644 resources/shaders/140/flat.fs create mode 100644 resources/shaders/140/flat.vs create mode 100644 resources/shaders/140/flat_texture.fs create mode 100644 resources/shaders/140/flat_texture.vs create mode 100644 resources/shaders/140/gouraud.fs create mode 100644 resources/shaders/140/gouraud.vs create mode 100644 resources/shaders/140/gouraud_light.fs create mode 100644 resources/shaders/140/gouraud_light.vs create mode 100644 resources/shaders/140/gouraud_light_instanced.fs create mode 100644 resources/shaders/140/gouraud_light_instanced.vs create mode 100644 resources/shaders/140/imgui.fs create mode 100644 resources/shaders/140/imgui.vs create mode 100644 resources/shaders/140/mm_contour.fs create mode 100644 resources/shaders/140/mm_contour.vs create mode 100644 resources/shaders/140/mm_gouraud.fs create mode 100644 resources/shaders/140/mm_gouraud.vs create mode 100644 resources/shaders/140/printbed.fs create mode 100644 resources/shaders/140/printbed.vs create mode 100644 resources/shaders/140/thumbnail.fs create mode 100644 resources/shaders/140/thumbnail.vs create mode 100644 resources/shaders/140/variable_layer_height.fs create mode 100644 resources/shaders/140/variable_layer_height.vs diff --git a/resources/shaders/110/background.fs b/resources/shaders/110/background.fs new file mode 100644 index 00000000000..b1484408988 --- /dev/null +++ b/resources/shaders/110/background.fs @@ -0,0 +1,11 @@ +#version 110 + +uniform vec4 top_color; +uniform vec4 bottom_color; + +varying vec2 tex_coord; + +void main() +{ + gl_FragColor = mix(bottom_color, top_color, tex_coord.y); +} diff --git a/resources/shaders/background_attr.vs b/resources/shaders/110/background.vs similarity index 100% rename from resources/shaders/background_attr.vs rename to resources/shaders/110/background.vs diff --git a/resources/shaders/110/flat.fs b/resources/shaders/110/flat.fs new file mode 100644 index 00000000000..ab656998df7 --- /dev/null +++ b/resources/shaders/110/flat.fs @@ -0,0 +1,8 @@ +#version 110 + +uniform vec4 uniform_color; + +void main() +{ + gl_FragColor = uniform_color; +} diff --git a/resources/shaders/flat_attr.vs b/resources/shaders/110/flat.vs similarity index 100% rename from resources/shaders/flat_attr.vs rename to resources/shaders/110/flat.vs index 370eedb72de..d9063f0c70e 100644 --- a/resources/shaders/flat_attr.vs +++ b/resources/shaders/110/flat.vs @@ -1,10 +1,10 @@ #version 110 -attribute vec3 v_position; - uniform mat4 view_model_matrix; uniform mat4 projection_matrix; +attribute vec3 v_position; + void main() { gl_Position = projection_matrix * view_model_matrix * vec4(v_position, 1.0); diff --git a/resources/shaders/110/flat_texture.fs b/resources/shaders/110/flat_texture.fs new file mode 100644 index 00000000000..ffe193b1c00 --- /dev/null +++ b/resources/shaders/110/flat_texture.fs @@ -0,0 +1,10 @@ +#version 110 + +uniform sampler2D uniform_texture; + +varying vec2 tex_coord; + +void main() +{ + gl_FragColor = texture2D(uniform_texture, tex_coord); +} diff --git a/resources/shaders/flat_texture_attr.vs b/resources/shaders/110/flat_texture.vs similarity index 100% rename from resources/shaders/flat_texture_attr.vs rename to resources/shaders/110/flat_texture.vs index e59a99da357..dc4868b04df 100644 --- a/resources/shaders/flat_texture_attr.vs +++ b/resources/shaders/110/flat_texture.vs @@ -1,11 +1,11 @@ #version 110 -attribute vec3 v_position; -attribute vec2 v_tex_coord; - uniform mat4 view_model_matrix; uniform mat4 projection_matrix; +attribute vec3 v_position; +attribute vec2 v_tex_coord; + varying vec2 tex_coord; void main() diff --git a/resources/shaders/110/gouraud.fs b/resources/shaders/110/gouraud.fs new file mode 100644 index 00000000000..9513dbb9e9e --- /dev/null +++ b/resources/shaders/110/gouraud.fs @@ -0,0 +1,105 @@ +#version 110 + +const vec3 ZERO = vec3(0.0, 0.0, 0.0); +//BBS: add grey and orange +//const vec3 GREY = vec3(0.9, 0.9, 0.9); +const vec3 ORANGE = vec3(0.8, 0.4, 0.0); +const vec3 LightRed = vec3(0.78, 0.0, 0.0); +const vec3 LightBlue = vec3(0.73, 1.0, 1.0); +const float EPSILON = 0.0001; + +struct PrintVolumeDetection +{ + // 0 = rectangle, 1 = circle, 2 = custom, 3 = invalid + int type; + // type = 0 (rectangle): + // x = min.x, y = min.y, z = max.x, w = max.y + // type = 1 (circle): + // x = center.x, y = center.y, z = radius + vec4 xy_data; + // x = min z, y = max z + vec2 z_data; +}; + +struct SlopeDetection +{ + bool actived; + float normal_z; + mat3 volume_world_normal_matrix; +}; + +uniform vec4 uniform_color; +uniform SlopeDetection slope; + +//BBS: add outline_color +uniform bool is_outline; + +uniform bool offset_depth_buffer; + +#ifdef ENABLE_ENVIRONMENT_MAP + uniform sampler2D environment_tex; + uniform bool use_environment_tex; +#endif // ENABLE_ENVIRONMENT_MAP + +uniform PrintVolumeDetection print_volume; + +varying vec3 clipping_planes_dots; + +// x = diffuse, y = specular; +varying vec2 intensity; + +varying vec4 world_pos; +varying float world_normal_z; +varying vec3 eye_normal; + +void main() +{ + if (any(lessThan(clipping_planes_dots, ZERO))) + discard; + vec3 color = uniform_color.rgb; + float alpha = uniform_color.a; + + if (slope.actived) { + if(world_pos.z<0.1&&world_pos.z>-0.1) + { + color = LightBlue; + alpha = 0.8; + } + else if( world_normal_z < slope.normal_z - EPSILON) + { + color = color * 0.5 + LightRed * 0.5; + alpha = 0.8; + } + } + // if the fragment is outside the print volume -> use darker color + vec3 pv_check_min = ZERO; + vec3 pv_check_max = ZERO; + if (print_volume.type == 0) { + // rectangle + pv_check_min = world_pos.xyz - vec3(print_volume.xy_data.x, print_volume.xy_data.y, print_volume.z_data.x); + pv_check_max = world_pos.xyz - vec3(print_volume.xy_data.z, print_volume.xy_data.w, print_volume.z_data.y); + color = (any(lessThan(pv_check_min, ZERO)) || any(greaterThan(pv_check_max, ZERO))) ? mix(color, ZERO, 0.3333) : color; + } + else if (print_volume.type == 1) { + // circle + float delta_radius = print_volume.xy_data.z - distance(world_pos.xy, print_volume.xy_data.xy); + pv_check_min = vec3(delta_radius, 0.0, world_pos.z - print_volume.z_data.x); + pv_check_max = vec3(0.0, 0.0, world_pos.z - print_volume.z_data.y); + color = (any(lessThan(pv_check_min, ZERO)) || any(greaterThan(pv_check_max, ZERO))) ? mix(color, ZERO, 0.3333) : color; + } + + //BBS: add outline_color + if (is_outline) + gl_FragColor = uniform_color; +#ifdef ENABLE_ENVIRONMENT_MAP + else if (use_environment_tex) + gl_FragColor = vec4(0.45 * texture2D(environment_tex, normalize(eye_normal).xy * 0.5 + 0.5).xyz + 0.8 * color * intensity.x, alpha); +#endif + else + gl_FragColor = vec4(vec3(intensity.y) + color * intensity.x, alpha); + + // In the support painting gizmo and the seam painting gizmo are painted triangles rendered over the already + // rendered object. To resolved z-fighting between previously rendered object and painted triangles, values + // inside the depth buffer are offset by small epsilon for painted triangles inside those gizmos. + gl_FragDepth = gl_FragCoord.z - (offset_depth_buffer ? EPSILON : 0.0); +} \ No newline at end of file diff --git a/resources/shaders/gouraud_attr.vs b/resources/shaders/110/gouraud.vs similarity index 100% rename from resources/shaders/gouraud_attr.vs rename to resources/shaders/110/gouraud.vs index 87e524c14ae..70f71f886bc 100644 --- a/resources/shaders/gouraud_attr.vs +++ b/resources/shaders/110/gouraud.vs @@ -25,9 +25,6 @@ struct SlopeDetection mat3 volume_world_normal_matrix; }; -attribute vec3 v_position; -attribute vec3 v_normal; - uniform mat4 view_model_matrix; uniform mat4 projection_matrix; uniform mat3 normal_matrix; @@ -39,6 +36,9 @@ uniform vec2 z_range; // Clipping plane - general orientation. Used by the SLA gizmo. uniform vec4 clipping_plane; +attribute vec3 v_position; +attribute vec3 v_normal; + // x = diffuse, y = specular; varying vec2 intensity; diff --git a/resources/shaders/110/gouraud_light.fs b/resources/shaders/110/gouraud_light.fs new file mode 100644 index 00000000000..970185a00ed --- /dev/null +++ b/resources/shaders/110/gouraud_light.fs @@ -0,0 +1,12 @@ +#version 110 + +uniform vec4 uniform_color; +uniform float emission_factor; + +// x = tainted, y = specular; +varying vec2 intensity; + +void main() +{ + gl_FragColor = vec4(vec3(intensity.y) + uniform_color.rgb * (intensity.x + emission_factor), uniform_color.a); +} diff --git a/resources/shaders/gouraud_light_attr.vs b/resources/shaders/110/gouraud_light.vs similarity index 100% rename from resources/shaders/gouraud_light_attr.vs rename to resources/shaders/110/gouraud_light.vs index 2e1b5fb429e..a03653b8a30 100644 --- a/resources/shaders/gouraud_light_attr.vs +++ b/resources/shaders/110/gouraud_light.vs @@ -14,13 +14,13 @@ const vec3 LIGHT_FRONT_DIR = vec3(0.6985074, 0.1397015, 0.6985074); #define INTENSITY_AMBIENT 0.3 -attribute vec3 v_position; -attribute vec3 v_normal; - uniform mat4 view_model_matrix; uniform mat4 projection_matrix; uniform mat3 normal_matrix; +attribute vec3 v_position; +attribute vec3 v_normal; + // x = tainted, y = specular; varying vec2 intensity; diff --git a/resources/shaders/110/gouraud_light_instanced.fs b/resources/shaders/110/gouraud_light_instanced.fs new file mode 100644 index 00000000000..970185a00ed --- /dev/null +++ b/resources/shaders/110/gouraud_light_instanced.fs @@ -0,0 +1,12 @@ +#version 110 + +uniform vec4 uniform_color; +uniform float emission_factor; + +// x = tainted, y = specular; +varying vec2 intensity; + +void main() +{ + gl_FragColor = vec4(vec3(intensity.y) + uniform_color.rgb * (intensity.x + emission_factor), uniform_color.a); +} diff --git a/resources/shaders/gouraud_light_instanced_attr.vs b/resources/shaders/110/gouraud_light_instanced.vs similarity index 100% rename from resources/shaders/gouraud_light_instanced_attr.vs rename to resources/shaders/110/gouraud_light_instanced.vs index 7069feb65e8..87748ce6f05 100644 --- a/resources/shaders/gouraud_light_instanced_attr.vs +++ b/resources/shaders/110/gouraud_light_instanced.vs @@ -14,6 +14,10 @@ const vec3 LIGHT_FRONT_DIR = vec3(0.6985074, 0.1397015, 0.6985074); #define INTENSITY_AMBIENT 0.3 +uniform mat4 view_model_matrix; +uniform mat4 projection_matrix; +uniform mat3 normal_matrix; + // vertex attributes attribute vec3 v_position; attribute vec3 v_normal; @@ -21,10 +25,6 @@ attribute vec3 v_normal; attribute vec3 i_offset; attribute vec2 i_scales; -uniform mat4 view_model_matrix; -uniform mat4 projection_matrix; -uniform mat3 normal_matrix; - // x = tainted, y = specular; varying vec2 intensity; diff --git a/resources/shaders/imgui.fs b/resources/shaders/110/imgui.fs similarity index 100% rename from resources/shaders/imgui.fs rename to resources/shaders/110/imgui.fs diff --git a/resources/shaders/imgui.vs b/resources/shaders/110/imgui.vs similarity index 100% rename from resources/shaders/imgui.vs rename to resources/shaders/110/imgui.vs diff --git a/resources/shaders/mm_contour_attr.fs b/resources/shaders/110/mm_contour.fs similarity index 100% rename from resources/shaders/mm_contour_attr.fs rename to resources/shaders/110/mm_contour.fs diff --git a/resources/shaders/mm_contour_attr.vs b/resources/shaders/110/mm_contour.vs similarity index 100% rename from resources/shaders/mm_contour_attr.vs rename to resources/shaders/110/mm_contour.vs index 370eedb72de..d9063f0c70e 100644 --- a/resources/shaders/mm_contour_attr.vs +++ b/resources/shaders/110/mm_contour.vs @@ -1,10 +1,10 @@ #version 110 -attribute vec3 v_position; - uniform mat4 view_model_matrix; uniform mat4 projection_matrix; +attribute vec3 v_position; + void main() { gl_Position = projection_matrix * view_model_matrix * vec4(v_position, 1.0); diff --git a/resources/shaders/mm_gouraud_attr.fs b/resources/shaders/110/mm_gouraud.fs similarity index 100% rename from resources/shaders/mm_gouraud_attr.fs rename to resources/shaders/110/mm_gouraud.fs diff --git a/resources/shaders/mm_gouraud_attr.vs b/resources/shaders/110/mm_gouraud.vs similarity index 100% rename from resources/shaders/mm_gouraud_attr.vs rename to resources/shaders/110/mm_gouraud.vs index d51c53b82b3..e8c679b6bf3 100644 --- a/resources/shaders/mm_gouraud_attr.vs +++ b/resources/shaders/110/mm_gouraud.vs @@ -2,8 +2,6 @@ const vec3 ZERO = vec3(0.0, 0.0, 0.0); -attribute vec3 v_position; - uniform mat4 view_model_matrix; uniform mat4 projection_matrix; @@ -13,6 +11,8 @@ uniform vec2 z_range; // Clipping plane - general orientation. Used by the SLA gizmo. uniform vec4 clipping_plane; +attribute vec3 v_position; + varying vec3 clipping_planes_dots; varying vec4 model_pos; varying vec4 world_pos; diff --git a/resources/shaders/110/printbed.fs b/resources/shaders/110/printbed.fs new file mode 100644 index 00000000000..833dff08f46 --- /dev/null +++ b/resources/shaders/110/printbed.fs @@ -0,0 +1,34 @@ +#version 110 + +const vec3 back_color_dark = vec3(0.235, 0.235, 0.235); +const vec3 back_color_light = vec3(0.365, 0.365, 0.365); + +uniform sampler2D texture; +uniform bool transparent_background; +uniform bool svg_source; + +varying vec2 tex_coord; + +vec4 svg_color() +{ + // takes foreground from texture + vec4 fore_color = texture2D(texture, tex_coord); + + // calculates radial gradient + vec3 back_color = vec3(mix(back_color_light, back_color_dark, smoothstep(0.0, 0.5, length(abs(tex_coord.xy) - vec2(0.5))))); + + // blends foreground with background + return vec4(mix(back_color, fore_color.rgb, fore_color.a), transparent_background ? fore_color.a : 1.0); +} + +vec4 non_svg_color() +{ + // takes foreground from texture + vec4 color = texture2D(texture, tex_coord); + return vec4(color.rgb, transparent_background ? color.a * 0.25 : color.a); +} + +void main() +{ + gl_FragColor = svg_source ? svg_color() : non_svg_color(); +} \ No newline at end of file diff --git a/resources/shaders/printbed_attr.vs b/resources/shaders/110/printbed.vs similarity index 100% rename from resources/shaders/printbed_attr.vs rename to resources/shaders/110/printbed.vs index e59a99da357..dc4868b04df 100644 --- a/resources/shaders/printbed_attr.vs +++ b/resources/shaders/110/printbed.vs @@ -1,11 +1,11 @@ #version 110 -attribute vec3 v_position; -attribute vec2 v_tex_coord; - uniform mat4 view_model_matrix; uniform mat4 projection_matrix; +attribute vec3 v_position; +attribute vec2 v_tex_coord; + varying vec2 tex_coord; void main() diff --git a/resources/shaders/110/thumbnail.fs b/resources/shaders/110/thumbnail.fs new file mode 100644 index 00000000000..4b269734ee6 --- /dev/null +++ b/resources/shaders/110/thumbnail.fs @@ -0,0 +1,16 @@ +#version 110 + +uniform vec4 uniform_color; +uniform float emission_factor; + +// x = tainted, y = specular; +varying vec2 intensity; +//varying float drop; +varying vec4 world_pos; + +void main() +{ + if (world_pos.z < 0.0) + discard; + gl_FragColor = vec4(vec3(intensity.y) + uniform_color.rgb * (intensity.x + emission_factor), uniform_color.a); +} diff --git a/resources/shaders/thumbnail_attr.vs b/resources/shaders/110/thumbnail.vs similarity index 100% rename from resources/shaders/thumbnail_attr.vs rename to resources/shaders/110/thumbnail.vs diff --git a/resources/shaders/110/variable_layer_height.fs b/resources/shaders/110/variable_layer_height.fs new file mode 100644 index 00000000000..693c1c6a0b2 --- /dev/null +++ b/resources/shaders/110/variable_layer_height.fs @@ -0,0 +1,41 @@ +#version 110 + +#define M_PI 3.1415926535897932384626433832795 + +// 2D texture (1D texture split by the rows) of color along the object Z axis. +uniform sampler2D z_texture; +// Scaling from the Z texture rows coordinate to the normalized texture row coordinate. +uniform float z_to_texture_row; +uniform float z_texture_row_to_normalized; +uniform float z_cursor; +uniform float z_cursor_band_width; + +// x = tainted, y = specular; +varying vec2 intensity; + +varying float object_z; + +void main() +{ + float object_z_row = z_to_texture_row * object_z; + // Index of the row in the texture. + float z_texture_row = floor(object_z_row); + // Normalized coordinate from 0. to 1. + float z_texture_col = object_z_row - z_texture_row; + float z_blend = 0.25 * cos(min(M_PI, abs(M_PI * (object_z - z_cursor) * 1.8 / z_cursor_band_width))) + 0.25; + // Calculate level of detail from the object Z coordinate. + // This makes the slowly sloping surfaces to be shown with high detail (with stripes), + // and the vertical surfaces to be shown with low detail (no stripes) + float z_in_cells = object_z_row * 190.; + // Gradient of Z projected on the screen. + float dx_vtc = dFdx(z_in_cells); + float dy_vtc = dFdy(z_in_cells); + float lod = clamp(0.5 * log2(max(dx_vtc * dx_vtc, dy_vtc * dy_vtc)), 0., 1.); + // Sample the Z texture. Texture coordinates are normalized to <0, 1>. + vec4 color = vec4(0.25, 0.25, 0.25, 1.0); + if (z_texture_row >= 0.0) + color = mix(texture2D(z_texture, vec2(z_texture_col, z_texture_row_to_normalized * (z_texture_row + 0.5 )), -10000.), + texture2D(z_texture, vec2(z_texture_col, z_texture_row_to_normalized * (z_texture_row * 2. + 1.)), 10000.), lod); + // Mix the final color. + gl_FragColor = vec4(vec3(intensity.y), 1.0) + intensity.x * mix(color, vec4(1.0, 1.0, 0.0, 1.0), z_blend); +} diff --git a/resources/shaders/variable_layer_height_attr.vs b/resources/shaders/110/variable_layer_height.vs similarity index 100% rename from resources/shaders/variable_layer_height_attr.vs rename to resources/shaders/110/variable_layer_height.vs index 40609bd0d92..e6c88fa8097 100644 --- a/resources/shaders/variable_layer_height_attr.vs +++ b/resources/shaders/110/variable_layer_height.vs @@ -14,16 +14,16 @@ const vec3 LIGHT_FRONT_DIR = vec3(0.6985074, 0.1397015, 0.6985074); #define INTENSITY_AMBIENT 0.3 -attribute vec3 v_position; -attribute vec3 v_normal; -attribute vec2 v_tex_coord; - uniform mat4 view_model_matrix; uniform mat4 projection_matrix; uniform mat3 normal_matrix; uniform mat4 volume_world_matrix; uniform float object_max_z; +attribute vec3 v_position; +attribute vec3 v_normal; +attribute vec2 v_tex_coord; + // x = tainted, y = specular; varying vec2 intensity; diff --git a/resources/shaders/140/background.fs b/resources/shaders/140/background.fs new file mode 100644 index 00000000000..c21f3a70cd0 --- /dev/null +++ b/resources/shaders/140/background.fs @@ -0,0 +1,11 @@ +#version 140 + +uniform vec4 top_color; +uniform vec4 bottom_color; + +in vec2 tex_coord; + +void main() +{ + gl_FragColor = mix(bottom_color, top_color, tex_coord.y); +} diff --git a/resources/shaders/140/background.vs b/resources/shaders/140/background.vs new file mode 100644 index 00000000000..13609b3a210 --- /dev/null +++ b/resources/shaders/140/background.vs @@ -0,0 +1,12 @@ +#version 140 + +in vec3 v_position; +in vec2 v_tex_coord; + +out vec2 tex_coord; + +void main() +{ + tex_coord = v_tex_coord; + gl_Position = vec4(v_position, 1.0); +} diff --git a/resources/shaders/140/flat.fs b/resources/shaders/140/flat.fs new file mode 100644 index 00000000000..e74124dcaef --- /dev/null +++ b/resources/shaders/140/flat.fs @@ -0,0 +1,8 @@ +#version 140 + +uniform vec4 uniform_color; + +void main() +{ + gl_FragColor = uniform_color; +} diff --git a/resources/shaders/140/flat.vs b/resources/shaders/140/flat.vs new file mode 100644 index 00000000000..7042671de20 --- /dev/null +++ b/resources/shaders/140/flat.vs @@ -0,0 +1,11 @@ +#version 140 + +uniform mat4 view_model_matrix; +uniform mat4 projection_matrix; + +in vec3 v_position; + +void main() +{ + gl_Position = projection_matrix * view_model_matrix * vec4(v_position, 1.0); +} diff --git a/resources/shaders/140/flat_texture.fs b/resources/shaders/140/flat_texture.fs new file mode 100644 index 00000000000..dec946721e3 --- /dev/null +++ b/resources/shaders/140/flat_texture.fs @@ -0,0 +1,10 @@ +#version 140 + +uniform sampler2D uniform_texture; + +in vec2 tex_coord; + +void main() +{ + gl_FragColor = texture(uniform_texture, tex_coord); +} diff --git a/resources/shaders/140/flat_texture.vs b/resources/shaders/140/flat_texture.vs new file mode 100644 index 00000000000..57d8ca3b7c6 --- /dev/null +++ b/resources/shaders/140/flat_texture.vs @@ -0,0 +1,15 @@ +#version 140 + +uniform mat4 view_model_matrix; +uniform mat4 projection_matrix; + +in vec3 v_position; +in vec2 v_tex_coord; + +out vec2 tex_coord; + +void main() +{ + tex_coord = v_tex_coord; + gl_Position = projection_matrix * view_model_matrix * vec4(v_position, 1.0); +} diff --git a/resources/shaders/140/gouraud.fs b/resources/shaders/140/gouraud.fs new file mode 100644 index 00000000000..6e8c63e0c55 --- /dev/null +++ b/resources/shaders/140/gouraud.fs @@ -0,0 +1,105 @@ +#version 140 + +const vec3 ZERO = vec3(0.0, 0.0, 0.0); +//BBS: add grey and orange +//const vec3 GREY = vec3(0.9, 0.9, 0.9); +const vec3 ORANGE = vec3(0.8, 0.4, 0.0); +const vec3 LightRed = vec3(0.78, 0.0, 0.0); +const vec3 LightBlue = vec3(0.73, 1.0, 1.0); +const float EPSILON = 0.0001; + +struct PrintVolumeDetection +{ + // 0 = rectangle, 1 = circle, 2 = custom, 3 = invalid + int type; + // type = 0 (rectangle): + // x = min.x, y = min.y, z = max.x, w = max.y + // type = 1 (circle): + // x = center.x, y = center.y, z = radius + vec4 xy_data; + // x = min z, y = max z + vec2 z_data; +}; + +struct SlopeDetection +{ + bool actived; + float normal_z; + mat3 volume_world_normal_matrix; +}; + +uniform vec4 uniform_color; +uniform SlopeDetection slope; + +//BBS: add outline_color +uniform bool is_outline; + +uniform bool offset_depth_buffer; + +#ifdef ENABLE_ENVIRONMENT_MAP + uniform sampler2D environment_tex; + uniform bool use_environment_tex; +#endif // ENABLE_ENVIRONMENT_MAP + +uniform PrintVolumeDetection print_volume; + +in vec3 clipping_planes_dots; + +// x = diffuse, y = specular; +in vec2 intensity; + +in vec4 world_pos; +in float world_normal_z; +in vec3 eye_normal; + +void main() +{ + if (any(lessThan(clipping_planes_dots, ZERO))) + discard; + vec3 color = uniform_color.rgb; + float alpha = uniform_color.a; + + if (slope.actived) { + if(world_pos.z<0.1&&world_pos.z>-0.1) + { + color = LightBlue; + alpha = 0.8; + } + else if( world_normal_z < slope.normal_z - EPSILON) + { + color = color * 0.5 + LightRed * 0.5; + alpha = 0.8; + } + } + // if the fragment is outside the print volume -> use darker color + vec3 pv_check_min = ZERO; + vec3 pv_check_max = ZERO; + if (print_volume.type == 0) { + // rectangle + pv_check_min = world_pos.xyz - vec3(print_volume.xy_data.x, print_volume.xy_data.y, print_volume.z_data.x); + pv_check_max = world_pos.xyz - vec3(print_volume.xy_data.z, print_volume.xy_data.w, print_volume.z_data.y); + color = (any(lessThan(pv_check_min, ZERO)) || any(greaterThan(pv_check_max, ZERO))) ? mix(color, ZERO, 0.3333) : color; + } + else if (print_volume.type == 1) { + // circle + float delta_radius = print_volume.xy_data.z - distance(world_pos.xy, print_volume.xy_data.xy); + pv_check_min = vec3(delta_radius, 0.0, world_pos.z - print_volume.z_data.x); + pv_check_max = vec3(0.0, 0.0, world_pos.z - print_volume.z_data.y); + color = (any(lessThan(pv_check_min, ZERO)) || any(greaterThan(pv_check_max, ZERO))) ? mix(color, ZERO, 0.3333) : color; + } + + //BBS: add outline_color + if (is_outline) + gl_FragColor = uniform_color; +#ifdef ENABLE_ENVIRONMENT_MAP + else if (use_environment_tex) + gl_FragColor = vec4(0.45 * texture(environment_tex, normalize(eye_normal).xy * 0.5 + 0.5).xyz + 0.8 * color * intensity.x, alpha); +#endif + else + gl_FragColor = vec4(vec3(intensity.y) + color * intensity.x, alpha); + + // In the support painting gizmo and the seam painting gizmo are painted triangles rendered over the already + // rendered object. To resolved z-fighting between previously rendered object and painted triangles, values + // inside the depth buffer are offset by small epsilon for painted triangles inside those gizmos. + gl_FragDepth = gl_FragCoord.z - (offset_depth_buffer ? EPSILON : 0.0); +} \ No newline at end of file diff --git a/resources/shaders/140/gouraud.vs b/resources/shaders/140/gouraud.vs new file mode 100644 index 00000000000..aaf251c42d4 --- /dev/null +++ b/resources/shaders/140/gouraud.vs @@ -0,0 +1,77 @@ +#version 140 + +#define INTENSITY_CORRECTION 0.6 + +// normalized values for (-0.6/1.31, 0.6/1.31, 1./1.31) +const vec3 LIGHT_TOP_DIR = vec3(-0.4574957, 0.4574957, 0.7624929); +#define LIGHT_TOP_DIFFUSE (0.8 * INTENSITY_CORRECTION) +#define LIGHT_TOP_SPECULAR (0.125 * INTENSITY_CORRECTION) +#define LIGHT_TOP_SHININESS 20.0 + +// normalized values for (1./1.43, 0.2/1.43, 1./1.43) +const vec3 LIGHT_FRONT_DIR = vec3(0.6985074, 0.1397015, 0.6985074); +#define LIGHT_FRONT_DIFFUSE (0.3 * INTENSITY_CORRECTION) +//#define LIGHT_FRONT_SPECULAR (0.0 * INTENSITY_CORRECTION) +//#define LIGHT_FRONT_SHININESS 5.0 + +#define INTENSITY_AMBIENT 0.3 + +const vec3 ZERO = vec3(0.0, 0.0, 0.0); + +struct SlopeDetection +{ + bool actived; + float normal_z; + mat3 volume_world_normal_matrix; +}; + +uniform mat4 view_model_matrix; +uniform mat4 projection_matrix; +uniform mat3 normal_matrix; +uniform mat4 volume_world_matrix; +uniform SlopeDetection slope; + +// Clipping plane, x = min z, y = max z. Used by the FFF and SLA previews to clip with a top / bottom plane. +uniform vec2 z_range; +// Clipping plane - general orientation. Used by the SLA gizmo. +uniform vec4 clipping_plane; + +in vec3 v_position; +in vec3 v_normal; + +// x = diffuse, y = specular; +out vec2 intensity; + +out vec3 clipping_planes_dots; + +out vec4 world_pos; +out float world_normal_z; +out vec3 eye_normal; + +void main() +{ + // First transform the normal into camera space and normalize the result. + eye_normal = normalize(normal_matrix * v_normal); + + // Compute the cos of the angle between the normal and lights direction. The light is directional so the direction is constant for every vertex. + // Since these two are normalized the cosine is the dot product. We also need to clamp the result to the [0,1] range. + float NdotL = max(dot(eye_normal, LIGHT_TOP_DIR), 0.0); + + intensity.x = INTENSITY_AMBIENT + NdotL * LIGHT_TOP_DIFFUSE; + vec4 position = view_model_matrix * vec4(v_position, 1.0); + intensity.y = LIGHT_TOP_SPECULAR * pow(max(dot(-normalize(position.xyz), reflect(-LIGHT_TOP_DIR, eye_normal)), 0.0), LIGHT_TOP_SHININESS); + + // Perform the same lighting calculation for the 2nd light source (no specular applied). + NdotL = max(dot(eye_normal, LIGHT_FRONT_DIR), 0.0); + intensity.x += NdotL * LIGHT_FRONT_DIFFUSE; + + // Point in homogenous coordinates. + world_pos = volume_world_matrix * vec4(v_position, 1.0); + + // z component of normal vector in world coordinate used for slope shading + world_normal_z = slope.actived ? (normalize(slope.volume_world_normal_matrix * v_normal)).z : 0.0; + + gl_Position = projection_matrix * position; + // Fill in the scalars for fragment shader clipping. Fragments with any of these components lower than zero are discarded. + clipping_planes_dots = vec3(dot(world_pos, clipping_plane), world_pos.z - z_range.x, z_range.y - world_pos.z); +} diff --git a/resources/shaders/140/gouraud_light.fs b/resources/shaders/140/gouraud_light.fs new file mode 100644 index 00000000000..de616e066ad --- /dev/null +++ b/resources/shaders/140/gouraud_light.fs @@ -0,0 +1,12 @@ +#version 140 + +uniform vec4 uniform_color; +uniform float emission_factor; + +// x = tainted, y = specular; +in vec2 intensity; + +void main() +{ + gl_FragColor = vec4(vec3(intensity.y) + uniform_color.rgb * (intensity.x + emission_factor), uniform_color.a); +} diff --git a/resources/shaders/140/gouraud_light.vs b/resources/shaders/140/gouraud_light.vs new file mode 100644 index 00000000000..b75a8440587 --- /dev/null +++ b/resources/shaders/140/gouraud_light.vs @@ -0,0 +1,45 @@ +#version 140 + +#define INTENSITY_CORRECTION 0.6 + +// normalized values for (-0.6/1.31, 0.6/1.31, 1./1.31) +const vec3 LIGHT_TOP_DIR = vec3(-0.4574957, 0.4574957, 0.7624929); +#define LIGHT_TOP_DIFFUSE (0.8 * INTENSITY_CORRECTION) +#define LIGHT_TOP_SPECULAR (0.125 * INTENSITY_CORRECTION) +#define LIGHT_TOP_SHININESS 20.0 + +// normalized values for (1./1.43, 0.2/1.43, 1./1.43) +const vec3 LIGHT_FRONT_DIR = vec3(0.6985074, 0.1397015, 0.6985074); +#define LIGHT_FRONT_DIFFUSE (0.3 * INTENSITY_CORRECTION) + +#define INTENSITY_AMBIENT 0.3 + +uniform mat4 view_model_matrix; +uniform mat4 projection_matrix; +uniform mat3 normal_matrix; + +in vec3 v_position; +in vec3 v_normal; + +// x = tainted, y = specular; +out vec2 intensity; + +void main() +{ + // First transform the normal into camera space and normalize the result. + vec3 normal = normalize(normal_matrix * v_normal); + + // Compute the cos of the angle between the normal and lights direction. The light is directional so the direction is constant for every vertex. + // Since these two are normalized the cosine is the dot product. We also need to clamp the result to the [0,1] range. + float NdotL = max(dot(normal, LIGHT_TOP_DIR), 0.0); + + intensity.x = INTENSITY_AMBIENT + NdotL * LIGHT_TOP_DIFFUSE; + vec4 position = view_model_matrix * vec4(v_position, 1.0); + intensity.y = LIGHT_TOP_SPECULAR * pow(max(dot(-normalize(position.xyz), reflect(-LIGHT_TOP_DIR, normal)), 0.0), LIGHT_TOP_SHININESS); + + // Perform the same lighting calculation for the 2nd light source (no specular applied). + NdotL = max(dot(normal, LIGHT_FRONT_DIR), 0.0); + intensity.x += NdotL * LIGHT_FRONT_DIFFUSE; + + gl_Position = projection_matrix * position; +} diff --git a/resources/shaders/140/gouraud_light_instanced.fs b/resources/shaders/140/gouraud_light_instanced.fs new file mode 100644 index 00000000000..de616e066ad --- /dev/null +++ b/resources/shaders/140/gouraud_light_instanced.fs @@ -0,0 +1,12 @@ +#version 140 + +uniform vec4 uniform_color; +uniform float emission_factor; + +// x = tainted, y = specular; +in vec2 intensity; + +void main() +{ + gl_FragColor = vec4(vec3(intensity.y) + uniform_color.rgb * (intensity.x + emission_factor), uniform_color.a); +} diff --git a/resources/shaders/140/gouraud_light_instanced.vs b/resources/shaders/140/gouraud_light_instanced.vs new file mode 100644 index 00000000000..b6b9ab8be7e --- /dev/null +++ b/resources/shaders/140/gouraud_light_instanced.vs @@ -0,0 +1,50 @@ +#version 140 + +#define INTENSITY_CORRECTION 0.6 + +// normalized values for (-0.6/1.31, 0.6/1.31, 1./1.31) +const vec3 LIGHT_TOP_DIR = vec3(-0.4574957, 0.4574957, 0.7624929); +#define LIGHT_TOP_DIFFUSE (0.8 * INTENSITY_CORRECTION) +#define LIGHT_TOP_SPECULAR (0.125 * INTENSITY_CORRECTION) +#define LIGHT_TOP_SHININESS 20.0 + +// normalized values for (1./1.43, 0.2/1.43, 1./1.43) +const vec3 LIGHT_FRONT_DIR = vec3(0.6985074, 0.1397015, 0.6985074); +#define LIGHT_FRONT_DIFFUSE (0.3 * INTENSITY_CORRECTION) + +#define INTENSITY_AMBIENT 0.3 + +uniform mat4 view_model_matrix; +uniform mat4 projection_matrix; +uniform mat3 normal_matrix; + +// vertex attributes +in vec3 v_position; +in vec3 v_normal; +// instance attributes +in vec3 i_offset; +in vec2 i_scales; + +// x = tainted, y = specular; +out vec2 intensity; + +void main() +{ + // First transform the normal into camera space and normalize the result. + vec3 eye_normal = normalize(normal_matrix * v_normal); + + // Compute the cos of the angle between the normal and lights direction. The light is directional so the direction is constant for every vertex. + // Since these two are normalized the cosine is the dot product. We also need to clamp the result to the [0,1] range. + float NdotL = max(dot(eye_normal, LIGHT_TOP_DIR), 0.0); + + intensity.x = INTENSITY_AMBIENT + NdotL * LIGHT_TOP_DIFFUSE; + vec4 world_position = vec4(v_position * vec3(vec2(1.5 * i_scales.x), 1.5 * i_scales.y) + i_offset - vec3(0.0, 0.0, 0.5 * i_scales.y), 1.0); + vec4 eye_position = view_model_matrix * world_position; + intensity.y = LIGHT_TOP_SPECULAR * pow(max(dot(-normalize(eye_position.xyz), reflect(-LIGHT_TOP_DIR, eye_normal)), 0.0), LIGHT_TOP_SHININESS); + + // Perform the same lighting calculation for the 2nd light source (no specular applied). + NdotL = max(dot(eye_normal, LIGHT_FRONT_DIR), 0.0); + intensity.x += NdotL * LIGHT_FRONT_DIFFUSE; + + gl_Position = projection_matrix * eye_position; +} diff --git a/resources/shaders/140/imgui.fs b/resources/shaders/140/imgui.fs new file mode 100644 index 00000000000..4b2571749fa --- /dev/null +++ b/resources/shaders/140/imgui.fs @@ -0,0 +1,11 @@ +#version 140 + +uniform sampler2D Texture; + +in vec2 Frag_UV; +in vec4 Frag_Color; + +void main() +{ + gl_FragColor = Frag_Color * texture(Texture, Frag_UV.st); +} \ No newline at end of file diff --git a/resources/shaders/140/imgui.vs b/resources/shaders/140/imgui.vs new file mode 100644 index 00000000000..fd743bdf2d1 --- /dev/null +++ b/resources/shaders/140/imgui.vs @@ -0,0 +1,17 @@ +#version 140 + +uniform mat4 ProjMtx; + +in vec2 Position; +in vec2 UV; +in vec4 Color; + +out vec2 Frag_UV; +out vec4 Frag_Color; + +void main() +{ + Frag_UV = UV; + Frag_Color = Color; + gl_Position = ProjMtx * vec4(Position.xy, 0.0, 1.0); +} \ No newline at end of file diff --git a/resources/shaders/140/mm_contour.fs b/resources/shaders/140/mm_contour.fs new file mode 100644 index 00000000000..3681d76c184 --- /dev/null +++ b/resources/shaders/140/mm_contour.fs @@ -0,0 +1,13 @@ +#version 140 + +const float EPSILON = 0.0001; + +uniform vec4 uniform_color; + +void main() +{ + gl_FragColor = uniform_color; + // Values inside depth buffer for fragments of the contour of a selected area are offset + // by small epsilon to solve z-fighting between painted triangles and contour lines. + gl_FragDepth = gl_FragCoord.z - EPSILON; +} diff --git a/resources/shaders/140/mm_contour.vs b/resources/shaders/140/mm_contour.vs new file mode 100644 index 00000000000..7042671de20 --- /dev/null +++ b/resources/shaders/140/mm_contour.vs @@ -0,0 +1,11 @@ +#version 140 + +uniform mat4 view_model_matrix; +uniform mat4 projection_matrix; + +in vec3 v_position; + +void main() +{ + gl_Position = projection_matrix * view_model_matrix * vec4(v_position, 1.0); +} diff --git a/resources/shaders/140/mm_gouraud.fs b/resources/shaders/140/mm_gouraud.fs new file mode 100644 index 00000000000..b7b0f26351d --- /dev/null +++ b/resources/shaders/140/mm_gouraud.fs @@ -0,0 +1,90 @@ +#version 140 + +#define INTENSITY_CORRECTION 0.6 + +// normalized values for (-0.6/1.31, 0.6/1.31, 1./1.31) +const vec3 LIGHT_TOP_DIR = vec3(-0.4574957, 0.4574957, 0.7624929); +#define LIGHT_TOP_DIFFUSE (0.8 * INTENSITY_CORRECTION) +#define LIGHT_TOP_SPECULAR (0.125 * INTENSITY_CORRECTION) +#define LIGHT_TOP_SHININESS 20.0 + +// normalized values for (1./1.43, 0.2/1.43, 1./1.43) +const vec3 LIGHT_FRONT_DIR = vec3(0.6985074, 0.1397015, 0.6985074); +#define LIGHT_FRONT_DIFFUSE (0.3 * INTENSITY_CORRECTION) + +#define INTENSITY_AMBIENT 0.3 + +const vec3 ZERO = vec3(0.0, 0.0, 0.0); +const float EPSILON = 0.0001; +//BBS: add grey and orange +//const vec3 GREY = vec3(0.9, 0.9, 0.9); +const vec3 ORANGE = vec3(0.8, 0.4, 0.0); +const vec3 LightRed = vec3(0.78, 0.0, 0.0); +const vec3 LightBlue = vec3(0.73, 1.0, 1.0); +uniform vec4 uniform_color; + +uniform bool volume_mirrored; + +uniform mat4 view_model_matrix; +uniform mat3 normal_matrix; + +in vec3 clipping_planes_dots; +in vec4 model_pos; +in vec4 world_pos; + +struct SlopeDetection +{ + bool actived; + float normal_z; + mat3 volume_world_normal_matrix; +}; +uniform SlopeDetection slope; + +void main() +{ + if (any(lessThan(clipping_planes_dots, ZERO))) + discard; + vec3 color = uniform_color.rgb; + float alpha = uniform_color.a; + + vec3 triangle_normal = normalize(cross(dFdx(model_pos.xyz), dFdy(model_pos.xyz))); +#ifdef FLIP_TRIANGLE_NORMALS + triangle_normal = -triangle_normal; +#endif + + if (volume_mirrored) + triangle_normal = -triangle_normal; + + vec3 transformed_normal = normalize(slope.volume_world_normal_matrix * triangle_normal); + + if (slope.actived) { + if(world_pos.z<0.1&&world_pos.z>-0.1) + { + color = LightBlue; + alpha = 1.0; + } + else if( transformed_normal.z < slope.normal_z - EPSILON) + { + color = color * 0.5 + LightRed * 0.5; + alpha = 1.0; + } + } + // First transform the normal into camera space and normalize the result. + vec3 eye_normal = normalize(normal_matrix * triangle_normal); + + // Compute the cos of the angle between the normal and lights direction. The light is directional so the direction is constant for every vertex. + // Since these two are normalized the cosine is the dot product. We also need to clamp the result to the [0,1] range. + float NdotL = max(dot(eye_normal, LIGHT_TOP_DIR), 0.0); + + // x = diffuse, y = specular; + vec2 intensity = vec2(0.0); + intensity.x = INTENSITY_AMBIENT + NdotL * LIGHT_TOP_DIFFUSE; + vec3 position = (view_model_matrix * model_pos).xyz; + intensity.y = LIGHT_TOP_SPECULAR * pow(max(dot(-normalize(position), reflect(-LIGHT_TOP_DIR, eye_normal)), 0.0), LIGHT_TOP_SHININESS); + + // Perform the same lighting calculation for the 2nd light source (no specular applied). + NdotL = max(dot(eye_normal, LIGHT_FRONT_DIR), 0.0); + intensity.x += NdotL * LIGHT_FRONT_DIFFUSE; + + gl_FragColor = vec4(vec3(intensity.y) + color * intensity.x, alpha); +} diff --git a/resources/shaders/140/mm_gouraud.vs b/resources/shaders/140/mm_gouraud.vs new file mode 100644 index 00000000000..4add5c0aeed --- /dev/null +++ b/resources/shaders/140/mm_gouraud.vs @@ -0,0 +1,35 @@ +#version 140 + +const vec3 ZERO = vec3(0.0, 0.0, 0.0); + +uniform mat4 view_model_matrix; +uniform mat4 projection_matrix; + +uniform mat4 volume_world_matrix; +// Clipping plane, x = min z, y = max z. Used by the FFF and SLA previews to clip with a top / bottom plane. +uniform vec2 z_range; +// Clipping plane - general orientation. Used by the SLA gizmo. +uniform vec4 clipping_plane; + +in vec3 v_position; + +out vec3 clipping_planes_dots; +out vec4 model_pos; +out vec4 world_pos; +struct SlopeDetection +{ + bool actived; + float normal_z; + mat3 volume_world_normal_matrix; +}; +uniform SlopeDetection slope; +void main() +{ + model_pos = vec4(v_position, 1.0); + // Point in homogenous coordinates. + world_pos = volume_world_matrix * model_pos; + + gl_Position = projection_matrix * view_model_matrix * model_pos; + // Fill in the scalars for fragment shader clipping. Fragments with any of these components lower than zero are discarded. + clipping_planes_dots = vec3(dot(world_pos, clipping_plane), world_pos.z - z_range.x, z_range.y - world_pos.z); +} diff --git a/resources/shaders/140/printbed.fs b/resources/shaders/140/printbed.fs new file mode 100644 index 00000000000..6d927a749c4 --- /dev/null +++ b/resources/shaders/140/printbed.fs @@ -0,0 +1,35 @@ +#version 140 + +const vec3 back_color_dark = vec3(0.235, 0.235, 0.235); +const vec3 back_color_light = vec3(0.365, 0.365, 0.365); + +uniform sampler2D in_texture; +uniform bool transparent_background; +uniform bool svg_source; + +in vec2 tex_coord; +out vec4 frag_color; + +vec4 svg_color() +{ + // takes foreground from texture + vec4 fore_color = texture(in_texture, tex_coord); + + // calculates radial gradient + vec3 back_color = vec3(mix(back_color_light, back_color_dark, smoothstep(0.0, 0.5, length(abs(tex_coord.xy) - vec2(0.5))))); + + // blends foreground with background + return vec4(mix(back_color, fore_color.rgb, fore_color.a), transparent_background ? fore_color.a : 1.0); +} + +vec4 non_svg_color() +{ + // takes foreground from texture + vec4 color = texture(in_texture, tex_coord); + return vec4(color.rgb, transparent_background ? color.a * 0.25 : color.a); +} + +void main() +{ + frag_color = svg_source ? svg_color() : non_svg_color(); +} \ No newline at end of file diff --git a/resources/shaders/140/printbed.vs b/resources/shaders/140/printbed.vs new file mode 100644 index 00000000000..57d8ca3b7c6 --- /dev/null +++ b/resources/shaders/140/printbed.vs @@ -0,0 +1,15 @@ +#version 140 + +uniform mat4 view_model_matrix; +uniform mat4 projection_matrix; + +in vec3 v_position; +in vec2 v_tex_coord; + +out vec2 tex_coord; + +void main() +{ + tex_coord = v_tex_coord; + gl_Position = projection_matrix * view_model_matrix * vec4(v_position, 1.0); +} diff --git a/resources/shaders/140/thumbnail.fs b/resources/shaders/140/thumbnail.fs new file mode 100644 index 00000000000..9e6d5d854cb --- /dev/null +++ b/resources/shaders/140/thumbnail.fs @@ -0,0 +1,16 @@ +#version 140 + +uniform vec4 uniform_color; +uniform float emission_factor; + +// x = tainted, y = specular; +in vec2 intensity; +//varying float drop; +in vec4 world_pos; + +void main() +{ + if (world_pos.z < 0.0) + discard; + gl_FragColor = vec4(vec3(intensity.y) + uniform_color.rgb * (intensity.x + emission_factor), uniform_color.a); +} diff --git a/resources/shaders/140/thumbnail.vs b/resources/shaders/140/thumbnail.vs new file mode 100644 index 00000000000..d7996d99c93 --- /dev/null +++ b/resources/shaders/140/thumbnail.vs @@ -0,0 +1,51 @@ +#version 140 + +#define INTENSITY_CORRECTION 0.6 + +// normalized values for (-0.6/1.31, 0.6/1.31, 1./1.31) +const vec3 LIGHT_TOP_DIR = vec3(-0.4574957, 0.4574957, 0.7624929); +#define LIGHT_TOP_DIFFUSE (0.8 * INTENSITY_CORRECTION) +#define LIGHT_TOP_SPECULAR (0.125 * INTENSITY_CORRECTION) +#define LIGHT_TOP_SHININESS 20.0 + +// normalized values for (1./1.43, 0.2/1.43, 1./1.43) +const vec3 LIGHT_FRONT_DIR = vec3(0.6985074, 0.1397015, 0.6985074); +#define LIGHT_FRONT_DIFFUSE (0.3 * INTENSITY_CORRECTION) + +#define INTENSITY_AMBIENT 0.3 + +in vec3 v_position; +in vec3 v_normal; + +uniform mat4 view_model_matrix; +uniform mat4 projection_matrix; +uniform mat3 normal_matrix; + +uniform mat4 volume_world_matrix; + +// x = tainted, y = specular; +out vec2 intensity; +out vec4 world_pos; + +void main() +{ + // First transform the normal into camera space and normalize the result. + vec3 normal = normalize(normal_matrix * v_normal); + + // Compute the cos of the angle between the normal and lights direction. The light is directional so the direction is constant for every vertex. + // Since these two are normalized the cosine is the dot product. We also need to clamp the result to the [0,1] range. + float NdotL = max(dot(normal, LIGHT_TOP_DIR), 0.0); + + intensity.x = INTENSITY_AMBIENT + NdotL * LIGHT_TOP_DIFFUSE; + vec4 position = view_model_matrix * vec4(v_position, 1.0); + intensity.y = LIGHT_TOP_SPECULAR * pow(max(dot(-normalize(position.xyz), reflect(-LIGHT_TOP_DIR, normal)), 0.0), LIGHT_TOP_SHININESS); + + // Perform the same lighting calculation for the 2nd light source (no specular applied). + NdotL = max(dot(normal, LIGHT_FRONT_DIR), 0.0); + intensity.x += NdotL * LIGHT_FRONT_DIFFUSE; + + // Point in homogenous coordinates. + world_pos = volume_world_matrix * gl_Vertex; + + gl_Position = projection_matrix * position; +} diff --git a/resources/shaders/140/variable_layer_height.fs b/resources/shaders/140/variable_layer_height.fs new file mode 100644 index 00000000000..cf1fc309cc4 --- /dev/null +++ b/resources/shaders/140/variable_layer_height.fs @@ -0,0 +1,41 @@ +#version 140 + +#define M_PI 3.1415926535897932384626433832795 + +// 2D texture (1D texture split by the rows) of color along the object Z axis. +uniform sampler2D z_texture; +// Scaling from the Z texture rows coordinate to the normalized texture row coordinate. +uniform float z_to_texture_row; +uniform float z_texture_row_to_normalized; +uniform float z_cursor; +uniform float z_cursor_band_width; + +// x = tainted, y = specular; +in vec2 intensity; + +in float object_z; + +void main() +{ + float object_z_row = z_to_texture_row * object_z; + // Index of the row in the texture. + float z_texture_row = floor(object_z_row); + // Normalized coordinate from 0. to 1. + float z_texture_col = object_z_row - z_texture_row; + float z_blend = 0.25 * cos(min(M_PI, abs(M_PI * (object_z - z_cursor) * 1.8 / z_cursor_band_width))) + 0.25; + // Calculate level of detail from the object Z coordinate. + // This makes the slowly sloping surfaces to be shown with high detail (with stripes), + // and the vertical surfaces to be shown with low detail (no stripes) + float z_in_cells = object_z_row * 190.; + // Gradient of Z projected on the screen. + float dx_vtc = dFdx(z_in_cells); + float dy_vtc = dFdy(z_in_cells); + float lod = clamp(0.5 * log2(max(dx_vtc * dx_vtc, dy_vtc * dy_vtc)), 0., 1.); + // Sample the Z texture. Texture coordinates are normalized to <0, 1>. + vec4 color = vec4(0.25, 0.25, 0.25, 1.0); + if (z_texture_row >= 0.0) + color = mix(texture(z_texture, vec2(z_texture_col, z_texture_row_to_normalized * (z_texture_row + 0.5 )), -10000.), + texture(z_texture, vec2(z_texture_col, z_texture_row_to_normalized * (z_texture_row * 2. + 1.)), 10000.), lod); + // Mix the final color. + gl_FragColor = vec4(vec3(intensity.y), 1.0) + intensity.x * mix(color, vec4(1.0, 1.0, 0.0, 1.0), z_blend); +} diff --git a/resources/shaders/140/variable_layer_height.vs b/resources/shaders/140/variable_layer_height.vs new file mode 100644 index 00000000000..dd463b9c7af --- /dev/null +++ b/resources/shaders/140/variable_layer_height.vs @@ -0,0 +1,60 @@ +#version 140 + +#define INTENSITY_CORRECTION 0.6 + +const vec3 LIGHT_TOP_DIR = vec3(-0.4574957, 0.4574957, 0.7624929); +#define LIGHT_TOP_DIFFUSE (0.8 * INTENSITY_CORRECTION) +#define LIGHT_TOP_SPECULAR (0.125 * INTENSITY_CORRECTION) +#define LIGHT_TOP_SHININESS 20.0 + +const vec3 LIGHT_FRONT_DIR = vec3(0.6985074, 0.1397015, 0.6985074); +#define LIGHT_FRONT_DIFFUSE (0.3 * INTENSITY_CORRECTION) +//#define LIGHT_FRONT_SPECULAR (0.0 * INTENSITY_CORRECTION) +//#define LIGHT_FRONT_SHININESS 5.0 + +#define INTENSITY_AMBIENT 0.3 + +uniform mat4 view_model_matrix; +uniform mat4 projection_matrix; +uniform mat3 normal_matrix; +uniform mat4 volume_world_matrix; +uniform float object_max_z; + +in vec3 v_position; +in vec3 v_normal; +in vec2 v_tex_coord; + +// x = tainted, y = specular; +out vec2 intensity; + +out float object_z; + +void main() +{ + // ===================================================== + // NOTE: + // when object_max_z > 0.0 we are rendering the overlay + // when object_max_z == 0.0 we are rendering the volumes + // ===================================================== + + // First transform the normal into camera space and normalize the result. + vec3 normal = (object_max_z > 0.0) ? vec3(0.0, 0.0, 1.0) : normalize(normal_matrix * v_normal); + + // Compute the cos of the angle between the normal and lights direction. The light is directional so the direction is constant for every vertex. + // Since these two are normalized the cosine is the dot product. We also need to clamp the result to the [0,1] range. + float NdotL = max(dot(normal, LIGHT_TOP_DIR), 0.0); + + intensity.x = INTENSITY_AMBIENT + NdotL * LIGHT_TOP_DIFFUSE; + vec4 position = view_model_matrix * vec4(v_position, 1.0); + intensity.y = LIGHT_TOP_SPECULAR * pow(max(dot(-normalize(position.xyz), reflect(-LIGHT_TOP_DIR, normal)), 0.0), LIGHT_TOP_SHININESS); + + // Perform the same lighting calculation for the 2nd light source (no specular) + NdotL = max(dot(normal, LIGHT_FRONT_DIR), 0.0); + + intensity.x += NdotL * LIGHT_FRONT_DIFFUSE; + + // Scaled to widths of the Z texture. + object_z = (object_max_z > 0.0) ? object_max_z * v_tex_coord.y : (volume_world_matrix * vec4(v_position, 1.0)).z; + + gl_Position = projection_matrix * position; +} diff --git a/src/OrcaSlicer.cpp b/src/OrcaSlicer.cpp index 9c99e6f6864..c8ba1cdd313 100644 --- a/src/OrcaSlicer.cpp +++ b/src/OrcaSlicer.cpp @@ -2370,7 +2370,7 @@ int CLI::run(int argc, char **argv) } ThumbnailsParams thumbnail_params; - GLShaderProgram* shader = opengl_mgr.get_shader("thumbnail_attr"); + GLShaderProgram* shader = opengl_mgr.get_shader("thumbnail"); if (!shader) { BOOST_LOG_TRIVIAL(error) << boost::format("can not get shader for rendering thumbnail"); } diff --git a/src/slic3r/GUI/3DBed.cpp b/src/slic3r/GUI/3DBed.cpp index 620a84c171b..420629ca42f 100644 --- a/src/slic3r/GUI/3DBed.cpp +++ b/src/slic3r/GUI/3DBed.cpp @@ -218,7 +218,7 @@ void Bed3D::Axes::render() if (!m_arrow.is_initialized()) m_arrow.init_from(stilized_arrow(16, DefaultTipRadius, DefaultTipLength, DefaultStemRadius, m_stem_length)); - GLShaderProgram* shader = wxGetApp().get_shader("gouraud_light_attr"); + GLShaderProgram* shader = wxGetApp().get_shader("gouraud_light"); if (shader == nullptr) return; @@ -536,7 +536,7 @@ void Bed3D::render_system(GLCanvas3D& canvas, const Transform3d& view_matrix, co } if (m_triangles.get_vertices_count() > 0) { - GLShaderProgram* shader = wxGetApp().get_shader("printbed_attr"); + GLShaderProgram* shader = wxGetApp().get_shader("printbed"); if (shader != nullptr) { shader->start_using(); const Camera& camera = wxGetApp().plater()->get_camera(); @@ -671,7 +671,7 @@ void Bed3D::render_model(const Transform3d& view_matrix, const Transform3d& proj } if (!m_model.get_filename().empty()) { - GLShaderProgram* shader = wxGetApp().get_shader("gouraud_light_attr"); + GLShaderProgram* shader = wxGetApp().get_shader("gouraud_light"); if (shader != nullptr) { shader->start_using(); shader->set_uniform("emission_factor", 0.0f); @@ -706,7 +706,7 @@ void Bed3D::render_default(bool bottom, const Transform3d& view_matrix, const Tr update_bed_triangles(); - GLShaderProgram* shader = wxGetApp().get_shader("flat_attr"); + GLShaderProgram* shader = wxGetApp().get_shader("flat"); if (shader != nullptr) { shader->start_using(); diff --git a/src/slic3r/GUI/3DScene.cpp b/src/slic3r/GUI/3DScene.cpp index 2be7dd9afc0..eff2212ab37 100644 --- a/src/slic3r/GUI/3DScene.cpp +++ b/src/slic3r/GUI/3DScene.cpp @@ -821,9 +821,8 @@ void GLVolumeCollection::render(GLVolumeCollection::ERenderType type, bool disab if (shader == nullptr) return; - GLShaderProgram* sink_shader = GUI::wxGetApp().get_shader("flat_attr"); - GLShaderProgram* edges_shader = GUI::wxGetApp().get_shader("flat_attr"); - assert(boost::algorithm::iends_with(shader->get_name(), "_attr")); + GLShaderProgram* sink_shader = GUI::wxGetApp().get_shader("flat"); + GLShaderProgram* edges_shader = GUI::wxGetApp().get_shader("flat"); if (type == ERenderType::Transparent) { glsafe(::glEnable(GL_BLEND)); diff --git a/src/slic3r/GUI/GCodeViewer.cpp b/src/slic3r/GUI/GCodeViewer.cpp index a5eb7412a9f..43424d97519 100644 --- a/src/slic3r/GUI/GCodeViewer.cpp +++ b/src/slic3r/GUI/GCodeViewer.cpp @@ -307,7 +307,7 @@ void GCodeViewer::SequentialView::Marker::render(int canvas_width, int canvas_he if (!m_visible) return; - GLShaderProgram* shader = wxGetApp().get_shader("gouraud_light_attr"); + GLShaderProgram* shader = wxGetApp().get_shader("gouraud_light"); if (shader == nullptr) return; @@ -788,7 +788,7 @@ void GCodeViewer::init(ConfigOptionMode mode, PresetBundle* preset_bundle) case EMoveType::Seam: { // if (wxGetApp().is_gl_version_greater_or_equal_to(3, 3)) { // buffer.render_primitive_type = TBuffer::ERenderPrimitiveType::InstancedModel; -// buffer.shader = "gouraud_light_instanced_attr"; +// buffer.shader = "gouraud_light_instanced"; // buffer.model.model.init_from(diamond(16)); // buffer.model.color = option_color(type); // buffer.model.instances.format = InstanceVBuffer::EFormat::InstancedModel; @@ -799,7 +799,7 @@ void GCodeViewer::init(ConfigOptionMode mode, PresetBundle* preset_bundle) buffer.render_primitive_type = TBuffer::ERenderPrimitiveType::BatchedModel; buffer.vertices.format = VBuffer::EFormat::PositionNormal3; - buffer.shader = "gouraud_light_attr"; + buffer.shader = "gouraud_light"; buffer.model.data = diamond(16); buffer.model.color = option_color(type); @@ -811,13 +811,13 @@ void GCodeViewer::init(ConfigOptionMode mode, PresetBundle* preset_bundle) case EMoveType::Extrude: { buffer.render_primitive_type = TBuffer::ERenderPrimitiveType::Triangle; buffer.vertices.format = VBuffer::EFormat::PositionNormal3; - buffer.shader = "gouraud_light_attr"; + buffer.shader = "gouraud_light"; break; } case EMoveType::Travel: { buffer.render_primitive_type = TBuffer::ERenderPrimitiveType::Line; buffer.vertices.format = VBuffer::EFormat::Position; - buffer.shader = "flat_attr"; + buffer.shader = "flat"; break; } } @@ -1425,7 +1425,7 @@ void GCodeViewer::_render_calibration_thumbnail_internal(ThumbnailData& thumbnai if (!buffer.visible || !buffer.has_data()) continue; - GLShaderProgram* shader = opengl_manager.get_shader("flat_attr"); + GLShaderProgram* shader = opengl_manager.get_shader("flat"); if (shader != nullptr) { shader->start_using(); @@ -4029,7 +4029,7 @@ void GCodeViewer::render_shells() //if (!m_shells.visible || m_shells.volumes.empty()) return; - GLShaderProgram* shader = wxGetApp().get_shader("gouraud_light_attr"); + GLShaderProgram* shader = wxGetApp().get_shader("gouraud_light"); if (shader == nullptr) return; diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index a6d32d8d5ff..e77aac4a2c3 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -163,7 +163,7 @@ void GLCanvas3D::LayersEditing::select_object(const Model& model, int object_id) bool GLCanvas3D::LayersEditing::is_allowed() const { - return wxGetApp().get_shader("variable_layer_height_attr") != nullptr && m_z_texture_id > 0; + return wxGetApp().get_shader("variable_layer_height") != nullptr && m_z_texture_id > 0; } bool GLCanvas3D::LayersEditing::is_enabled() const @@ -355,7 +355,7 @@ Rect GLCanvas3D::LayersEditing::get_bar_rect_screen(const GLCanvas3D& canvas) bool GLCanvas3D::LayersEditing::is_initialized() const { - return wxGetApp().get_shader("variable_layer_height_attr") != nullptr; + return wxGetApp().get_shader("variable_layer_height") != nullptr; } std::string GLCanvas3D::LayersEditing::get_tooltip(const GLCanvas3D& canvas) const @@ -397,7 +397,7 @@ void GLCanvas3D::LayersEditing::render_active_object_annotations(const GLCanvas3 const float cnv_inv_width = 1.0f / cnv_width; - GLShaderProgram* shader = wxGetApp().get_shader("variable_layer_height_attr"); + GLShaderProgram* shader = wxGetApp().get_shader("variable_layer_height"); if (shader == nullptr) return; @@ -513,7 +513,7 @@ void GLCanvas3D::LayersEditing::render_profile(const GLCanvas3D& canvas) m_profile.profile.init_from(std::move(init_data)); } - GLShaderProgram* shader = wxGetApp().get_shader("flat_attr"); + GLShaderProgram* shader = wxGetApp().get_shader("flat"); if (shader != nullptr) { shader->start_using(); shader->set_uniform("view_model_matrix", Transform3d::Identity()); @@ -534,7 +534,7 @@ void GLCanvas3D::LayersEditing::render_volumes(const GLCanvas3D& canvas, const G if (current_shader != nullptr) current_shader->stop_using(); - GLShaderProgram* shader = wxGetApp().get_shader("variable_layer_height_attr"); + GLShaderProgram* shader = wxGetApp().get_shader("variable_layer_height"); if (shader == nullptr) return; @@ -946,7 +946,7 @@ void GLCanvas3D::SequentialPrintClearance::render() const ColorRGBA FILL_COLOR = { 0.7f, 0.7f, 1.0f, 0.5f }; const ColorRGBA NO_FILL_COLOR = { 0.75f, 0.75f, 0.75f, 0.75f }; - GLShaderProgram* shader = wxGetApp().get_shader("flat_attr"); + GLShaderProgram* shader = wxGetApp().get_shader("flat"); if (shader == nullptr) return; @@ -2006,7 +2006,7 @@ void GLCanvas3D::render_thumbnail(ThumbnailData& thumbnail_data, unsigned int w, void GLCanvas3D::render_thumbnail(ThumbnailData& thumbnail_data, unsigned int w, unsigned int h, const ThumbnailsParams& thumbnail_params, const GLVolumeCollection& volumes, Camera::EType camera_type, bool use_top_view, bool for_picking) { - GLShaderProgram* shader = wxGetApp().get_shader("thumbnail_attr"); + GLShaderProgram* shader = wxGetApp().get_shader("thumbnail"); ModelObjectPtrs& model_objects = GUI::wxGetApp().model().objects; std::vector colors = ::get_extruders_colors(); switch (OpenGLManager::get_framebuffers_type()) @@ -5557,7 +5557,7 @@ void GLCanvas3D::render_thumbnail_internal(ThumbnailData& thumbnail_data, const camera.apply_projection(plate_build_volume); - //GLShaderProgram* shader = wxGetApp().get_shader("gouraud_light_attr"); + //GLShaderProgram* shader = wxGetApp().get_shader("gouraud_light"); if (!for_picking && (shader == nullptr)) { BOOST_LOG_TRIVIAL(info) << boost::format("render_thumbnail with no picking: shader is null, return directly"); return; @@ -6619,7 +6619,7 @@ void GLCanvas3D::_render_background() m_background.init_from(std::move(init_data)); } - GLShaderProgram* shader = wxGetApp().get_shader("background_attr"); + GLShaderProgram* shader = wxGetApp().get_shader("background"); if (shader != nullptr) { shader->start_using(); shader->set_uniform("top_color", use_error_color ? ERROR_BG_LIGHT_COLOR : DEFAULT_BG_LIGHT_COLOR); @@ -6742,7 +6742,7 @@ void GLCanvas3D::_render_objects(GLVolumeCollection::ERenderType type, bool with else m_volumes.set_show_sinking_contours(!m_gizmos.is_hiding_instances()); - GLShaderProgram* shader = wxGetApp().get_shader("gouraud_attr"); + GLShaderProgram* shader = wxGetApp().get_shader("gouraud"); ECanvasType canvas_type = this->m_canvas_type; if (shader != nullptr) { shader->start_using(); @@ -7170,7 +7170,7 @@ void GLCanvas3D::_render_style_editor() void GLCanvas3D::_render_volumes_for_picking() const { - GLShaderProgram* shader = wxGetApp().get_shader("flat_attr"); + GLShaderProgram* shader = wxGetApp().get_shader("flat"); if (shader == nullptr) return; @@ -8008,7 +8008,7 @@ void GLCanvas3D::_render_camera_target() } } - GLShaderProgram* shader = wxGetApp().get_shader("flat_attr"); + GLShaderProgram* shader = wxGetApp().get_shader("flat"); if (shader != nullptr) { shader->start_using(); const Camera& camera = wxGetApp().plater()->get_camera(); @@ -8127,7 +8127,7 @@ void GLCanvas3D::_render_sla_slices() } } - GLShaderProgram* shader = wxGetApp().get_shader("flat_attr"); + GLShaderProgram* shader = wxGetApp().get_shader("flat"); if (shader != nullptr) { shader->start_using(); diff --git a/src/slic3r/GUI/GLModel.cpp b/src/slic3r/GUI/GLModel.cpp index eaaf4b4bd38..9ef9f301f3c 100644 --- a/src/slic3r/GUI/GLModel.cpp +++ b/src/slic3r/GUI/GLModel.cpp @@ -575,21 +575,21 @@ void GLModel::render(const std::pair& range) if (position) { position_id = shader->get_attrib_location("v_position"); if (position_id != -1) { - glsafe(::glVertexAttribPointer(position_id, Geometry::position_stride_floats(data.format), GL_FLOAT, GL_FALSE, vertex_stride_bytes, (GLvoid*)Geometry::position_offset_bytes(data.format))); + glsafe(::glVertexAttribPointer(position_id, Geometry::position_stride_floats(data.format), GL_FLOAT, GL_FALSE, vertex_stride_bytes, (const void*)Geometry::position_offset_bytes(data.format))); glsafe(::glEnableVertexAttribArray(position_id)); } } if (normal) { normal_id = shader->get_attrib_location("v_normal"); if (normal_id != -1) { - glsafe(::glVertexAttribPointer(normal_id, Geometry::normal_stride_floats(data.format), GL_FLOAT, GL_FALSE, vertex_stride_bytes, (GLvoid*)Geometry::normal_offset_bytes(data.format))); + glsafe(::glVertexAttribPointer(normal_id, Geometry::normal_stride_floats(data.format), GL_FLOAT, GL_FALSE, vertex_stride_bytes, (const void*)Geometry::normal_offset_bytes(data.format))); glsafe(::glEnableVertexAttribArray(normal_id)); } } if (tex_coord) { tex_coord_id = shader->get_attrib_location("v_tex_coord"); if (tex_coord_id != -1) { - glsafe(::glVertexAttribPointer(tex_coord_id, Geometry::tex_coord_stride_floats(data.format), GL_FLOAT, GL_FALSE, vertex_stride_bytes, (GLvoid*)Geometry::tex_coord_offset_bytes(data.format))); + glsafe(::glVertexAttribPointer(tex_coord_id, Geometry::tex_coord_stride_floats(data.format), GL_FLOAT, GL_FALSE, vertex_stride_bytes, (const void*)Geometry::tex_coord_offset_bytes(data.format))); glsafe(::glEnableVertexAttribArray(tex_coord_id)); } } @@ -612,11 +612,11 @@ void GLModel::render(const std::pair& range) void GLModel::render_instanced(unsigned int instances_vbo, unsigned int instances_count) { - if (instances_vbo == 0) + if (instances_vbo == 0 || instances_count == 0) return; GLShaderProgram* shader = wxGetApp().get_current_shader(); - if (shader == nullptr || !boost::algorithm::iends_with(shader->get_name(), "_instanced_attr")) + if (shader == nullptr || !boost::algorithm::iends_with(shader->get_name(), "_instanced")) return; // vertex attributes @@ -637,11 +637,12 @@ void GLModel::render_instanced(unsigned int instances_vbo, unsigned int instance } glsafe(::glBindBuffer(GL_ARRAY_BUFFER, instances_vbo)); - glsafe(::glVertexAttribPointer(offset_id, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (GLvoid*)0)); + const size_t instance_stride = 5 * sizeof(float); + glsafe(::glVertexAttribPointer(offset_id, 3, GL_FLOAT, GL_FALSE, instance_stride, (const void*)0)); glsafe(::glEnableVertexAttribArray(offset_id)); glsafe(::glVertexAttribDivisor(offset_id, 1)); - glsafe(::glVertexAttribPointer(scales_id, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (GLvoid*)(3 * sizeof(float)))); + glsafe(::glVertexAttribPointer(scales_id, 2, GL_FLOAT, GL_FALSE, instance_stride, (const void*)(3 * sizeof(float)))); glsafe(::glEnableVertexAttribArray(scales_id)); glsafe(::glVertexAttribDivisor(scales_id, 1)); @@ -650,8 +651,6 @@ void GLModel::render_instanced(unsigned int instances_vbo, unsigned int instance const GLenum mode = get_primitive_mode(data.format); const GLenum index_type = get_index_type(data); - shader->set_uniform("uniform_color", data.color); - const size_t vertex_stride_bytes = Geometry::vertex_stride_bytes(data.format); const bool position = Geometry::has_position(data.format); const bool normal = Geometry::has_normal(data.format); @@ -659,15 +658,17 @@ void GLModel::render_instanced(unsigned int instances_vbo, unsigned int instance glsafe(::glBindBuffer(GL_ARRAY_BUFFER, m_render_data.vbo_id)); if (position) { - glsafe(::glVertexAttribPointer(position_id, Geometry::position_stride_floats(data.format), GL_FLOAT, GL_FALSE, vertex_stride_bytes, (GLvoid*)Geometry::position_offset_bytes(data.format))); + glsafe(::glVertexAttribPointer(position_id, Geometry::position_stride_floats(data.format), GL_FLOAT, GL_FALSE, vertex_stride_bytes, (const void*)Geometry::position_offset_bytes(data.format))); glsafe(::glEnableVertexAttribArray(position_id)); } if (normal) { - glsafe(::glVertexAttribPointer(normal_id, Geometry::normal_stride_floats(data.format), GL_FLOAT, GL_FALSE, vertex_stride_bytes, (GLvoid*)Geometry::normal_offset_bytes(data.format))); + glsafe(::glVertexAttribPointer(normal_id, Geometry::normal_stride_floats(data.format), GL_FLOAT, GL_FALSE, vertex_stride_bytes, (const void*)Geometry::normal_offset_bytes(data.format))); glsafe(::glEnableVertexAttribArray(normal_id)); } + shader->set_uniform("uniform_color", data.color); + glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_render_data.ibo_id)); glsafe(::glDrawElementsInstanced(mode, indices_count(), index_type, (const void*)0, instances_count)); glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0)); diff --git a/src/slic3r/GUI/GLSelectionRectangle.cpp b/src/slic3r/GUI/GLSelectionRectangle.cpp index 3f0e7cf66bb..ecced3c5644 100644 --- a/src/slic3r/GUI/GLSelectionRectangle.cpp +++ b/src/slic3r/GUI/GLSelectionRectangle.cpp @@ -95,7 +95,7 @@ namespace GUI { glsafe(::glLineStipple(4, 0xAAAA)); glsafe(::glEnable(GL_LINE_STIPPLE)); - GLShaderProgram* shader = wxGetApp().get_shader("flat_attr"); + GLShaderProgram* shader = wxGetApp().get_shader("flat"); if (shader != nullptr) { shader->start_using(); diff --git a/src/slic3r/GUI/GLShadersManager.cpp b/src/slic3r/GUI/GLShadersManager.cpp index 1a03c3f8677..3c874526be1 100644 --- a/src/slic3r/GUI/GLShadersManager.cpp +++ b/src/slic3r/GUI/GLShadersManager.cpp @@ -33,46 +33,36 @@ std::pair GLShadersManager::init() bool valid = true; + const std::string prefix = GUI::wxGetApp().is_gl_version_greater_or_equal_to(3, 1) ? "140/" : "110/"; // imgui shader - valid &= append_shader("imgui", { "imgui.vs", "imgui.fs" }); + valid &= append_shader("imgui", { prefix + "imgui.vs", prefix + "imgui.fs" }); // basic shader, used to render all what was previously rendered using the immediate mode - valid &= append_shader("flat_attr", { "flat_attr.vs", "flat.fs" }); + valid &= append_shader("flat", { prefix + "flat.vs", prefix + "flat.fs" }); // basic shader for textures, used to render textures - valid &= append_shader("flat_texture_attr", { "flat_texture_attr.vs", "flat_texture.fs" }); + valid &= append_shader("flat_texture", { prefix + "flat_texture.vs", prefix + "flat_texture.fs" }); // used to render 3D scene background - valid &= append_shader("background_attr", { "background_attr.vs", "background.fs" }); + valid &= append_shader("background", { prefix + "background.vs", prefix + "background.fs" }); // used to render bed axes and model, selection hints, gcode sequential view marker model, preview shells, options in gcode preview - valid &= append_shader("gouraud_light_attr", { "gouraud_light_attr.vs", "gouraud_light.fs" }); + valid &= append_shader("gouraud_light", { prefix + "gouraud_light.vs", prefix + "gouraud_light.fs" }); //used to render thumbnail - valid &= append_shader("thumbnail_attr", {"thumbnail_attr.vs", "thumbnail.fs"}); - valid &= append_shader("thumbnail", {"thumbnail.vs", "thumbnail.fs"}); + valid &= append_shader("thumbnail", { prefix + "thumbnail.vs", prefix + "thumbnail.fs"}); // used to render printbed - valid &= append_shader("printbed_attr", { "printbed_attr.vs", "printbed.fs" }); + valid &= append_shader("printbed", { prefix + "printbed.vs", prefix + "printbed.fs" }); // used to render options in gcode preview if (GUI::wxGetApp().is_gl_version_greater_or_equal_to(3, 3)) { - valid &= append_shader("gouraud_light_instanced_attr", { "gouraud_light_instanced_attr.vs", "gouraud_light_instanced.fs" }); + valid &= append_shader("gouraud_light_instanced", { prefix + "gouraud_light_instanced.vs", prefix + "gouraud_light_instanced.fs" }); } // used to render objects in 3d editor - //if (GUI::wxGetApp().is_gl_version_greater_or_equal_to(3, 0)) { - if (0) { - valid &= append_shader("gouraud", { "gouraud_130.vs", "gouraud_130.fs" } -#if ENABLE_ENVIRONMENT_MAP - , { "ENABLE_ENVIRONMENT_MAP"sv } -#endif // ENABLE_ENVIRONMENT_MAP - ); - } - else { - valid &= append_shader("gouraud_attr", { "gouraud_attr.vs", "gouraud.fs" } + valid &= append_shader("gouraud", { prefix + "gouraud.vs", prefix + "gouraud.fs" } #if ENABLE_ENVIRONMENT_MAP , { "ENABLE_ENVIRONMENT_MAP"sv } #endif // ENABLE_ENVIRONMENT_MAP ); - } // used to render variable layers heights in 3d editor - valid &= append_shader("variable_layer_height_attr", { "variable_layer_height_attr.vs", "variable_layer_height.fs" }); + valid &= append_shader("variable_layer_height", { prefix + "variable_layer_height.vs", prefix + "variable_layer_height.fs" }); // used to render highlight contour around selected triangles inside the multi-material gizmo - valid &= append_shader("mm_contour_attr", { "mm_contour_attr.vs", "mm_contour_attr.fs" }); + valid &= append_shader("mm_contour", { prefix + "mm_contour.vs", prefix + "mm_contour.fs" }); // Used to render painted triangles inside the multi-material gizmo. Triangle normals are computed inside fragment shader. // For Apple's on Arm CPU computed triangle normals inside fragment shader using dFdx and dFdy has the opposite direction. // Because of this, objects had darker colors inside the multi-material gizmo. @@ -80,12 +70,9 @@ std::pair GLShadersManager::init() // Since macOS 12 (Monterey), this issue with the opposite direction on Apple's Arm CPU seems to be fixed, and computed // triangle normals inside fragment shader have the right direction. if (platform_flavor() == PlatformFlavor::OSXOnArm && wxPlatformInfo::Get().GetOSMajorVersion() < 12) - valid &= append_shader("mm_gouraud_attr", { "mm_gouraud_attr.vs", "mm_gouraud_attr.fs" }, { "FLIP_TRIANGLE_NORMALS"sv }); + valid &= append_shader("mm_gouraud", { prefix + "mm_gouraud.vs", prefix + "mm_gouraud.fs" }, { "FLIP_TRIANGLE_NORMALS"sv }); else - valid &= append_shader("mm_gouraud_attr", { "mm_gouraud_attr.vs", "mm_gouraud_attr.fs" }); - - //BBS: add shader for outline - valid &= append_shader("outline", { "outline.vs", "outline.fs" }); + valid &= append_shader("mm_gouraud", { prefix + "mm_gouraud.vs", prefix + "mm_gouraud.fs" }); return { valid, error }; } diff --git a/src/slic3r/GUI/GLTexture.cpp b/src/slic3r/GUI/GLTexture.cpp index 041653a6c47..d71110973b0 100644 --- a/src/slic3r/GUI/GLTexture.cpp +++ b/src/slic3r/GUI/GLTexture.cpp @@ -680,7 +680,7 @@ void GLTexture::render_sub_texture(unsigned int tex_id, float left, float right, GLModel model; model.init_from(std::move(init_data)); - GLShaderProgram* shader = wxGetApp().get_shader("flat_texture_attr"); + GLShaderProgram* shader = wxGetApp().get_shader("flat_texture"); if (shader != nullptr) { shader->start_using(); shader->set_uniform("view_model_matrix", Transform3d::Identity()); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoAdvancedCut.cpp b/src/slic3r/GUI/Gizmos/GLGizmoAdvancedCut.cpp index fc132f57bc8..2c67d8889cc 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoAdvancedCut.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoAdvancedCut.cpp @@ -500,7 +500,7 @@ void GLGizmoAdvancedCut::on_render_for_picking() #endif m_move_grabber.color = picking_color_component(0); - GLShaderProgram *shader = wxGetApp().get_shader("flat_attr"); + GLShaderProgram *shader = wxGetApp().get_shader("flat"); if (shader != nullptr) { shader->start_using(); const Camera &camera = wxGetApp().plater()->get_camera(); @@ -866,7 +866,7 @@ void GLGizmoAdvancedCut::render_cut_plane_and_grabbers() glsafe(::glEnable(GL_BLEND)); glsafe(::glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)); - GLShaderProgram *shader = wxGetApp().get_shader("flat_attr"); + GLShaderProgram *shader = wxGetApp().get_shader("flat"); if (shader != nullptr) { shader->start_using(); @@ -934,7 +934,7 @@ void GLGizmoAdvancedCut::render_cut_plane_and_grabbers() } { - GLShaderProgram *shader = wxGetApp().get_shader("gouraud_light_attr"); + GLShaderProgram *shader = wxGetApp().get_shader("gouraud_light"); if (shader == nullptr) return; shader->start_using(); @@ -1069,9 +1069,9 @@ void GLGizmoAdvancedCut::render_connector_model(GLModel &model, const ColorRGBA { GLShaderProgram *shader = nullptr; if (for_picking) - shader = wxGetApp().get_shader("flat_attr"); + shader = wxGetApp().get_shader("flat"); else - shader = wxGetApp().get_shader("gouraud_light_attr"); + shader = wxGetApp().get_shader("gouraud_light"); if (shader) { shader->start_using(); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoBase.cpp b/src/slic3r/GUI/Gizmos/GLGizmoBase.cpp index 5dc0cc38e74..961ec5104dd 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoBase.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoBase.cpp @@ -262,7 +262,7 @@ void GLGizmoBase::render_grabbers(const BoundingBoxf3& box) const void GLGizmoBase::render_grabbers(float size) const { - GLShaderProgram* shader = wxGetApp().get_shader("gouraud_light_attr"); + GLShaderProgram* shader = wxGetApp().get_shader("gouraud_light"); if (shader == nullptr) return; shader->start_using(); @@ -276,7 +276,7 @@ void GLGizmoBase::render_grabbers(float size) const void GLGizmoBase::render_grabbers_for_picking(const BoundingBoxf3& box) const { - GLShaderProgram* shader = wxGetApp().get_shader("flat_attr"); + GLShaderProgram* shader = wxGetApp().get_shader("flat"); if (shader != nullptr) { shader->start_using(); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp b/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp index 6aa834ad963..37d8615cd3a 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp @@ -155,7 +155,7 @@ bool GLGizmoFdmSupports::on_key_down_select_tool_type(int keyCode) { void GLGizmoFdmSupports::render_triangles(const Selection& selection) const { ClippingPlaneDataWrapper clp_data = this->get_clipping_plane_data(); - auto* shader = wxGetApp().get_shader("mm_gouraud_attr"); + auto* shader = wxGetApp().get_shader("mm_gouraud"); if (!shader) return; shader->start_using(); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoFlatten.cpp b/src/slic3r/GUI/Gizmos/GLGizmoFlatten.cpp index c47e1225d82..da87aa1e888 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoFlatten.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoFlatten.cpp @@ -64,7 +64,7 @@ void GLGizmoFlatten::on_render() { const Selection& selection = m_parent.get_selection(); - GLShaderProgram* shader = wxGetApp().get_shader("flat_attr"); + GLShaderProgram* shader = wxGetApp().get_shader("flat"); if (shader == nullptr) return; @@ -98,7 +98,7 @@ void GLGizmoFlatten::on_render() void GLGizmoFlatten::on_render_for_picking() { const Selection& selection = m_parent.get_selection(); - GLShaderProgram* shader = wxGetApp().get_shader("flat_attr"); + GLShaderProgram* shader = wxGetApp().get_shader("flat"); if (shader == nullptr) return; diff --git a/src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp b/src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp index 59026be85eb..41a5aed7e4a 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp @@ -103,7 +103,7 @@ void GLGizmoHollow::on_render_for_picking() void GLGizmoHollow::render_points(const Selection& selection, bool picking) { - GLShaderProgram* shader = picking ? wxGetApp().get_shader("flat_attr") : wxGetApp().get_shader("gouraud_light_attr"); + GLShaderProgram* shader = picking ? wxGetApp().get_shader("flat") : wxGetApp().get_shader("gouraud_light"); if (shader == nullptr) return; diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp index 1313b33bd24..8fba22870ec 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp @@ -192,7 +192,7 @@ void GLGizmoMmuSegmentation::set_painter_gizmo_data(const Selection &selection) void GLGizmoMmuSegmentation::render_triangles(const Selection &selection) const { ClippingPlaneDataWrapper clp_data = this->get_clipping_plane_data(); - auto* shader = wxGetApp().get_shader("mm_gouraud_attr"); + auto* shader = wxGetApp().get_shader("mm_gouraud"); if (!shader) return; shader->start_using(); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMove.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMove.cpp index ebdf6ec390a..cdf9662cc43 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMove.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMove.cpp @@ -162,7 +162,7 @@ void GLGizmoMove3D::on_render() } }; - GLShaderProgram* shader = wxGetApp().get_shader("flat_attr"); + GLShaderProgram* shader = wxGetApp().get_shader("flat"); if (shader != nullptr) { shader->start_using(); const Camera& camera = wxGetApp().plater()->get_camera(); @@ -256,7 +256,7 @@ void GLGizmoMove3D::render_grabber_extension(Axis axis, const BoundingBoxf3& box } } - GLShaderProgram* shader = wxGetApp().get_shader(picking ? "flat_attr" : "gouraud_light_attr"); + GLShaderProgram* shader = wxGetApp().get_shader(picking ? "flat" : "gouraud_light"); if (shader == nullptr) return; diff --git a/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp b/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp index 296506cad66..2afcb119bf4 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp @@ -75,7 +75,7 @@ GLGizmoPainterBase::ClippingPlaneDataWrapper GLGizmoPainterBase::get_clipping_pl void GLGizmoPainterBase::render_triangles(const Selection& selection) const { - auto* shader = wxGetApp().get_shader("gouraud_attr"); + auto* shader = wxGetApp().get_shader("gouraud"); if (! shader) return; shader->start_using(); @@ -219,7 +219,7 @@ void GLGizmoPainterBase::render_cursor_circle() m_circle.set_color(render_color); - GLShaderProgram* shader = wxGetApp().get_shader("flat_attr"); + GLShaderProgram* shader = wxGetApp().get_shader("flat"); if (shader != nullptr) { shader->start_using(); shader->set_uniform("view_model_matrix", Transform3d::Identity()); @@ -240,7 +240,7 @@ void GLGizmoPainterBase::render_cursor_sphere(const Transform3d& trafo) const s_sphere->init_from(its_make_sphere(1.0, double(PI) / 12.0)); } - GLShaderProgram* shader = wxGetApp().get_shader("flat_attr"); + GLShaderProgram* shader = wxGetApp().get_shader("flat"); if (shader == nullptr) return; @@ -278,7 +278,7 @@ void GLGizmoPainterBase::render_cursor_sphere(const Transform3d& trafo) const // BBS void GLGizmoPainterBase::render_cursor_height_range(const Transform3d& trafo) const { - GLShaderProgram *shader = wxGetApp().get_shader("flat_attr"); + GLShaderProgram *shader = wxGetApp().get_shader("flat"); if (shader == nullptr) return; @@ -1070,7 +1070,7 @@ void TriangleSelectorGUI::render(ImGuiWrapper* imgui, const Transform3d& matrix) auto* shader = wxGetApp().get_current_shader(); if (! shader) return; - assert(shader->get_name() == "gouraud_attr" || shader->get_name() == "mm_gouraud_attr"); + assert(shader->get_name() == "gouraud" || shader->get_name() == "mm_gouraud"); ScopeGuard guard([shader]() { if (shader) shader->set_uniform("offset_depth_buffer", false);}); shader->set_uniform("offset_depth_buffer", true); for (auto iva : {std::make_pair(&m_iva_enforcers, enforcers_color), @@ -1178,7 +1178,7 @@ void TriangleSelectorPatch::render(ImGuiWrapper* imgui, const Transform3d& matri auto* shader = wxGetApp().get_current_shader(); if (!shader) return; - assert(shader->get_name() == "gouraud_attr" || shader->get_name() == "mm_gouraud_attr"); + assert(shader->get_name() == "gouraud" || shader->get_name() == "mm_gouraud"); for (size_t buffer_idx = 0; buffer_idx < m_triangle_patches.size(); ++buffer_idx) { if (this->has_VBOs(buffer_idx)) { @@ -1604,7 +1604,7 @@ void TriangleSelectorGUI::render_debug(ImGuiWrapper* imgui) if (curr_shader != nullptr) curr_shader->stop_using(); - GLShaderProgram* shader = wxGetApp().get_shader("flat_attr"); + GLShaderProgram* shader = wxGetApp().get_shader("flat"); if (shader != nullptr) { shader->start_using(); @@ -1661,7 +1661,7 @@ void TriangleSelectorGUI::render_paint_contour(const Transform3d& matrix) if (curr_shader != nullptr) curr_shader->stop_using(); - auto* contour_shader = wxGetApp().get_shader("mm_contour_attr"); + auto* contour_shader = wxGetApp().get_shader("mm_contour"); if (contour_shader != nullptr) { contour_shader->start_using(); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp b/src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp index 7924fea1898..4e974e77e84 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp @@ -129,7 +129,7 @@ void GLGizmoRotate::on_render() m_grabbers.front().matrix = local_transform(selection); glsafe(::glLineWidth((m_hover_id != -1) ? 2.0f : 1.5f)); - GLShaderProgram* shader = wxGetApp().get_shader("flat_attr"); + GLShaderProgram* shader = wxGetApp().get_shader("flat"); if (shader != nullptr) { shader->start_using(); @@ -400,7 +400,7 @@ void GLGizmoRotate::render_grabber_extension(const BoundingBoxf3& box, bool pick if (!picking && m_hover_id != -1) color = m_grabbers.front().hover_color; - GLShaderProgram* shader = wxGetApp().get_shader(picking ? "flat_attr" : "gouraud_light_attr"); + GLShaderProgram* shader = wxGetApp().get_shader(picking ? "flat" : "gouraud_light"); if (shader == nullptr) return; diff --git a/src/slic3r/GUI/Gizmos/GLGizmoScale.cpp b/src/slic3r/GUI/Gizmos/GLGizmoScale.cpp index aa3abff9bc0..61f40a3e0ff 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoScale.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoScale.cpp @@ -234,7 +234,7 @@ void GLGizmoScale3D::on_render() const float grabber_mean_size = (float)((selection_box.size().x() + selection_box.size().y() + selection_box.size().z()) / 3.0); //draw connections - GLShaderProgram* shader = wxGetApp().get_shader("flat_attr"); + GLShaderProgram* shader = wxGetApp().get_shader("flat"); if (shader != nullptr) { shader->start_using(); // BBS: when select multiple objects, uniform scale can be deselected, display the connection(4,5) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSeam.cpp b/src/slic3r/GUI/Gizmos/GLGizmoSeam.cpp index 57019b951dc..7aefc0364a7 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSeam.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSeam.cpp @@ -98,7 +98,7 @@ bool GLGizmoSeam::on_key_down_select_tool_type(int keyCode) { void GLGizmoSeam::render_triangles(const Selection& selection) const { ClippingPlaneDataWrapper clp_data = this->get_clipping_plane_data(); - auto* shader = wxGetApp().get_shader("mm_gouraud_attr"); + auto* shader = wxGetApp().get_shader("mm_gouraud"); if (!shader) return; shader->start_using(); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSimplify.cpp b/src/slic3r/GUI/Gizmos/GLGizmoSimplify.cpp index 3beb4f0a989..951cd43657e 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSimplify.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSimplify.cpp @@ -641,7 +641,7 @@ void GLGizmoSimplify::on_render() return; const Transform3d trafo_matrix = selected_volume->world_matrix(); - auto* gouraud_shader = wxGetApp().get_shader("gouraud_light_attr"); + auto* gouraud_shader = wxGetApp().get_shader("gouraud_light"); glsafe(::glPushAttrib(GL_DEPTH_TEST)); glsafe(::glEnable(GL_DEPTH_TEST)); gouraud_shader->start_using(); @@ -654,7 +654,7 @@ void GLGizmoSimplify::on_render() gouraud_shader->stop_using(); if (m_show_wireframe) { - auto* contour_shader = wxGetApp().get_shader("mm_contour_attr"); + auto* contour_shader = wxGetApp().get_shader("mm_contour"); contour_shader->start_using(); contour_shader->set_uniform("view_model_matrix", view_model_matrix); contour_shader->set_uniform("projection_matrix", camera.get_projection_matrix()); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp index 820c6769037..91b429c00ef 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp @@ -127,7 +127,7 @@ void GLGizmoSlaSupports::render_points(const Selection& selection, bool picking) if (! has_points && ! has_holes) return; - GLShaderProgram* shader = picking ? wxGetApp().get_shader("flat_attr") : wxGetApp().get_shader("gouraud_light_attr"); + GLShaderProgram* shader = picking ? wxGetApp().get_shader("flat") : wxGetApp().get_shader("gouraud_light"); if (shader == nullptr) return; diff --git a/src/slic3r/GUI/Gizmos/GLGizmoText.cpp b/src/slic3r/GUI/Gizmos/GLGizmoText.cpp index 6d31534d4ab..6001af544fd 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoText.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoText.cpp @@ -448,7 +448,7 @@ void GLGizmoText::on_render() ColorRGBA color = picking_color_component(0); m_grabbers[0].color = color; - GLShaderProgram *shader = wxGetApp().get_shader("gouraud_light_attr"); + GLShaderProgram *shader = wxGetApp().get_shader("gouraud_light"); if (shader != nullptr) { shader->start_using(); m_grabbers[0].render_for_picking(mean_size); @@ -500,7 +500,7 @@ void GLGizmoText::on_render_for_picking() ColorRGBA color = picking_color_component(0); m_grabbers[0].color = color; - GLShaderProgram *shader = wxGetApp().get_shader("flat_attr"); + GLShaderProgram *shader = wxGetApp().get_shader("flat"); if (shader != nullptr) { shader->start_using(); m_grabbers[0].render_for_picking(mean_size); diff --git a/src/slic3r/GUI/ImGuiWrapper.cpp b/src/slic3r/GUI/ImGuiWrapper.cpp index 22606d1e902..037ba161dd0 100644 --- a/src/slic3r/GUI/ImGuiWrapper.cpp +++ b/src/slic3r/GUI/ImGuiWrapper.cpp @@ -2411,10 +2411,10 @@ void ImGuiWrapper::render_draw_data(ImDrawData *draw_data) // We are using the OpenGL fixed pipeline to make the example code simpler to read! // Setup render state: alpha-blending enabled, no face culling, no depth testing, scissor enabled, vertex/texcoord/color pointers, polygon fill. - GLint last_texture; glsafe(::glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture)); - GLint last_polygon_mode[2]; glsafe(::glGetIntegerv(GL_POLYGON_MODE, last_polygon_mode)); - GLint last_viewport[4]; glsafe(::glGetIntegerv(GL_VIEWPORT, last_viewport)); - GLint last_scissor_box[4]; glsafe(::glGetIntegerv(GL_SCISSOR_BOX, last_scissor_box)); + GLint last_texture; glsafe(::glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture)); + GLint last_polygon_mode[2]; glsafe(::glGetIntegerv(GL_POLYGON_MODE, last_polygon_mode)); + GLint last_viewport[4]; glsafe(::glGetIntegerv(GL_VIEWPORT, last_viewport)); + GLint last_scissor_box[4]; glsafe(::glGetIntegerv(GL_SCISSOR_BOX, last_scissor_box)); GLint last_texture_env_mode; glsafe(::glGetTexEnviv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, &last_texture_env_mode)); glsafe(::glPushAttrib(GL_ENABLE_BIT | GL_COLOR_BUFFER_BIT | GL_TRANSFORM_BIT)); glsafe(::glEnable(GL_BLEND)); @@ -2468,17 +2468,17 @@ void ImGuiWrapper::render_draw_data(ImDrawData *draw_data) const int position_id = shader->get_attrib_location("Position"); if (position_id != -1) { - glsafe(::glVertexAttribPointer(position_id, 2, GL_FLOAT, GL_FALSE, sizeof(ImDrawVert), (GLvoid*)IM_OFFSETOF(ImDrawVert, pos))); + glsafe(::glVertexAttribPointer(position_id, 2, GL_FLOAT, GL_FALSE, sizeof(ImDrawVert), (const void*)IM_OFFSETOF(ImDrawVert, pos))); glsafe(::glEnableVertexAttribArray(position_id)); } const int uv_id = shader->get_attrib_location("UV"); if (uv_id != -1) { - glsafe(::glVertexAttribPointer(uv_id, 2, GL_FLOAT, GL_FALSE, sizeof(ImDrawVert), (GLvoid*)IM_OFFSETOF(ImDrawVert, uv))); + glsafe(::glVertexAttribPointer(uv_id, 2, GL_FLOAT, GL_FALSE, sizeof(ImDrawVert), (const void*)IM_OFFSETOF(ImDrawVert, uv))); glsafe(::glEnableVertexAttribArray(uv_id)); } const int color_id = shader->get_attrib_location("Color"); if (color_id != -1) { - glsafe(::glVertexAttribPointer(color_id, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(ImDrawVert), (GLvoid*)IM_OFFSETOF(ImDrawVert, col))); + glsafe(::glVertexAttribPointer(color_id, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(ImDrawVert), (const void*)IM_OFFSETOF(ImDrawVert, col))); glsafe(::glEnableVertexAttribArray(color_id)); } @@ -2521,10 +2521,13 @@ void ImGuiWrapper::render_draw_data(ImDrawData *draw_data) glsafe(::glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, last_texture_env_mode)); glsafe(::glBindTexture(GL_TEXTURE_2D, (GLuint)last_texture)); glsafe(::glPopAttrib()); - glsafe(::glPolygonMode(GL_FRONT, (GLenum)last_polygon_mode[0]); glPolygonMode(GL_BACK, (GLenum)last_polygon_mode[1])); + glsafe(::glPolygonMode(GL_FRONT, (GLenum)last_polygon_mode[0]); + glsafe(::glPolygonMode(GL_BACK, (GLenum)last_polygon_mode[1]))); glsafe(::glViewport(last_viewport[0], last_viewport[1], (GLsizei)last_viewport[2], (GLsizei)last_viewport[3])); glsafe(::glScissor(last_scissor_box[0], last_scissor_box[1], (GLsizei)last_scissor_box[2], (GLsizei)last_scissor_box[3])); + shader->stop_using(); + if (curr_shader != nullptr) curr_shader->start_using(); } diff --git a/src/slic3r/GUI/MeshUtils.cpp b/src/slic3r/GUI/MeshUtils.cpp index be30f4c732e..eaf0df314d2 100644 --- a/src/slic3r/GUI/MeshUtils.cpp +++ b/src/slic3r/GUI/MeshUtils.cpp @@ -81,7 +81,7 @@ void MeshClipper::render_cut(const ColorRGBA& color) if (curr_shader != nullptr) curr_shader->stop_using(); - GLShaderProgram* shader = wxGetApp().get_shader("flat_attr"); + GLShaderProgram* shader = wxGetApp().get_shader("flat"); if (shader != nullptr) { shader->start_using(); const Camera& camera = wxGetApp().plater()->get_camera(); diff --git a/src/slic3r/GUI/PartPlate.cpp b/src/slic3r/GUI/PartPlate.cpp index ced8d15c59f..ba41d160aed 100644 --- a/src/slic3r/GUI/PartPlate.cpp +++ b/src/slic3r/GUI/PartPlate.cpp @@ -577,7 +577,7 @@ void PartPlate::render_logo_texture(GLTexture &logo_texture, GLModel& logo_buffe } if (logo_buffer.is_initialized()) { - GLShaderProgram* shader = wxGetApp().get_shader("printbed_attr"); + GLShaderProgram* shader = wxGetApp().get_shader("printbed"); if (shader != nullptr) { shader->start_using(); const Camera &camera = wxGetApp().plater()->get_camera(); @@ -849,7 +849,7 @@ void PartPlate::show_tooltip(const std::string tooltip) void PartPlate::render_icons(bool bottom, bool only_name, int hover_id) { - GLShaderProgram* shader = wxGetApp().get_shader("printbed_attr"); + GLShaderProgram* shader = wxGetApp().get_shader("printbed"); if (shader != nullptr) { shader->start_using(); const Camera &camera = wxGetApp().plater()->get_camera(); @@ -940,7 +940,7 @@ void PartPlate::render_icons(bool bottom, bool only_name, int hover_id) void PartPlate::render_only_numbers(bool bottom) { - GLShaderProgram* shader = wxGetApp().get_shader("printbed_attr"); + GLShaderProgram* shader = wxGetApp().get_shader("printbed"); if (shader != nullptr) { shader->start_using(); const Camera &camera = wxGetApp().plater()->get_camera(); @@ -973,7 +973,7 @@ void PartPlate::render_only_numbers(bool bottom) void PartPlate::render_rectangle_for_picking(const Transform3d &view_matrix, const Transform3d &projection_matrix, GLModel &buffer, const ColorRGBA render_color) { - GLShaderProgram *shader = wxGetApp().get_shader("flat_attr"); + GLShaderProgram *shader = wxGetApp().get_shader("flat"); if (shader != nullptr) { shader->start_using(); @@ -2502,7 +2502,7 @@ void PartPlate::render(const Transform3d& view_matrix, const Transform3d& projec { glsafe(::glEnable(GL_DEPTH_TEST)); - GLShaderProgram *shader = wxGetApp().get_shader("flat_attr"); + GLShaderProgram *shader = wxGetApp().get_shader("flat"); if (shader != nullptr) { shader->start_using(); glsafe(::glEnable(GL_BLEND)); diff --git a/src/slic3r/GUI/Selection.cpp b/src/slic3r/GUI/Selection.cpp index 455616e3f2b..f0a2893ece9 100644 --- a/src/slic3r/GUI/Selection.cpp +++ b/src/slic3r/GUI/Selection.cpp @@ -1570,7 +1570,7 @@ void Selection::render_center(bool gizmo_is_dragging) if (!m_valid || is_empty()) return; - GLShaderProgram* shader = wxGetApp().get_shader("flat_attr"); + GLShaderProgram* shader = wxGetApp().get_shader("flat"); if (shader == nullptr) return; @@ -1600,7 +1600,7 @@ void Selection::render_sidebar_hints(const std::string& sidebar_field, bool unif if (sidebar_field.empty()) return; - GLShaderProgram* shader = wxGetApp().get_shader(boost::starts_with(sidebar_field, "layer") ? "flat_attr" : "gouraud_light_attr"); + GLShaderProgram* shader = wxGetApp().get_shader(boost::starts_with(sidebar_field, "layer") ? "flat" : "gouraud_light"); if (shader == nullptr) return; @@ -2231,7 +2231,7 @@ void Selection::render_bounding_box(const BoundingBoxf3& box, const ColorRGB& co glsafe(::glLineWidth(2.0f * m_scale_factor)); - GLShaderProgram* shader = wxGetApp().get_shader("flat_attr"); + GLShaderProgram* shader = wxGetApp().get_shader("flat"); if (shader == nullptr) return; diff --git a/src/slic3r/Utils/CalibUtils.cpp b/src/slic3r/Utils/CalibUtils.cpp index 9530a4eb7d6..a496d1ff34a 100644 --- a/src/slic3r/Utils/CalibUtils.cpp +++ b/src/slic3r/Utils/CalibUtils.cpp @@ -917,7 +917,7 @@ void CalibUtils::process_and_store_3mf(Model *model, const DynamicPrintConfig &f ThumbnailData* thumbnail_data = &plate_data_list[0]->plate_thumbnail; unsigned int thumbnail_width = 512, thumbnail_height = 512; const ThumbnailsParams thumbnail_params = {{}, false, true, true, true, 0}; - GLShaderProgram* shader = wxGetApp().get_shader("thumbnail_attr"); + GLShaderProgram* shader = wxGetApp().get_shader("thumbnail"); for (unsigned int obj_idx = 0; obj_idx < (unsigned int)model->objects.size(); ++ obj_idx) { const ModelObject &model_object = *model->objects[obj_idx]; From 59b7c52862e933b375a8ed46cdb0151a1a779daa Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Fri, 27 Oct 2023 11:03:15 +0800 Subject: [PATCH 48/99] Tech ENABLE_LEGACY_OPENGL_REMOVAL - Calculation of camera projection matrix (cherry picked from commit prusa3d/PrusaSlicer@a0630420d9ed417a8848718702a6b01cc3c1975f) --- src/slic3r/GUI/Camera.cpp | 58 ++++++++++++++++------------------ src/slic3r/GUI/Camera.hpp | 1 - src/slic3r/GUI/GCodeViewer.cpp | 1 - src/slic3r/GUI/GLCanvas3D.cpp | 7 ---- 4 files changed, 27 insertions(+), 40 deletions(-) diff --git a/src/slic3r/GUI/Camera.cpp b/src/slic3r/GUI/Camera.cpp index cebd49ce75b..420ac15c9ea 100644 --- a/src/slic3r/GUI/Camera.cpp +++ b/src/slic3r/GUI/Camera.cpp @@ -121,14 +121,7 @@ double Camera::get_fov() const void Camera::apply_viewport(int x, int y, unsigned int w, unsigned int h) { glsafe(::glViewport(0, 0, w, h)); - glsafe(::glGetIntegerv(GL_VIEWPORT, m_viewport.data())); -} - -void Camera::apply_view_matrix() -{ - glsafe(::glMatrixMode(GL_MODELVIEW)); - glsafe(::glLoadIdentity()); - glsafe(::glMultMatrixd(m_view_matrix.data())); + m_viewport = { 0, 0, int(w), int(h) }; } void Camera::apply_projection(const BoundingBoxf3& box, double near_z, double far_z) @@ -136,11 +129,7 @@ void Camera::apply_projection(const BoundingBoxf3& box, double near_z, double fa double w = 0.0; double h = 0.0; - const double old_distance = m_distance; m_frustrum_zs = calc_tight_frustrum_zs_around(box); - if (m_distance != old_distance) - // the camera has been moved re-apply view matrix - apply_view_matrix(); if (near_z > 0.0) m_frustrum_zs.first = std::max(std::min(m_frustrum_zs.first, near_z), FrustrumMinNearZ); @@ -174,26 +163,33 @@ void Camera::apply_projection(const BoundingBoxf3& box, double near_z, double fa } } - glsafe(::glMatrixMode(GL_PROJECTION)); - glsafe(::glLoadIdentity()); - switch (m_type) { default: case EType::Ortho: { - glsafe(::glOrtho(-w, w, -h, h, m_frustrum_zs.first, m_frustrum_zs.second)); + const double dz = m_frustrum_zs.second - m_frustrum_zs.first; + const double zz = m_frustrum_zs.first + m_frustrum_zs.second; + m_projection_matrix.matrix() << 1.0 / w, 0.0, 0.0, 0.0, + 0.0, 1.0 / h, 0.0, 0.0, + 0.0, 0.0, -2.0 / dz, -zz / dz, + 0.0, 0.0, 0.0, 1.0; break; } case EType::Perspective: { - glsafe(::glFrustum(-w, w, -h, h, m_frustrum_zs.first, m_frustrum_zs.second)); + const double n = m_frustrum_zs.first; + const double f = m_frustrum_zs.second; + const double dz = f - n; + const double zz = n + f; + const double fn = n * f; + m_projection_matrix.matrix() << n / w, 0.0, 0.0, 0.0, + 0.0, n / h, 0.0, 0.0, + 0.0, 0.0, -zz / dz, -2.0 * fn / dz, + 0.0, 0.0, -1.0, 0.0; break; } } - - glsafe(::glGetDoublev(GL_PROJECTION_MATRIX, m_projection_matrix.data())); - glsafe(::glMatrixMode(GL_MODELVIEW)); } void Camera::zoom_to_box(const BoundingBoxf3& box, double margin_factor) @@ -351,8 +347,8 @@ std::pair Camera::calc_tight_frustrum_zs_around(const BoundingBo // box in eye space const BoundingBoxf3 eye_box = box.transformed(m_view_matrix); - near_z = -eye_box.max(2); - far_z = -eye_box.min(2); + near_z = -eye_box.max.z(); + far_z = -eye_box.min.z(); // apply margin near_z -= FrustrumZMargin; @@ -533,19 +529,19 @@ void Camera::look_at(const Vec3d& position, const Vec3d& target, const Vec3d& up m_distance = (position - target).norm(); const Vec3d new_position = m_target + m_distance * unit_z; - m_view_matrix(0, 0) = unit_x(0); - m_view_matrix(0, 1) = unit_x(1); - m_view_matrix(0, 2) = unit_x(2); + m_view_matrix(0, 0) = unit_x.x(); + m_view_matrix(0, 1) = unit_x.y(); + m_view_matrix(0, 2) = unit_x.z(); m_view_matrix(0, 3) = -unit_x.dot(new_position); - m_view_matrix(1, 0) = unit_y(0); - m_view_matrix(1, 1) = unit_y(1); - m_view_matrix(1, 2) = unit_y(2); + m_view_matrix(1, 0) = unit_y.x(); + m_view_matrix(1, 1) = unit_y.y(); + m_view_matrix(1, 2) = unit_y.z(); m_view_matrix(1, 3) = -unit_y.dot(new_position); - m_view_matrix(2, 0) = unit_z(0); - m_view_matrix(2, 1) = unit_z(1); - m_view_matrix(2, 2) = unit_z(2); + m_view_matrix(2, 0) = unit_z.x(); + m_view_matrix(2, 1) = unit_z.y(); + m_view_matrix(2, 2) = unit_z.z(); m_view_matrix(2, 3) = -unit_z.dot(new_position); m_view_matrix(3, 0) = 0.0; diff --git a/src/slic3r/GUI/Camera.hpp b/src/slic3r/GUI/Camera.hpp index 401365ad4e5..2fdd16461ed 100644 --- a/src/slic3r/GUI/Camera.hpp +++ b/src/slic3r/GUI/Camera.hpp @@ -110,7 +110,6 @@ struct Camera double get_fov() const; void apply_viewport(int x, int y, unsigned int w, unsigned int h); - void apply_view_matrix(); // Calculates and applies the projection matrix tighting the frustrum z range around the given box. // If larger z span is needed, pass the desired values of near and far z (negative values are ignored) void apply_projection(const BoundingBoxf3& box, double near_z = -1.0, double far_z = -1.0); diff --git a/src/slic3r/GUI/GCodeViewer.cpp b/src/slic3r/GUI/GCodeViewer.cpp index 43424d97519..f0aa295d9e8 100644 --- a/src/slic3r/GUI/GCodeViewer.cpp +++ b/src/slic3r/GUI/GCodeViewer.cpp @@ -1308,7 +1308,6 @@ void GCodeViewer::_render_calibration_thumbnail_internal(ThumbnailData& thumbnai camera.set_type(Camera::EType::Ortho); camera.set_target(center); camera.select_view("top"); - camera.apply_view_matrix(); camera.zoom_to_box(plate_box, 1.0f); camera.apply_projection(plate_box); diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index e77aac4a2c3..f2e42699658 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -1807,14 +1807,8 @@ void GLCanvas3D::render(bool only_init) camera.requires_zoom_to_volumes = false; } - camera.apply_view_matrix(); camera.apply_projection(_max_bounding_box(true, true, true)); - GLfloat position_cam[4] = { 1.0f, 0.0f, 1.0f, 0.0f }; - glsafe(::glLightfv(GL_LIGHT1, GL_POSITION, position_cam)); - GLfloat position_top[4] = { -0.5f, -0.5f, 1.0f, 0.0f }; - glsafe(::glLightfv(GL_LIGHT0, GL_POSITION, position_top)); - wxGetApp().imgui()->new_frame(); if (m_picking_enabled) { @@ -5551,7 +5545,6 @@ void GLCanvas3D::render_thumbnail_internal(ThumbnailData& thumbnail_data, const camera.zoom_to_box(volumes_box); camera.select_view("iso"); } - camera.apply_view_matrix(); const Transform3d &view_matrix = camera.get_view_matrix(); From eb2b6af0d7b5e691549aea16b6698d871fc299aa Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Fri, 27 Oct 2023 11:09:47 +0800 Subject: [PATCH 49/99] Tech ENABLE_LEGACY_OPENGL_REMOVAL - Fix into GLModel::send_to_gpu() (cherry picked from commit prusa3d/PrusaSlicer@4b4ed423ef0c606d3f95ab5e9ac9dc9f765d4a8e) --- src/slic3r/GUI/GLModel.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/slic3r/GUI/GLModel.cpp b/src/slic3r/GUI/GLModel.cpp index 9ef9f301f3c..2671076c378 100644 --- a/src/slic3r/GUI/GLModel.cpp +++ b/src/slic3r/GUI/GLModel.cpp @@ -730,6 +730,7 @@ bool GLModel::send_to_gpu() glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0)); } else { + data.index_type = Geometry::EIndexType::UINT; glsafe(::glBufferData(GL_ELEMENT_ARRAY_BUFFER, data.indices_size_bytes(), data.indices.data(), GL_STATIC_DRAW)); glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0)); } From 0d27e084f3adbd39e277d15961b8f3fbf5198869 Mon Sep 17 00:00:00 2001 From: Noisyfox Date: Fri, 27 Oct 2023 12:00:41 +0800 Subject: [PATCH 50/99] Fix thumbnail shader --- resources/shaders/110/thumbnail.vs | 9 ++++----- resources/shaders/140/thumbnail.vs | 9 ++++----- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/resources/shaders/110/thumbnail.vs b/resources/shaders/110/thumbnail.vs index a9a3c984b2e..aa718b00671 100644 --- a/resources/shaders/110/thumbnail.vs +++ b/resources/shaders/110/thumbnail.vs @@ -14,15 +14,14 @@ const vec3 LIGHT_FRONT_DIR = vec3(0.6985074, 0.1397015, 0.6985074); #define INTENSITY_AMBIENT 0.3 -attribute vec3 v_position; -attribute vec3 v_normal; - uniform mat4 view_model_matrix; uniform mat4 projection_matrix; uniform mat3 normal_matrix; - uniform mat4 volume_world_matrix; +attribute vec3 v_position; +attribute vec3 v_normal; + // x = tainted, y = specular; varying vec2 intensity; varying vec4 world_pos; @@ -45,7 +44,7 @@ void main() intensity.x += NdotL * LIGHT_FRONT_DIFFUSE; // Point in homogenous coordinates. - world_pos = volume_world_matrix * gl_Vertex; + world_pos = volume_world_matrix * vec4(v_position, 1.0); gl_Position = projection_matrix * position; } diff --git a/resources/shaders/140/thumbnail.vs b/resources/shaders/140/thumbnail.vs index d7996d99c93..19e40c614ab 100644 --- a/resources/shaders/140/thumbnail.vs +++ b/resources/shaders/140/thumbnail.vs @@ -14,15 +14,14 @@ const vec3 LIGHT_FRONT_DIR = vec3(0.6985074, 0.1397015, 0.6985074); #define INTENSITY_AMBIENT 0.3 -in vec3 v_position; -in vec3 v_normal; - uniform mat4 view_model_matrix; uniform mat4 projection_matrix; uniform mat3 normal_matrix; - uniform mat4 volume_world_matrix; +in vec3 v_position; +in vec3 v_normal; + // x = tainted, y = specular; out vec2 intensity; out vec4 world_pos; @@ -45,7 +44,7 @@ void main() intensity.x += NdotL * LIGHT_FRONT_DIFFUSE; // Point in homogenous coordinates. - world_pos = volume_world_matrix * gl_Vertex; + world_pos = volume_world_matrix * vec4(v_position, 1.0); gl_Position = projection_matrix * position; } From a50c5a2b7afa5f22a461678e4b9905a59183e5ac Mon Sep 17 00:00:00 2001 From: Noisyfox Date: Fri, 27 Oct 2023 14:24:08 +0800 Subject: [PATCH 51/99] Fix preview shell transparency --- src/slic3r/GUI/3DScene.cpp | 8 +++++++- src/slic3r/GUI/3DScene.hpp | 2 +- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/slic3r/GUI/3DScene.cpp b/src/slic3r/GUI/3DScene.cpp index eff2212ab37..c84c56952b9 100644 --- a/src/slic3r/GUI/3DScene.cpp +++ b/src/slic3r/GUI/3DScene.cpp @@ -458,7 +458,7 @@ void GLVolume::render_with_outline(const Transform3d &view_model_matrix) } //BBS add render for simple case -void GLVolume::simple_render(GLShaderProgram* shader, ModelObjectPtrs& model_objects, std::vector& extruder_colors) +void GLVolume::simple_render(GLShaderProgram* shader, ModelObjectPtrs& model_objects, std::vector extruder_colors) { if (this->is_left_handed()) glFrontFace(GL_CW); @@ -493,6 +493,12 @@ void GLVolume::simple_render(GLShaderProgram* shader, ModelObjectPtrs& model_obj } while (0); if (color_volume && !picking) { + // when force_transparent, we need to keep the alpha + if (force_native_color && render_color.is_transparent()) { + for (auto &extruder_color : extruder_colors) + extruder_color.a(render_color.a()); + } + for (int idx = 0; idx < mmuseg_models.size(); idx++) { GUI::GLModel &m = mmuseg_models[idx]; if (!m.is_initialized()) diff --git a/src/slic3r/GUI/3DScene.hpp b/src/slic3r/GUI/3DScene.hpp index 18a8ec279d1..0352d2990be 100644 --- a/src/slic3r/GUI/3DScene.hpp +++ b/src/slic3r/GUI/3DScene.hpp @@ -320,7 +320,7 @@ class GLVolume { virtual void render_with_outline(const Transform3d &view_model_matrix); //BBS: add simple render function for thumbnail - void simple_render(GLShaderProgram* shader, ModelObjectPtrs& model_objects, std::vector& extruder_colors); + void simple_render(GLShaderProgram* shader, ModelObjectPtrs& model_objects, std::vector extruder_colors); void set_bounding_boxes_as_dirty() { m_transformed_bounding_box.reset(); From fe78e40cb44f822bedbcba9628c91a21c4148f7d Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Fri, 27 Oct 2023 19:23:19 +0800 Subject: [PATCH 52/99] Various fixes --- resources/shaders/110/flat_clip.fs | 15 +++++++++ resources/shaders/110/flat_clip.vs | 23 ++++++++++++++ resources/shaders/110/gouraud.fs | 7 ----- resources/shaders/110/mm_contour.fs | 5 --- resources/shaders/110/mm_contour.vs | 6 +++- resources/shaders/140/flat_clip.fs | 17 ++++++++++ resources/shaders/140/flat_clip.vs | 23 ++++++++++++++ resources/shaders/140/gouraud.fs | 7 ----- resources/shaders/140/mm_contour.fs | 5 --- resources/shaders/140/mm_contour.vs | 6 +++- src/libslic3r/Color.cpp | 8 +++++ src/slic3r/GUI/3DScene.cpp | 4 +-- src/slic3r/GUI/3DScene.hpp | 9 ++++-- src/slic3r/GUI/GLCanvas3D.cpp | 12 +++---- src/slic3r/GUI/GLModel.hpp | 3 +- src/slic3r/GUI/GLShader.cpp | 6 ++++ src/slic3r/GUI/GLShader.hpp | 2 ++ src/slic3r/GUI/GLShadersManager.cpp | 2 ++ .../GUI/Gizmos/GLGizmoMmuSegmentation.cpp | 15 +++++++++ .../GUI/Gizmos/GLGizmoMmuSegmentation.hpp | 1 + src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp | 31 ++++++++++++++----- src/slic3r/GUI/Gizmos/GLGizmoPainterBase.hpp | 2 ++ src/slic3r/GUI/Gizmos/GLGizmoSimplify.cpp | 2 ++ src/slic3r/GUI/MeshUtils.hpp | 16 ++++------ src/slic3r/GUI/OpenGLManager.cpp | 5 +++ src/slic3r/GUI/OpenGLManager.hpp | 2 ++ 26 files changed, 176 insertions(+), 58 deletions(-) create mode 100644 resources/shaders/110/flat_clip.fs create mode 100644 resources/shaders/110/flat_clip.vs create mode 100644 resources/shaders/140/flat_clip.fs create mode 100644 resources/shaders/140/flat_clip.vs diff --git a/resources/shaders/110/flat_clip.fs b/resources/shaders/110/flat_clip.fs new file mode 100644 index 00000000000..ececb8eb1ae --- /dev/null +++ b/resources/shaders/110/flat_clip.fs @@ -0,0 +1,15 @@ +#version 110 + +const vec3 ZERO = vec3(0.0, 0.0, 0.0); + +uniform vec4 uniform_color; + +varying vec3 clipping_planes_dots; + +void main() +{ + if (any(lessThan(clipping_planes_dots, ZERO))) + discard; + + gl_FragColor = uniform_color; +} diff --git a/resources/shaders/110/flat_clip.vs b/resources/shaders/110/flat_clip.vs new file mode 100644 index 00000000000..cdf7d4b3b2c --- /dev/null +++ b/resources/shaders/110/flat_clip.vs @@ -0,0 +1,23 @@ +#version 110 + +uniform mat4 view_model_matrix; +uniform mat4 projection_matrix; +uniform mat4 volume_world_matrix; + +// Clipping plane, x = min z, y = max z. Used by the FFF and SLA previews to clip with a top / bottom plane. +uniform vec2 z_range; +// Clipping plane - general orientation. Used by the SLA gizmo. +uniform vec4 clipping_plane; + +attribute vec3 v_position; + +varying vec3 clipping_planes_dots; + +void main() +{ + // Fill in the scalars for fragment shader clipping. Fragments with any of these components lower than zero are discarded. + vec4 world_pos = volume_world_matrix * vec4(v_position, 1.0); + clipping_planes_dots = vec3(dot(world_pos, clipping_plane), world_pos.z - z_range.x, z_range.y - world_pos.z); + + gl_Position = projection_matrix * view_model_matrix * vec4(v_position, 1.0); +} diff --git a/resources/shaders/110/gouraud.fs b/resources/shaders/110/gouraud.fs index 9513dbb9e9e..fce2a6f39f0 100644 --- a/resources/shaders/110/gouraud.fs +++ b/resources/shaders/110/gouraud.fs @@ -34,8 +34,6 @@ uniform SlopeDetection slope; //BBS: add outline_color uniform bool is_outline; -uniform bool offset_depth_buffer; - #ifdef ENABLE_ENVIRONMENT_MAP uniform sampler2D environment_tex; uniform bool use_environment_tex; @@ -97,9 +95,4 @@ void main() #endif else gl_FragColor = vec4(vec3(intensity.y) + color * intensity.x, alpha); - - // In the support painting gizmo and the seam painting gizmo are painted triangles rendered over the already - // rendered object. To resolved z-fighting between previously rendered object and painted triangles, values - // inside the depth buffer are offset by small epsilon for painted triangles inside those gizmos. - gl_FragDepth = gl_FragCoord.z - (offset_depth_buffer ? EPSILON : 0.0); } \ No newline at end of file diff --git a/resources/shaders/110/mm_contour.fs b/resources/shaders/110/mm_contour.fs index 14477a59e6e..ab656998df7 100644 --- a/resources/shaders/110/mm_contour.fs +++ b/resources/shaders/110/mm_contour.fs @@ -1,13 +1,8 @@ #version 110 -const float EPSILON = 0.0001; - uniform vec4 uniform_color; void main() { gl_FragColor = uniform_color; - // Values inside depth buffer for fragments of the contour of a selected area are offset - // by small epsilon to solve z-fighting between painted triangles and contour lines. - gl_FragDepth = gl_FragCoord.z - EPSILON; } diff --git a/resources/shaders/110/mm_contour.vs b/resources/shaders/110/mm_contour.vs index d9063f0c70e..b37394b6191 100644 --- a/resources/shaders/110/mm_contour.vs +++ b/resources/shaders/110/mm_contour.vs @@ -2,10 +2,14 @@ uniform mat4 view_model_matrix; uniform mat4 projection_matrix; +uniform float offset; attribute vec3 v_position; void main() { - gl_Position = projection_matrix * view_model_matrix * vec4(v_position, 1.0); + // Add small epsilon to z to solve z-fighting between painted triangles and contour lines. + vec4 clip_position = projection_matrix * view_model_matrix * vec4(v_position, 1.0); + clip_position.z -= offset * abs(clip_position.w); + gl_Position = clip_position; } diff --git a/resources/shaders/140/flat_clip.fs b/resources/shaders/140/flat_clip.fs new file mode 100644 index 00000000000..b77e0bfaa69 --- /dev/null +++ b/resources/shaders/140/flat_clip.fs @@ -0,0 +1,17 @@ +#version 140 + +const vec3 ZERO = vec3(0.0, 0.0, 0.0); + +uniform vec4 uniform_color; + +in vec3 clipping_planes_dots; + +out vec4 out_color; + +void main() +{ + if (any(lessThan(clipping_planes_dots, ZERO))) + discard; + + out_color = uniform_color; +} diff --git a/resources/shaders/140/flat_clip.vs b/resources/shaders/140/flat_clip.vs new file mode 100644 index 00000000000..40cddf1e5a6 --- /dev/null +++ b/resources/shaders/140/flat_clip.vs @@ -0,0 +1,23 @@ +#version 140 + +uniform mat4 view_model_matrix; +uniform mat4 projection_matrix; +uniform mat4 volume_world_matrix; + +// Clipping plane, x = min z, y = max z. Used by the FFF and SLA previews to clip with a top / bottom plane. +uniform vec2 z_range; +// Clipping plane - general orientation. Used by the SLA gizmo. +uniform vec4 clipping_plane; + +in vec3 v_position; + +out vec3 clipping_planes_dots; + +void main() +{ + // Fill in the scalars for fragment shader clipping. Fragments with any of these components lower than zero are discarded. + vec4 world_pos = volume_world_matrix * vec4(v_position, 1.0); + clipping_planes_dots = vec3(dot(world_pos, clipping_plane), world_pos.z - z_range.x, z_range.y - world_pos.z); + + gl_Position = projection_matrix * view_model_matrix * vec4(v_position, 1.0); +} diff --git a/resources/shaders/140/gouraud.fs b/resources/shaders/140/gouraud.fs index 6e8c63e0c55..bff8434aa92 100644 --- a/resources/shaders/140/gouraud.fs +++ b/resources/shaders/140/gouraud.fs @@ -34,8 +34,6 @@ uniform SlopeDetection slope; //BBS: add outline_color uniform bool is_outline; -uniform bool offset_depth_buffer; - #ifdef ENABLE_ENVIRONMENT_MAP uniform sampler2D environment_tex; uniform bool use_environment_tex; @@ -97,9 +95,4 @@ void main() #endif else gl_FragColor = vec4(vec3(intensity.y) + color * intensity.x, alpha); - - // In the support painting gizmo and the seam painting gizmo are painted triangles rendered over the already - // rendered object. To resolved z-fighting between previously rendered object and painted triangles, values - // inside the depth buffer are offset by small epsilon for painted triangles inside those gizmos. - gl_FragDepth = gl_FragCoord.z - (offset_depth_buffer ? EPSILON : 0.0); } \ No newline at end of file diff --git a/resources/shaders/140/mm_contour.fs b/resources/shaders/140/mm_contour.fs index 3681d76c184..e74124dcaef 100644 --- a/resources/shaders/140/mm_contour.fs +++ b/resources/shaders/140/mm_contour.fs @@ -1,13 +1,8 @@ #version 140 -const float EPSILON = 0.0001; - uniform vec4 uniform_color; void main() { gl_FragColor = uniform_color; - // Values inside depth buffer for fragments of the contour of a selected area are offset - // by small epsilon to solve z-fighting between painted triangles and contour lines. - gl_FragDepth = gl_FragCoord.z - EPSILON; } diff --git a/resources/shaders/140/mm_contour.vs b/resources/shaders/140/mm_contour.vs index 7042671de20..679291ba6d0 100644 --- a/resources/shaders/140/mm_contour.vs +++ b/resources/shaders/140/mm_contour.vs @@ -2,10 +2,14 @@ uniform mat4 view_model_matrix; uniform mat4 projection_matrix; +uniform float offset; in vec3 v_position; void main() { - gl_Position = projection_matrix * view_model_matrix * vec4(v_position, 1.0); + // Add small epsilon to z to solve z-fighting between painted triangles and contour lines. + vec4 clip_position = projection_matrix * view_model_matrix * vec4(v_position, 1.0); + clip_position.z -= offset * abs(clip_position.w); + gl_Position = clip_position; } diff --git a/src/libslic3r/Color.cpp b/src/libslic3r/Color.cpp index b911d170e3b..c282e307ed5 100644 --- a/src/libslic3r/Color.cpp +++ b/src/libslic3r/Color.cpp @@ -130,6 +130,8 @@ 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; + else if (m_data[i] > other.m_data[i]) + return false; } return false; @@ -140,6 +142,8 @@ 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; + else if (m_data[i] < other.m_data[i]) + return false; } return false; @@ -179,6 +183,8 @@ 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; + else if (m_data[i] > other.m_data[i]) + return false; } return false; @@ -189,6 +195,8 @@ 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; + else if (m_data[i] < other.m_data[i]) + return false; } return false; diff --git a/src/slic3r/GUI/3DScene.cpp b/src/slic3r/GUI/3DScene.cpp index c84c56952b9..7d35500d34a 100644 --- a/src/slic3r/GUI/3DScene.cpp +++ b/src/slic3r/GUI/3DScene.cpp @@ -870,8 +870,8 @@ void GLVolumeCollection::render(GLVolumeCollection::ERenderType type, bool disab if (!volume.first->model.is_initialized()) shader->set_uniform("uniform_color", volume.first->render_color); - shader->set_uniform("z_range", m_z_range, 2); - shader->set_uniform("clipping_plane", m_clipping_plane, 4); + shader->set_uniform("z_range", m_z_range); + shader->set_uniform("clipping_plane", m_clipping_plane); //BOOST_LOG_TRIVIAL(info) << boost::format("set uniform_color to {%1%, %2%, %3%, %4%}, with_outline=%5%, selected %6%") // %volume.first->render_color[0]%volume.first->render_color[1]%volume.first->render_color[2]%volume.first->render_color[3] // %with_outline%volume.first->selected; diff --git a/src/slic3r/GUI/3DScene.hpp b/src/slic3r/GUI/3DScene.hpp index 0352d2990be..4dce6857538 100644 --- a/src/slic3r/GUI/3DScene.hpp +++ b/src/slic3r/GUI/3DScene.hpp @@ -392,10 +392,10 @@ class GLVolumeCollection PrintVolume m_render_volume; // z range for clipping in shaders - float m_z_range[2]; + std::array m_z_range; // plane coeffs for clipping in shaders - float m_clipping_plane[4]; + std::array m_clipping_plane; struct Slope { @@ -463,7 +463,10 @@ class GLVolumeCollection void set_print_volume(const PrintVolume& print_volume) { m_print_volume = print_volume; } void set_z_range(float min_z, float max_z) { m_z_range[0] = min_z; m_z_range[1] = max_z; } - void set_clipping_plane(const double* coeffs) { m_clipping_plane[0] = coeffs[0]; m_clipping_plane[1] = coeffs[1]; m_clipping_plane[2] = coeffs[2]; m_clipping_plane[3] = coeffs[3]; } + void set_clipping_plane(const std::array& coeffs) { m_clipping_plane = coeffs; } + + const std::array& get_z_range() const { return m_z_range; } + const std::array& get_clipping_plane() const { return m_clipping_plane; } bool is_slope_GlobalActive() const { return m_slope.isGlobalActive; } bool is_slope_active() const { return m_slope.active; } diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index f2e42699658..074ccb81579 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -6417,14 +6417,7 @@ void GLCanvas3D::_picking_pass() _render_plates_for_picking(camera.get_view_matrix(), camera.get_projection_matrix()); } - m_camera_clipping_plane = m_gizmos.get_clipping_plane(); - if (m_camera_clipping_plane.is_active()) { - ::glClipPlane(GL_CLIP_PLANE0, (GLdouble*)m_camera_clipping_plane.get_data()); - ::glEnable(GL_CLIP_PLANE0); - } _render_volumes_for_picking(); - if (m_camera_clipping_plane.is_active()) - ::glDisable(GL_CLIP_PLANE0); //BBS: remove the bed picking logic //_render_bed_for_picking(!wxGetApp().plater()->get_camera().is_looking_downward()); @@ -7163,7 +7156,7 @@ void GLCanvas3D::_render_style_editor() void GLCanvas3D::_render_volumes_for_picking() const { - GLShaderProgram* shader = wxGetApp().get_shader("flat"); + GLShaderProgram* shader = wxGetApp().get_shader("flat_clip"); if (shader == nullptr) return; @@ -7186,6 +7179,9 @@ void GLCanvas3D::_render_volumes_for_picking() const const Camera& camera = wxGetApp().plater()->get_camera(); shader->set_uniform("view_model_matrix", camera.get_view_matrix() * volume.first->world_matrix()); shader->set_uniform("projection_matrix", camera.get_projection_matrix()); + shader->set_uniform("volume_world_matrix", volume.first->world_matrix()); + shader->set_uniform("z_range", m_volumes.get_z_range()); + shader->set_uniform("clipping_plane", m_volumes.get_clipping_plane()); volume.first->picking = true; volume.first->render(); volume.first->picking = false; diff --git a/src/slic3r/GUI/GLModel.hpp b/src/slic3r/GUI/GLModel.hpp index 28485cd40ee..e2a3e75daff 100644 --- a/src/slic3r/GUI/GLModel.hpp +++ b/src/slic3r/GUI/GLModel.hpp @@ -63,8 +63,7 @@ namespace GUI { ColorRGBA color{ ColorRGBA::BLACK() }; void reserve_vertices(size_t vertices_count) { vertices.reserve(vertices_count * vertex_stride_floats(format)); } - void reserve_indices(size_t indices_count) { indices.reserve(indices_count * index_stride_bytes(*this)); } - + void reserve_indices(size_t indices_count) { indices.reserve(indices_count); } void add_vertex(const Vec2f& position); // EVertexLayout::P2 void add_vertex(const Vec2f& position, const Vec2f& tex_coord); // EVertexLayout::P2T2 diff --git a/src/slic3r/GUI/GLShader.cpp b/src/slic3r/GUI/GLShader.cpp index d510a81b401..9f13269c8d8 100644 --- a/src/slic3r/GUI/GLShader.cpp +++ b/src/slic3r/GUI/GLShader.cpp @@ -264,6 +264,12 @@ void GLShaderProgram::set_uniform(int id, const std::array& value) con glsafe(::glUniform4fv(id, 1, static_cast(value.data()))); } +void GLShaderProgram::set_uniform(int id, const std::array& value) const +{ + const std::array f_value = { float(value[0]), float(value[1]), float(value[2]), float(value[3]) }; + set_uniform(id, f_value); +} + void GLShaderProgram::set_uniform(int id, const float* value, size_t size) const { if (id >= 0) { diff --git a/src/slic3r/GUI/GLShader.hpp b/src/slic3r/GUI/GLShader.hpp index fd30b3750de..e1b2915e0d6 100644 --- a/src/slic3r/GUI/GLShader.hpp +++ b/src/slic3r/GUI/GLShader.hpp @@ -57,6 +57,7 @@ class GLShaderProgram void set_uniform(const char* name, const std::array& value) const { set_uniform(get_uniform_location(name), value); } void set_uniform(const char* name, const std::array& value) const { set_uniform(get_uniform_location(name), value); } void set_uniform(const char* name, const std::array& value) const { set_uniform(get_uniform_location(name), value); } + void set_uniform(const char* name, const std::array& value) const { set_uniform(get_uniform_location(name), value); } void set_uniform(const char* name, const float* value, size_t size) const { set_uniform(get_uniform_location(name), value, size); } void set_uniform(const char* name, const Transform3f& value) const { set_uniform(get_uniform_location(name), value); } void set_uniform(const char* name, const Transform3d& value) const { set_uniform(get_uniform_location(name), value); } @@ -79,6 +80,7 @@ class GLShaderProgram void set_uniform(int id, const std::array& value) const; void set_uniform(int id, const std::array& value) const; void set_uniform(int id, const std::array& value) const; + void set_uniform(int id, const std::array& value) const; void set_uniform(int id, const float* value, size_t size) const; void set_uniform(int id, const Transform3f& value) const; void set_uniform(int id, const Transform3d& value) const; diff --git a/src/slic3r/GUI/GLShadersManager.cpp b/src/slic3r/GUI/GLShadersManager.cpp index 3c874526be1..d525ce272ef 100644 --- a/src/slic3r/GUI/GLShadersManager.cpp +++ b/src/slic3r/GUI/GLShadersManager.cpp @@ -38,6 +38,8 @@ std::pair GLShadersManager::init() valid &= append_shader("imgui", { prefix + "imgui.vs", prefix + "imgui.fs" }); // basic shader, used to render all what was previously rendered using the immediate mode valid &= append_shader("flat", { prefix + "flat.vs", prefix + "flat.fs" }); + // basic shader with plane clipping, used to render volumes in picking pass + valid &= append_shader("flat_clip", { prefix + "flat_clip.vs", prefix + "flat_clip.fs" }); // basic shader for textures, used to render textures valid &= append_shader("flat_texture", { prefix + "flat_texture.vs", prefix + "flat_texture.fs" }); // used to render 3D scene background diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp index 8fba22870ec..c1aed1867eb 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp @@ -908,6 +908,11 @@ void GLMmSegmentationGizmo3DScene::release_geometry() { glsafe(::glDeleteBuffers(1, &triangle_indices_VBO_id)); triangle_indices_VBO_id = 0; } + if (this->vertices_VAO_id) { + glsafe(::glDeleteVertexArrays(1, &this->vertices_VAO_id)); + this->vertices_VAO_id = 0; + } + this->clear(); } @@ -915,6 +920,7 @@ void GLMmSegmentationGizmo3DScene::render(size_t triangle_indices_idx) const { assert(triangle_indices_idx < this->triangle_indices_VBO_ids.size()); assert(this->triangle_patches.size() == this->triangle_indices_VBO_ids.size()); + assert(this->vertices_VAO_id != 0); assert(this->vertices_VBO_id != 0); assert(this->triangle_indices_VBO_ids[triangle_indices_idx] != 0); @@ -922,6 +928,8 @@ void GLMmSegmentationGizmo3DScene::render(size_t triangle_indices_idx) const if (shader == nullptr) return; + glsafe(::glBindVertexArray(this->vertices_VAO_id)); + // the following binding is needed to set the vertex attributes glsafe(::glBindBuffer(GL_ARRAY_BUFFER, this->vertices_VBO_id)); const GLint position_id = shader->get_attrib_location("v_position"); if (position_id != -1) { @@ -941,17 +949,24 @@ void GLMmSegmentationGizmo3DScene::render(size_t triangle_indices_idx) const glsafe(::glDisableVertexAttribArray(position_id)); glsafe(::glBindBuffer(GL_ARRAY_BUFFER, 0)); + glsafe(::glBindVertexArray(0)); } void GLMmSegmentationGizmo3DScene::finalize_vertices() { + assert(this->vertices_VAO_id == 0); assert(this->vertices_VBO_id == 0); if (!this->vertices.empty()) { + glsafe(::glGenVertexArrays(1, &this->vertices_VAO_id)); + glsafe(::glBindVertexArray(this->vertices_VAO_id)); + glsafe(::glGenBuffers(1, &this->vertices_VBO_id)); glsafe(::glBindBuffer(GL_ARRAY_BUFFER, this->vertices_VBO_id)); glsafe(::glBufferData(GL_ARRAY_BUFFER, this->vertices.size() * sizeof(float), this->vertices.data(), GL_STATIC_DRAW)); glsafe(::glBindBuffer(GL_ARRAY_BUFFER, 0)); this->vertices.clear(); + + glsafe(::glBindVertexArray(0)); } } diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.hpp b/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.hpp index 7457d971014..ac8238e911a 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.hpp @@ -57,6 +57,7 @@ class GLMmSegmentationGizmo3DScene // IDs of the Vertex Array Objects, into which the geometry has been loaded. // Zero if the VBOs are not sent to GPU yet. + unsigned int vertices_VAO_id{ 0 }; unsigned int vertices_VBO_id{0}; std::vector triangle_indices_VBO_ids; }; diff --git a/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp b/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp index 2afcb119bf4..1d577a45b4f 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp @@ -8,6 +8,7 @@ #include "slic3r/GUI/GUI_App.hpp" #include "slic3r/GUI/Camera.hpp" #include "slic3r/GUI/Plater.hpp" +#include "slic3r/GUI/OpenGLManager.hpp" #include "slic3r/Utils/UndoRedo.hpp" #include "libslic3r/Model.hpp" #include "libslic3r/PresetBundle.hpp" @@ -1071,8 +1072,7 @@ void TriangleSelectorGUI::render(ImGuiWrapper* imgui, const Transform3d& matrix) if (! shader) return; assert(shader->get_name() == "gouraud" || shader->get_name() == "mm_gouraud"); - ScopeGuard guard([shader]() { if (shader) shader->set_uniform("offset_depth_buffer", false);}); - shader->set_uniform("offset_depth_buffer", true); + for (auto iva : {std::make_pair(&m_iva_enforcers, enforcers_color), std::make_pair(&m_iva_blockers, blockers_color)}) { iva.first->set_color(iva.second); @@ -1120,6 +1120,9 @@ void TriangleSelectorGUI::update_render_data() for (auto& data : iva_seed_fills_data) data.format = { GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3N3 }; + // small value used to offset triangles along their normal to avoid z-fighting + static const float offset = 0.001f; + for (const Triangle &tr : m_triangles) { bool is_valid = tr.valid(); bool is_split = tr.is_split(); @@ -1141,9 +1144,11 @@ void TriangleSelectorGUI::update_render_data() //FIXME the normal may likely be pulled from m_triangle_selectors, but it may not be worth the effort // or the current implementation may be more cache friendly. const Vec3f n = (v1 - v0).cross(v2 - v1).normalized(); - iva.add_vertex(v0, n); - iva.add_vertex(v1, n); - iva.add_vertex(v2, n); + // small value used to offset triangles along their normal to avoid z-fighting + const Vec3f offset_n = offset * n; + iva.add_vertex(v0 + offset_n, n); + iva.add_vertex(v1 + offset_n, n); + iva.add_vertex(v2 + offset_n, n); iva.add_triangle((unsigned int)cnt, (unsigned int)cnt + 1, (unsigned int)cnt + 2); cnt += 3; } @@ -1433,6 +1438,7 @@ void TriangleSelectorPatch::render(int triangle_indices_idx) assert(this->m_triangle_patches.size() == this->m_triangle_indices_VBO_ids.size()); //assert(this->m_vertices_VBO_id != 0); assert(this->m_triangle_patches.size() == this->m_vertices_VBO_ids.size()); + assert(this->m_vertices_VAO_ids[triangle_indices_idx] != 0); assert(this->m_vertices_VBO_ids[triangle_indices_idx] != 0); assert(this->m_triangle_indices_VBO_ids[triangle_indices_idx] != 0); @@ -1440,6 +1446,8 @@ void TriangleSelectorPatch::render(int triangle_indices_idx) if (shader == nullptr) return; + glsafe(::glBindVertexArray(this->m_vertices_VAO_ids[triangle_indices_idx])); + // the following binding is needed to set the vertex attributes glsafe(::glBindBuffer(GL_ARRAY_BUFFER, this->m_vertices_VBO_ids[triangle_indices_idx])); const GLint position_id = shader->get_attrib_location("v_position"); if (position_id != -1) { @@ -1459,6 +1467,7 @@ void TriangleSelectorPatch::render(int triangle_indices_idx) glsafe(::glDisableVertexAttribArray(position_id)); glsafe(::glBindBuffer(GL_ARRAY_BUFFER, 0)); + glsafe(::glBindVertexArray(0)); } void TriangleSelectorPatch::release_geometry() @@ -1471,6 +1480,10 @@ void TriangleSelectorPatch::release_geometry() glsafe(::glDeleteBuffers(1, &vertice_VBO_id)); vertice_VBO_id = 0; } + for (auto &vertice_VAO_id : m_vertices_VAO_ids) { + glsafe(::glDeleteVertexArrays(1, &vertice_VAO_id)); + vertice_VAO_id = 0; + } for (auto& triangle_indices_VBO_id : m_triangle_indices_VBO_ids) { glsafe(::glDeleteBuffers(1, &triangle_indices_VBO_id)); triangle_indices_VBO_id = 0; @@ -1495,6 +1508,7 @@ void TriangleSelectorPatch::finalize_vertices() void TriangleSelectorPatch::finalize_triangle_indices() { m_vertices_VBO_ids.resize(m_triangle_patches.size()); + m_vertices_VAO_ids.resize(m_triangle_patches.size()); m_triangle_indices_VBO_ids.resize(m_triangle_patches.size()); m_triangle_indices_sizes.resize(m_triangle_patches.size()); assert(std::all_of(m_triangle_indices_VBO_ids.cbegin(), m_triangle_indices_VBO_ids.cend(), [](const auto& ti_VBO_id) { return ti_VBO_id == 0; })); @@ -1502,6 +1516,9 @@ void TriangleSelectorPatch::finalize_triangle_indices() for (size_t buffer_idx = 0; buffer_idx < m_triangle_patches.size(); ++buffer_idx) { std::vector& patch_vertices = m_triangle_patches[buffer_idx].patch_vertices; if (!patch_vertices.empty()) { + glsafe(::glGenVertexArrays(1, &m_vertices_VAO_ids[buffer_idx])); + glsafe(::glBindVertexArray(m_vertices_VAO_ids[buffer_idx])); + glsafe(::glGenBuffers(1, &m_vertices_VBO_ids[buffer_idx])); glsafe(::glBindBuffer(GL_ARRAY_BUFFER, m_vertices_VBO_ids[buffer_idx])); glsafe(::glBufferData(GL_ARRAY_BUFFER, patch_vertices.size() * sizeof(float), patch_vertices.data(), GL_STATIC_DRAW)); @@ -1520,6 +1537,7 @@ void TriangleSelectorPatch::finalize_triangle_indices() //BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(", Line %1%: buffer_idx %2%, vertices size %3%, buffer id %4%")%__LINE__%buffer_idx%triangle_indices.size()%m_triangle_indices_VBO_ids[buffer_idx]; triangle_indices.clear(); } + glsafe(::glBindVertexArray(0)); } } @@ -1665,13 +1683,12 @@ void TriangleSelectorGUI::render_paint_contour(const Transform3d& matrix) if (contour_shader != nullptr) { contour_shader->start_using(); + contour_shader->set_uniform("offset", OpenGLManager::get_gl_info().is_mesa() ? 0.0005 : 0.00001); const Camera& camera = wxGetApp().plater()->get_camera(); contour_shader->set_uniform("view_model_matrix", camera.get_view_matrix() * matrix); contour_shader->set_uniform("projection_matrix", camera.get_projection_matrix()); - glsafe(::glDepthFunc(GL_LEQUAL)); m_paint_contour.render(); - glsafe(::glDepthFunc(GL_LESS)); contour_shader->stop_using(); } diff --git a/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.hpp b/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.hpp index afba98fd7e1..8e0fc1f756a 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.hpp @@ -133,6 +133,7 @@ class TriangleSelectorPatch : public TriangleSelectorGUI { void clear() { // BBS + this->m_vertices_VAO_ids.clear(); this->m_vertices_VBO_ids.clear(); this->m_triangle_indices_VBO_ids.clear(); this->m_triangle_indices_sizes.clear(); @@ -161,6 +162,7 @@ class TriangleSelectorPatch : public TriangleSelectorGUI { // IDs of the Vertex Array Objects, into which the geometry has been loaded. // Zero if the VBOs are not sent to GPU yet. //unsigned int m_vertices_VBO_id{ 0 }; + std::vector m_vertices_VAO_ids; std::vector m_vertices_VBO_ids; std::vector m_triangle_indices_VBO_ids; diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSimplify.cpp b/src/slic3r/GUI/Gizmos/GLGizmoSimplify.cpp index 951cd43657e..c8397049bce 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSimplify.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSimplify.cpp @@ -6,6 +6,7 @@ #include "slic3r/GUI/NotificationManager.hpp" #include "slic3r/GUI/Plater.hpp" #include "slic3r/GUI/format.hpp" +#include "slic3r/GUI/OpenGLManager.hpp" #include "libslic3r/AppConfig.hpp" #include "libslic3r/Model.hpp" #include "libslic3r/QuadricEdgeCollapse.hpp" @@ -656,6 +657,7 @@ void GLGizmoSimplify::on_render() if (m_show_wireframe) { auto* contour_shader = wxGetApp().get_shader("mm_contour"); contour_shader->start_using(); + contour_shader->set_uniform("offset", OpenGLManager::get_gl_info().is_mesa() ? 0.0005 : 0.00001); contour_shader->set_uniform("view_model_matrix", view_model_matrix); contour_shader->set_uniform("projection_matrix", camera.get_projection_matrix()); const ColorRGBA color = m_glmodel.get_color(); diff --git a/src/slic3r/GUI/MeshUtils.hpp b/src/slic3r/GUI/MeshUtils.hpp index db0bf1c0aaf..4f0210b3555 100644 --- a/src/slic3r/GUI/MeshUtils.hpp +++ b/src/slic3r/GUI/MeshUtils.hpp @@ -20,16 +20,14 @@ struct Camera; // lm_FIXME: Following class might possibly be replaced by Eigen::Hyperplane class ClippingPlane { - double m_data[4]; + std::array m_data; public: - ClippingPlane() - { + ClippingPlane() { *this = ClipsNothing(); } - ClippingPlane(const Vec3d& direction, double offset) - { + ClippingPlane(const Vec3d& direction, double offset) { set_normal(direction); set_offset(offset); } @@ -45,8 +43,7 @@ class ClippingPlane } bool is_point_clipped(const Vec3d& point) const { return distance(point) < 0.; } - void set_normal(const Vec3d& normal) - { + void set_normal(const Vec3d& normal) { const Vec3d norm_dir = normal.normalized(); m_data[0] = norm_dir.x(); m_data[1] = norm_dir.y(); @@ -57,12 +54,11 @@ class ClippingPlane Vec3d get_normal() const { return Vec3d(m_data[0], m_data[1], m_data[2]); } bool is_active() const { return m_data[3] != DBL_MAX; } static ClippingPlane ClipsNothing() { return ClippingPlane(Vec3d(0., 0., 1.), DBL_MAX); } - const double* get_data() const { return m_data; } + const std::array& get_data() const { return m_data; } // Serialization through cereal library template - void serialize( Archive & ar ) - { + void serialize( Archive & ar ) { ar( m_data[0], m_data[1], m_data[2], m_data[3] ); } }; diff --git a/src/slic3r/GUI/OpenGLManager.cpp b/src/slic3r/GUI/OpenGLManager.cpp index 3f38e15bc3e..d5781d52d84 100644 --- a/src/slic3r/GUI/OpenGLManager.cpp +++ b/src/slic3r/GUI/OpenGLManager.cpp @@ -65,6 +65,11 @@ const std::string& OpenGLManager::GLInfo::get_renderer() const return m_renderer; } +bool OpenGLManager::GLInfo::is_mesa() const +{ + return boost::icontains(m_version, "mesa"); +} + int OpenGLManager::GLInfo::get_max_tex_size() const { if (!m_detected) diff --git a/src/slic3r/GUI/OpenGLManager.hpp b/src/slic3r/GUI/OpenGLManager.hpp index f2670f8af04..28af5946f9d 100644 --- a/src/slic3r/GUI/OpenGLManager.hpp +++ b/src/slic3r/GUI/OpenGLManager.hpp @@ -40,6 +40,8 @@ class OpenGLManager const std::string& get_vendor() const; const std::string& get_renderer() const; + bool is_mesa() const; + int get_max_tex_size() const; float get_max_anisotropy() const; From 5ce3ec716e355127734e6795722d04f6e77047be Mon Sep 17 00:00:00 2001 From: Noisyfox Date: Fri, 27 Oct 2023 23:07:00 +0800 Subject: [PATCH 53/99] Fix draw cut line --- src/slic3r/GUI/Gizmos/GLGizmoAdvancedCut.cpp | 44 ++++++++++++++++---- src/slic3r/GUI/Gizmos/GLGizmoAdvancedCut.hpp | 1 + 2 files changed, 36 insertions(+), 9 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoAdvancedCut.cpp b/src/slic3r/GUI/Gizmos/GLGizmoAdvancedCut.cpp index 2c67d8889cc..0871ca3df22 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoAdvancedCut.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoAdvancedCut.cpp @@ -1054,15 +1054,41 @@ void GLGizmoAdvancedCut::render_cut_line() if (!cut_line_processing() || m_cut_line_end == Vec3d::Zero()) return; - glsafe(::glEnable(GL_DEPTH_TEST)); - glsafe(::glClear(GL_DEPTH_BUFFER_BIT)); - glsafe(::glColor3f(0.0, 1.0, 0.0)); - glEnable(GL_LINE_STIPPLE); - ::glBegin(GL_LINES); - ::glVertex3dv(m_cut_line_begin.data()); - ::glVertex3dv(m_cut_line_end.data()); - glsafe(::glEnd()); - glDisable(GL_LINE_STIPPLE); + glsafe(::glDisable(GL_DEPTH_TEST)); + + GLShaderProgram *shader = wxGetApp().get_shader("flat"); + if (shader != nullptr) { + shader->start_using(); + + { + m_cut_line.reset(); + + GLModel::Geometry init_data; + init_data.format = {GLModel::Geometry::EPrimitiveType::Lines, GLModel::Geometry::EVertexLayout::P3}; + init_data.color = ColorRGBA::GREEN(); + init_data.reserve_vertices(2); + init_data.reserve_vertices(2); + + // vertices + init_data.add_vertex((Vec3f) m_cut_line_begin.cast()); + init_data.add_vertex((Vec3f) m_cut_line_end.cast()); + + // indices + init_data.add_line(0, 1); + + m_cut_line.init_from(std::move(init_data)); + } + const Camera &camera = wxGetApp().plater()->get_camera(); + shader->set_uniform("view_model_matrix", camera.get_view_matrix()); + shader->set_uniform("projection_matrix", camera.get_projection_matrix()); + + glEnable(GL_LINE_STIPPLE); + glLineStipple(1, 0x0FFF); + m_cut_line.render(); + glDisable(GL_LINE_STIPPLE); + + shader->stop_using(); + } } void GLGizmoAdvancedCut::render_connector_model(GLModel &model, const ColorRGBA &color, Transform3d view_model_matrix, bool for_picking) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoAdvancedCut.hpp b/src/slic3r/GUI/Gizmos/GLGizmoAdvancedCut.hpp index c381dffff02..4943f087fcb 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoAdvancedCut.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoAdvancedCut.hpp @@ -55,6 +55,7 @@ struct Rotate_data { bool m_rotate_lower{false}; GLModel m_plane; GLModel m_grabber_connection; + GLModel m_cut_line; bool m_do_segment; double m_segment_smoothing_alpha; From 4fb5b1f904968b248b72b9e68527e23bae47f170 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Fri, 27 Oct 2023 23:23:57 +0800 Subject: [PATCH 54/99] Cherry-picked a few changes from Tech ENABLE_GL_CORE_PROFILE --- src/libslic3r/Point.hpp | 2 +- src/slic3r/GUI/GLModel.cpp | 23 +++++++++++++++++++---- src/slic3r/GUI/GLModel.hpp | 2 ++ src/slic3r/GUI/GLShader.cpp | 11 +++++++++++ src/slic3r/GUI/GLShader.hpp | 4 ++++ 5 files changed, 37 insertions(+), 5 deletions(-) diff --git a/src/libslic3r/Point.hpp b/src/libslic3r/Point.hpp index 6c6bac8800c..73252f44597 100644 --- a/src/libslic3r/Point.hpp +++ b/src/libslic3r/Point.hpp @@ -55,7 +55,7 @@ using Vec2f = Eigen::Matrix; using Vec3f = Eigen::Matrix; using Vec2d = Eigen::Matrix; using Vec3d = Eigen::Matrix; -// BBS +using Vec4f = Eigen::Matrix; using Vec4d = Eigen::Matrix; using Points = std::vector; diff --git a/src/slic3r/GUI/GLModel.cpp b/src/slic3r/GUI/GLModel.cpp index 2671076c378..bab13ba2515 100644 --- a/src/slic3r/GUI/GLModel.cpp +++ b/src/slic3r/GUI/GLModel.cpp @@ -97,6 +97,15 @@ void GLModel::Geometry::add_vertex(const Vec3f& position, const Vec3f& normal) vertices.emplace_back(normal.z()); } +void GLModel::Geometry::add_vertex(const Vec4f& position) +{ + assert(format.vertex_layout == EVertexLayout::P4); + vertices.emplace_back(position.x()); + vertices.emplace_back(position.y()); + vertices.emplace_back(position.z()); + vertices.emplace_back(position.w()); +} + void GLModel::Geometry::add_index(unsigned int id) { indices.emplace_back(id); @@ -234,6 +243,7 @@ size_t GLModel::Geometry::vertex_stride_floats(const Format& format) case EVertexLayout::P3: { return 3; } case EVertexLayout::P3T2: { return 5; } case EVertexLayout::P3N3: { return 6; } + case EVertexLayout::P4: { return 4; } default: { assert(false); return 0; } }; } @@ -247,6 +257,7 @@ size_t GLModel::Geometry::position_stride_floats(const Format& format) case EVertexLayout::P3: case EVertexLayout::P3T2: case EVertexLayout::P3N3: { return 3; } + case EVertexLayout::P4: { return 4; } default: { assert(false); return 0; } }; } @@ -259,7 +270,8 @@ size_t GLModel::Geometry::position_offset_floats(const Format& format) case EVertexLayout::P2T2: case EVertexLayout::P3: case EVertexLayout::P3T2: - case EVertexLayout::P3N3: { return 0; } + case EVertexLayout::P3N3: + case EVertexLayout::P4: { return 0; } default: { assert(false); return 0; } }; } @@ -321,7 +333,8 @@ bool GLModel::Geometry::has_position(const Format& format) case EVertexLayout::P2T2: case EVertexLayout::P3: case EVertexLayout::P3T2: - case EVertexLayout::P3N3: { return true; } + case EVertexLayout::P3N3: + case EVertexLayout::P4: { return true; } default: { assert(false); return false; } }; } @@ -333,7 +346,8 @@ bool GLModel::Geometry::has_normal(const Format& format) case EVertexLayout::P2: case EVertexLayout::P2T2: case EVertexLayout::P3: - case EVertexLayout::P3T2: { return false; } + case EVertexLayout::P3T2: + case EVertexLayout::P4: { return false; } case EVertexLayout::P3N3: { return true; } default: { assert(false); return false; } }; @@ -347,7 +361,8 @@ bool GLModel::Geometry::has_tex_coord(const Format& format) case EVertexLayout::P3T2: { return true; } case EVertexLayout::P2: case EVertexLayout::P3: - case EVertexLayout::P3N3: { return false; } + case EVertexLayout::P3N3: + case EVertexLayout::P4: { return false; } default: { assert(false); return false; } }; } diff --git a/src/slic3r/GUI/GLModel.hpp b/src/slic3r/GUI/GLModel.hpp index e2a3e75daff..a3fa6c38d0f 100644 --- a/src/slic3r/GUI/GLModel.hpp +++ b/src/slic3r/GUI/GLModel.hpp @@ -41,6 +41,7 @@ namespace GUI { P3, // position 3 floats P3T2, // position 3 floats + texture coords 2 floats P3N3, // position 3 floats + normal 3 floats + P4, // position 4 floats }; enum class EIndexType : unsigned char @@ -70,6 +71,7 @@ namespace GUI { void add_vertex(const Vec3f& position); // EVertexLayout::P3 void add_vertex(const Vec3f& position, const Vec2f& tex_coord); // EVertexLayout::P3T2 void add_vertex(const Vec3f& position, const Vec3f& normal); // EVertexLayout::P3N3 + void add_vertex(const Vec4f& position); // EVertexLayout::P4 void set_vertex(size_t id, const Vec3f& position, const Vec3f& normal); // EVertexLayout::P3N3 diff --git a/src/slic3r/GUI/GLShader.cpp b/src/slic3r/GUI/GLShader.cpp index 9f13269c8d8..5146f03fc6e 100644 --- a/src/slic3r/GUI/GLShader.cpp +++ b/src/slic3r/GUI/GLShader.cpp @@ -317,6 +317,17 @@ void GLShaderProgram::set_uniform(int id, const Matrix4d& value) const set_uniform(id, (Matrix4f)value.cast()); } +void GLShaderProgram::set_uniform(int id, const Vec2f& value) const +{ + if (id >= 0) + glsafe(::glUniform2fv(id, 1, static_cast(value.data()))); +} + +void GLShaderProgram::set_uniform(int id, const Vec2d& value) const +{ + set_uniform(id, static_cast(value.cast())); +} + void GLShaderProgram::set_uniform(int id, const Vec3f& value) const { if (id >= 0) diff --git a/src/slic3r/GUI/GLShader.hpp b/src/slic3r/GUI/GLShader.hpp index e1b2915e0d6..935daaaeaaa 100644 --- a/src/slic3r/GUI/GLShader.hpp +++ b/src/slic3r/GUI/GLShader.hpp @@ -65,6 +65,8 @@ class GLShaderProgram void set_uniform(const char* name, const Matrix3d& value) const { set_uniform(get_uniform_location(name), value); } void set_uniform(const char* name, const Matrix4f& value) const { set_uniform(get_uniform_location(name), value); } void set_uniform(const char* name, const Matrix4d& value) const { set_uniform(get_uniform_location(name), value); } + void set_uniform(const char* name, const Vec2f& value) const { set_uniform(get_uniform_location(name), value); } + void set_uniform(const char* name, const Vec2d& value) const { set_uniform(get_uniform_location(name), value); } void set_uniform(const char* name, const Vec3f& value) const { set_uniform(get_uniform_location(name), value); } void set_uniform(const char* name, const Vec3d& value) const { set_uniform(get_uniform_location(name), value); } void set_uniform(const char* name, const ColorRGB& value) const { set_uniform(get_uniform_location(name), value); } @@ -88,6 +90,8 @@ class GLShaderProgram void set_uniform(int id, const Matrix3d& value) const; void set_uniform(int id, const Matrix4f& value) const; void set_uniform(int id, const Matrix4d& value) const; + void set_uniform(int id, const Vec2f& value) const; + void set_uniform(int id, const Vec2d& value) const; void set_uniform(int id, const Vec3f& value) const; void set_uniform(int id, const Vec3d& value) const; void set_uniform(int id, const ColorRGB& value) const; From 19ad0ca4d9f512c3d637559f63d7e4176d557f21 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Sat, 28 Oct 2023 00:01:28 +0800 Subject: [PATCH 55/99] Tech ENABLE_LEGACY_OPENGL_REMOVAL - Fixed calculation of normal matrices sent to shaders (cherry picked from commit prusa3d/PrusaSlicer@c468dcbed7ec79f90d380b0e76fe61ba5eafa4c6) --- resources/shaders/110/gouraud.vs | 4 +- resources/shaders/110/gouraud_light.vs | 4 +- .../shaders/110/gouraud_light_instanced.vs | 4 +- resources/shaders/110/mm_gouraud.fs | 4 +- resources/shaders/110/thumbnail.vs | 4 +- .../shaders/110/variable_layer_height.vs | 4 +- resources/shaders/140/gouraud.vs | 4 +- resources/shaders/140/gouraud_light.vs | 4 +- .../shaders/140/gouraud_light_instanced.vs | 4 +- resources/shaders/140/mm_gouraud.fs | 4 +- resources/shaders/140/thumbnail.vs | 4 +- .../shaders/140/variable_layer_height.vs | 4 +- src/slic3r/GUI/3DBed.cpp | 14 ++-- src/slic3r/GUI/3DScene.cpp | 11 +-- src/slic3r/GUI/GCodeViewer.cpp | 18 ++--- src/slic3r/GUI/GLCanvas3D.cpp | 24 ++++--- src/slic3r/GUI/Gizmos/GLGizmoAdvancedCut.cpp | 36 +++++----- src/slic3r/GUI/Gizmos/GLGizmoAdvancedCut.hpp | 2 +- src/slic3r/GUI/Gizmos/GLGizmoBase.cpp | 10 +-- src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp | 7 +- src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp | 8 +-- .../GUI/Gizmos/GLGizmoMmuSegmentation.cpp | 7 +- src/slic3r/GUI/Gizmos/GLGizmoMove.cpp | 14 ++-- src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp | 7 +- src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp | 20 +++--- src/slic3r/GUI/Gizmos/GLGizmoSeam.cpp | 7 +- src/slic3r/GUI/Gizmos/GLGizmoSimplify.cpp | 6 +- src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp | 21 +++--- src/slic3r/GUI/Selection.cpp | 67 ++++++++++--------- 29 files changed, 175 insertions(+), 152 deletions(-) diff --git a/resources/shaders/110/gouraud.vs b/resources/shaders/110/gouraud.vs index 70f71f886bc..0e8562871b3 100644 --- a/resources/shaders/110/gouraud.vs +++ b/resources/shaders/110/gouraud.vs @@ -27,7 +27,7 @@ struct SlopeDetection uniform mat4 view_model_matrix; uniform mat4 projection_matrix; -uniform mat3 normal_matrix; +uniform mat3 view_normal_matrix; uniform mat4 volume_world_matrix; uniform SlopeDetection slope; @@ -51,7 +51,7 @@ varying vec3 eye_normal; void main() { // First transform the normal into camera space and normalize the result. - eye_normal = normalize(normal_matrix * v_normal); + eye_normal = normalize(view_normal_matrix * v_normal); // Compute the cos of the angle between the normal and lights direction. The light is directional so the direction is constant for every vertex. // Since these two are normalized the cosine is the dot product. We also need to clamp the result to the [0,1] range. diff --git a/resources/shaders/110/gouraud_light.vs b/resources/shaders/110/gouraud_light.vs index a03653b8a30..135a23b3da8 100644 --- a/resources/shaders/110/gouraud_light.vs +++ b/resources/shaders/110/gouraud_light.vs @@ -16,7 +16,7 @@ const vec3 LIGHT_FRONT_DIR = vec3(0.6985074, 0.1397015, 0.6985074); uniform mat4 view_model_matrix; uniform mat4 projection_matrix; -uniform mat3 normal_matrix; +uniform mat3 view_normal_matrix; attribute vec3 v_position; attribute vec3 v_normal; @@ -27,7 +27,7 @@ varying vec2 intensity; void main() { // First transform the normal into camera space and normalize the result. - vec3 normal = normalize(normal_matrix * v_normal); + vec3 normal = normalize(view_normal_matrix * v_normal); // Compute the cos of the angle between the normal and lights direction. The light is directional so the direction is constant for every vertex. // Since these two are normalized the cosine is the dot product. We also need to clamp the result to the [0,1] range. diff --git a/resources/shaders/110/gouraud_light_instanced.vs b/resources/shaders/110/gouraud_light_instanced.vs index 87748ce6f05..f512a9cafcf 100644 --- a/resources/shaders/110/gouraud_light_instanced.vs +++ b/resources/shaders/110/gouraud_light_instanced.vs @@ -16,7 +16,7 @@ const vec3 LIGHT_FRONT_DIR = vec3(0.6985074, 0.1397015, 0.6985074); uniform mat4 view_model_matrix; uniform mat4 projection_matrix; -uniform mat3 normal_matrix; +uniform mat3 view_normal_matrix; // vertex attributes attribute vec3 v_position; @@ -31,7 +31,7 @@ varying vec2 intensity; void main() { // First transform the normal into camera space and normalize the result. - vec3 eye_normal = normalize(normal_matrix * v_normal); + vec3 eye_normal = normalize(view_normal_matrix * v_normal); // Compute the cos of the angle between the normal and lights direction. The light is directional so the direction is constant for every vertex. // Since these two are normalized the cosine is the dot product. We also need to clamp the result to the [0,1] range. diff --git a/resources/shaders/110/mm_gouraud.fs b/resources/shaders/110/mm_gouraud.fs index 4ecf7bf70c1..8ca23df66d9 100644 --- a/resources/shaders/110/mm_gouraud.fs +++ b/resources/shaders/110/mm_gouraud.fs @@ -26,7 +26,7 @@ uniform vec4 uniform_color; uniform bool volume_mirrored; uniform mat4 view_model_matrix; -uniform mat3 normal_matrix; +uniform mat3 view_normal_matrix; varying vec3 clipping_planes_dots; varying vec4 model_pos; @@ -70,7 +70,7 @@ void main() } } // First transform the normal into camera space and normalize the result. - vec3 eye_normal = normalize(normal_matrix * triangle_normal); + vec3 eye_normal = normalize(view_normal_matrix * triangle_normal); // Compute the cos of the angle between the normal and lights direction. The light is directional so the direction is constant for every vertex. // Since these two are normalized the cosine is the dot product. We also need to clamp the result to the [0,1] range. diff --git a/resources/shaders/110/thumbnail.vs b/resources/shaders/110/thumbnail.vs index aa718b00671..69fd0c753cb 100644 --- a/resources/shaders/110/thumbnail.vs +++ b/resources/shaders/110/thumbnail.vs @@ -16,7 +16,7 @@ const vec3 LIGHT_FRONT_DIR = vec3(0.6985074, 0.1397015, 0.6985074); uniform mat4 view_model_matrix; uniform mat4 projection_matrix; -uniform mat3 normal_matrix; +uniform mat3 view_normal_matrix; uniform mat4 volume_world_matrix; attribute vec3 v_position; @@ -29,7 +29,7 @@ varying vec4 world_pos; void main() { // First transform the normal into camera space and normalize the result. - vec3 normal = normalize(normal_matrix * v_normal); + vec3 normal = normalize(view_normal_matrix * v_normal); // Compute the cos of the angle between the normal and lights direction. The light is directional so the direction is constant for every vertex. // Since these two are normalized the cosine is the dot product. We also need to clamp the result to the [0,1] range. diff --git a/resources/shaders/110/variable_layer_height.vs b/resources/shaders/110/variable_layer_height.vs index e6c88fa8097..2d6334f44e8 100644 --- a/resources/shaders/110/variable_layer_height.vs +++ b/resources/shaders/110/variable_layer_height.vs @@ -16,7 +16,7 @@ const vec3 LIGHT_FRONT_DIR = vec3(0.6985074, 0.1397015, 0.6985074); uniform mat4 view_model_matrix; uniform mat4 projection_matrix; -uniform mat3 normal_matrix; +uniform mat3 view_normal_matrix; uniform mat4 volume_world_matrix; uniform float object_max_z; @@ -38,7 +38,7 @@ void main() // ===================================================== // First transform the normal into camera space and normalize the result. - vec3 normal = (object_max_z > 0.0) ? vec3(0.0, 0.0, 1.0) : normalize(normal_matrix * v_normal); + vec3 normal = (object_max_z > 0.0) ? vec3(0.0, 0.0, 1.0) : normalize(view_normal_matrix * v_normal); // Compute the cos of the angle between the normal and lights direction. The light is directional so the direction is constant for every vertex. // Since these two are normalized the cosine is the dot product. We also need to clamp the result to the [0,1] range. diff --git a/resources/shaders/140/gouraud.vs b/resources/shaders/140/gouraud.vs index aaf251c42d4..8e657205fbc 100644 --- a/resources/shaders/140/gouraud.vs +++ b/resources/shaders/140/gouraud.vs @@ -27,7 +27,7 @@ struct SlopeDetection uniform mat4 view_model_matrix; uniform mat4 projection_matrix; -uniform mat3 normal_matrix; +uniform mat3 view_normal_matrix; uniform mat4 volume_world_matrix; uniform SlopeDetection slope; @@ -51,7 +51,7 @@ out vec3 eye_normal; void main() { // First transform the normal into camera space and normalize the result. - eye_normal = normalize(normal_matrix * v_normal); + eye_normal = normalize(view_normal_matrix * v_normal); // Compute the cos of the angle between the normal and lights direction. The light is directional so the direction is constant for every vertex. // Since these two are normalized the cosine is the dot product. We also need to clamp the result to the [0,1] range. diff --git a/resources/shaders/140/gouraud_light.vs b/resources/shaders/140/gouraud_light.vs index b75a8440587..fad848f8bd5 100644 --- a/resources/shaders/140/gouraud_light.vs +++ b/resources/shaders/140/gouraud_light.vs @@ -16,7 +16,7 @@ const vec3 LIGHT_FRONT_DIR = vec3(0.6985074, 0.1397015, 0.6985074); uniform mat4 view_model_matrix; uniform mat4 projection_matrix; -uniform mat3 normal_matrix; +uniform mat3 view_normal_matrix; in vec3 v_position; in vec3 v_normal; @@ -27,7 +27,7 @@ out vec2 intensity; void main() { // First transform the normal into camera space and normalize the result. - vec3 normal = normalize(normal_matrix * v_normal); + vec3 normal = normalize(view_normal_matrix * v_normal); // Compute the cos of the angle between the normal and lights direction. The light is directional so the direction is constant for every vertex. // Since these two are normalized the cosine is the dot product. We also need to clamp the result to the [0,1] range. diff --git a/resources/shaders/140/gouraud_light_instanced.vs b/resources/shaders/140/gouraud_light_instanced.vs index b6b9ab8be7e..e0437ca3970 100644 --- a/resources/shaders/140/gouraud_light_instanced.vs +++ b/resources/shaders/140/gouraud_light_instanced.vs @@ -16,7 +16,7 @@ const vec3 LIGHT_FRONT_DIR = vec3(0.6985074, 0.1397015, 0.6985074); uniform mat4 view_model_matrix; uniform mat4 projection_matrix; -uniform mat3 normal_matrix; +uniform mat3 view_normal_matrix; // vertex attributes in vec3 v_position; @@ -31,7 +31,7 @@ out vec2 intensity; void main() { // First transform the normal into camera space and normalize the result. - vec3 eye_normal = normalize(normal_matrix * v_normal); + vec3 eye_normal = normalize(view_normal_matrix * v_normal); // Compute the cos of the angle between the normal and lights direction. The light is directional so the direction is constant for every vertex. // Since these two are normalized the cosine is the dot product. We also need to clamp the result to the [0,1] range. diff --git a/resources/shaders/140/mm_gouraud.fs b/resources/shaders/140/mm_gouraud.fs index b7b0f26351d..2156394bea9 100644 --- a/resources/shaders/140/mm_gouraud.fs +++ b/resources/shaders/140/mm_gouraud.fs @@ -26,7 +26,7 @@ uniform vec4 uniform_color; uniform bool volume_mirrored; uniform mat4 view_model_matrix; -uniform mat3 normal_matrix; +uniform mat3 view_normal_matrix; in vec3 clipping_planes_dots; in vec4 model_pos; @@ -70,7 +70,7 @@ void main() } } // First transform the normal into camera space and normalize the result. - vec3 eye_normal = normalize(normal_matrix * triangle_normal); + vec3 eye_normal = normalize(view_normal_matrix * triangle_normal); // Compute the cos of the angle between the normal and lights direction. The light is directional so the direction is constant for every vertex. // Since these two are normalized the cosine is the dot product. We also need to clamp the result to the [0,1] range. diff --git a/resources/shaders/140/thumbnail.vs b/resources/shaders/140/thumbnail.vs index 19e40c614ab..90ca720a379 100644 --- a/resources/shaders/140/thumbnail.vs +++ b/resources/shaders/140/thumbnail.vs @@ -16,7 +16,7 @@ const vec3 LIGHT_FRONT_DIR = vec3(0.6985074, 0.1397015, 0.6985074); uniform mat4 view_model_matrix; uniform mat4 projection_matrix; -uniform mat3 normal_matrix; +uniform mat3 view_normal_matrix; uniform mat4 volume_world_matrix; in vec3 v_position; @@ -29,7 +29,7 @@ out vec4 world_pos; void main() { // First transform the normal into camera space and normalize the result. - vec3 normal = normalize(normal_matrix * v_normal); + vec3 normal = normalize(view_normal_matrix * v_normal); // Compute the cos of the angle between the normal and lights direction. The light is directional so the direction is constant for every vertex. // Since these two are normalized the cosine is the dot product. We also need to clamp the result to the [0,1] range. diff --git a/resources/shaders/140/variable_layer_height.vs b/resources/shaders/140/variable_layer_height.vs index dd463b9c7af..d8deb2f9eef 100644 --- a/resources/shaders/140/variable_layer_height.vs +++ b/resources/shaders/140/variable_layer_height.vs @@ -16,7 +16,7 @@ const vec3 LIGHT_FRONT_DIR = vec3(0.6985074, 0.1397015, 0.6985074); uniform mat4 view_model_matrix; uniform mat4 projection_matrix; -uniform mat3 normal_matrix; +uniform mat3 view_normal_matrix; uniform mat4 volume_world_matrix; uniform float object_max_z; @@ -38,7 +38,7 @@ void main() // ===================================================== // First transform the normal into camera space and normalize the result. - vec3 normal = (object_max_z > 0.0) ? vec3(0.0, 0.0, 1.0) : normalize(normal_matrix * v_normal); + vec3 normal = (object_max_z > 0.0) ? vec3(0.0, 0.0, 1.0) : normalize(view_normal_matrix * v_normal); // Compute the cos of the angle between the normal and lights direction. The light is directional so the direction is constant for every vertex. // Since these two are normalized the cosine is the dot product. We also need to clamp the result to the [0,1] range. diff --git a/src/slic3r/GUI/3DBed.cpp b/src/slic3r/GUI/3DBed.cpp index 420629ca42f..066da6b3363 100644 --- a/src/slic3r/GUI/3DBed.cpp +++ b/src/slic3r/GUI/3DBed.cpp @@ -208,10 +208,11 @@ void Bed3D::Axes::render() { auto render_axis = [this](GLShaderProgram* shader, const Transform3d& transform) { const Camera& camera = wxGetApp().plater()->get_camera(); - const Transform3d matrix = camera.get_view_matrix() * transform; - shader->set_uniform("view_model_matrix", matrix); + const Transform3d& view_matrix = camera.get_view_matrix(); + shader->set_uniform("view_model_matrix", view_matrix * transform); shader->set_uniform("projection_matrix", camera.get_projection_matrix()); - shader->set_uniform("normal_matrix", (Matrix3d)matrix.matrix().block(0, 0, 3, 3).inverse().transpose()); + const Matrix3d view_normal_matrix = view_matrix.matrix().block(0, 0, 3, 3) * transform.matrix().block(0, 0, 3, 3).inverse().transpose(); + shader->set_uniform("view_normal_matrix", view_normal_matrix); m_arrow.render(); }; @@ -675,10 +676,11 @@ void Bed3D::render_model(const Transform3d& view_matrix, const Transform3d& proj if (shader != nullptr) { shader->start_using(); shader->set_uniform("emission_factor", 0.0f); - const Transform3d matrix = view_matrix * Geometry::assemble_transform(m_model_offset); - shader->set_uniform("view_model_matrix", matrix); + const Transform3d model_matrix = Geometry::assemble_transform(m_model_offset); + shader->set_uniform("view_model_matrix", view_matrix * model_matrix); shader->set_uniform("projection_matrix", projection_matrix); - shader->set_uniform("normal_matrix", (Matrix3d)matrix.matrix().block(0, 0, 3, 3).inverse().transpose()); + const Matrix3d view_normal_matrix = view_matrix.matrix().block(0, 0, 3, 3) * model_matrix.matrix().block(0, 0, 3, 3).inverse().transpose(); + shader->set_uniform("view_normal_matrix", view_normal_matrix); m_model.render(); shader->stop_using(); } diff --git a/src/slic3r/GUI/3DScene.cpp b/src/slic3r/GUI/3DScene.cpp index 7d35500d34a..af1eb34bfe4 100644 --- a/src/slic3r/GUI/3DScene.cpp +++ b/src/slic3r/GUI/3DScene.cpp @@ -912,13 +912,14 @@ void GLVolumeCollection::render(GLVolumeCollection::ERenderType type, bool disab glcheck(); volume.first->model.set_color(volume.first->render_color); - const Transform3d matrix = view_matrix * volume.first->world_matrix(); - shader->set_uniform("view_model_matrix", matrix); + const Transform3d model_matrix = volume.first->world_matrix(); + shader->set_uniform("view_model_matrix", view_matrix * model_matrix); shader->set_uniform("projection_matrix", projection_matrix); - shader->set_uniform("normal_matrix", (Matrix3d)matrix.matrix().block(0, 0, 3, 3).inverse().transpose()); - //BBS: add outline related logic + const Matrix3d view_normal_matrix = view_matrix.matrix().block(0, 0, 3, 3) * model_matrix.matrix().block(0, 0, 3, 3).inverse().transpose(); + shader->set_uniform("view_normal_matrix", view_normal_matrix); + //BBS: add outline related logic if (with_outline && volume.first->selected) - volume.first->render_with_outline(matrix); + volume.first->render_with_outline(view_matrix * model_matrix); else volume.first->render(); diff --git a/src/slic3r/GUI/GCodeViewer.cpp b/src/slic3r/GUI/GCodeViewer.cpp index f0aa295d9e8..948632e1591 100644 --- a/src/slic3r/GUI/GCodeViewer.cpp +++ b/src/slic3r/GUI/GCodeViewer.cpp @@ -318,10 +318,12 @@ void GCodeViewer::SequentialView::Marker::render(int canvas_width, int canvas_he shader->set_uniform("emission_factor", 0.0f); const Camera& camera = wxGetApp().plater()->get_camera(); - const Transform3d matrix = camera.get_view_matrix() * m_world_transform.cast(); - shader->set_uniform("view_model_matrix", matrix); + const Transform3d& view_matrix = camera.get_view_matrix(); + const Transform3d model_matrix = m_world_transform.cast(); + shader->set_uniform("view_model_matrix", view_matrix * model_matrix); shader->set_uniform("projection_matrix", camera.get_projection_matrix()); - shader->set_uniform("normal_matrix", (Matrix3d)matrix.matrix().block(0, 0, 3, 3).inverse().transpose()); + const Matrix3d view_normal_matrix = view_matrix.matrix().block(0, 0, 3, 3) * model_matrix.matrix().block(0, 0, 3, 3).inverse().transpose(); + shader->set_uniform("view_normal_matrix", view_normal_matrix); m_model.render(); @@ -3887,10 +3889,9 @@ void GCodeViewer::render_toolpaths() shader->start_using(); - const Transform3d& view_matrix = camera.get_view_matrix(); - shader->set_uniform("view_model_matrix", view_matrix); + shader->set_uniform("view_model_matrix", camera.get_view_matrix()); shader->set_uniform("projection_matrix", camera.get_projection_matrix()); - shader->set_uniform("normal_matrix", (Matrix3d)view_matrix.matrix().block(0, 0, 3, 3).inverse().transpose()); + shader->set_uniform("view_normal_matrix", (Matrix3d)Matrix3d::Identity()); if (buffer.render_primitive_type == TBuffer::ERenderPrimitiveType::InstancedModel) { shader->set_uniform("emission_factor", 0.25f); @@ -3974,10 +3975,9 @@ void GCodeViewer::render_toolpaths() shader->start_using(); - const Transform3d& view_matrix = camera.get_view_matrix(); - shader->set_uniform("view_model_matrix", view_matrix); + shader->set_uniform("view_model_matrix", camera.get_view_matrix()); shader->set_uniform("projection_matrix", camera.get_projection_matrix()); - shader->set_uniform("normal_matrix", (Matrix3d)view_matrix.matrix().block(0, 0, 3, 3).inverse().transpose()); + shader->set_uniform("view_normal_matrix", (Matrix3d)Matrix3d::Identity()); const int position_id = shader->get_attrib_location("v_position"); const int normal_id = shader->get_attrib_location("v_normal"); diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 074ccb81579..832f248a255 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -410,7 +410,7 @@ void GLCanvas3D::LayersEditing::render_active_object_annotations(const GLCanvas3 shader->set_uniform("object_max_z", m_object_max_z); shader->set_uniform("view_model_matrix", Transform3d::Identity()); shader->set_uniform("projection_matrix", Transform3d::Identity()); - shader->set_uniform("normal_matrix", (Matrix3d)Eigen::Matrix3d::Identity()); + shader->set_uniform("view_normal_matrix", (Matrix3d)Matrix3d::Identity()); glsafe(::glPixelStorei(GL_UNPACK_ALIGNMENT, 1)); glsafe(::glBindTexture(GL_TEXTURE_2D, m_z_texture_id)); @@ -569,9 +569,11 @@ void GLCanvas3D::LayersEditing::render_volumes(const GLCanvas3D& canvas, const G shader->set_uniform("volume_world_matrix", glvolume->world_matrix()); shader->set_uniform("object_max_z", 0.0f); - const Transform3d view_model_matrix = camera.get_view_matrix() * glvolume->world_matrix(); - shader->set_uniform("view_model_matrix", view_model_matrix); - shader->set_uniform("normal_matrix", (Matrix3d)view_model_matrix.matrix().block(0, 0, 3, 3).inverse().transpose()); + const Transform3d& view_matrix = camera.get_view_matrix(); + const Transform3d model_matrix = glvolume->world_matrix(); + shader->set_uniform("view_model_matrix", view_matrix * model_matrix); + const Matrix3d view_normal_matrix = view_matrix.matrix().block(0, 0, 3, 3) * model_matrix.matrix().block(0, 0, 3, 3).inverse().transpose(); + shader->set_uniform("view_normal_matrix", view_normal_matrix); glvolume->render(); } @@ -5597,10 +5599,11 @@ void GLCanvas3D::render_thumbnail_internal(ThumbnailData& thumbnail_data, const const bool is_active = vol->is_active; vol->is_active = true; - const Transform3d matrix = view_matrix * vol->world_matrix(); - shader->set_uniform("view_model_matrix", matrix); + const Transform3d model_matrix = vol->world_matrix(); + shader->set_uniform("view_model_matrix", view_matrix * model_matrix); shader->set_uniform("projection_matrix", projection_matrix); - shader->set_uniform("normal_matrix", (Matrix3d) matrix.matrix().block(0, 0, 3, 3).inverse().transpose()); + const Matrix3d view_normal_matrix = view_matrix.matrix().block(0, 0, 3, 3) * model_matrix.matrix().block(0, 0, 3, 3).inverse().transpose(); + shader->set_uniform("view_normal_matrix", view_normal_matrix); vol->simple_render(shader, model_objects, extruder_colors); vol->is_active = is_active; } @@ -5634,10 +5637,11 @@ void GLCanvas3D::render_thumbnail_internal(ThumbnailData& thumbnail_data, const // the volume may have been deactivated by an active gizmo const bool is_active = vol->is_active; vol->is_active = true; - const Transform3d matrix = view_matrix * vol->world_matrix(); - shader->set_uniform("view_model_matrix", matrix); + const Transform3d model_matrix = vol->world_matrix(); + shader->set_uniform("view_model_matrix", view_matrix * model_matrix); shader->set_uniform("projection_matrix", projection_matrix); - shader->set_uniform("normal_matrix", (Matrix3d) matrix.matrix().block(0, 0, 3, 3).inverse().transpose()); + const Matrix3d view_normal_matrix = view_matrix.matrix().block(0, 0, 3, 3) * model_matrix.matrix().block(0, 0, 3, 3).inverse().transpose(); + shader->set_uniform("view_normal_matrix", view_normal_matrix); vol->simple_render(shader, model_objects, extruder_colors); vol->is_active = is_active; } diff --git a/src/slic3r/GUI/Gizmos/GLGizmoAdvancedCut.cpp b/src/slic3r/GUI/Gizmos/GLGizmoAdvancedCut.cpp index 0871ca3df22..19ab81021c5 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoAdvancedCut.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoAdvancedCut.cpp @@ -527,7 +527,6 @@ void GLGizmoAdvancedCut::on_render_for_picking() Vec3d pos = connector.pos + instance_offset + sla_shift * Vec3d::UnitZ(); float height = connector.height; - const Camera &camera = wxGetApp().plater()->get_camera(); if (connector.attribs.type == CutConnectorType::Dowel && connector.attribs.style == CutConnectorStyle::Prizm) { pos -= height * m_cut_plane_normal; height *= 2; @@ -540,11 +539,10 @@ void GLGizmoAdvancedCut::on_render_for_picking() Transform3d scale_tf = Transform3d::Identity(); scale_tf.scale(Vec3f(connector.radius, connector.radius, height).cast()); - const Transform3d view_model_matrix = translate_tf * m_rotate_matrix * scale_tf; - + const Transform3d model_matrix = translate_tf * m_rotate_matrix * scale_tf; ColorRGBA color = picking_color_component(i+1); - render_connector_model(m_shapes[connectors[i].attribs], color, view_model_matrix, true); + render_connector_model(m_shapes[connectors[i].attribs], color, model_matrix, true); } } @@ -961,14 +959,14 @@ void GLGizmoAdvancedCut::render_cut_plane_and_grabbers() cube.set_color(render_color); + const Transform3d trafo_matrix = Geometry::assemble_transform(m_move_grabber.center) * m_rotate_matrix * + Geometry::assemble_transform(Vec3d::Zero(), Vec3d::Zero(), fullsize * Vec3d::Ones()); const Camera& camera = wxGetApp().plater()->get_camera(); - const Transform3d view_model_matrix = camera.get_view_matrix() * Geometry::assemble_transform(m_move_grabber.center) * - m_rotate_matrix * - Geometry::assemble_transform(Vec3d::Zero(), Vec3d::Zero(), fullsize * Vec3d::Ones()); - const Transform3d& projection_matrix = camera.get_projection_matrix(); - shader->set_uniform("view_model_matrix", view_model_matrix); - shader->set_uniform("projection_matrix", projection_matrix); - shader->set_uniform("normal_matrix", (Matrix3d) view_model_matrix.matrix().block(0, 0, 3, 3).inverse().transpose()); + const Transform3d& view_matrix = camera.get_view_matrix(); + shader->set_uniform("view_model_matrix", view_matrix * trafo_matrix); + shader->set_uniform("projection_matrix", camera.get_projection_matrix()); + const Matrix3d view_normal_matrix = view_matrix.matrix().block(0, 0, 3, 3) * trafo_matrix.matrix().block(0, 0, 3, 3).inverse().transpose(); + shader->set_uniform("view_normal_matrix", view_normal_matrix); cube.render(); shader->stop_using(); } @@ -1036,9 +1034,9 @@ void GLGizmoAdvancedCut::render_connectors() Transform3d scale_tf = Transform3d::Identity(); scale_tf.scale(Vec3f(connector.radius, connector.radius, height).cast()); - const Transform3d view_model_matrix = translate_tf * m_rotate_matrix * scale_tf; + const Transform3d model_matrix = translate_tf * m_rotate_matrix * scale_tf; - render_connector_model(m_shapes[connector.attribs], render_color, view_model_matrix); + render_connector_model(m_shapes[connector.attribs], render_color, model_matrix); } } @@ -1091,7 +1089,7 @@ void GLGizmoAdvancedCut::render_cut_line() } } -void GLGizmoAdvancedCut::render_connector_model(GLModel &model, const ColorRGBA &color, Transform3d view_model_matrix, bool for_picking) +void GLGizmoAdvancedCut::render_connector_model(GLModel &model, const ColorRGBA &color, Transform3d model_matrix, bool for_picking) { GLShaderProgram *shader = nullptr; if (for_picking) @@ -1102,11 +1100,11 @@ void GLGizmoAdvancedCut::render_connector_model(GLModel &model, const ColorRGBA shader->start_using(); const Camera& camera = wxGetApp().plater()->get_camera(); - view_model_matrix = camera.get_view_matrix() * view_model_matrix; - const Transform3d &projection_matrix = camera.get_projection_matrix(); - shader->set_uniform("view_model_matrix", view_model_matrix); - shader->set_uniform("projection_matrix", projection_matrix); - shader->set_uniform("normal_matrix", (Matrix3d) view_model_matrix.matrix().block(0, 0, 3, 3).inverse().transpose()); + const Transform3d& view_matrix = camera.get_view_matrix(); + shader->set_uniform("view_model_matrix", view_matrix * model_matrix); + shader->set_uniform("projection_matrix", camera.get_projection_matrix()); + const Matrix3d view_normal_matrix = view_matrix.matrix().block(0, 0, 3, 3) * model_matrix.matrix().block(0, 0, 3, 3).inverse().transpose(); + shader->set_uniform("view_normal_matrix", view_normal_matrix); model.set_color(color); model.render(); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoAdvancedCut.hpp b/src/slic3r/GUI/Gizmos/GLGizmoAdvancedCut.hpp index 4943f087fcb..5d6354c1171 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoAdvancedCut.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoAdvancedCut.hpp @@ -204,7 +204,7 @@ struct Rotate_data { void render_connectors(); void render_clipper_cut(); void render_cut_line(); - void render_connector_model(GLModel &model, const ColorRGBA& color, Transform3d view_model_matrix, bool for_picking = false); + void render_connector_model(GLModel &model, const ColorRGBA& color, Transform3d model_matrix, bool for_picking = false); void clear_selection(); void init_connector_shapes(); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoBase.cpp b/src/slic3r/GUI/Gizmos/GLGizmoBase.cpp index 961ec5104dd..5aed864aa9d 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoBase.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoBase.cpp @@ -121,12 +121,14 @@ void GLGizmoBase::Grabber::render(float size, const ColorRGBA& render_color, boo m_cube.set_color(render_color); const Camera& camera = wxGetApp().plater()->get_camera(); - const Transform3d view_model_matrix = camera.get_view_matrix() * matrix * Geometry::assemble_transform(center, angles, fullsize * Vec3d::Ones()); - const Transform3d& projection_matrix = camera.get_projection_matrix(); + const Transform3d& view_matrix = camera.get_view_matrix(); + const Transform3d model_matrix = matrix * Geometry::assemble_transform(center, angles, fullsize * Vec3d::Ones()); + const Transform3d view_model_matrix = view_matrix * model_matrix; shader->set_uniform("view_model_matrix", view_model_matrix); - shader->set_uniform("projection_matrix", projection_matrix); - shader->set_uniform("normal_matrix", (Matrix3d)view_model_matrix.matrix().block(0, 0, 3, 3).inverse().transpose()); + shader->set_uniform("projection_matrix", camera.get_projection_matrix()); + const Matrix3d view_normal_matrix = view_matrix.matrix().block(0, 0, 3, 3) * model_matrix.matrix().block(0, 0, 3, 3).inverse().transpose(); + shader->set_uniform("view_normal_matrix", view_normal_matrix); m_cube.render(); } diff --git a/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp b/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp index 37d8615cd3a..e66e511f52f 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp @@ -178,10 +178,11 @@ void GLGizmoFdmSupports::render_triangles(const Selection& selection) const glsafe(::glFrontFace(GL_CW)); const Camera& camera = wxGetApp().plater()->get_camera(); - const Transform3d matrix = camera.get_view_matrix() * trafo_matrix; - shader->set_uniform("view_model_matrix", matrix); + const Transform3d& view_matrix = camera.get_view_matrix(); + shader->set_uniform("view_model_matrix", view_matrix * trafo_matrix); shader->set_uniform("projection_matrix", camera.get_projection_matrix()); - shader->set_uniform("normal_matrix", (Matrix3d)matrix.matrix().block(0, 0, 3, 3).inverse().transpose()); + const Matrix3d view_normal_matrix = view_matrix.matrix().block(0, 0, 3, 3) * trafo_matrix.matrix().block(0, 0, 3, 3).inverse().transpose(); + shader->set_uniform("view_normal_matrix", view_normal_matrix); float normal_z = -::cos(Geometry::deg2rad(m_highlight_by_angle_threshold_deg)); Matrix3f normal_matrix = static_cast(trafo_matrix.matrix().block(0, 0, 3, 3).inverse().transpose().cast()); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp b/src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp index 41a5aed7e4a..733ae7494de 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp @@ -158,11 +158,11 @@ void GLGizmoHollow::render_points(const Selection& selection, bool picking) Eigen::Quaterniond q; q.setFromTwoVectors(Vec3d::UnitZ(), instance_scaling_matrix_inverse * (-drain_hole.normal).cast()); const Eigen::AngleAxisd aa(q); - const Transform3d view_model_matrix = view_matrix * instance_matrix * hole_matrix * Transform3d(aa.toRotationMatrix()) * + const Transform3d model_matrix = instance_matrix * hole_matrix * Transform3d(aa.toRotationMatrix()) * Geometry::assemble_transform(-drain_hole.height * Vec3d::UnitZ(), Vec3d::Zero(), Vec3d(drain_hole.radius, drain_hole.radius, drain_hole.height + sla::HoleStickOutLength)); - - shader->set_uniform("view_model_matrix", view_model_matrix); - shader->set_uniform("normal_matrix", (Matrix3d)view_model_matrix.matrix().block(0, 0, 3, 3).inverse().transpose()); + shader->set_uniform("view_model_matrix", view_matrix * model_matrix); + const Matrix3d view_normal_matrix = view_matrix.matrix().block(0, 0, 3, 3) * model_matrix.matrix().block(0, 0, 3, 3).inverse().transpose(); + shader->set_uniform("view_normal_matrix", view_normal_matrix); m_cylinder.render(); if (vol->is_left_handed()) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp index c1aed1867eb..e99a7bb34ae 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp @@ -226,10 +226,11 @@ void GLGizmoMmuSegmentation::render_triangles(const Selection &selection) const glsafe(::glFrontFace(GL_CW)); const Camera& camera = wxGetApp().plater()->get_camera(); - const Transform3d matrix = camera.get_view_matrix() * trafo_matrix; - shader->set_uniform("view_model_matrix", matrix); + const Transform3d& view_matrix = camera.get_view_matrix(); + shader->set_uniform("view_model_matrix", view_matrix * trafo_matrix); shader->set_uniform("projection_matrix", camera.get_projection_matrix()); - shader->set_uniform("normal_matrix", (Matrix3d)matrix.matrix().block(0, 0, 3, 3).inverse().transpose()); + const Matrix3d view_normal_matrix = view_matrix.matrix().block(0, 0, 3, 3) * trafo_matrix.matrix().block(0, 0, 3, 3).inverse().transpose(); + shader->set_uniform("view_normal_matrix", view_normal_matrix); shader->set_uniform("volume_world_matrix", trafo_matrix); shader->set_uniform("volume_mirrored", is_left_handed); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMove.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMove.cpp index cdf9662cc43..5ffe69f8ec3 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMove.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMove.cpp @@ -265,16 +265,18 @@ void GLGizmoMove3D::render_grabber_extension(Axis axis, const BoundingBoxf3& box shader->set_uniform("emission_factor", 0.1f); const Camera& camera = wxGetApp().plater()->get_camera(); - Transform3d view_model_matrix = camera.get_view_matrix() * Geometry::assemble_transform(m_grabbers[axis].center); + const Transform3d& view_matrix = camera.get_view_matrix(); + Transform3d model_matrix = Geometry::assemble_transform(m_grabbers[axis].center); if (axis == X) - view_model_matrix = view_model_matrix * Geometry::assemble_transform(Vec3d::Zero(), 0.5 * PI * Vec3d::UnitY()); + model_matrix = model_matrix * Geometry::assemble_transform(Vec3d::Zero(), 0.5 * PI * Vec3d::UnitY()); else if (axis == Y) - view_model_matrix = view_model_matrix * Geometry::assemble_transform(Vec3d::Zero(), -0.5 * PI * Vec3d::UnitX()); - view_model_matrix = view_model_matrix * Geometry::assemble_transform(Vec3d::Zero(), Vec3d::Zero(), Vec3d(0.75 * size, 0.75 * size, 2.0 * size)); + model_matrix = model_matrix * Geometry::assemble_transform(Vec3d::Zero(), -0.5 * PI * Vec3d::UnitX()); + model_matrix = model_matrix * Geometry::assemble_transform(2.0 * size * Vec3d::UnitZ(), Vec3d::Zero(), Vec3d(0.75 * size, 0.75 * size, 3.0 * size)); - shader->set_uniform("view_model_matrix", view_model_matrix); + shader->set_uniform("view_model_matrix", view_matrix * model_matrix); shader->set_uniform("projection_matrix", camera.get_projection_matrix()); - shader->set_uniform("normal_matrix", (Matrix3d)view_model_matrix.matrix().block(0, 0, 3, 3).inverse().transpose()); + const Matrix3d view_normal_matrix = view_matrix.matrix().block(0, 0, 3, 3) * model_matrix.matrix().block(0, 0, 3, 3).inverse().transpose(); + shader->set_uniform("view_normal_matrix", view_normal_matrix); m_cone.render(); shader->stop_using(); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp b/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp index 1d577a45b4f..4afaf06b492 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp @@ -107,10 +107,11 @@ void GLGizmoPainterBase::render_triangles(const Selection& selection) const glsafe(::glFrontFace(GL_CW)); const Camera& camera = wxGetApp().plater()->get_camera(); - const Transform3d matrix = camera.get_view_matrix() * trafo_matrix; - shader->set_uniform("view_model_matrix", matrix); + const Transform3d& view_matrix = camera.get_view_matrix(); + shader->set_uniform("view_model_matrix", view_matrix * trafo_matrix); shader->set_uniform("projection_matrix", camera.get_projection_matrix()); - shader->set_uniform("normal_matrix", (Matrix3d)matrix.matrix().block(0, 0, 3, 3).inverse().transpose()); + const Matrix3d view_normal_matrix = view_matrix.matrix().block(0, 0, 3, 3) * trafo_matrix.matrix().block(0, 0, 3, 3).inverse().transpose(); + shader->set_uniform("view_normal_matrix", view_normal_matrix); // For printers with multiple extruders, it is necessary to pass trafo_matrix // to the shader input variable print_box.volume_world_matrix before diff --git a/src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp b/src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp index 4e974e77e84..ce6d0d93d6e 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp @@ -415,19 +415,19 @@ void GLGizmoRotate::render_grabber_extension(const BoundingBoxf3& box, bool pick const Transform3d& view_matrix = camera.get_view_matrix(); shader->set_uniform("projection_matrix", camera.get_projection_matrix()); - Transform3d view_model_matrix = view_matrix * m_grabbers.front().matrix * - Geometry::assemble_transform(center, Vec3d(0.5 * PI, 0.0, m_angle)) * - Geometry::assemble_transform(1.5 * size * Vec3d::UnitZ(), Vec3d::Zero(), Vec3d(0.75 * size, 0.75 * size, 3.0 * size)); + Transform3d model_matrix = m_grabbers.front().matrix * Geometry::assemble_transform(center, Vec3d(0.5 * PI, 0.0, m_angle)) * + Geometry::assemble_transform(2.0 * size * Vec3d::UnitZ(), Vec3d::Zero(), Vec3d(0.75 * size, 0.75 * size, 3.0 * size)); - shader->set_uniform("view_model_matrix", view_model_matrix); - shader->set_uniform("normal_matrix", (Matrix3d)view_model_matrix.matrix().block(0, 0, 3, 3).inverse().transpose()); + shader->set_uniform("view_model_matrix", view_matrix * model_matrix); + Matrix3d view_normal_matrix = view_matrix.matrix().block(0, 0, 3, 3) * model_matrix.matrix().block(0, 0, 3, 3).inverse().transpose(); + shader->set_uniform("view_normal_matrix", view_normal_matrix); m_cone.render(); - view_model_matrix = view_matrix * m_grabbers.front().matrix * - Geometry::assemble_transform(center, Vec3d(-0.5 * PI, 0.0, m_angle)) * - Geometry::assemble_transform(1.5 * size * Vec3d::UnitZ(), Vec3d::Zero(), Vec3d(0.75 * size, 0.75 * size, 3.0 * size)); + model_matrix = m_grabbers.front().matrix * Geometry::assemble_transform(center, Vec3d(-0.5 * PI, 0.0, m_angle)) * + Geometry::assemble_transform(2.0 * size * Vec3d::UnitZ(), Vec3d::Zero(), Vec3d(0.75 * size, 0.75 * size, 3.0 * size)); - shader->set_uniform("view_model_matrix", view_model_matrix); - shader->set_uniform("normal_matrix", (Matrix3d)view_model_matrix.matrix().block(0, 0, 3, 3).inverse().transpose()); + shader->set_uniform("view_model_matrix", view_matrix * model_matrix); + view_normal_matrix = view_matrix.matrix().block(0, 0, 3, 3) * model_matrix.matrix().block(0, 0, 3, 3).inverse().transpose(); + shader->set_uniform("view_normal_matrix", view_normal_matrix); m_cone.render(); shader->stop_using(); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSeam.cpp b/src/slic3r/GUI/Gizmos/GLGizmoSeam.cpp index 7aefc0364a7..54909592f15 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSeam.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSeam.cpp @@ -121,10 +121,11 @@ void GLGizmoSeam::render_triangles(const Selection& selection) const glsafe(::glFrontFace(GL_CW)); const Camera& camera = wxGetApp().plater()->get_camera(); - const Transform3d matrix = camera.get_view_matrix() * trafo_matrix; - shader->set_uniform("view_model_matrix", matrix); + const Transform3d& view_matrix = camera.get_view_matrix(); + shader->set_uniform("view_model_matrix", view_matrix * trafo_matrix); shader->set_uniform("projection_matrix", camera.get_projection_matrix()); - shader->set_uniform("normal_matrix", (Matrix3d)matrix.matrix().block(0, 0, 3, 3).inverse().transpose()); + const Matrix3d view_normal_matrix = view_matrix.matrix().block(0, 0, 3, 3) * trafo_matrix.matrix().block(0, 0, 3, 3).inverse().transpose(); + shader->set_uniform("view_normal_matrix", view_normal_matrix); float normal_z = -::cos(Geometry::deg2rad(m_highlight_by_angle_threshold_deg)); Matrix3f normal_matrix = static_cast(trafo_matrix.matrix().block(0, 0, 3, 3).inverse().transpose().cast()); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSimplify.cpp b/src/slic3r/GUI/Gizmos/GLGizmoSimplify.cpp index c8397049bce..4c7042a0059 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSimplify.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSimplify.cpp @@ -647,10 +647,12 @@ void GLGizmoSimplify::on_render() glsafe(::glEnable(GL_DEPTH_TEST)); gouraud_shader->start_using(); const Camera& camera = wxGetApp().plater()->get_camera(); - const Transform3d view_model_matrix = camera.get_view_matrix() * trafo_matrix; + const Transform3d& view_matrix = camera.get_view_matrix(); + const Transform3d view_model_matrix = view_matrix * trafo_matrix; gouraud_shader->set_uniform("view_model_matrix", view_model_matrix); gouraud_shader->set_uniform("projection_matrix", camera.get_projection_matrix()); - gouraud_shader->set_uniform("normal_matrix", (Matrix3d)view_model_matrix.matrix().block(0, 0, 3, 3).inverse().transpose()); + const Matrix3d view_normal_matrix = view_matrix.matrix().block(0, 0, 3, 3) * trafo_matrix.matrix().block(0, 0, 3, 3).inverse().transpose(); + gouraud_shader->set_uniform("view_normal_matrix", view_normal_matrix); m_glmodel.render(); gouraud_shader->stop_using(); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp index 91b429c00ef..12449eedaf4 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp @@ -197,21 +197,23 @@ void GLGizmoSlaSupports::render_points(const Selection& selection, bool picking) const Eigen::AngleAxisd aa(q); const double cone_radius = 0.25; // mm const double cone_height = 0.75; - const Transform3d view_model_matrix = view_matrix * instance_matrix * support_matrix * Transform3d(aa.toRotationMatrix()) * + const Transform3d model_matrix = instance_matrix * support_matrix * Transform3d(aa.toRotationMatrix()) * Geometry::assemble_transform((cone_height + support_point.head_front_radius * RenderPointScale) * Vec3d::UnitZ(), Vec3d(PI, 0.0, 0.0), Vec3d(cone_radius, cone_radius, cone_height)); - shader->set_uniform("view_model_matrix", view_model_matrix); - shader->set_uniform("normal_matrix", (Matrix3d)view_model_matrix.matrix().block(0, 0, 3, 3).inverse().transpose()); + shader->set_uniform("view_model_matrix", view_matrix * model_matrix); + const Matrix3d view_normal_matrix = view_matrix.matrix().block(0, 0, 3, 3) * model_matrix.matrix().block(0, 0, 3, 3).inverse().transpose(); + shader->set_uniform("view_normal_matrix", view_normal_matrix); m_cone.render(); } const double radius = (double)support_point.head_front_radius * RenderPointScale; - const Transform3d view_model_matrix = view_matrix * instance_matrix * support_matrix * + const Transform3d model_matrix = instance_matrix * support_matrix * Geometry::assemble_transform(Vec3d::Zero(), Vec3d::Zero(), radius * Vec3d::Ones()); - shader->set_uniform("view_model_matrix", view_model_matrix); - shader->set_uniform("normal_matrix", (Matrix3d)view_model_matrix.matrix().block(0, 0, 3, 3).inverse().transpose()); + shader->set_uniform("view_model_matrix", view_matrix * model_matrix); + const Matrix3d view_normal_matrix = view_matrix.matrix().block(0, 0, 3, 3) * model_matrix.matrix().block(0, 0, 3, 3).inverse().transpose(); + shader->set_uniform("view_normal_matrix", view_normal_matrix); m_sphere.render(); if (vol->is_left_handed()) @@ -236,11 +238,12 @@ void GLGizmoSlaSupports::render_points(const Selection& selection, bool picking) Eigen::Quaterniond q; q.setFromTwoVectors(Vec3d::UnitZ(), instance_scaling_matrix_inverse * (-drain_hole.normal).cast()); const Eigen::AngleAxisd aa(q); - const Transform3d view_model_matrix = view_matrix * instance_matrix * hole_matrix * Transform3d(aa.toRotationMatrix()) * + const Transform3d model_matrix = instance_matrix * hole_matrix * Transform3d(aa.toRotationMatrix()) * Geometry::assemble_transform(-drain_hole.height * Vec3d::UnitZ(), Vec3d::Zero(), Vec3d(drain_hole.radius, drain_hole.radius, drain_hole.height + sla::HoleStickOutLength)); - shader->set_uniform("view_model_matrix", view_model_matrix); - shader->set_uniform("normal_matrix", (Matrix3d)view_model_matrix.matrix().block(0, 0, 3, 3).inverse().transpose()); + shader->set_uniform("view_model_matrix", view_matrix * model_matrix); + const Matrix3d view_normal_matrix = view_matrix.matrix().block(0, 0, 3, 3) * model_matrix.matrix().block(0, 0, 3, 3).inverse().transpose(); + shader->set_uniform("view_normal_matrix", view_normal_matrix); m_cylinder.render(); if (vol->is_left_handed()) diff --git a/src/slic3r/GUI/Selection.cpp b/src/slic3r/GUI/Selection.cpp index f0a2893ece9..42e004b8683 100644 --- a/src/slic3r/GUI/Selection.cpp +++ b/src/slic3r/GUI/Selection.cpp @@ -2252,26 +2252,28 @@ static ColorRGBA get_color(Axis axis) void Selection::render_sidebar_position_hints(const std::string& sidebar_field, GLShaderProgram& shader, const Transform3d& matrix) { const Camera& camera = wxGetApp().plater()->get_camera(); - const Transform3d view_matrix = camera.get_view_matrix() * matrix; + const Transform3d& view_matrix = camera.get_view_matrix(); shader.set_uniform("projection_matrix", camera.get_projection_matrix()); if (boost::ends_with(sidebar_field, "x")) { - const Transform3d view_model_matrix = view_matrix * Geometry::assemble_transform(Vec3d::Zero(), -0.5 * PI * Vec3d::UnitZ()); - shader.set_uniform("view_model_matrix", view_model_matrix); - shader.set_uniform("normal_matrix", (Matrix3d)view_model_matrix.matrix().block(0, 0, 3, 3).inverse().transpose()); + const Transform3d model_matrix = matrix * Geometry::assemble_transform(Vec3d::Zero(), -0.5 * PI * Vec3d::UnitZ()); + shader.set_uniform("view_model_matrix", view_matrix * model_matrix); + const Matrix3d view_normal_matrix = view_matrix.matrix().block(0, 0, 3, 3) * model_matrix.matrix().block(0, 0, 3, 3).inverse().transpose(); + shader.set_uniform("view_normal_matrix", view_normal_matrix); m_arrow.set_color(get_color(X)); m_arrow.render(); } else if (boost::ends_with(sidebar_field, "y")) { - shader.set_uniform("view_model_matrix", view_matrix); - shader.set_uniform("normal_matrix", (Matrix3d)view_matrix.matrix().block(0, 0, 3, 3).inverse().transpose()); + shader.set_uniform("view_model_matrix", view_matrix * matrix); + shader.set_uniform("view_normal_matrix", (Matrix3d)Matrix3d::Identity()); m_arrow.set_color(get_color(Y)); m_arrow.render(); } else if (boost::ends_with(sidebar_field, "z")) { - const Transform3d view_model_matrix = view_matrix * Geometry::assemble_transform(Vec3d::Zero(), 0.5 * PI * Vec3d::UnitX()); - shader.set_uniform("view_model_matrix", view_model_matrix); - shader.set_uniform("normal_matrix", (Matrix3d)view_model_matrix.matrix().block(0, 0, 3, 3).inverse().transpose()); + const Transform3d model_matrix = matrix * Geometry::assemble_transform(Vec3d::Zero(), 0.5 * PI * Vec3d::UnitX()); + shader.set_uniform("view_model_matrix", view_matrix * model_matrix); + const Matrix3d view_normal_matrix = view_matrix.matrix().block(0, 0, 3, 3) * model_matrix.matrix().block(0, 0, 3, 3).inverse().transpose(); + shader.set_uniform("view_normal_matrix", view_normal_matrix); m_arrow.set_color(get_color(Z)); m_arrow.render(); } @@ -2279,32 +2281,33 @@ void Selection::render_sidebar_position_hints(const std::string& sidebar_field, void Selection::render_sidebar_rotation_hints(const std::string& sidebar_field, GLShaderProgram& shader, const Transform3d& matrix) { - auto render_sidebar_rotation_hint = [this](GLShaderProgram& shader, const Transform3d& matrix) { - Transform3d view_model_matrix = matrix; - shader.set_uniform("view_model_matrix", view_model_matrix); - shader.set_uniform("normal_matrix", (Matrix3d)view_model_matrix.matrix().block(0, 0, 3, 3).inverse().transpose()); + auto render_sidebar_rotation_hint = [this](GLShaderProgram& shader, const Transform3d& view_matrix, const Transform3d& model_matrix) { + shader.set_uniform("view_model_matrix", view_matrix * model_matrix); + Matrix3d view_normal_matrix = view_matrix.matrix().block(0, 0, 3, 3) * model_matrix.matrix().block(0, 0, 3, 3).inverse().transpose(); + shader.set_uniform("view_normal_matrix", view_normal_matrix); m_curved_arrow.render(); - view_model_matrix = matrix * Geometry::assemble_transform(Vec3d::Zero(), PI * Vec3d::UnitZ()); - shader.set_uniform("view_model_matrix", view_model_matrix); - shader.set_uniform("normal_matrix", (Matrix3d)view_model_matrix.matrix().block(0, 0, 3, 3).inverse().transpose()); + const Transform3d matrix = model_matrix * Geometry::assemble_transform(Vec3d::Zero(), PI * Vec3d::UnitZ()); + shader.set_uniform("view_model_matrix", view_matrix * matrix); + view_normal_matrix = view_matrix.matrix().block(0, 0, 3, 3) * matrix.matrix().block(0, 0, 3, 3).inverse().transpose(); + shader.set_uniform("view_normal_matrix", view_normal_matrix); m_curved_arrow.render(); }; const Camera& camera = wxGetApp().plater()->get_camera(); - const Transform3d view_matrix = camera.get_view_matrix() * matrix; + const Transform3d& view_matrix = camera.get_view_matrix(); shader.set_uniform("projection_matrix", camera.get_projection_matrix()); if (boost::ends_with(sidebar_field, "x")) { m_curved_arrow.set_color(get_color(X)); - render_sidebar_rotation_hint(shader, view_matrix * Geometry::assemble_transform(Vec3d::Zero(), 0.5 * PI * Vec3d::UnitY())); + render_sidebar_rotation_hint(shader, view_matrix, matrix * Geometry::assemble_transform(Vec3d::Zero(), 0.5 * PI * Vec3d::UnitY())); } else if (boost::ends_with(sidebar_field, "y")) { m_curved_arrow.set_color(get_color(Y)); - render_sidebar_rotation_hint(shader, view_matrix * Geometry::assemble_transform(Vec3d::Zero(), -0.5 * PI * Vec3d::UnitX())); + render_sidebar_rotation_hint(shader, view_matrix, matrix * Geometry::assemble_transform(Vec3d::Zero(), -0.5 * PI * Vec3d::UnitX())); } else if (boost::ends_with(sidebar_field, "z")) { m_curved_arrow.set_color(get_color(Z)); - render_sidebar_rotation_hint(shader, view_matrix); + render_sidebar_rotation_hint(shader, view_matrix, matrix); } } @@ -2315,33 +2318,35 @@ void Selection::render_sidebar_scale_hints(const std::string& sidebar_field, boo //bool uniform_scale = requires_uniform_scale() || wxGetApp().obj_manipul()->get_uniform_scaling(); bool uniform_scale = requires_uniform_scale() || gizmo_uniform_scale; - auto render_sidebar_scale_hint = [this, uniform_scale](Axis axis, GLShaderProgram& shader, const Transform3d& matrix) { + auto render_sidebar_scale_hint = [this, uniform_scale](Axis axis, GLShaderProgram& shader, const Transform3d& view_matrix, const Transform3d& model_matrix) { m_arrow.set_color(uniform_scale ? UNIFORM_SCALE_COLOR : get_color(axis)); - Transform3d view_model_matrix = matrix * Geometry::assemble_transform(5.0 * Vec3d::UnitY()); - shader.set_uniform("view_model_matrix", view_model_matrix); - shader.set_uniform("normal_matrix", (Matrix3d)view_model_matrix.matrix().block(0, 0, 3, 3).inverse().transpose()); + Transform3d matrix = model_matrix * Geometry::assemble_transform(5.0 * Vec3d::UnitY()); + shader.set_uniform("view_model_matrix", view_matrix * matrix); + Matrix3d view_normal_matrix = view_matrix.matrix().block(0, 0, 3, 3) * matrix.matrix().block(0, 0, 3, 3).inverse().transpose(); + shader.set_uniform("view_normal_matrix", view_normal_matrix); m_arrow.render(); - view_model_matrix = matrix * Geometry::assemble_transform(-5.0 * Vec3d::UnitY(), PI * Vec3d::UnitZ()); - shader.set_uniform("view_model_matrix", view_model_matrix); - shader.set_uniform("normal_matrix", (Matrix3d)view_model_matrix.matrix().block(0, 0, 3, 3).inverse().transpose()); + matrix = model_matrix * Geometry::assemble_transform(-5.0 * Vec3d::UnitY(), PI * Vec3d::UnitZ()); + shader.set_uniform("view_model_matrix", view_matrix * matrix); + view_normal_matrix = view_matrix.matrix().block(0, 0, 3, 3) * matrix.matrix().block(0, 0, 3, 3).inverse().transpose(); + shader.set_uniform("view_normal_matrix", view_normal_matrix); m_arrow.render(); }; const Camera& camera = wxGetApp().plater()->get_camera(); - const Transform3d view_matrix = camera.get_view_matrix() * matrix; + const Transform3d& view_matrix = camera.get_view_matrix(); shader.set_uniform("projection_matrix", camera.get_projection_matrix()); if (boost::ends_with(sidebar_field, "x") || uniform_scale) { - render_sidebar_scale_hint(X, shader, view_matrix * Geometry::assemble_transform(Vec3d::Zero(), -0.5 * PI * Vec3d::UnitZ())); + render_sidebar_scale_hint(X, shader, view_matrix, matrix * Geometry::assemble_transform(Vec3d::Zero(), -0.5 * PI * Vec3d::UnitZ())); } if (boost::ends_with(sidebar_field, "y") || uniform_scale) { - render_sidebar_scale_hint(Y, shader, view_matrix); + render_sidebar_scale_hint(Y, shader, view_matrix, matrix); } if (boost::ends_with(sidebar_field, "z") || uniform_scale) { - render_sidebar_scale_hint(Z, shader, view_matrix * Geometry::assemble_transform(Vec3d::Zero(), 0.5 * PI * Vec3d::UnitX())); + render_sidebar_scale_hint(Z, shader, view_matrix, matrix * Geometry::assemble_transform(Vec3d::Zero(), 0.5 * PI * Vec3d::UnitX())); } } From 461fa63cbff3d2030df1e948f5325c93d25a11a1 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Sat, 28 Oct 2023 00:08:26 +0800 Subject: [PATCH 56/99] Tech ENABLE_LEGACY_OPENGL_REMOVAL - Fixed rendering of layer editing background on older OpenGL compatibility profile (cherry picked from commit prusa3d/PrusaSlicer@642f64cb41f9a56306bba09ad306690fad906224) --- src/slic3r/GUI/GLCanvas3D.cpp | 10 ++--- src/slic3r/GUI/GLModel.cpp | 75 +++++++++++++++++++++++------------ src/slic3r/GUI/GLModel.hpp | 14 ++++--- 3 files changed, 62 insertions(+), 37 deletions(-) diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 832f248a255..0725c489703 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -421,7 +421,7 @@ void GLCanvas3D::LayersEditing::render_active_object_annotations(const GLCanvas3 m_profile.background.reset(); GLModel::Geometry init_data; - init_data.format = { GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P2T2 }; + init_data.format = { GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3N3T2 }; init_data.reserve_vertices(4); init_data.reserve_indices(6); @@ -430,10 +430,10 @@ void GLCanvas3D::LayersEditing::render_active_object_annotations(const GLCanvas3 const float r = 1.0f; const float t = 1.0f; const float b = -1.0f; - init_data.add_vertex(Vec2f(l, b), Vec2f(0.0f, 0.0f)); - init_data.add_vertex(Vec2f(r, b), Vec2f(1.0f, 0.0f)); - init_data.add_vertex(Vec2f(r, t), Vec2f(1.0f, 1.0f)); - init_data.add_vertex(Vec2f(l, t), Vec2f(0.0f, 1.0f)); + init_data.add_vertex(Vec3f(l, b, 0.0f), Vec3f::UnitZ(), Vec2f(0.0f, 0.0f)); + init_data.add_vertex(Vec3f(r, b, 0.0f), Vec3f::UnitZ(), Vec2f(1.0f, 0.0f)); + init_data.add_vertex(Vec3f(r, t, 0.0f), Vec3f::UnitZ(), Vec2f(1.0f, 1.0f)); + init_data.add_vertex(Vec3f(l, t, 0.0f), Vec3f::UnitZ(), Vec2f(0.0f, 1.0f)); // indices init_data.add_triangle(0, 1, 2); diff --git a/src/slic3r/GUI/GLModel.cpp b/src/slic3r/GUI/GLModel.cpp index bab13ba2515..97ef65978fb 100644 --- a/src/slic3r/GUI/GLModel.cpp +++ b/src/slic3r/GUI/GLModel.cpp @@ -97,6 +97,19 @@ void GLModel::Geometry::add_vertex(const Vec3f& position, const Vec3f& normal) vertices.emplace_back(normal.z()); } +void GLModel::Geometry::add_vertex(const Vec3f& position, const Vec3f& normal, const Vec2f& tex_coord) +{ + assert(format.vertex_layout == EVertexLayout::P3N3T2); + vertices.emplace_back(position.x()); + vertices.emplace_back(position.y()); + vertices.emplace_back(position.z()); + vertices.emplace_back(normal.x()); + vertices.emplace_back(normal.y()); + vertices.emplace_back(normal.z()); + vertices.emplace_back(tex_coord.x()); + vertices.emplace_back(tex_coord.y()); +} + void GLModel::Geometry::add_vertex(const Vec4f& position) { assert(format.vertex_layout == EVertexLayout::P4); @@ -238,13 +251,14 @@ size_t GLModel::Geometry::vertex_stride_floats(const Format& format) { switch (format.vertex_layout) { - case EVertexLayout::P2: { return 2; } - case EVertexLayout::P2T2: { return 4; } - case EVertexLayout::P3: { return 3; } - case EVertexLayout::P3T2: { return 5; } - case EVertexLayout::P3N3: { return 6; } - case EVertexLayout::P4: { return 4; } - default: { assert(false); return 0; } + case EVertexLayout::P2: { return 2; } + case EVertexLayout::P2T2: { return 4; } + case EVertexLayout::P3: { return 3; } + case EVertexLayout::P3T2: { return 5; } + case EVertexLayout::P3N3: { return 6; } + case EVertexLayout::P3N3T2: { return 8; } + case EVertexLayout::P4: { return 4; } + default: { assert(false); return 0; } }; } @@ -253,12 +267,13 @@ size_t GLModel::Geometry::position_stride_floats(const Format& format) switch (format.vertex_layout) { case EVertexLayout::P2: - case EVertexLayout::P2T2: { return 2; } + case EVertexLayout::P2T2: { return 2; } case EVertexLayout::P3: case EVertexLayout::P3T2: - case EVertexLayout::P3N3: { return 3; } - case EVertexLayout::P4: { return 4; } - default: { assert(false); return 0; } + case EVertexLayout::P3N3: + case EVertexLayout::P3N3T2: { return 3; } + case EVertexLayout::P4: { return 4; } + default: { assert(false); return 0; } }; } @@ -271,6 +286,7 @@ size_t GLModel::Geometry::position_offset_floats(const Format& format) case EVertexLayout::P3: case EVertexLayout::P3T2: case EVertexLayout::P3N3: + case EVertexLayout::P3N3T2: case EVertexLayout::P4: { return 0; } default: { assert(false); return 0; } }; @@ -280,8 +296,9 @@ size_t GLModel::Geometry::normal_stride_floats(const Format& format) { switch (format.vertex_layout) { - case EVertexLayout::P3N3: { return 3; } - default: { assert(false); return 0; } + case EVertexLayout::P3N3: + case EVertexLayout::P3N3T2: { return 3; } + default: { assert(false); return 0; } }; } @@ -289,8 +306,9 @@ size_t GLModel::Geometry::normal_offset_floats(const Format& format) { switch (format.vertex_layout) { - case EVertexLayout::P3N3: { return 3; } - default: { assert(false); return 0; } + case EVertexLayout::P3N3: + case EVertexLayout::P3N3T2: { return 3; } + default: { assert(false); return 0; } }; } @@ -299,8 +317,9 @@ size_t GLModel::Geometry::tex_coord_stride_floats(const Format& format) switch (format.vertex_layout) { case EVertexLayout::P2T2: - case EVertexLayout::P3T2: { return 2; } - default: { assert(false); return 0; } + case EVertexLayout::P3T2: + case EVertexLayout::P3N3T2: { return 2; } + default: { assert(false); return 0; } }; } @@ -308,9 +327,10 @@ size_t GLModel::Geometry::tex_coord_offset_floats(const Format& format) { switch (format.vertex_layout) { - case EVertexLayout::P2T2: { return 2; } - case EVertexLayout::P3T2: { return 3; } - default: { assert(false); return 0; } + case EVertexLayout::P2T2: { return 2; } + case EVertexLayout::P3T2: { return 3; } + case EVertexLayout::P3N3T2: { return 6; } + default: { assert(false); return 0; } }; } @@ -334,6 +354,7 @@ bool GLModel::Geometry::has_position(const Format& format) case EVertexLayout::P3: case EVertexLayout::P3T2: case EVertexLayout::P3N3: + case EVertexLayout::P3N3T2: case EVertexLayout::P4: { return true; } default: { assert(false); return false; } }; @@ -347,9 +368,10 @@ bool GLModel::Geometry::has_normal(const Format& format) case EVertexLayout::P2T2: case EVertexLayout::P3: case EVertexLayout::P3T2: - case EVertexLayout::P4: { return false; } - case EVertexLayout::P3N3: { return true; } - default: { assert(false); return false; } + case EVertexLayout::P4: { return false; } + case EVertexLayout::P3N3: + case EVertexLayout::P3N3T2: { return true; } + default: { assert(false); return false; } }; } @@ -358,12 +380,13 @@ bool GLModel::Geometry::has_tex_coord(const Format& format) switch (format.vertex_layout) { case EVertexLayout::P2T2: - case EVertexLayout::P3T2: { return true; } + case EVertexLayout::P3T2: + case EVertexLayout::P3N3T2: { return true; } case EVertexLayout::P2: case EVertexLayout::P3: case EVertexLayout::P3N3: - case EVertexLayout::P4: { return false; } - default: { assert(false); return false; } + case EVertexLayout::P4: { return false; } + default: { assert(false); return false; } }; } diff --git a/src/slic3r/GUI/GLModel.hpp b/src/slic3r/GUI/GLModel.hpp index a3fa6c38d0f..7089f11e15a 100644 --- a/src/slic3r/GUI/GLModel.hpp +++ b/src/slic3r/GUI/GLModel.hpp @@ -41,6 +41,7 @@ namespace GUI { P3, // position 3 floats P3T2, // position 3 floats + texture coords 2 floats P3N3, // position 3 floats + normal 3 floats + P3N3T2, // position 3 floats + normal 3 floats + texture coords 2 floats P4, // position 4 floats }; @@ -66,12 +67,13 @@ namespace GUI { void reserve_vertices(size_t vertices_count) { vertices.reserve(vertices_count * vertex_stride_floats(format)); } void reserve_indices(size_t indices_count) { indices.reserve(indices_count); } - void add_vertex(const Vec2f& position); // EVertexLayout::P2 - void add_vertex(const Vec2f& position, const Vec2f& tex_coord); // EVertexLayout::P2T2 - void add_vertex(const Vec3f& position); // EVertexLayout::P3 - void add_vertex(const Vec3f& position, const Vec2f& tex_coord); // EVertexLayout::P3T2 - void add_vertex(const Vec3f& position, const Vec3f& normal); // EVertexLayout::P3N3 - void add_vertex(const Vec4f& position); // EVertexLayout::P4 + void add_vertex(const Vec2f& position); // EVertexLayout::P2 + void add_vertex(const Vec2f& position, const Vec2f& tex_coord); // EVertexLayout::P2T2 + void add_vertex(const Vec3f& position); // EVertexLayout::P3 + void add_vertex(const Vec3f& position, const Vec2f& tex_coord); // EVertexLayout::P3T2 + void add_vertex(const Vec3f& position, const Vec3f& normal); // EVertexLayout::P3N3 + void add_vertex(const Vec3f& position, const Vec3f& normal, const Vec2f& tex_coord); // EVertexLayout::P3N3T2 + void add_vertex(const Vec4f& position); // EVertexLayout::P4 void set_vertex(size_t id, const Vec3f& position, const Vec3f& normal); // EVertexLayout::P3N3 From 467223b8b0d254a722a48bfa64defe1accb077be Mon Sep 17 00:00:00 2001 From: Noisyfox Date: Sat, 28 Oct 2023 18:39:53 +0800 Subject: [PATCH 57/99] Fix move gizmo grabber rendering --- src/slic3r/GUI/Gizmos/GLGizmoMove.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMove.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMove.cpp index 5ffe69f8ec3..a5b29ff885c 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMove.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMove.cpp @@ -271,7 +271,7 @@ void GLGizmoMove3D::render_grabber_extension(Axis axis, const BoundingBoxf3& box model_matrix = model_matrix * Geometry::assemble_transform(Vec3d::Zero(), 0.5 * PI * Vec3d::UnitY()); else if (axis == Y) model_matrix = model_matrix * Geometry::assemble_transform(Vec3d::Zero(), -0.5 * PI * Vec3d::UnitX()); - model_matrix = model_matrix * Geometry::assemble_transform(2.0 * size * Vec3d::UnitZ(), Vec3d::Zero(), Vec3d(0.75 * size, 0.75 * size, 3.0 * size)); + model_matrix = model_matrix * Geometry::assemble_transform(Vec3d::Zero(), Vec3d::Zero(), Vec3d(0.75 * size, 0.75 * size, 2.0 * size)); shader->set_uniform("view_model_matrix", view_matrix * model_matrix); shader->set_uniform("projection_matrix", camera.get_projection_matrix()); From 65b6856262ea89120a8fa6aef037e30fb22d067b Mon Sep 17 00:00:00 2001 From: Noisyfox Date: Sun, 29 Oct 2023 11:29:46 +0800 Subject: [PATCH 58/99] Fix macos build --- src/slic3r/GUI/GLCanvas3D.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 0725c489703..6c65212016a 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -34,6 +34,7 @@ #include "slic3r/GUI/Gizmos/GLGizmoPainterBase.hpp" #include "slic3r/Utils/UndoRedo.hpp" +#include "slic3r/Utils/MacDarkMode.hpp" #include From b2f94e16aac491be549dcfd2500a168ed1d52ab4 Mon Sep 17 00:00:00 2001 From: Noisyfox Date: Sun, 29 Oct 2023 14:27:12 +0800 Subject: [PATCH 59/99] Fix variable init --- src/slic3r/GUI/3DScene.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/slic3r/GUI/3DScene.cpp b/src/slic3r/GUI/3DScene.cpp index af1eb34bfe4..d2768172345 100644 --- a/src/slic3r/GUI/3DScene.cpp +++ b/src/slic3r/GUI/3DScene.cpp @@ -216,6 +216,7 @@ GLVolume::GLVolume(float r, float g, float b, float a) , force_native_color(false) , force_neutral_color(false) , force_sinking_contours(false) + , picking(false) , tverts_range(0, size_t(-1)) { color = { r, g, b, a }; From 02f83f29c794165b102db06df5d2aa362c5d6412 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Sat, 28 Oct 2023 21:04:44 +0800 Subject: [PATCH 60/99] Tech ENABLE_GIZMO_GRABBER_REFACTOR - Refactoring of GLGizmoBase::Grabber to have a single static instance of the cube and cone models to be shared by all grabbers (cherry picked from commit prusa3d/PrusaSlicer@f5042367345c3c74162c95adf23020859f3a33a4) --- src/slic3r/GUI/Gizmos/GLGizmoBase.cpp | 84 ++++++++++++++++++------- src/slic3r/GUI/Gizmos/GLGizmoBase.hpp | 19 +++++- src/slic3r/GUI/Gizmos/GLGizmoMove.cpp | 71 ++------------------- src/slic3r/GUI/Gizmos/GLGizmoMove.hpp | 2 - src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp | 47 +------------- src/slic3r/GUI/Gizmos/GLGizmoRotate.hpp | 2 - 6 files changed, 83 insertions(+), 142 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoBase.cpp b/src/slic3r/GUI/Gizmos/GLGizmoBase.cpp index 5aed864aa9d..e19c10da1ff 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoBase.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoBase.cpp @@ -69,9 +69,16 @@ void GLGizmoBase::load_render_colors() RenderColor::colors[RenderCol_Flatten_Plane_Hover] = ImGuiWrapper::to_ImVec4(GLGizmoBase::FLATTEN_HOVER_COLOR); } -void GLGizmoBase::Grabber::render(bool hover, float size) +GLModel GLGizmoBase::Grabber::s_cube; +GLModel GLGizmoBase::Grabber::s_cone; + +GLGizmoBase::Grabber::~Grabber() { - render(size, hover ? hover_color : color, false); + if (s_cube.is_initialized()) + s_cube.reset(); + + if (s_cone.is_initialized()) + s_cone.reset(); } float GLGizmoBase::Grabber::get_half_size(float size) const @@ -86,14 +93,14 @@ float GLGizmoBase::Grabber::get_dragging_half_size(float size) const GLModel& GLGizmoBase::Grabber::get_cube() { - if (!m_cube.is_initialized()) { + if (!s_cube.is_initialized()) { // This cannot be done in constructor, OpenGL is not yet // initialized at that point (on Linux at least). - indexed_triangle_set its = its_make_cube(1., 1., 1.); - its_translate(its, Vec3f(-0.5, -0.5, -0.5)); - m_cube.init_from(its); + indexed_triangle_set its = its_make_cube(1.0, 1.0, 1.0); + its_translate(its, -0.5f * Vec3f::Ones()); + s_cube.init_from(its); } - return m_cube; + return s_cube; } void GLGizmoBase::Grabber::render(float size, const ColorRGBA& render_color, bool picking) @@ -102,34 +109,63 @@ void GLGizmoBase::Grabber::render(float size, const ColorRGBA& render_color, boo if (shader == nullptr) return; - if (!m_cube.is_initialized()) { + if (!s_cube.is_initialized()) { // This cannot be done in constructor, OpenGL is not yet // initialized at that point (on Linux at least). - indexed_triangle_set its = its_make_cube(1., 1., 1.); + indexed_triangle_set its = its_make_cube(1.0, 1.0, 1.0); its_translate(its, -0.5f * Vec3f::Ones()); - m_cube.init_from(its); + s_cube.init_from(its); } - //BBS set to fixed size grabber - //float fullsize = 2 * (dragging ? get_dragging_half_size(size) : get_half_size(size)); - float fullsize = 8.0f; - if (GLGizmoBase::INV_ZOOM > 0) { - fullsize = FixedGrabberSize * GLGizmoBase::INV_ZOOM; - } + if (!s_cone.is_initialized()) + s_cone.init_from(its_make_cone(1.0, 1.0, double(PI) / 18.0)); + //BBS set to fixed size grabber + const float grabber_size = FixedGrabberSize * INV_ZOOM; + const double extension_size = 0.75 * FixedGrabberSize * INV_ZOOM; - m_cube.set_color(render_color); + s_cube.set_color(render_color); + s_cone.set_color(render_color); const Camera& camera = wxGetApp().plater()->get_camera(); const Transform3d& view_matrix = camera.get_view_matrix(); - const Transform3d model_matrix = matrix * Geometry::assemble_transform(center, angles, fullsize * Vec3d::Ones()); - const Transform3d view_model_matrix = view_matrix * model_matrix; - - shader->set_uniform("view_model_matrix", view_model_matrix); shader->set_uniform("projection_matrix", camera.get_projection_matrix()); - const Matrix3d view_normal_matrix = view_matrix.matrix().block(0, 0, 3, 3) * model_matrix.matrix().block(0, 0, 3, 3).inverse().transpose(); - shader->set_uniform("view_normal_matrix", view_normal_matrix); - m_cube.render(); + + auto render_extension = [&view_matrix, shader](GLModel &model, const Transform3d &model_matrix) { + shader->set_uniform("view_model_matrix", view_matrix * model_matrix); + const Matrix3d view_normal_matrix = view_matrix.matrix().block(0, 0, 3, 3) * model_matrix.matrix().block(0, 0, 3, 3).inverse().transpose(); + shader->set_uniform("view_normal_matrix", view_normal_matrix); + model.render(); + }; + + if (extensions == EGrabberExtension::PosZ) { + const Transform3d model_matrix = matrix * Geometry::assemble_transform(center, angles, Vec3d(0.75 * extension_size, 0.75 * extension_size, 2.0 * extension_size)); + render_extension(s_cone, model_matrix); + } else { + const Transform3d model_matrix = matrix * Geometry::assemble_transform(center, angles, grabber_size * Vec3d::Ones()); + render_extension(s_cube, model_matrix); + + const Transform3d extension_model_matrix_base = matrix * Geometry::assemble_transform(center, angles); + const Vec3d extension_scale(0.75 * extension_size, 0.75 * extension_size, 3.0 * extension_size); + if ((int(extensions) & int(GLGizmoBase::EGrabberExtension::PosX)) != 0) { + render_extension(s_cone, extension_model_matrix_base * Geometry::assemble_transform(2.0 * extension_size * Vec3d::UnitX(), Vec3d(0.0, 0.5 * double(PI), 0.0), extension_scale)); + } + if ((int(extensions) & int(GLGizmoBase::EGrabberExtension::NegX)) != 0) { + render_extension(s_cone, extension_model_matrix_base * Geometry::assemble_transform(-2.0 * extension_size * Vec3d::UnitX(), Vec3d(0.0, -0.5 * double(PI), 0.0), extension_scale)); + } + if ((int(extensions) & int(GLGizmoBase::EGrabberExtension::PosY)) != 0) { + render_extension(s_cone, extension_model_matrix_base * Geometry::assemble_transform(2.0 * extension_size * Vec3d::UnitY(), Vec3d(-0.5 * double(PI), 0.0, 0.0), extension_scale)); + } + if ((int(extensions) & int(GLGizmoBase::EGrabberExtension::NegY)) != 0) { + render_extension(s_cone, extension_model_matrix_base * Geometry::assemble_transform(-2.0 * extension_size * Vec3d::UnitY(), Vec3d(0.5 * double(PI), 0.0, 0.0), extension_scale)); + } + if ((int(extensions) & int(GLGizmoBase::EGrabberExtension::PosZ)) != 0) { + render_extension(s_cone, extension_model_matrix_base * Geometry::assemble_transform(2.0 * extension_size * Vec3d::UnitZ(), Vec3d::Zero(), extension_scale)); + } + if ((int(extensions) & int(GLGizmoBase::EGrabberExtension::NegZ)) != 0) { + render_extension(s_cone, extension_model_matrix_base * Geometry::assemble_transform(-2.0 * extension_size * Vec3d::UnitZ(), Vec3d(double(PI), 0.0, 0.0), extension_scale)); + } + } } GLGizmoBase::GLGizmoBase(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoBase.hpp b/src/slic3r/GUI/Gizmos/GLGizmoBase.hpp index 4e8a6dc1d04..91f367f3252 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoBase.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoBase.hpp @@ -55,6 +55,17 @@ class GLGizmoBase static void update_render_colors(); static void load_render_colors(); + enum class EGrabberExtension + { + None = 0, + PosX = 1 << 0, + NegX = 1 << 1, + PosY = 1 << 2, + NegY = 1 << 3, + PosZ = 1 << 4, + NegZ = 1 << 5, + }; + protected: struct Grabber { @@ -71,10 +82,12 @@ class GLGizmoBase Transform3d matrix{ Transform3d::Identity() }; ColorRGBA color{GRABBER_NORMAL_COL}; ColorRGBA hover_color{GRABBER_HOVER_COL}; + EGrabberExtension extensions{ EGrabberExtension::None }; Grabber() = default; + ~Grabber(); - void render(bool hover, float size); + void render(bool hover, float size) { render(size, hover ? hover_color : color, false); } void render_for_picking(float size) { render(size, color, true); } float get_half_size(float size) const; @@ -84,7 +97,8 @@ class GLGizmoBase private: void render(float size, const ColorRGBA& render_color, bool picking); - GLModel m_cube; + static GLModel s_cube; + static GLModel s_cone; }; public: @@ -107,7 +121,6 @@ class GLGizmoBase protected: GLCanvas3D& m_parent; - int m_group_id; EState m_state; int m_shortcut_key; diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMove.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMove.cpp index a5b29ff885c..67fce2f2b74 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMove.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMove.cpp @@ -47,8 +47,12 @@ bool GLGizmoMove3D::on_init() { for (int i = 0; i < 3; ++i) { m_grabbers.push_back(Grabber()); + m_grabbers.back().extensions = GLGizmoBase::EGrabberExtension::PosZ; } + m_grabbers[0].angles = { 0.0, 0.5 * double(PI), 0.0 }; + m_grabbers[1].angles = { -0.5 * double(PI), 0.0, 0.0 }; + m_shortcut_key = WXK_CONTROL_M; return true; @@ -93,9 +97,6 @@ void GLGizmoMove3D::on_update(const UpdateData& data) void GLGizmoMove3D::on_render() { - if (!m_cone.is_initialized()) - m_cone.init_from(its_make_cone(1.0, 1.0, double(PI) / 18.0)); - const Selection& selection = m_parent.get_selection(); glsafe(::glClear(GL_DEPTH_BUFFER_BIT)); @@ -178,10 +179,7 @@ void GLGizmoMove3D::on_render() } // draw grabbers - for (unsigned int i = 0; i < 3; ++i) { - if (m_grabbers[i].enabled) - render_grabber_extension((Axis) i, box, false); - } + render_grabbers(box); } void GLGizmoMove3D::on_render_for_picking() @@ -189,20 +187,7 @@ void GLGizmoMove3D::on_render_for_picking() glsafe(::glDisable(GL_DEPTH_TEST)); const BoundingBoxf3& box = m_parent.get_selection().get_bounding_box(); - //BBS donot render base grabber for picking - //render_grabbers_for_picking(box); - - //get picking colors only - for (unsigned int i = 0; i < (unsigned int) m_grabbers.size(); ++i) { - if (m_grabbers[i].enabled) { - ColorRGBA color = picking_color_component(i); - m_grabbers[i].color = color; - } - } - - render_grabber_extension(X, box, true); - render_grabber_extension(Y, box, true); - render_grabber_extension(Z, box, true); + render_grabbers_for_picking(box); } //BBS: add input window for move @@ -238,49 +223,5 @@ double GLGizmoMove3D::calc_projection(const UpdateData& data) const return projection; } - -void GLGizmoMove3D::render_grabber_extension(Axis axis, const BoundingBoxf3& box, bool picking) -{ -#if ENABLE_FIXED_GRABBER - const float mean_size = (float)(GLGizmoBase::Grabber::FixedGrabberSize); -#else - const float mean_size = (float)((box.size().x() + box.size().y() + box.size().z()) / 3.0); -#endif - - const double size = 0.75 * GLGizmoBase::Grabber::FixedGrabberSize * GLGizmoBase::INV_ZOOM; - - ColorRGBA color = m_grabbers[axis].color; - if (!picking && m_hover_id != -1) { - if (m_hover_id == axis) { - color = m_grabbers[axis].hover_color; - } - } - - GLShaderProgram* shader = wxGetApp().get_shader(picking ? "flat" : "gouraud_light"); - if (shader == nullptr) - return; - - m_cone.set_color(color); - shader->start_using(); - shader->set_uniform("emission_factor", 0.1f); - - const Camera& camera = wxGetApp().plater()->get_camera(); - const Transform3d& view_matrix = camera.get_view_matrix(); - Transform3d model_matrix = Geometry::assemble_transform(m_grabbers[axis].center); - if (axis == X) - model_matrix = model_matrix * Geometry::assemble_transform(Vec3d::Zero(), 0.5 * PI * Vec3d::UnitY()); - else if (axis == Y) - model_matrix = model_matrix * Geometry::assemble_transform(Vec3d::Zero(), -0.5 * PI * Vec3d::UnitX()); - model_matrix = model_matrix * Geometry::assemble_transform(Vec3d::Zero(), Vec3d::Zero(), Vec3d(0.75 * size, 0.75 * size, 2.0 * size)); - - shader->set_uniform("view_model_matrix", view_matrix * model_matrix); - shader->set_uniform("projection_matrix", camera.get_projection_matrix()); - const Matrix3d view_normal_matrix = view_matrix.matrix().block(0, 0, 3, 3) * model_matrix.matrix().block(0, 0, 3, 3).inverse().transpose(); - shader->set_uniform("view_normal_matrix", view_normal_matrix); - m_cone.render(); - - shader->stop_using(); -} - } // namespace GUI } // namespace Slic3r diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMove.hpp b/src/slic3r/GUI/Gizmos/GLGizmoMove.hpp index f4cc4f6c74c..c8ac84c6e3c 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMove.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMove.hpp @@ -21,7 +21,6 @@ class GLGizmoMove3D : public GLGizmoBase Vec3d m_starting_box_center{ Vec3d::Zero() }; Vec3d m_starting_box_bottom_center{ Vec3d::Zero() }; - GLModel m_cone; struct GrabberConnection { GLModel model; @@ -59,7 +58,6 @@ class GLGizmoMove3D : public GLGizmoBase private: double calc_projection(const UpdateData& data) const; - void render_grabber_extension(Axis axis, const BoundingBoxf3& box, bool picking); }; diff --git a/src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp b/src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp index ce6d0d93d6e..b27b620df12 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp @@ -53,8 +53,8 @@ std::string GLGizmoRotate::get_tooltip() const bool GLGizmoRotate::on_init() { - m_cone.init_from(its_make_cone(1., 1., 2 * PI / 24)); m_grabbers.push_back(Grabber()); + m_grabbers.back().extensions = (GLGizmoBase::EGrabberExtension)(int(GLGizmoBase::EGrabberExtension::PosY) | int(GLGizmoBase::EGrabberExtension::NegY)); return true; } @@ -159,7 +159,6 @@ void GLGizmoRotate::on_render() } render_grabber(box); - render_grabber_extension(box, false); } void GLGizmoRotate::on_render_for_picking() @@ -172,7 +171,6 @@ void GLGizmoRotate::on_render_for_picking() const BoundingBoxf3& box = selection.get_bounding_box(); render_grabbers_for_picking(box); - render_grabber_extension(box, true); } //BBS: add input window for move @@ -390,49 +388,6 @@ void GLGizmoRotate::render_grabber(const BoundingBoxf3& box) render_grabbers(box); } -void GLGizmoRotate::render_grabber_extension(const BoundingBoxf3& box, bool picking) -{ - const double size = 0.75 * GLGizmoBase::Grabber::FixedGrabberSize * GLGizmoBase::INV_ZOOM; - //float mean_size = (float)((box.size()(0) + box.size()(1) + box.size()(2)) / 3.0); - //double size = m_dragging ? (double)m_grabbers[0].get_dragging_half_size(mean_size) : (double)m_grabbers[0].get_half_size(mean_size); - - ColorRGBA color = m_grabbers.front().color; - if (!picking && m_hover_id != -1) - color = m_grabbers.front().hover_color; - - GLShaderProgram* shader = wxGetApp().get_shader(picking ? "flat" : "gouraud_light"); - if (shader == nullptr) - return; - - m_cone.set_color(color); - - shader->start_using(); - shader->set_uniform("emission_factor", 0.1f); - - const Vec3d& center = m_grabbers.front().center; - - const Camera& camera = wxGetApp().plater()->get_camera(); - const Transform3d& view_matrix = camera.get_view_matrix(); - shader->set_uniform("projection_matrix", camera.get_projection_matrix()); - - Transform3d model_matrix = m_grabbers.front().matrix * Geometry::assemble_transform(center, Vec3d(0.5 * PI, 0.0, m_angle)) * - Geometry::assemble_transform(2.0 * size * Vec3d::UnitZ(), Vec3d::Zero(), Vec3d(0.75 * size, 0.75 * size, 3.0 * size)); - - shader->set_uniform("view_model_matrix", view_matrix * model_matrix); - Matrix3d view_normal_matrix = view_matrix.matrix().block(0, 0, 3, 3) * model_matrix.matrix().block(0, 0, 3, 3).inverse().transpose(); - shader->set_uniform("view_normal_matrix", view_normal_matrix); - m_cone.render(); - model_matrix = m_grabbers.front().matrix * Geometry::assemble_transform(center, Vec3d(-0.5 * PI, 0.0, m_angle)) * - Geometry::assemble_transform(2.0 * size * Vec3d::UnitZ(), Vec3d::Zero(), Vec3d(0.75 * size, 0.75 * size, 3.0 * size)); - - shader->set_uniform("view_model_matrix", view_matrix * model_matrix); - view_normal_matrix = view_matrix.matrix().block(0, 0, 3, 3) * model_matrix.matrix().block(0, 0, 3, 3).inverse().transpose(); - shader->set_uniform("view_normal_matrix", view_normal_matrix); - m_cone.render(); - - shader->stop_using(); -} - Transform3d GLGizmoRotate::local_transform(const Selection& selection) const { Transform3d ret; diff --git a/src/slic3r/GUI/Gizmos/GLGizmoRotate.hpp b/src/slic3r/GUI/Gizmos/GLGizmoRotate.hpp index 80d16172bf9..7432a6584e3 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoRotate.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoRotate.hpp @@ -40,7 +40,6 @@ class GLGizmoRotate : public GLGizmoBase float m_snap_fine_in_radius{ 0.0f }; float m_snap_fine_out_radius{ 0.0f }; - GLModel m_cone; GLModel m_circle; GLModel m_scale; GLModel m_snap_radii; @@ -83,7 +82,6 @@ class GLGizmoRotate : public GLGizmoBase void render_angle_arc(const ColorRGBA& color, bool radius_changed); void render_grabber_connection(const ColorRGBA& color, bool radius_changed); void render_grabber(const BoundingBoxf3& box); - void render_grabber_extension(const BoundingBoxf3& box, bool picking); Transform3d local_transform(const Selection& selection) const; From 3577a259d5b5576359dc1bc067609991eca21887 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Sat, 28 Oct 2023 17:54:09 +0800 Subject: [PATCH 61/99] Tech ENABLE_RAYCAST_PICKING - Raytraced picking of volumes --- src/libslic3r/Format/bbs_3mf.cpp | 4 +- src/libslic3r/Geometry.cpp | 75 +++++-- src/libslic3r/Geometry.hpp | 54 ++++- src/libslic3r/Model.hpp | 2 +- src/libslic3r/Technologies.hpp | 2 + src/slic3r/CMakeLists.txt | 2 + src/slic3r/GUI/3DBed.cpp | 36 ++- src/slic3r/GUI/3DBed.hpp | 4 +- src/slic3r/GUI/3DScene.cpp | 16 +- src/slic3r/GUI/3DScene.hpp | 3 + src/slic3r/GUI/GLCanvas3D.cpp | 211 ++++++++++-------- src/slic3r/GUI/GLCanvas3D.hpp | 14 +- src/slic3r/GUI/Gizmos/GLGizmoMeshBoolean.cpp | 2 +- src/slic3r/GUI/Gizmos/GLGizmoText.cpp | 4 +- src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp | 2 +- src/slic3r/GUI/MeshUtils.cpp | 32 +++ src/slic3r/GUI/MeshUtils.hpp | 39 +++- src/slic3r/GUI/SceneRaycaster.cpp | 220 +++++++++++++++++++ src/slic3r/GUI/SceneRaycaster.hpp | 114 ++++++++++ 19 files changed, 687 insertions(+), 149 deletions(-) create mode 100644 src/slic3r/GUI/SceneRaycaster.cpp create mode 100644 src/slic3r/GUI/SceneRaycaster.hpp diff --git a/src/libslic3r/Format/bbs_3mf.cpp b/src/libslic3r/Format/bbs_3mf.cpp index 6be38e14a14..f6936efaaa1 100644 --- a/src/libslic3r/Format/bbs_3mf.cpp +++ b/src/libslic3r/Format/bbs_3mf.cpp @@ -6233,7 +6233,7 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) continue; volume_count++; if (m_share_mesh) { - auto iter = m_shared_meshes.find(volume->mesh_ptr()); + auto iter = m_shared_meshes.find(volume->mesh_ptr().get()); if (iter != m_shared_meshes.end()) { const ModelVolume* shared_volume = iter->second.second; @@ -6248,7 +6248,7 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) continue; } } - const_cast<_BBS_3MF_Exporter *>(this)->m_shared_meshes.insert({volume->mesh_ptr(), {&object_data, volume}}); + const_cast<_BBS_3MF_Exporter *>(this)->m_shared_meshes.insert({volume->mesh_ptr().get(), {&object_data, volume}}); } if (m_from_backup_save) volume_id = (volume_count << 16 | backup_id); diff --git a/src/libslic3r/Geometry.cpp b/src/libslic3r/Geometry.cpp index d1c1a03e0d5..ecee432bbad 100644 --- a/src/libslic3r/Geometry.cpp +++ b/src/libslic3r/Geometry.cpp @@ -320,6 +320,67 @@ Transform3d assemble_transform(const Vec3d& translation, const Vec3d& rotation, return transform; } +void assemble_transform(Transform3d& transform, const Transform3d& translation, const Transform3d& rotation, const Transform3d& scale, const Transform3d& mirror) +{ + transform = translation * rotation * scale * mirror; +} + +Transform3d assemble_transform(const Transform3d& translation, const Transform3d& rotation, const Transform3d& scale, const Transform3d& mirror) +{ + Transform3d transform; + assemble_transform(transform, translation, rotation, scale, mirror); + return transform; +} + +void translation_transform(Transform3d& transform, const Vec3d& translation) +{ + transform = Transform3d::Identity(); + transform.translate(translation); +} + +Transform3d translation_transform(const Vec3d& translation) +{ + Transform3d transform; + translation_transform(transform, translation); + return transform; +} + +void rotation_transform(Transform3d& transform, const Vec3d& rotation) +{ + transform = Transform3d::Identity(); + transform.rotate(Eigen::AngleAxisd(rotation.z(), Vec3d::UnitZ()) * Eigen::AngleAxisd(rotation.y(), Vec3d::UnitY()) * Eigen::AngleAxisd(rotation.x(), Vec3d::UnitX())); +} + +Transform3d rotation_transform(const Vec3d& rotation) +{ + Transform3d transform; + rotation_transform(transform, rotation); + return transform; +} + +void scale_transform(Transform3d& transform, double scale) +{ + return scale_transform(transform, scale * Vec3d::Ones()); +} + +void scale_transform(Transform3d& transform, const Vec3d& scale) +{ + transform = Transform3d::Identity(); + transform.scale(scale); +} + +Transform3d scale_transform(double scale) +{ + return scale_transform(scale * Vec3d::Ones()); +} + +Transform3d scale_transform(const Vec3d& scale) +{ + Transform3d transform; + scale_transform(transform, scale); + return transform; +} + Vec3d extract_euler_angles(const Eigen::Matrix& rotation_matrix) { // reference: http://www.gregslabaugh.net/publications/euler.pdf @@ -405,20 +466,6 @@ void rotation_from_two_vectors(Vec3d from, Vec3d to, Vec3d& rotation_axis, doubl } } -Transform3d translation_transform(const Vec3d &translation) -{ - Transform3d transform = Transform3d::Identity(); - transform.translate(translation); - return transform; -} - -Transform3d rotation_transform(const Vec3d& rotation) -{ - Transform3d transform = Transform3d::Identity(); - transform.rotate(Eigen::AngleAxisd(rotation.z(), Vec3d::UnitZ()) * Eigen::AngleAxisd(rotation.y(), Vec3d::UnitY()) * Eigen::AngleAxisd(rotation.x(), Vec3d::UnitX())); - return transform; -} - bool Transformation::Flags::needs_update(bool dont_translate, bool dont_rotate, bool dont_scale, bool dont_mirror) const { return (this->dont_translate != dont_translate) || (this->dont_rotate != dont_rotate) || (this->dont_scale != dont_scale) || (this->dont_mirror != dont_mirror); diff --git a/src/libslic3r/Geometry.hpp b/src/libslic3r/Geometry.hpp index cbb5df6a81b..bafed3b9cf3 100644 --- a/src/libslic3r/Geometry.hpp +++ b/src/libslic3r/Geometry.hpp @@ -324,7 +324,8 @@ bool arrange( // 4) rotate Y // 5) rotate Z // 6) translate -void assemble_transform(Transform3d& transform, const Vec3d& translation = Vec3d::Zero(), const Vec3d& rotation = Vec3d::Zero(), const Vec3d& scale = Vec3d::Ones(), const Vec3d& mirror = Vec3d::Ones()); +void assemble_transform(Transform3d& transform, const Vec3d& translation = Vec3d::Zero(), const Vec3d& rotation = Vec3d::Zero(), + const Vec3d& scale = Vec3d::Ones(), const Vec3d& mirror = Vec3d::Ones()); // Returns the transform obtained by assembling the given transformations in the following order: // 1) mirror @@ -333,7 +334,45 @@ void assemble_transform(Transform3d& transform, const Vec3d& translation = Vec3d // 4) rotate Y // 5) rotate Z // 6) translate -Transform3d assemble_transform(const Vec3d& translation = Vec3d::Zero(), const Vec3d& rotation = Vec3d::Zero(), const Vec3d& scale = Vec3d::Ones(), const Vec3d& mirror = Vec3d::Ones()); +Transform3d assemble_transform(const Vec3d& translation = Vec3d::Zero(), const Vec3d& rotation = Vec3d::Zero(), + const Vec3d& scale = Vec3d::Ones(), const Vec3d& mirror = Vec3d::Ones()); + +// Sets the given transform by multiplying the given transformations in the following order: +// T = translation * rotation * scale * mirror +void assemble_transform(Transform3d& transform, const Transform3d& translation = Transform3d::Identity(), + const Transform3d& rotation = Transform3d::Identity(), const Transform3d& scale = Transform3d::Identity(), + const Transform3d& mirror = Transform3d::Identity()); + +// Returns the transform obtained by multiplying the given transformations in the following order: +// T = translation * rotation * scale * mirror +Transform3d assemble_transform(const Transform3d& translation = Transform3d::Identity(), const Transform3d& rotation = Transform3d::Identity(), + const Transform3d& scale = Transform3d::Identity(), const Transform3d& mirror = Transform3d::Identity()); + +// Sets the given transform by assembling the given translation +void translation_transform(Transform3d& transform, const Vec3d& translation); + +// Returns the transform obtained by assembling the given translation +Transform3d translation_transform(const Vec3d& translation); + +// Sets the given transform by assembling the given rotations in the following order: +// 1) rotate X +// 2) rotate Y +// 3) rotate Z +void rotation_transform(Transform3d& transform, const Vec3d& rotation); + +// Returns the transform obtained by assembling the given rotations in the following order: +// 1) rotate X +// 2) rotate Y +// 3) rotate Z +Transform3d rotation_transform(const Vec3d& rotation); + +// Sets the given transform by assembling the given scale factors +void scale_transform(Transform3d& transform, double scale); +void scale_transform(Transform3d& transform, const Vec3d& scale); + +// Returns the transform obtained by assembling the given scale factors +Transform3d scale_transform(double scale); +Transform3d scale_transform(const Vec3d& scale); // Returns the euler angles extracted from the given rotation matrix // Warning -> The matrix should not contain any scale or shear !!! @@ -346,16 +385,7 @@ Vec3d extract_euler_angles(const Transform3d& transform); // get rotation from two vectors. // Default output is axis-angle. If rotation_matrix pointer is provided, also output rotation matrix // Euler angles can be obtained by extract_euler_angles() -void rotation_from_two_vectors(Vec3d from, Vec3d to, Vec3d& rotation_axis, double& phi, Matrix3d* rotation_matrix = nullptr); - -// Returns the transform obtained by assembling the given translation -Transform3d translation_transform(const Vec3d &translation); - -// Returns the transform obtained by assembling the given rotations in the following order: -// 1) rotate X -// 2) rotate Y -// 3) rotate Z -Transform3d rotation_transform(const Vec3d &rotation); +void rotation_from_two_vectors(Vec3d from, Vec3d to, Vec3d &rotation_axis, double &phi, Matrix3d *rotation_matrix = nullptr); class Transformation { diff --git a/src/libslic3r/Model.hpp b/src/libslic3r/Model.hpp index 481552c058c..33e7ff6a905 100644 --- a/src/libslic3r/Model.hpp +++ b/src/libslic3r/Model.hpp @@ -883,7 +883,7 @@ class ModelVolume final : public ObjectBase // The triangular model. const TriangleMesh& mesh() const { return *m_mesh.get(); } - const TriangleMesh* mesh_ptr() const { return m_mesh.get(); } + std::shared_ptr mesh_ptr() const { return m_mesh; } void set_mesh(const TriangleMesh &mesh) { m_mesh = std::make_shared(mesh); } void set_mesh(TriangleMesh &&mesh) { m_mesh = std::make_shared(std::move(mesh)); } void set_mesh(const indexed_triangle_set &mesh) { m_mesh = std::make_shared(mesh); } diff --git a/src/libslic3r/Technologies.hpp b/src/libslic3r/Technologies.hpp index aa014a6dc9c..40ac478c37f 100644 --- a/src/libslic3r/Technologies.hpp +++ b/src/libslic3r/Technologies.hpp @@ -61,6 +61,8 @@ #define ENABLE_ENHANCED_IMGUI_SLIDER_FLOAT (1 && ENABLE_2_4_0_BETA2) // Enable fit print volume command for circular printbeds #define ENABLE_ENHANCED_PRINT_VOLUME_FIT (1 && ENABLE_2_4_0_BETA2) +// Enable picking using raytracing +#define ENABLE_RAYCAST_PICKING_DEBUG (1) #endif // _prusaslicer_technologies_h_ diff --git a/src/slic3r/CMakeLists.txt b/src/slic3r/CMakeLists.txt index 21d8fd6c858..b3d6f514425 100644 --- a/src/slic3r/CMakeLists.txt +++ b/src/slic3r/CMakeLists.txt @@ -99,6 +99,8 @@ set(SLIC3R_GUI_SOURCES GUI/GLShader.hpp GUI/GLCanvas3D.hpp GUI/GLCanvas3D.cpp + GUI/SceneRaycaster.hpp + GUI/SceneRaycaster.cpp GUI/OpenGLManager.hpp GUI/OpenGLManager.cpp GUI/Selection.hpp diff --git a/src/slic3r/GUI/3DBed.cpp b/src/slic3r/GUI/3DBed.cpp index 066da6b3363..202912f3d7b 100644 --- a/src/slic3r/GUI/3DBed.cpp +++ b/src/slic3r/GUI/3DBed.cpp @@ -30,7 +30,6 @@ static const float GROUND_Z = -0.04f; static const Slic3r::ColorRGBA DEFAULT_MODEL_COLOR = { 0.3255f, 0.337f, 0.337f, 1.0f }; static const Slic3r::ColorRGBA DEFAULT_MODEL_COLOR_DARK = { 0.255f, 0.255f, 0.283f, 1.0f }; -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 }; @@ -326,6 +325,10 @@ bool Bed3D::set_shape(const Pointfs& printable_area, const double printable_heig m_axes.set_origin({ 0.0, 0.0, static_cast(GROUND_Z) }); m_axes.set_stem_length(0.1f * static_cast(m_build_volume.bounding_volume().max_size())); + // unregister from picking + // BBS: remove the bed picking logic + // wxGetApp().plater()->canvas3D()->remove_raycasters_for_picking(SceneRaycaster::EType::Bed); + // Let the calee to update the UI. return true; } @@ -366,11 +369,6 @@ void Bed3D::render(GLCanvas3D& canvas, const Transform3d& view_matrix, const Tra render_internal(canvas, view_matrix, projection_matrix, bottom, scale_factor, show_axes); } -/*void Bed3D::render_for_picking(GLCanvas3D& canvas, const Transform3d& view_matrix, const Transform3d& projection_matrix, bool bottom, float scale_factor) -{ - render_internal(canvas, view_matrix, projection_matrix, bottom, scale_factor, false, false, true); -}*/ - void Bed3D::render_internal(GLCanvas3D& canvas, const Transform3d& view_matrix, const Transform3d& projection_matrix, bool bottom, float scale_factor, bool show_axes) { @@ -669,6 +667,9 @@ void Bed3D::render_model(const Transform3d& view_matrix, const Transform3d& proj m_model.set_color(m_is_dark ? DEFAULT_MODEL_COLOR_DARK : DEFAULT_MODEL_COLOR); update_model_offset(); + + // BBS: remove the bed picking logic + //register_raycasters_for_picking(m_model.model.get_geometry(), Geometry::assemble_transform(m_model_offset)); } if (!m_model.get_filename().empty()) { @@ -722,7 +723,7 @@ void Bed3D::render_default(bool bottom, const Transform3d& view_matrix, const Tr if (m_model.get_filename().empty() && !bottom) { // draw background glsafe(::glDepthMask(GL_FALSE)); - m_triangles.set_color(picking ? PICKING_MODEL_COLOR : DEFAULT_MODEL_COLOR); + m_triangles.set_color(DEFAULT_MODEL_COLOR); m_triangles.render(); glsafe(::glDepthMask(GL_TRUE)); } @@ -740,5 +741,26 @@ void Bed3D::render_default(bool bottom, const Transform3d& view_matrix, const Tr } } +// BBS: remove the bed picking logic +/* +void Bed3D::register_raycasters_for_picking(const GLModel::Geometry& geometry, const Transform3d& trafo) +{ + assert(m_model.mesh_raycaster == nullptr); + + indexed_triangle_set its; + its.vertices.reserve(geometry.vertices_count()); + for (size_t i = 0; i < geometry.vertices_count(); ++i) { + its.vertices.emplace_back(geometry.extract_position_3(i)); + } + its.indices.reserve(geometry.indices_count() / 3); + for (size_t i = 0; i < geometry.indices_count() / 3; ++i) { + const size_t tri_id = i * 3; + its.indices.emplace_back(geometry.extract_index(tri_id), geometry.extract_index(tri_id + 1), geometry.extract_index(tri_id + 2)); + } + + m_model.mesh_raycaster = std::make_unique(std::make_shared(std::move(its))); + wxGetApp().plater()->canvas3D()->add_raycaster_for_picking(SceneRaycaster::EType::Bed, 0, *m_model.mesh_raycaster, trafo); +} +*/ } // GUI } // Slic3r diff --git a/src/slic3r/GUI/3DBed.hpp b/src/slic3r/GUI/3DBed.hpp index 3fa40df084e..b668b5ed616 100644 --- a/src/slic3r/GUI/3DBed.hpp +++ b/src/slic3r/GUI/3DBed.hpp @@ -147,7 +147,6 @@ class Bed3D Point point_projection(const Point& point) const; void render(GLCanvas3D& canvas, const Transform3d& view_matrix, const Transform3d& projection_matrix, bool bottom, float scale_factor, bool show_axes); - //void render_for_picking(GLCanvas3D& canvas, const Transform3d& view_matrix, const Transform3d& projection_matrix, bool bottom, float scale_factor); void on_change_color_mode(bool is_dark); @@ -167,6 +166,9 @@ class Bed3D void render_model(const Transform3d& view_matrix, const Transform3d& projection_matrix); void render_custom(GLCanvas3D& canvas, const Transform3d& view_matrix, const Transform3d& projection_matrix, bool bottom); void render_default(bool bottom, const Transform3d& view_matrix, const Transform3d& projection_matrix); + + // BBS: remove the bed picking logic + // void register_raycasters_for_picking(const GLModel::Geometry& geometry, const Transform3d& trafo); }; } // GUI diff --git a/src/slic3r/GUI/3DScene.cpp b/src/slic3r/GUI/3DScene.cpp index d2768172345..3b735d8275b 100644 --- a/src/slic3r/GUI/3DScene.cpp +++ b/src/slic3r/GUI/3DScene.cpp @@ -623,7 +623,7 @@ int GLVolumeCollection::load_object_volume( const ModelVolume *model_volume = model_object->volumes[volume_idx]; const int extruder_id = model_volume->extruder_id(); const ModelInstance *instance = model_object->instances[instance_idx]; - const TriangleMesh &mesh = model_volume->mesh(); + std::shared_ptr mesh = model_volume->mesh_ptr(); this->volumes.emplace_back(new GLVolume()); GLVolume& v = *this->volumes.back(); v.set_color(color_from_model_volume(*model_volume)); @@ -632,7 +632,8 @@ int GLVolumeCollection::load_object_volume( #if ENABLE_SMOOTH_NORMALS v.model.init_from(mesh, true); #else - v.model.init_from(mesh); + v.model.init_from(*mesh); + v.mesh_raycaster = std::make_unique(mesh); #endif // ENABLE_SMOOTH_NORMALS v.composite_id = GLVolume::CompositeID(obj_idx, volume_idx, instance_idx); if (model_volume->is_model_part()) { @@ -686,8 +687,9 @@ void GLVolumeCollection::load_object_auxiliary( v.model.init_from(mesh, true); #else v.model.init_from(mesh); -#endif // ENABLE_SMOOTH_NORMALS v.model.set_color((milestone == slaposPad) ? GLVolume::SLA_PAD_COLOR : GLVolume::SLA_SUPPORT_COLOR); + v.mesh_raycaster = std::make_unique(std::make_shared(mesh)); +#endif // ENABLE_SMOOTH_NORMALS v.composite_id = GLVolume::CompositeID(obj_idx, -int(milestone), (int)instance_idx.first); v.geometry_id = std::pair(timestamp, model_instance.id().id); // Create a copy of the convex hull mesh for each instance. Use a move operator on the last instance. @@ -726,13 +728,6 @@ int GLVolumeCollection::load_wipe_tower_preview( colors.push_back(extruder_colors[0]); } -#if 0 - // We'll make another mesh to show the brim (fixed layer height): - TriangleMesh brim_mesh = make_cube(width + 2.f * brim_width, depth + 2.f * brim_width, 0.2f); - brim_mesh.translate(-brim_width, -brim_width, 0.f); - mesh.merge(brim_mesh); -#endif - // Orca: make it transparent for(auto& color : colors) color.a(0.66f); @@ -745,6 +740,7 @@ int GLVolumeCollection::load_wipe_tower_preview( v.model_per_colors[i].init_from(color_part); } v.model.init_from(wipe_tower_shell); + v.mesh_raycaster = std::make_unique(std::make_shared(wipe_tower_shell)); v.set_convex_hull(wipe_tower_shell); v.set_volume_offset(Vec3d(pos_x, pos_y, 0.0)); v.set_volume_rotation(Vec3d(0., 0., (M_PI / 180.) * rotation_angle)); diff --git a/src/slic3r/GUI/3DScene.hpp b/src/slic3r/GUI/3DScene.hpp index 4dce6857538..e04e71ab45f 100644 --- a/src/slic3r/GUI/3DScene.hpp +++ b/src/slic3r/GUI/3DScene.hpp @@ -13,6 +13,7 @@ #include "GLModel.hpp" #include "GLShader.hpp" +#include "MeshUtils.hpp" #include #include @@ -202,6 +203,8 @@ class GLVolume { EHoverState hover; GUI::GLModel model; + // raycaster used for picking + std::unique_ptr mesh_raycaster; // BBS mutable std::vector mmuseg_models; mutable ObjectBase::Timestamp mmuseg_ts; diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 6c65212016a..e8839e777c2 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -1820,9 +1820,17 @@ void GLCanvas3D::render(bool only_init) _rectangular_selection_picking_pass(); //BBS: enable picking when no volumes for partplate logic //else if (!m_volumes.empty()) - else + else { // regular picking pass _picking_pass(); + +#if ENABLE_RAYCAST_PICKING_DEBUG + ImGuiWrapper& imgui = *wxGetApp().imgui(); + imgui.begin(std::string("Hit result"), ImGuiWindowFlags_AlwaysAutoResize); + imgui.text("Picking disabled"); + imgui.end(); +#endif // ENABLE_RAYCAST_PICKING_DEBUG + } } #if ENABLE_RENDER_PICKING_PASS @@ -1896,6 +1904,11 @@ void GLCanvas3D::render(bool only_init) } #endif // ENABLE_RENDER_PICKING_PASS +#if ENABLE_RAYCAST_PICKING_DEBUG + if (m_picking_enabled && !m_mouse.dragging) + m_scene_raycaster.render_hit(camera); +#endif // ENABLE_RAYCAST_PICKING_DEBUG + #if ENABLE_SHOW_CAMERA_TARGET _render_camera_target(); #endif // ENABLE_SHOW_CAMERA_TARGET @@ -2516,6 +2529,7 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re volume.model.init_from(mesh, true); #else volume.model.init_from(mesh); + volume.mesh_raycaster = std::make_unique(std::make_shared(mesh)); #endif // ENABLE_SMOOTH_NORMALS } else { @@ -2523,7 +2537,9 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re #if ENABLE_SMOOTH_NORMALS volume.model.init_from(m_model->objects[volume.object_idx()]->volumes[volume.volume_idx()]->mesh(), true); #else - volume.model.init_from(m_model->objects[volume.object_idx()]->volumes[volume.volume_idx()]->mesh()); + const TriangleMesh& new_mesh = m_model->objects[volume.object_idx()]->volumes[volume.volume_idx()]->mesh(); + volume.model.init_from(new_mesh); + volume.mesh_raycaster = std::make_unique(std::make_shared(new_mesh)); #endif // ENABLE_SMOOTH_NORMALS } } @@ -2688,6 +2704,13 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re #endif } + // refresh volume raycasters for picking + m_scene_raycaster.remove_raycasters(SceneRaycaster::EType::Volume); + for (size_t i = 0; i < m_volumes.volumes.size(); ++i) { + assert(m_volumes.volumes[i]->mesh_raycaster != nullptr); + add_raycaster_for_picking(SceneRaycaster::EType::Volume, i, *m_volumes.volumes[i]->mesh_raycaster, m_volumes.volumes[i]->world_matrix()); + } + // and force this canvas to be redrawn. m_dirty = true; } @@ -4205,6 +4228,8 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) } } else if (evt.LeftUp() || evt.MiddleUp() || evt.RightUp()) { + m_mouse.position = pos.cast(); + if (evt.LeftUp()) { m_selection.stop_dragging(); m_rotation_center(0) = m_rotation_center(1) = m_rotation_center(2) = 0.f; @@ -4247,7 +4272,6 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) deselect_all(); } else if (evt.RightUp() && !is_layers_editing_enabled()) { - m_mouse.position = pos.cast(); // forces a frame render to ensure that m_hover_volume_idxs is updated even when the user right clicks while // the context menu is already shown render(); @@ -6396,87 +6420,111 @@ void GLCanvas3D::_refresh_if_shown_on_screen() void GLCanvas3D::_picking_pass() { - std::vector* hover_volume_idxs = const_cast*>(&m_hover_volume_idxs); - std::vector* hover_plate_idxs = const_cast*>(&m_hover_plate_idxs); - - if (m_picking_enabled && !m_mouse.dragging && m_mouse.position != Vec2d(DBL_MAX, DBL_MAX)) { - hover_volume_idxs->clear(); - hover_plate_idxs->clear(); - - // Render the object for picking. - // FIXME This cannot possibly work in a multi - sampled context as the color gets mangled by the anti - aliasing. - // Better to use software ray - casting on a bounding - box hierarchy. + if (!m_picking_enabled || m_mouse.dragging || m_mouse.position == Vec2d(DBL_MAX, DBL_MAX)) { + ImGuiWrapper& imgui = *wxGetApp().imgui(); + imgui.begin(std::string("Hit result"), ImGuiWindowFlags_AlwaysAutoResize); + imgui.text("Picking disabled"); + imgui.end(); + return; + } - if (m_multisample_allowed) - // This flag is often ignored by NVIDIA drivers if rendering into a screen buffer. - glsafe(::glDisable(GL_MULTISAMPLE)); + m_hover_volume_idxs.clear(); + m_hover_plate_idxs.clear(); - glsafe(::glDisable(GL_BLEND)); - glsafe(::glEnable(GL_DEPTH_TEST)); + // TODO: Support plate picking - glsafe(::glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)); + const ClippingPlane clipping_plane = m_gizmos.get_clipping_plane().inverted_normal(); + const SceneRaycaster::HitResult hit = m_scene_raycaster.hit(m_mouse.position, wxGetApp().plater()->get_camera(), &clipping_plane); + if (hit.is_valid()) { + switch (hit.type) + { + case SceneRaycaster::EType::Volume: + { + if (0 <= hit.raycaster_id && hit.raycaster_id < (int)m_volumes.volumes.size()) { + const GLVolume* volume = m_volumes.volumes[hit.raycaster_id]; + if (volume->is_active && !volume->disabled && (volume->composite_id.volume_id >= 0 || m_render_sla_auxiliaries)) { + // do not add the volume id if any gizmo is active and CTRL is pressed + if (m_gizmos.get_current_type() == GLGizmosManager::EType::Undefined || !wxGetKeyState(WXK_CONTROL)) { + m_hover_volume_idxs.emplace_back(hit.raycaster_id); + m_gizmos.set_hover_id(-1); + } + } + } + else + assert(false); - //BBS: only render plate in view 3D - if (m_canvas_type == ECanvasType::CanvasView3D) { - const Camera &camera = wxGetApp().plater()->get_camera(); - _render_plates_for_picking(camera.get_view_matrix(), camera.get_projection_matrix()); + break; } - - _render_volumes_for_picking(); - - //BBS: remove the bed picking logic - //_render_bed_for_picking(!wxGetApp().plater()->get_camera().is_looking_downward()); - - m_gizmos.render_current_gizmo_for_picking_pass(); - - if (m_multisample_allowed) - glsafe(::glEnable(GL_MULTISAMPLE)); - - int volume_id = -1; - int gizmo_id = -1; - - std::array color = { 0, 0, 0, 0 }; - const Size& cnv_size = get_canvas_size(); - bool inside = 0 <= m_mouse.position(0) && m_mouse.position(0) < cnv_size.get_width() && 0 <= m_mouse.position(1) && m_mouse.position(1) < cnv_size.get_height(); - if (inside) { - glsafe(::glReadPixels(m_mouse.position(0), cnv_size.get_height() - m_mouse.position.y() - 1, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, (void*)color.data())); - if (picking_checksum_alpha_channel(color[0], color[1], color[2]) == color[3]) { - // Only non-interpolated colors are valid, those have their lowest three bits zeroed. - // we reserve color = (0,0,0) for occluders (as the printbed) - // volumes' id are shifted by 1 - // see: _render_volumes_for_picking() - unsigned int id = picking_encode(color[0], color[1], color[2]); - //BBS: remove the bed picking logic - //volume_id = id - 1; - volume_id = id; - // gizmos' id are instead properly encoded by the color - gizmo_id = id; - } + case SceneRaycaster::EType::Gizmo: + { + const Size& cnv_size = get_canvas_size(); + bool inside = 0 <= m_mouse.position.x() && m_mouse.position.x() < cnv_size.get_width() && + 0 <= m_mouse.position.y() && m_mouse.position.y() < cnv_size.get_height(); + m_gizmos.set_hover_id(inside ? hit.raycaster_id : -1); + break; } - else - m_gizmos.set_hover_id(inside && (unsigned int)gizmo_id <= GLGizmoBase::BASE_ID ? ((int)GLGizmoBase::BASE_ID - gizmo_id) : -1); - - //BBS: add plate picking logic - int plate_hover_id = PartPlate::PLATE_BASE_ID - volume_id; - if (plate_hover_id >= 0 && plate_hover_id < PartPlateList::MAX_PLATES_COUNT * PartPlate::GRABBER_COUNT) { - wxGetApp().plater()->get_partplate_list().set_hover_id(plate_hover_id); - hover_plate_idxs->emplace_back(plate_hover_id); - const_cast(&m_gizmos)->set_hover_id(-1); + case SceneRaycaster::EType::Bed: + { + m_gizmos.set_hover_id(-1); + break; + } + default: + { + assert(false); + break; } - else { - wxGetApp().plater()->get_partplate_list().reset_hover_id(); - if (0 <= volume_id && volume_id < (int)m_volumes.volumes.size()) { - // do not add the volume id if any gizmo is active and CTRL is pressed - if (m_gizmos.get_current_type() == GLGizmosManager::EType::Undefined || !wxGetKeyState(WXK_CONTROL)) - hover_volume_idxs->emplace_back(volume_id); - const_cast(&m_gizmos)->set_hover_id(-1); - } - else - const_cast(&m_gizmos)->set_hover_id(inside && (unsigned int)volume_id <= GLGizmoBase::BASE_ID ? ((int)GLGizmoBase::BASE_ID - volume_id) : -1); } + } + else + m_gizmos.set_hover_id(-1); - _update_volumes_hover_state(); + _update_volumes_hover_state(); + +#if ENABLE_RAYCAST_PICKING_DEBUG + ImGuiWrapper& imgui = *wxGetApp().imgui(); + imgui.begin(std::string("Hit result"), ImGuiWindowFlags_AlwaysAutoResize); + std::string object_type = "None"; + switch (hit.type) + { + case SceneRaycaster::EType::Bed: { object_type = "Bed"; break; } + case SceneRaycaster::EType::Gizmo: { object_type = "Gizmo element"; break; } + case SceneRaycaster::EType::Volume: + { + if (m_volumes.volumes[hit.raycaster_id]->is_wipe_tower) + object_type = "Wipe tower"; + else if (m_volumes.volumes[hit.raycaster_id]->volume_idx() == -int(slaposPad)) + object_type = "SLA pad"; + else if (m_volumes.volumes[hit.raycaster_id]->volume_idx() == -int(slaposSupportTree)) + object_type = "SLA supports"; + else + object_type = "Volume"; + break; + } + } + char buf[1024]; + if (hit.type != SceneRaycaster::EType::None) { + sprintf(buf, "Object ID: %d", hit.raycaster_id); + imgui.text(std::string(buf)); + sprintf(buf, "Type: %s", object_type.c_str()); + imgui.text(std::string(buf)); + sprintf(buf, "Position: %.3f, %.3f, %.3f", hit.position.x(), hit.position.y(), hit.position.z()); + imgui.text(std::string(buf)); + sprintf(buf, "Normal: %.3f, %.3f, %.3f", hit.normal.x(), hit.normal.y(), hit.normal.z()); + imgui.text(std::string(buf)); } + else + imgui.text("NO HIT"); + + ImGui::Separator(); + imgui.text("Registered for picking:"); + sprintf(buf, "Beds: %d", (int)m_scene_raycaster.beds_count()); + imgui.text(std::string(buf)); + sprintf(buf, "Volumes: %d", (int)m_scene_raycaster.volumes_count()); + imgui.text(std::string(buf)); + sprintf(buf, "Gizmo elements: %d", (int)m_scene_raycaster.gizmos_count()); + imgui.text(std::string(buf)); + imgui.end(); +#endif // ENABLE_RAYCAST_PICKING_DEBUG } void GLCanvas3D::_rectangular_selection_picking_pass() @@ -6643,26 +6691,11 @@ void GLCanvas3D::_render_bed(const Transform3d& view_matrix, const Transform3d& m_bed.render(*this, view_matrix, projection_matrix, bottom, scale_factor, show_axes); } -void GLCanvas3D::_render_bed_for_picking(const Transform3d& view_matrix, const Transform3d& projection_matrix, bool bottom) -{ - float scale_factor = 1.0; -#if ENABLE_RETINA_GL - scale_factor = m_retina_helper->get_scale_factor(); -#endif // ENABLE_RETINA_GL - - //m_bed.render_for_picking(*this, view_matrix, projection_matrix, bottom, scale_factor); -} - void GLCanvas3D::_render_platelist(const Transform3d& view_matrix, const Transform3d& projection_matrix, bool bottom, bool only_current, bool only_body, int hover_id, bool render_cali) { wxGetApp().plater()->get_partplate_list().render(view_matrix, projection_matrix, bottom, only_current, only_body, hover_id, render_cali); } -void GLCanvas3D::_render_plates_for_picking(const Transform3d &view_matrix, const Transform3d &projection_matrix) -{ - wxGetApp().plater()->get_partplate_list().render_for_picking_pass(view_matrix, projection_matrix); -} - void GLCanvas3D::_render_plane() const { ;//TODO render assemble plane diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp index 77ad6739474..89f5f969529 100644 --- a/src/slic3r/GUI/GLCanvas3D.hpp +++ b/src/slic3r/GUI/GLCanvas3D.hpp @@ -16,6 +16,7 @@ #include "libslic3r/GCode/GCodeProcessor.hpp" #include "GCodeViewer.hpp" #include "Camera.hpp" +#include "SceneRaycaster.hpp" #include "IMToolbar.hpp" #include "libslic3r/Slicing.hpp" @@ -501,6 +502,7 @@ class GLCanvas3D bool m_is_dark = false; wxGLCanvas* m_canvas; wxGLContext* m_context; + SceneRaycaster m_scene_raycaster; Bed3D &m_bed; #if ENABLE_RETINA_GL std::unique_ptr m_retina_helper; @@ -726,6 +728,16 @@ class GLCanvas3D bool init(); void post_event(wxEvent &&event); + + void add_raycaster_for_picking(SceneRaycaster::EType type, PickingId id, const MeshRaycaster& raycaster, const Transform3d& trafo) { + m_scene_raycaster.add_raycaster(type, id, raycaster, trafo); + } + void remove_raycasters_for_picking(SceneRaycaster::EType type, PickingId id) { + m_scene_raycaster.remove_raycasters(type, id); + } + void remove_raycasters_for_picking(SceneRaycaster::EType type) { + m_scene_raycaster.remove_raycasters(type); + } void reset_explosion_ratio() { m_explosion_ratio = 1.0; } void on_change_color_mode(bool is_dark, bool reinit = true); @@ -1116,10 +1128,8 @@ class GLCanvas3D void _rectangular_selection_picking_pass(); void _render_background(); void _render_bed(const Transform3d& view_matrix, const Transform3d& projection_matrix, bool bottom, bool show_axes); - void _render_bed_for_picking(const Transform3d& view_matrix, const Transform3d& projection_matrix, bool bottom); //BBS: add part plate related logic void _render_platelist(const Transform3d& view_matrix, const Transform3d& projection_matrix, bool bottom, bool only_current, bool only_body = false, int hover_id = -1, bool render_cali = false); - void _render_plates_for_picking(const Transform3d& view_matrix, const Transform3d& projection_matrix); //BBS: add outline drawing logic void _render_objects(GLVolumeCollection::ERenderType type, bool with_outline = true); //BBS: GUI refactor: add canvas size as parameters diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeshBoolean.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeshBoolean.cpp index dcff45494e0..df9def7ab47 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeshBoolean.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeshBoolean.cpp @@ -50,7 +50,7 @@ bool GLGizmoMeshBoolean::gizmo_event(SLAGizmoEventType action, const Vec2d& mous // Cast a ray on all meshes, pick the closest hit and save it for the respective mesh for (int mesh_id = 0; mesh_id < int(trafo_matrices.size()); ++mesh_id) { - MeshRaycaster mesh_raycaster = MeshRaycaster(mo->volumes[mesh_id]->mesh()); + MeshRaycaster mesh_raycaster = MeshRaycaster(mo->volumes[mesh_id]->mesh_ptr()); if (mesh_raycaster.unproject_on_mesh(mouse_position, trafo_matrices[mesh_id], camera, hit, normal, m_c->object_clipper()->get_clipping_plane(), &facet)) { // Is this hit the closest to the camera so far? diff --git a/src/slic3r/GUI/Gizmos/GLGizmoText.cpp b/src/slic3r/GUI/Gizmos/GLGizmoText.cpp index 6001af544fd..4c2399dcd58 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoText.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoText.cpp @@ -287,7 +287,7 @@ bool GLGizmoText::gizmo_event(SLAGizmoEventType action, const Vec2d &mouse_posit // Cast a ray on all meshes, pick the closest hit and save it for the respective mesh for (int mesh_id = 0; mesh_id < int(trafo_matrices.size()); ++mesh_id) { - MeshRaycaster mesh_raycaster = MeshRaycaster(mo->volumes[mesh_id]->mesh()); + MeshRaycaster mesh_raycaster = MeshRaycaster(mo->volumes[mesh_id]->mesh_ptr()); if (mesh_raycaster.unproject_on_mesh(mouse_position, trafo_matrices[mesh_id], camera, hit, normal, m_c->object_clipper()->get_clipping_plane(), &facet)) { @@ -543,7 +543,7 @@ void GLGizmoText::on_update(const UpdateData &data) if (mesh_id == m_volume_idx) continue; - MeshRaycaster mesh_raycaster = MeshRaycaster(mo->volumes[mesh_id]->mesh()); + MeshRaycaster mesh_raycaster = MeshRaycaster(mo->volumes[mesh_id]->mesh_ptr()); if (mesh_raycaster.unproject_on_mesh(mouse_pos, trafo_matrices[mesh_id], camera, hit, normal, m_c->object_clipper()->get_clipping_plane(), &facet)) { diff --git a/src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp b/src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp index 5a7d4c0f500..09a7cff3ecc 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp @@ -331,7 +331,7 @@ void Raycaster::on_update() if (meshes != m_old_meshes) { m_raycasters.clear(); for (const TriangleMesh* mesh : meshes) - m_raycasters.emplace_back(new MeshRaycaster(*mesh)); + m_raycasters.emplace_back(new MeshRaycaster(std::make_shared(*mesh))); m_old_meshes = meshes; } } diff --git a/src/slic3r/GUI/MeshUtils.cpp b/src/slic3r/GUI/MeshUtils.cpp index eaf0df314d2..878aa3a1cd0 100644 --- a/src/slic3r/GUI/MeshUtils.cpp +++ b/src/slic3r/GUI/MeshUtils.cpp @@ -357,6 +357,38 @@ std::vector MeshRaycaster::get_unobscured_idxs(const Geometry::Transfo return out; } +bool MeshRaycaster::closest_hit(const Vec2d& mouse_pos, const Transform3d& trafo, const Camera& camera, + Vec3f& position, Vec3f& normal, const ClippingPlane* clipping_plane, size_t* facet_idx) const +{ + Vec3d point; + Vec3d direction; + line_from_mouse_pos(mouse_pos, trafo, camera, point, direction); + + const std::vector hits = m_emesh.query_ray_hits(point, direction.normalized()); + + if (hits.empty()) + return false; // no intersection found + + size_t hit_id = 0; + if (clipping_plane != nullptr) { + while (hit_id < hits.size() && clipping_plane->is_point_clipped(trafo * hits[hit_id].position())) { + ++hit_id; + } + } + + if (hit_id == hits.size()) + return false; // all points are obscured or cut by the clipping plane. + + const sla::IndexedMesh::hit_result& hit = hits[hit_id]; + + position = hit.position().cast(); + normal = hit.normal().cast(); + + if (facet_idx != nullptr) + *facet_idx = hit.face(); + + return true; +} Vec3f MeshRaycaster::get_closest_point(const Vec3f& point, Vec3f* normal) const { diff --git a/src/slic3r/GUI/MeshUtils.hpp b/src/slic3r/GUI/MeshUtils.hpp index 4f0210b3555..b387966961c 100644 --- a/src/slic3r/GUI/MeshUtils.hpp +++ b/src/slic3r/GUI/MeshUtils.hpp @@ -9,6 +9,7 @@ #include "slic3r/GUI/GLModel.hpp" #include +#include namespace Slic3r { @@ -52,6 +53,8 @@ class ClippingPlane void set_offset(double offset) { m_data[3] = offset; } double get_offset() const { return m_data[3]; } Vec3d get_normal() const { return Vec3d(m_data[0], m_data[1], m_data[2]); } + void invert_normal() { m_data[0] *= -1.0; m_data[1] *= -1.0; m_data[2] *= -1.0; } + ClippingPlane inverted_normal() const { return ClippingPlane(-get_normal(), get_offset()); } bool is_active() const { return m_data[3] != DBL_MAX; } static ClippingPlane ClipsNothing() { return ClippingPlane(Vec3d(0., 0., 1.), DBL_MAX); } const std::array& get_data() const { return m_data; } @@ -125,11 +128,10 @@ class MeshClipper // whether certain points are visible or obscured by the mesh etc. class MeshRaycaster { public: - // The class references extern TriangleMesh, which must stay alive - // during MeshRaycaster existence. - MeshRaycaster(const TriangleMesh& mesh) - : m_emesh(mesh, true) // calculate epsilon for triangle-ray intersection from an average edge length - , m_normals(its_face_normals(mesh.its)) + explicit MeshRaycaster(std::shared_ptr mesh) + : m_mesh(mesh) + , m_emesh(*mesh, true) // calculate epsilon for triangle-ray intersection from an average edge length + , m_normals(its_face_normals(mesh->its)) { } @@ -161,10 +163,22 @@ class MeshRaycaster { const ClippingPlane* clipping_plane = nullptr // clipping plane (if active) ) const; + // Returns true if the ray, built from mouse position and camera direction, intersects the mesh. + // In this case, position and normal contain the position and normal, in model coordinates, of the intersection closest to the camera, + // depending on the position/orientation of the clipping_plane, if specified + bool closest_hit( + const Vec2d& mouse_pos, + const Transform3d& trafo, // how to get the mesh into world coords + const Camera& camera, // current camera position + Vec3f& position, // where to save the positibon of the hit (mesh coords) + Vec3f& normal, // normal of the triangle that was hit + const ClippingPlane* clipping_plane = nullptr, // clipping plane (if active) + size_t* facet_idx = nullptr // index of the facet hit + ) const; + // Given a point in world coords, the method returns closest point on the mesh. // The output is in mesh coords. // normal* can be used to also get normal of the respective triangle. - Vec3f get_closest_point(const Vec3f& point, Vec3f* normal = nullptr) const; // Given a point in mesh coords, the method returns the closest facet from mesh. @@ -173,11 +187,22 @@ class MeshRaycaster { Vec3f get_triangle_normal(size_t facet_idx) const; private: + std::shared_ptr m_mesh; sla::IndexedMesh m_emesh; std::vector m_normals; }; - +struct PickingModel +{ + GLModel model; + std::unique_ptr mesh_raycaster; + + void reset() { + model.reset(); + mesh_raycaster.reset(); + } +}; + } // namespace GUI } // namespace Slic3r diff --git a/src/slic3r/GUI/SceneRaycaster.cpp b/src/slic3r/GUI/SceneRaycaster.cpp new file mode 100644 index 00000000000..9a4f69b9d43 --- /dev/null +++ b/src/slic3r/GUI/SceneRaycaster.cpp @@ -0,0 +1,220 @@ +#include "libslic3r/libslic3r.h" +#include "SceneRaycaster.hpp" + +#include "Camera.hpp" +#include "GUI_App.hpp" + +namespace Slic3r { +namespace GUI { + +SceneRaycaster::SceneRaycaster() { +#if ENABLE_RAYCAST_PICKING_DEBUG + // hit point + m_sphere.init_from(its_make_sphere(1.0, double(PI) / 16.0)); + m_sphere.set_color(ColorRGBA::YELLOW()); + + // hit normal + GLModel::Geometry init_data; + init_data.format = { GLModel::Geometry::EPrimitiveType::Lines, GLModel::Geometry::EVertexLayout::P3 }; + init_data.color = ColorRGBA::YELLOW(); + init_data.reserve_vertices(2); + init_data.reserve_indices(2); + + // vertices + init_data.add_vertex((Vec3f)Vec3f::Zero()); + init_data.add_vertex((Vec3f)Vec3f::UnitZ()); + + // indices + init_data.add_line(0, 1); + + m_line.init_from(std::move(init_data)); +#endif // ENABLE_RAYCAST_PICKING_DEBUG +} + +void SceneRaycaster::add_raycaster(EType type, PickingId id, const MeshRaycaster& raycaster, const Transform3d& trafo) +{ + switch (type) { + case EType::Bed: { + m_bed.emplace_back(encode_id(type, id), raycaster, trafo); + break; + } + case EType::Volume: { + m_volumes.emplace_back(encode_id(type, id), raycaster, trafo); + break; + } + case EType::Gizmo: { + m_gizmos.emplace_back(encode_id(type, id), raycaster, trafo); + break; + } + default: { break; } + }; +} + +void SceneRaycaster::remove_raycasters(EType type, PickingId id) +{ + std::vector* raycasters = get_raycasters(type); + auto it = raycasters->begin(); + while (it != raycasters->end()) { + if (it->get_id() == encode_id(type, id)) + it = raycasters->erase(it); + else + ++it; + } +} + +void SceneRaycaster::remove_raycasters(EType type) +{ + switch (type) { + case EType::Bed: { m_bed.clear(); break; } + case EType::Volume: { m_volumes.clear(); break; } + case EType::Gizmo: { m_gizmos.clear(); break; } + default: { break; } + }; +} + +void SceneRaycaster::set_raycaster_active_state(EType type, PickingId id, bool active) +{ + std::vector* raycasters = get_raycasters(type); + for (SceneRaycasterItem& item : *raycasters) { + if (item.get_id() == encode_id(type, id)) { + item.set_active(active); + break; + } + } +} + +void SceneRaycaster::set_raycaster_transform(EType type, PickingId id, const Transform3d& trafo) +{ + std::vector* raycasters = get_raycasters(type); + for (SceneRaycasterItem& item : *raycasters) { + if (item.get_id() == encode_id(type, id)) { + item.set_transform(trafo); + break; + } + } +} + +SceneRaycaster::HitResult SceneRaycaster::hit(const Vec2d& mouse_pos, const Camera& camera, const ClippingPlane* clipping_plane) +{ + double closest_hit_squared_distance = std::numeric_limits::max(); + auto is_closest = [&closest_hit_squared_distance](const Camera& camera, const Vec3f& hit) { + const double hit_squared_distance = (camera.get_position() - hit.cast()).squaredNorm(); + const bool ret = hit_squared_distance < closest_hit_squared_distance; + if (ret) + closest_hit_squared_distance = hit_squared_distance; + return ret; + }; + +#if ENABLE_RAYCAST_PICKING_DEBUG + m_last_hit.reset(); +#endif // ENABLE_RAYCAST_PICKING_DEBUG + + HitResult ret; + + auto test_raycasters = [&](EType type) { + const ClippingPlane* clip_plane = (clipping_plane != nullptr && type == EType::Volume) ? clipping_plane : nullptr; + const std::vector* raycasters = get_raycasters(type); + HitResult current_hit = { type }; + for (const SceneRaycasterItem& item : *raycasters) { + if (!item.is_active()) + continue; + + current_hit.raycaster_id = item.get_id(); + const Transform3d& trafo = item.get_transform(); + if (item.get_raycaster()->closest_hit(mouse_pos, trafo, camera, current_hit.position, current_hit.normal, clip_plane)) { + current_hit.position = (trafo * current_hit.position.cast()).cast(); + if (is_closest(camera, current_hit.position)) { + const Transform3d matrix = camera.get_view_matrix() * trafo; + const Matrix3d normal_matrix = (Matrix3d)trafo.matrix().block(0, 0, 3, 3).inverse().transpose(); + current_hit.normal = (normal_matrix * current_hit.normal.cast()).normalized().cast(); + ret = current_hit; + } + } + } + }; + + if (!m_gizmos.empty()) + test_raycasters(EType::Gizmo); + + if (!m_gizmos_on_top || !ret.is_valid()) { + if (camera.is_looking_downward() && !m_bed.empty()) + test_raycasters(EType::Bed); + if (!m_volumes.empty()) + test_raycasters(EType::Volume); + } + + if (ret.is_valid()) + ret.raycaster_id = decode_id(ret.type, ret.raycaster_id); + +#if ENABLE_RAYCAST_PICKING_DEBUG + m_last_hit = ret; +#endif // ENABLE_RAYCAST_PICKING_DEBUG + return ret; +} + +#if ENABLE_RAYCAST_PICKING_DEBUG +void SceneRaycaster::render_hit(const Camera& camera) +{ + if (!m_last_hit.has_value() || !m_last_hit.value().is_valid()) + return; + + GLShaderProgram* shader = wxGetApp().get_shader("flat"); + shader->start_using(); + + shader->set_uniform("projection_matrix", camera.get_projection_matrix()); + + const Transform3d sphere_view_model_matrix = camera.get_view_matrix() * Geometry::translation_transform(m_last_hit.value().position.cast()) * + Geometry::scale_transform(4.0 * camera.get_inv_zoom()); + shader->set_uniform("view_model_matrix", sphere_view_model_matrix); + m_sphere.render(); + + Eigen::Quaterniond q; + Transform3d m = Transform3d::Identity(); + m.matrix().block(0, 0, 3, 3) = q.setFromTwoVectors(Vec3d::UnitZ(), m_last_hit.value().normal.cast()).toRotationMatrix(); + + const Transform3d line_view_model_matrix = sphere_view_model_matrix * m * Geometry::scale_transform(10.0); + shader->set_uniform("view_model_matrix", line_view_model_matrix); + m_line.render(); + + shader->stop_using(); +} +#endif // ENABLE_RAYCAST_PICKING_DEBUG + +std::vector* SceneRaycaster::get_raycasters(EType type) +{ + std::vector* ret = nullptr; + switch (type) + { + case EType::Bed: { ret = &m_bed; break; } + case EType::Volume: { ret = &m_volumes; break; } + case EType::Gizmo: { ret = &m_gizmos; break; } + } + assert(ret != nullptr); + return ret; +} + +PickingId SceneRaycaster::base_id(EType type) +{ + switch (type) + { + case EType::Bed: { return PickingId(EPickingIdBase::Bed); } + case EType::Volume: { return PickingId(EPickingIdBase::Volume); } + case EType::Gizmo: { return PickingId(EPickingIdBase::Gizmo); } + }; + + assert(false); + return -1; +} + +PickingId SceneRaycaster::encode_id(EType type, PickingId id) +{ + return base_id(type) + id; +} + +PickingId SceneRaycaster::decode_id(EType type, PickingId id) +{ + return id - base_id(type); +} + +} // namespace GUI +} // namespace Slic3r diff --git a/src/slic3r/GUI/SceneRaycaster.hpp b/src/slic3r/GUI/SceneRaycaster.hpp new file mode 100644 index 00000000000..1832ffc558d --- /dev/null +++ b/src/slic3r/GUI/SceneRaycaster.hpp @@ -0,0 +1,114 @@ +#ifndef slic3r_SceneRaycaster_hpp_ +#define slic3r_SceneRaycaster_hpp_ + +#include "MeshUtils.hpp" +#include "GLModel.hpp" + +#include +#include +#include + +namespace Slic3r { +namespace GUI { + +struct Camera; + +using PickingId = int; + +class SceneRaycasterItem +{ + PickingId m_id{ -1 }; + bool m_active{ true }; + const MeshRaycaster* m_raycaster; + Transform3d m_trafo; + +public: + SceneRaycasterItem(PickingId id, const MeshRaycaster& raycaster, const Transform3d& trafo) + : m_id(id), m_raycaster(&raycaster), m_trafo(trafo) + {} + + PickingId get_id() const { return m_id; } + bool is_active() const { return m_active; } + void set_active(bool active) { m_active = active; } + const MeshRaycaster* get_raycaster() const { return m_raycaster; } + const Transform3d& get_transform() const { return m_trafo; } + void set_transform(const Transform3d& trafo) { m_trafo = trafo; } +}; + +class SceneRaycaster +{ +public: + enum class EType + { + None, + Bed, + Volume, + Gizmo + }; + + enum class EPickingIdBase + { + Bed = 0, + Volume = 1000, + Gizmo = 1000000 + }; + + struct HitResult + { + EType type{ EType::None }; + PickingId raycaster_id{ -1 }; + Vec3f position{ Vec3f::Zero() }; + Vec3f normal{ Vec3f::Zero() }; + + bool is_valid() const { return raycaster_id != -1; } + }; + +private: + std::vector m_bed; + std::vector m_volumes; + std::vector m_gizmos; + + // When set to true, if checking gizmos returns a valid hit, + // the search is not performed on other types + bool m_gizmos_on_top{ false }; + +#if ENABLE_RAYCAST_PICKING_DEBUG + GLModel m_sphere; + GLModel m_line; + std::optional m_last_hit; +#endif // ENABLE_RAYCAST_PICKING_DEBUG + +public: + SceneRaycaster(); + + void add_raycaster(EType type, PickingId picking_id, const MeshRaycaster& raycaster, const Transform3d& trafo); + void remove_raycasters(EType type, PickingId id); + void remove_raycasters(EType type); + + void set_raycaster_active_state(EType type, PickingId picking_id, bool active); + void set_raycaster_transform(EType type, PickingId picking_id, const Transform3d& trafo); + + void set_gizmos_on_top(bool value) { m_gizmos_on_top = value; } + + HitResult hit(const Vec2d& mouse_pos, const Camera& camera, const ClippingPlane* clipping_plane = nullptr); + +#if ENABLE_RAYCAST_PICKING_DEBUG + void render_hit(const Camera& camera); + + size_t beds_count() const { return m_bed.size(); } + size_t volumes_count() const { return m_volumes.size(); } + size_t gizmos_count() const { return m_gizmos.size(); } +#endif // ENABLE_RAYCAST_PICKING_DEBUG + +private: + std::vector* get_raycasters(EType type); + + static PickingId encode_id(EType type, PickingId id); + static PickingId decode_id(EType type, PickingId id); + static PickingId base_id(EType type); +}; + +} // namespace GUI +} // namespace Slic3r + +#endif // slic3r_SceneRaycaster_hpp_ From cd1705e6eb662ed3612c442c321011be3e0b9909 Mon Sep 17 00:00:00 2001 From: Noisyfox Date: Sat, 28 Oct 2023 18:11:53 +0800 Subject: [PATCH 62/99] Implement plate picking --- src/slic3r/GUI/GLCanvas3D.cpp | 10 ++- src/slic3r/GUI/PartPlate.cpp | 161 ++++++++++++++++------------------ src/slic3r/GUI/PartPlate.hpp | 30 +++---- 3 files changed, 100 insertions(+), 101 deletions(-) diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index e8839e777c2..0e436e0089b 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -6431,8 +6431,6 @@ void GLCanvas3D::_picking_pass() m_hover_volume_idxs.clear(); m_hover_plate_idxs.clear(); - // TODO: Support plate picking - const ClippingPlane clipping_plane = m_gizmos.get_clipping_plane().inverted_normal(); const SceneRaycaster::HitResult hit = m_scene_raycaster.hit(m_mouse.position, wxGetApp().plater()->get_camera(), &clipping_plane); if (hit.is_valid()) { @@ -6465,6 +6463,14 @@ void GLCanvas3D::_picking_pass() } case SceneRaycaster::EType::Bed: { + // BBS: add plate picking logic + int plate_hover_id = PartPlate::PLATE_BASE_ID - hit.raycaster_id; + if (plate_hover_id >= 0 && plate_hover_id < PartPlateList::MAX_PLATES_COUNT * PartPlate::GRABBER_COUNT) { + wxGetApp().plater()->get_partplate_list().set_hover_id(plate_hover_id); + m_hover_plate_idxs.emplace_back(plate_hover_id); + } else { + wxGetApp().plater()->get_partplate_list().reset_hover_id(); + } m_gizmos.set_hover_id(-1); break; } diff --git a/src/slic3r/GUI/PartPlate.cpp b/src/slic3r/GUI/PartPlate.cpp index ba41d160aed..d3be25f8bd7 100644 --- a/src/slic3r/GUI/PartPlate.cpp +++ b/src/slic3r/GUI/PartPlate.cpp @@ -148,6 +148,7 @@ PartPlate::PartPlate(PartPlateList *partplate_list, Vec3d origin, int width, int PartPlate::~PartPlate() { + unregister_raycasters_for_picking(); clear(); //if (m_quadric != nullptr) // ::gluDeleteQuadric(m_quadric); @@ -335,7 +336,7 @@ void PartPlate::calc_triangles(const ExPolygon &poly) { m_triangles.reset(); - if (!init_model_from_poly(m_triangles, poly, GROUND_Z)) + if (!init_model_from_poly(m_triangles.model, poly, GROUND_Z)) BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << ":Unable to create plate triangles\n"; } @@ -387,6 +388,26 @@ static bool init_model_from_lines(GLModel &model, const Lines3 &lines) return true; } +static void init_raycaster_from_model(PickingModel& model) +{ + assert(model.mesh_raycaster == nullptr); + + const GLModel::Geometry &geometry = model.model.get_geometry(); + + indexed_triangle_set its; + its.vertices.reserve(geometry.vertices_count()); + for (size_t i = 0; i < geometry.vertices_count(); ++i) { + its.vertices.emplace_back(geometry.extract_position_3(i)); + } + its.indices.reserve(geometry.indices_count() / 3); + for (size_t i = 0; i < geometry.indices_count() / 3; ++i) { + const size_t tri_id = i * 3; + its.indices.emplace_back(geometry.extract_index(tri_id), geometry.extract_index(tri_id + 1), geometry.extract_index(tri_id + 2)); + } + + model.mesh_raycaster = std::make_unique(std::make_shared(std::move(its))); +} + void PartPlate::calc_gridlines(const ExPolygon& poly, const BoundingBox& pp_bbox) { m_gridlines.reset(); m_gridlines_bolder.reset(); @@ -506,9 +527,9 @@ void PartPlate::calc_vertex_for_number(int index, bool one_number, GLModel &buff BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << "Unable to generate geometry buffers for icons\n"; } -void PartPlate::calc_vertex_for_icons(int index, GLModel &buffer) +void PartPlate::calc_vertex_for_icons(int index, PickingModel &model) { - buffer.reset(); + model.reset(); ExPolygon poly; auto bed_ext = get_extents(m_shape); @@ -522,10 +543,13 @@ void PartPlate::calc_vertex_for_icons(int index, GLModel &buffer) poly.contour.append({ scale_(p(0) + PARTPLATE_ICON_GAP_LEFT + PARTPLATE_ICON_SIZE), scale_(p(1) - index * (PARTPLATE_ICON_SIZE + PARTPLATE_ICON_GAP_Y)- PARTPLATE_ICON_GAP_TOP)}); poly.contour.append({ scale_(p(0) + PARTPLATE_ICON_GAP_LEFT), scale_(p(1) - index * (PARTPLATE_ICON_SIZE + PARTPLATE_ICON_GAP_Y)- PARTPLATE_ICON_GAP_TOP) }); - if (!init_model_from_poly(buffer, poly, GROUND_Z)) + if (!init_model_from_poly(model.model, poly, GROUND_Z)) BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << "Unable to generate geometry buffers for icons\n"; + + init_raycaster_from_model(model); } +/* void PartPlate::calc_vertex_for_icons_background(int icon_count, GLModel &buffer) { buffer.reset(); @@ -542,6 +566,7 @@ void PartPlate::calc_vertex_for_icons_background(int icon_count, GLModel &buffer if (!init_model_from_poly(buffer, poly, GROUND_Z)) BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << "Unable to generate geometry buffers for icons\n"; } +*/ void PartPlate::render_background(bool force_default_color) { @@ -563,8 +588,8 @@ void PartPlate::render_background(bool force_default_color) else { color = PartPlate::DEFAULT_COLOR; } - m_triangles.set_color(color); - m_triangles.render(); + m_triangles.model.set_color(color); + m_triangles.model.render(); glsafe(::glDepthMask(GL_TRUE)); } @@ -868,57 +893,57 @@ void PartPlate::render_icons(bool bottom, bool only_name, int hover_id) if (!only_name) { if (hover_id == 1) { - render_icon_texture(m_del_icon, m_partplate_list->m_del_hovered_texture); + render_icon_texture(m_del_icon.model, m_partplate_list->m_del_hovered_texture); show_tooltip(_u8L("Remove current plate (if not last one)")); } else - render_icon_texture(m_del_icon, m_partplate_list->m_del_texture); + render_icon_texture(m_del_icon.model, m_partplate_list->m_del_texture); if (hover_id == 2) { - render_icon_texture(m_orient_icon, m_partplate_list->m_orient_hovered_texture); + render_icon_texture(m_orient_icon.model, m_partplate_list->m_orient_hovered_texture); show_tooltip(_u8L("Auto orient objects on current plate")); } else - render_icon_texture(m_orient_icon, m_partplate_list->m_orient_texture); + render_icon_texture(m_orient_icon.model, m_partplate_list->m_orient_texture); if (hover_id == 3) { - render_icon_texture(m_arrange_icon, m_partplate_list->m_arrange_hovered_texture); + render_icon_texture(m_arrange_icon.model, m_partplate_list->m_arrange_hovered_texture); show_tooltip(_u8L("Arrange objects on current plate")); } else - render_icon_texture(m_arrange_icon, m_partplate_list->m_arrange_texture); + render_icon_texture(m_arrange_icon.model, m_partplate_list->m_arrange_texture); if (hover_id == 4) { if (this->is_locked()) { - render_icon_texture(m_lock_icon, + render_icon_texture(m_lock_icon.model, m_partplate_list->m_locked_hovered_texture); show_tooltip(_u8L("Unlock current plate")); } else { - render_icon_texture(m_lock_icon, + render_icon_texture(m_lock_icon.model, m_partplate_list->m_lockopen_hovered_texture); show_tooltip(_u8L("Lock current plate")); } } else { if (this->is_locked()) - render_icon_texture(m_lock_icon, m_partplate_list->m_locked_texture); + render_icon_texture(m_lock_icon.model, m_partplate_list->m_locked_texture); else - render_icon_texture(m_lock_icon, m_partplate_list->m_lockopen_texture); + render_icon_texture(m_lock_icon.model, m_partplate_list->m_lockopen_texture); } if (m_partplate_list->render_plate_settings) { if (hover_id == 5) { if (get_bed_type() == BedType::btDefault && get_print_seq() == PrintSequence::ByDefault && get_first_layer_print_sequence().empty()) - render_icon_texture(m_plate_settings_icon, m_partplate_list->m_plate_settings_hovered_texture); + render_icon_texture(m_plate_settings_icon.model, m_partplate_list->m_plate_settings_hovered_texture); else - render_icon_texture(m_plate_settings_icon, m_partplate_list->m_plate_settings_changed_hovered_texture); + render_icon_texture(m_plate_settings_icon.model, m_partplate_list->m_plate_settings_changed_hovered_texture); show_tooltip(_u8L("Customize current plate")); } else { if (get_bed_type() == BedType::btDefault && get_print_seq() == PrintSequence::ByDefault && get_first_layer_print_sequence().empty()) - render_icon_texture(m_plate_settings_icon, m_partplate_list->m_plate_settings_texture); + render_icon_texture(m_plate_settings_icon.model, m_partplate_list->m_plate_settings_texture); else - render_icon_texture(m_plate_settings_icon, m_partplate_list->m_plate_settings_changed_texture); + render_icon_texture(m_plate_settings_icon.model, m_partplate_list->m_plate_settings_changed_texture); } } @@ -971,22 +996,11 @@ void PartPlate::render_only_numbers(bool bottom) } } -void PartPlate::render_rectangle_for_picking(const Transform3d &view_matrix, const Transform3d &projection_matrix, GLModel &buffer, const ColorRGBA render_color) +void PartPlate::register_rectangle_for_picking(PickingModel &model, int id) { - GLShaderProgram *shader = wxGetApp().get_shader("flat"); - if (shader != nullptr) { - shader->start_using(); - - shader->set_uniform("view_model_matrix", view_matrix); - shader->set_uniform("projection_matrix", projection_matrix); + wxGetApp().plater()->canvas3D()->add_raycaster_for_picking(SceneRaycaster::EType::Bed, id, *model.mesh_raycaster, Transform3d::Identity()); - //glsafe(::glDepthMask(GL_FALSE)); - buffer.set_color(render_color); - buffer.render(); - //glsafe(::glDepthMask(GL_TRUE)); - - shader->stop_using(); - } + picking_ids.emplace_back(id); } /* @@ -1207,48 +1221,31 @@ void PartPlate::render_right_arrow(const ColorRGBA render_color, bool use_lighti } */ -void PartPlate::on_render_for_picking(const Transform3d &view_matrix, const Transform3d &projection_matrix) { - //glsafe(::glDisable(GL_DEPTH_TEST)); - int hover_id = 0; - ColorRGBA color = picking_color_component(hover_id); - m_grabber_color = color; - //render_grabber(m_grabber_color, false); - render_rectangle_for_picking(view_matrix, projection_matrix, m_triangles, m_grabber_color); - hover_id = 1; - color = picking_color_component(hover_id); - m_grabber_color = color; - //render_left_arrow(m_grabber_color, false); - render_rectangle_for_picking(view_matrix, projection_matrix, m_del_icon, m_grabber_color); - hover_id = 2; - color = picking_color_component(hover_id); - m_grabber_color = color; - render_rectangle_for_picking(view_matrix, projection_matrix, m_orient_icon, m_grabber_color); - hover_id = 3; - color = picking_color_component(hover_id); - m_grabber_color = color; - render_rectangle_for_picking(view_matrix, projection_matrix, m_arrange_icon, m_grabber_color); - hover_id = 4; - color = picking_color_component(hover_id); - m_grabber_color = color; - //render_right_arrow(m_grabber_color, false); - render_rectangle_for_picking(view_matrix, projection_matrix, m_lock_icon, m_grabber_color); - hover_id = 5; - color = picking_color_component(hover_id); - m_grabber_color = color; +void PartPlate::register_raycasters_for_picking() +{ + unregister_raycasters_for_picking(); + + picking_ids.reserve(6); + register_rectangle_for_picking(m_triangles, picking_id_component(0)); + register_rectangle_for_picking(m_del_icon, picking_id_component(1)); + register_rectangle_for_picking(m_orient_icon, picking_id_component(2)); + register_rectangle_for_picking(m_arrange_icon, picking_id_component(3)); + register_rectangle_for_picking(m_lock_icon, picking_id_component(4)); if (m_partplate_list->render_plate_settings) - render_rectangle_for_picking(view_matrix, projection_matrix, m_plate_settings_icon, m_grabber_color); + register_rectangle_for_picking(m_plate_settings_icon, picking_id_component(5)); } -ColorRGBA PartPlate::picking_color_component(int idx) const +void PartPlate::unregister_raycasters_for_picking() { + for (int picking_id : picking_ids) { + wxGetApp().plater()->canvas3D()->remove_raycasters_for_picking(SceneRaycaster::EType::Bed, picking_id); + } + picking_ids.clear(); +} + +int PartPlate::picking_id_component(int idx) const { - static const float INV_255 = 1.0f / 255.0f; unsigned int id = PLATE_BASE_ID - this->m_plate_index * GRABBER_COUNT - idx; - return ColorRGBA { - float((id >> 0) & 0xff)* INV_255, // red - float((id >> 8) & 0xff)* INV_255, // greeen - float((id >> 16) & 0xff)* INV_255, // blue - float(picking_checksum_alpha_channel(id & 0xff, (id >> 8) & 0xff, (id >> 16) & 0xff))* INV_255 - }; + return id; } std::vector PartPlate::get_extruders(bool conside_custom_gcode) const @@ -2428,6 +2425,7 @@ bool PartPlate::set_shape(const Pointfs& shape, const Pointfs& exclude_areas, Ve }*/ generate_print_polygon(poly); calc_triangles(poly); + init_raycaster_from_model(m_triangles); ExPolygon exclude_poly; /*for (const Vec2d& p : m_exclude_area) { @@ -2442,14 +2440,16 @@ bool PartPlate::set_shape(const Pointfs& shape, const Pointfs& exclude_areas, Ve //calc_vertex_for_icons_background(5, m_del_and_background_icon); //calc_vertex_for_icons(4, m_del_icon); calc_vertex_for_icons(0, m_del_icon); - calc_vertex_for_icons(1, m_orient_icon); - calc_vertex_for_icons(2, m_arrange_icon); - calc_vertex_for_icons(3, m_lock_icon); - calc_vertex_for_icons(4, m_plate_settings_icon); + calc_vertex_for_icons(1, m_orient_icon); + calc_vertex_for_icons(2, m_arrange_icon); + calc_vertex_for_icons(3, m_lock_icon); + calc_vertex_for_icons(4, m_plate_settings_icon); //calc_vertex_for_number(0, (m_plate_index < 9), m_plate_idx_icon); calc_vertex_for_number(0, false, m_plate_idx_icon); // calc vertex for plate name generate_plate_name_texture(); + + register_raycasters_for_picking(); } calc_height_limit(); @@ -3361,6 +3361,8 @@ int PartPlateList::delete_plate(int index) return -1; } + plate->unregister_raycasters_for_picking(); + if (m_plater) { // In GUI mode // BBS: add wipe tower logic @@ -4396,15 +4398,6 @@ void PartPlateList::render(const Transform3d& view_matrix, const Transform3d& pr } } -void PartPlateList::render_for_picking_pass(const Transform3d &view_matrix, const Transform3d &projection_matrix) -{ - const std::lock_guard local_lock(m_plates_mutex); - std::vector::iterator it = m_plate_list.begin(); - for (it = m_plate_list.begin(); it != m_plate_list.end(); it++) { - (*it)->render_for_picking(view_matrix, projection_matrix); - } -} - /*int PartPlateList::select_plate_by_hover_id(int hover_id) { int index = hover_id / PartPlate::GRABBER_COUNT; diff --git a/src/slic3r/GUI/PartPlate.hpp b/src/slic3r/GUI/PartPlate.hpp index b93e4f4dfaa..7b5eee70e3a 100644 --- a/src/slic3r/GUI/PartPlate.hpp +++ b/src/slic3r/GUI/PartPlate.hpp @@ -21,6 +21,7 @@ #include "3DScene.hpp" #include "GLModel.hpp" #include "3DBed.hpp" +#include "MeshUtils.hpp" class GLUquadric; typedef class GLUquadric GLUquadricObject; @@ -115,7 +116,7 @@ class PartPlate : public ObjectBase Transform3d m_grabber_trans_matrix; Slic3r::Geometry::Transformation position; std::vector positions; - GLModel m_triangles; + PickingModel m_triangles; GLModel m_exclude_triangles; GLModel m_logo_triangles; GLModel m_gridlines; @@ -123,16 +124,15 @@ class PartPlate : public ObjectBase GLModel m_height_limit_common; GLModel m_height_limit_bottom; GLModel m_height_limit_top; - GLModel m_del_icon; - //GLModel m_del_and_background_icon; - GLModel m_arrange_icon; - GLModel m_orient_icon; - GLModel m_lock_icon; - GLModel m_plate_settings_icon; + PickingModel m_del_icon; + PickingModel m_arrange_icon; + PickingModel m_orient_icon; + PickingModel m_lock_icon; + PickingModel m_plate_settings_icon; GLModel m_plate_idx_icon; GLTexture m_texture; + std::vector picking_ids; - mutable ColorRGBA m_grabber_color; float m_scale_factor{ 1.0f }; GLUquadricObject* m_quadric; int m_hover_id; @@ -161,8 +161,8 @@ class PartPlate : public ObjectBase void calc_gridlines(const ExPolygon& poly, const BoundingBox& pp_bbox); void calc_height_limit(); void calc_vertex_for_number(int index, bool one_number, GLModel &buffer); - void calc_vertex_for_icons(int index, GLModel &buffer); - void calc_vertex_for_icons_background(int icon_count, GLModel &buffer); + void calc_vertex_for_icons(int index, PickingModel &model); + // void calc_vertex_for_icons_background(int icon_count, GLModel &buffer); void render_background(bool force_default_color = false); void render_logo(bool bottom, bool render_cali = true); void render_logo_texture(GLTexture &logo_texture, GLModel &logo_buffer, bool bottom); @@ -181,9 +181,10 @@ class PartPlate : public ObjectBase void render_icons(bool bottom, bool only_name = false, int hover_id = -1); void render_only_numbers(bool bottom); void render_plate_name_texture(); - void render_rectangle_for_picking(const Transform3d &view_matrix, const Transform3d &projection_matrix, GLModel &buffer, const ColorRGBA render_color); - void on_render_for_picking(const Transform3d &view_matrix, const Transform3d &projection_matrix); - ColorRGBA picking_color_component(int idx) const; + void register_rectangle_for_picking(PickingModel &model, int id); + void register_raycasters_for_picking(); + void unregister_raycasters_for_picking(); + int picking_id_component(int idx) const; public: static const unsigned int PLATE_BASE_ID = 255 * 255 * 253; @@ -342,7 +343,7 @@ class PartPlate : public ObjectBase bool intersects(const BoundingBoxf3& bb) const; void render(const Transform3d& view_matrix, const Transform3d& projection_matrix, bool bottom, bool only_body = false, bool force_background_color = false, HeightLimitMode mode = HEIGHT_LIMIT_NONE, int hover_id = -1, bool render_cali = false); - void render_for_picking(const Transform3d &view_matrix, const Transform3d &projection_matrix) { on_render_for_picking(view_matrix, projection_matrix); } + void set_selected(); void set_unselected(); void set_hover_id(int id) { m_hover_id = id; } @@ -741,7 +742,6 @@ class PartPlateList : public ObjectBase /*rendering related functions*/ void on_change_color_mode(bool is_dark) { m_is_dark = is_dark; } void render(const Transform3d& view_matrix, const Transform3d& projection_matrix, bool bottom, bool only_current = false, bool only_body = false, int hover_id = -1, bool render_cali = false); - void render_for_picking_pass(const Transform3d& view_matrix, const Transform3d& projection_matrix); void set_render_option(bool bedtype_texture, bool plate_settings); void set_render_cali(bool value = true) { render_cali_logo = value; } BoundingBoxf3& get_bounding_box() { return m_bounding_box; } From 1cd421c4b13ee0764a81e06401680920a4a7cd8b Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Sat, 28 Oct 2023 22:22:18 +0800 Subject: [PATCH 63/99] Tech ENABLE_RAYCAST_PICKING - Raytraced picking of gizmos - Move Gizmo (cherry picked from commit prusa3d/PrusaSlicer@df47ba7122cd3ed9f11d4eebdf7839b9300828bd) --- src/slic3r/GUI/GLCanvas3D.cpp | 9 ++ src/slic3r/GUI/GLCanvas3D.hpp | 4 + src/slic3r/GUI/Gizmos/GLGizmoAdvancedCut.cpp | 10 +- src/slic3r/GUI/Gizmos/GLGizmoAdvancedCut.hpp | 1 - src/slic3r/GUI/Gizmos/GLGizmoBase.cpp | 107 ++++++++++--------- src/slic3r/GUI/Gizmos/GLGizmoBase.hpp | 43 +++++--- src/slic3r/GUI/Gizmos/GLGizmoFlatten.cpp | 2 + src/slic3r/GUI/Gizmos/GLGizmoFlatten.hpp | 1 - src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp | 12 --- src/slic3r/GUI/Gizmos/GLGizmoHollow.hpp | 1 - src/slic3r/GUI/Gizmos/GLGizmoMeshBoolean.hpp | 1 - src/slic3r/GUI/Gizmos/GLGizmoMove.cpp | 11 +- src/slic3r/GUI/Gizmos/GLGizmoMove.hpp | 3 +- src/slic3r/GUI/Gizmos/GLGizmoPainterBase.hpp | 1 - src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp | 12 --- src/slic3r/GUI/Gizmos/GLGizmoRotate.hpp | 6 -- src/slic3r/GUI/Gizmos/GLGizmoScale.cpp | 6 -- src/slic3r/GUI/Gizmos/GLGizmoScale.hpp | 1 - src/slic3r/GUI/Gizmos/GLGizmoSimplify.hpp | 1 - src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp | 8 -- src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp | 1 - src/slic3r/GUI/Gizmos/GLGizmoText.cpp | 4 +- src/slic3r/GUI/Gizmos/GLGizmoText.hpp | 1 - src/slic3r/GUI/Gizmos/GLGizmosCommon.hpp | 2 +- src/slic3r/GUI/Gizmos/GLGizmosManager.cpp | 37 ++++--- src/slic3r/GUI/Gizmos/GLGizmosManager.hpp | 1 - 26 files changed, 140 insertions(+), 146 deletions(-) diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 0e436e0089b..8667ae9cfd8 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -2192,6 +2192,10 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re m_hover_volume_idxs.clear(); + GLGizmoBase* curr_gizmo = m_gizmos.get_current(); + if (curr_gizmo != nullptr) + curr_gizmo->unregister_raycasters_for_picking(); + struct ModelVolumeState { ModelVolumeState(const GLVolume* volume) : model_volume(nullptr), geometry_id(volume->geometry_id), volume_idx(-1) {} @@ -2711,6 +2715,11 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re add_raycaster_for_picking(SceneRaycaster::EType::Volume, i, *m_volumes.volumes[i]->mesh_raycaster, m_volumes.volumes[i]->world_matrix()); } + // refresh gizmo elements raycasters for picking + m_scene_raycaster.remove_raycasters(SceneRaycaster::EType::Gizmo); + if (curr_gizmo != nullptr && !m_selection.is_empty()) + curr_gizmo->register_raycasters_for_picking(); + // and force this canvas to be redrawn. m_dirty = true; } diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp index 89f5f969529..86c126f8be6 100644 --- a/src/slic3r/GUI/GLCanvas3D.hpp +++ b/src/slic3r/GUI/GLCanvas3D.hpp @@ -739,6 +739,10 @@ class GLCanvas3D m_scene_raycaster.remove_raycasters(type); } + void set_raycaster_gizmos_on_top(bool value) { + m_scene_raycaster.set_gizmos_on_top(value); + } + void reset_explosion_ratio() { m_explosion_ratio = 1.0; } void on_change_color_mode(bool is_dark, bool reinit = true); const bool get_dark_mode_status() { return m_is_dark; } diff --git a/src/slic3r/GUI/Gizmos/GLGizmoAdvancedCut.cpp b/src/slic3r/GUI/Gizmos/GLGizmoAdvancedCut.cpp index 19ab81021c5..a7851318a6c 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoAdvancedCut.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoAdvancedCut.cpp @@ -485,7 +485,7 @@ void GLGizmoAdvancedCut::on_render() render_cut_line(); } - +/* void GLGizmoAdvancedCut::on_render_for_picking() { GLGizmoRotate3D::on_render_for_picking(); @@ -545,7 +545,7 @@ void GLGizmoAdvancedCut::on_render_for_picking() render_connector_model(m_shapes[connectors[i].attribs], color, model_matrix, true); } } - +*/ void GLGizmoAdvancedCut::on_render_input_window(float x, float y, float bottom_limit) { GizmoImguiSetNextWIndowPos(x, y, ImGuiCond_Always, 0.0f, 0.0f); @@ -949,7 +949,7 @@ void GLGizmoAdvancedCut::render_cut_plane_and_grabbers() else render_color = GrabberColor; - GLModel &cube = m_move_grabber.get_cube(); + PickingModel &cube = m_move_grabber.get_cube(); // BBS set to fixed size grabber // float fullsize = 2 * (dragging ? get_dragging_half_size(size) : get_half_size(size)); float fullsize = 8.0f; @@ -957,7 +957,7 @@ void GLGizmoAdvancedCut::render_cut_plane_and_grabbers() fullsize = m_move_grabber.FixedGrabberSize * GLGizmoBase::INV_ZOOM; } - cube.set_color(render_color); + cube.model.set_color(render_color); const Transform3d trafo_matrix = Geometry::assemble_transform(m_move_grabber.center) * m_rotate_matrix * Geometry::assemble_transform(Vec3d::Zero(), Vec3d::Zero(), fullsize * Vec3d::Ones()); @@ -967,7 +967,7 @@ void GLGizmoAdvancedCut::render_cut_plane_and_grabbers() shader->set_uniform("projection_matrix", camera.get_projection_matrix()); const Matrix3d view_normal_matrix = view_matrix.matrix().block(0, 0, 3, 3) * trafo_matrix.matrix().block(0, 0, 3, 3).inverse().transpose(); shader->set_uniform("view_normal_matrix", view_normal_matrix); - cube.render(); + cube.model.render(); shader->stop_using(); } diff --git a/src/slic3r/GUI/Gizmos/GLGizmoAdvancedCut.hpp b/src/slic3r/GUI/Gizmos/GLGizmoAdvancedCut.hpp index 5d6354c1171..a61fcdc1e1d 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoAdvancedCut.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoAdvancedCut.hpp @@ -150,7 +150,6 @@ struct Rotate_data { virtual void on_stop_dragging() override; virtual void on_update(const UpdateData& data); virtual void on_render(); - virtual void on_render_for_picking(); virtual void on_render_input_window(float x, float y, float bottom_limit); void show_tooltip_information(float x, float y); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoBase.cpp b/src/slic3r/GUI/Gizmos/GLGizmoBase.cpp index e19c10da1ff..7638ea251da 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoBase.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoBase.cpp @@ -69,16 +69,16 @@ void GLGizmoBase::load_render_colors() RenderColor::colors[RenderCol_Flatten_Plane_Hover] = ImGuiWrapper::to_ImVec4(GLGizmoBase::FLATTEN_HOVER_COLOR); } -GLModel GLGizmoBase::Grabber::s_cube; -GLModel GLGizmoBase::Grabber::s_cone; +PickingModel GLGizmoBase::Grabber::s_cube; +PickingModel GLGizmoBase::Grabber::s_cone; GLGizmoBase::Grabber::~Grabber() { - if (s_cube.is_initialized()) - s_cube.reset(); + if (s_cube.model.is_initialized()) + s_cube.model.reset(); - if (s_cone.is_initialized()) - s_cone.reset(); + if (s_cone.model.is_initialized()) + s_cone.model.reset(); } float GLGizmoBase::Grabber::get_half_size(float size) const @@ -91,51 +91,75 @@ float GLGizmoBase::Grabber::get_dragging_half_size(float size) const return get_half_size(size) * DraggingScaleFactor; } -GLModel& GLGizmoBase::Grabber::get_cube() +PickingModel &GLGizmoBase::Grabber::get_cube() { - if (!s_cube.is_initialized()) { + if (!s_cube.model.is_initialized()) { // This cannot be done in constructor, OpenGL is not yet // initialized at that point (on Linux at least). indexed_triangle_set its = its_make_cube(1.0, 1.0, 1.0); its_translate(its, -0.5f * Vec3f::Ones()); - s_cube.init_from(its); + s_cube.model.init_from(its); + s_cube.mesh_raycaster = std::make_unique(std::make_shared(std::move(its))); } return s_cube; } +void GLGizmoBase::Grabber::register_raycasters_for_picking(int id) +{ + picking_id = id; + assert(elements_registered_for_picking == false); +} + +void GLGizmoBase::Grabber::unregister_raycasters_for_picking() +{ + wxGetApp().plater()->canvas3D()->remove_raycasters_for_picking(SceneRaycaster::EType::Gizmo, picking_id); + picking_id = -1; + elements_registered_for_picking = false; +} + void GLGizmoBase::Grabber::render(float size, const ColorRGBA& render_color, bool picking) { GLShaderProgram* shader = wxGetApp().get_current_shader(); if (shader == nullptr) return; - if (!s_cube.is_initialized()) { + if (!s_cube.model.is_initialized()) { // This cannot be done in constructor, OpenGL is not yet // initialized at that point (on Linux at least). indexed_triangle_set its = its_make_cube(1.0, 1.0, 1.0); its_translate(its, -0.5f * Vec3f::Ones()); - s_cube.init_from(its); + s_cube.model.init_from(its); + s_cube.mesh_raycaster = std::make_unique(std::make_shared(std::move(its))); } - if (!s_cone.is_initialized()) - s_cone.init_from(its_make_cone(1.0, 1.0, double(PI) / 18.0)); + if (!s_cone.model.is_initialized()) { + indexed_triangle_set its = its_make_cone(1.0, 1.0, double(PI) / 18.0); + s_cone.model.init_from(its); + s_cone.mesh_raycaster = std::make_unique(std::make_shared(std::move(its))); + } //BBS set to fixed size grabber const float grabber_size = FixedGrabberSize * INV_ZOOM; const double extension_size = 0.75 * FixedGrabberSize * INV_ZOOM; - s_cube.set_color(render_color); - s_cone.set_color(render_color); + s_cube.model.set_color(render_color); + s_cone.model.set_color(render_color); const Camera& camera = wxGetApp().plater()->get_camera(); - const Transform3d& view_matrix = camera.get_view_matrix(); shader->set_uniform("projection_matrix", camera.get_projection_matrix()); + const Transform3d& view_matrix = camera.get_view_matrix(); + const Matrix3d view_matrix_no_offset = view_matrix.matrix().block(0, 0, 3, 3); - auto render_extension = [&view_matrix, shader](GLModel &model, const Transform3d &model_matrix) { + auto render_extension = [&view_matrix, &view_matrix_no_offset, shader, register_for_picking = !elements_registered_for_picking, picking_id = picking_id](PickingModel &model, const Transform3d &model_matrix) { shader->set_uniform("view_model_matrix", view_matrix * model_matrix); - const Matrix3d view_normal_matrix = view_matrix.matrix().block(0, 0, 3, 3) * model_matrix.matrix().block(0, 0, 3, 3).inverse().transpose(); + const Matrix3d view_normal_matrix = view_matrix_no_offset * model_matrix.matrix().block(0, 0, 3, 3).inverse().transpose(); shader->set_uniform("view_normal_matrix", view_normal_matrix); - model.render(); + model.model.render(); + + if (register_for_picking) { + GLCanvas3D &canvas = *wxGetApp().plater()->canvas3D(); + canvas.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, picking_id, *model.mesh_raycaster, model_matrix); + } }; if (extensions == EGrabberExtension::PosZ) { @@ -166,20 +190,15 @@ void GLGizmoBase::Grabber::render(float size, const ColorRGBA& render_color, boo render_extension(s_cone, extension_model_matrix_base * Geometry::assemble_transform(-2.0 * extension_size * Vec3d::UnitZ(), Vec3d(double(PI), 0.0, 0.0), extension_scale)); } } + + elements_registered_for_picking = true; } GLGizmoBase::GLGizmoBase(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id) : m_parent(parent) - , m_group_id(-1) - , m_state(Off) - , m_shortcut_key(0) , m_icon_filename(icon_filename) , m_sprite_id(sprite_id) - , m_hover_id(-1) - , m_dragging(false) , m_imgui(wxGetApp().imgui()) - , m_first_input_window_render(true) - , m_dirty(false) { m_base_color = DEFAULT_BASE_COLOR; m_drag_color = DEFAULT_DRAG_COLOR; @@ -280,6 +299,20 @@ void GLGizmoBase::GizmoImguiSetNextWIndowPos(float &x, float y, int flag, float m_imgui->set_next_window_pos(x, y, flag, pivot_x, pivot_y); } +void GLGizmoBase::register_grabbers_for_picking() +{ + for (size_t i = 0; i < m_grabbers.size(); ++i) { + m_grabbers[i].register_raycasters_for_picking(i); + } +} + +void GLGizmoBase::unregister_grabbers_for_picking() +{ + for (size_t i = 0; i < m_grabbers.size(); ++i) { + m_grabbers[i].unregister_raycasters_for_picking(); + } +} + ColorRGBA GLGizmoBase::picking_color_component(unsigned int id) const { id = BASE_ID - id; @@ -312,28 +345,6 @@ void GLGizmoBase::render_grabbers(float size) const shader->stop_using(); } -void GLGizmoBase::render_grabbers_for_picking(const BoundingBoxf3& box) const -{ - GLShaderProgram* shader = wxGetApp().get_shader("flat"); - if (shader != nullptr) { - shader->start_using(); - -#if ENABLE_FIXED_GRABBER - const float mean_size = (float)(GLGizmoBase::Grabber::FixedGrabberSize); -#else - const float mean_size = (float)((box.size().x() + box.size().y() + box.size().z()) / 3.0); -#endif - - for (unsigned int i = 0; i < (unsigned int)m_grabbers.size(); ++i) { - if (m_grabbers[i].enabled) { - m_grabbers[i].color = picking_color_component(i); - m_grabbers[i].render_for_picking(mean_size); - } - } - shader->stop_using(); - } -} - std::string GLGizmoBase::format(float value, unsigned int decimals) const { return Slic3r::string_printf("%.*f", decimals, value); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoBase.hpp b/src/slic3r/GUI/Gizmos/GLGizmoBase.hpp index 91f367f3252..227e96a77bd 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoBase.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoBase.hpp @@ -6,6 +6,7 @@ #include "slic3r/GUI/I18N.hpp" #include "slic3r/GUI/GLModel.hpp" +#include "slic3r/GUI/MeshUtils.hpp" #include @@ -83,22 +84,27 @@ class GLGizmoBase ColorRGBA color{GRABBER_NORMAL_COL}; ColorRGBA hover_color{GRABBER_HOVER_COL}; EGrabberExtension extensions{ EGrabberExtension::None }; + // the picking id shared by all the elements + int picking_id{ -1 }; + bool elements_registered_for_picking{ false }; Grabber() = default; ~Grabber(); void render(bool hover, float size) { render(size, hover ? hover_color : color, false); } - void render_for_picking(float size) { render(size, color, true); } float get_half_size(float size) const; float get_dragging_half_size(float size) const; - GLModel& get_cube(); + PickingModel &get_cube(); + + void register_raycasters_for_picking(int id); + void unregister_raycasters_for_picking(); private: void render(float size, const ColorRGBA& render_color, bool picking); - static GLModel s_cube; - static GLModel s_cone; + static PickingModel s_cube; + static PickingModel s_cone; }; public: @@ -121,21 +127,22 @@ class GLGizmoBase protected: GLCanvas3D& m_parent; - int m_group_id; - EState m_state; - int m_shortcut_key; + + int m_group_id{ -1 }; // TODO: remove only for rotate + EState m_state{ Off }; + int m_shortcut_key{ 0 }; std::string m_icon_filename; unsigned int m_sprite_id; - int m_hover_id; - bool m_dragging; + int m_hover_id{ -1 }; + bool m_dragging{ false }; ColorRGBA m_base_color; ColorRGBA m_drag_color; ColorRGBA m_highlight_color; mutable std::vector m_grabbers; ImGuiWrapper* m_imgui; - bool m_first_input_window_render; + bool m_first_input_window_render{ true }; mutable std::string m_tooltip; - CommonGizmosDataPool* m_c; + CommonGizmosDataPool* m_c{ nullptr }; bool m_is_dark_mode = false; @@ -196,7 +203,6 @@ class GLGizmoBase bool update_items_state(); void render() { m_tooltip.clear(); on_render(); } - void render_for_picking() { on_render_for_picking(); } void render_input_window(float x, float y, float bottom_limit); virtual void on_change_color_mode(bool is_dark) { m_is_dark_mode = is_dark; } @@ -205,6 +211,9 @@ class GLGizmoBase int get_count() { return ++count; } std::string get_gizmo_name() { return on_get_name(); } + void register_raycasters_for_picking() { register_grabbers_for_picking(); on_register_raycasters_for_picking(); } + void unregister_raycasters_for_picking() { unregister_grabbers_for_picking(); on_unregister_raycasters_for_picking(); } + protected: float last_input_window_width = 0; virtual bool on_init() = 0; @@ -222,18 +231,22 @@ class GLGizmoBase virtual void on_stop_dragging() {} virtual void on_update(const UpdateData& data) {} virtual void on_render() = 0; - virtual void on_render_for_picking() = 0; virtual void on_render_input_window(float x, float y, float bottom_limit) {} bool GizmoImguiBegin(const std::string& name, int flags); void GizmoImguiEnd(); void GizmoImguiSetNextWIndowPos(float &x, float y, int flag, float pivot_x = 0.0f, float pivot_y = 0.0f); + + void register_grabbers_for_picking(); + void unregister_grabbers_for_picking(); + virtual void on_register_raycasters_for_picking() {} + virtual void on_unregister_raycasters_for_picking() {} + // Returns the picking color for the given id, based on the BASE_ID constant // No check is made for clashing with other picking color (i.e. GLVolumes) ColorRGBA picking_color_component(unsigned int id) const; void render_grabbers(const BoundingBoxf3& box) const; void render_grabbers(float size) const; - void render_grabbers_for_picking(const BoundingBoxf3& box) const; std::string format(float value, unsigned int decimals) const; @@ -242,7 +255,7 @@ class GLGizmoBase private: // Flag for dirty visible state of Gizmo // When True then need new rendering - bool m_dirty; + bool m_dirty{ false }; int count = 0; }; diff --git a/src/slic3r/GUI/Gizmos/GLGizmoFlatten.cpp b/src/slic3r/GUI/Gizmos/GLGizmoFlatten.cpp index da87aa1e888..881086881ec 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoFlatten.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoFlatten.cpp @@ -95,6 +95,7 @@ void GLGizmoFlatten::on_render() shader->stop_using(); } +/* void GLGizmoFlatten::on_render_for_picking() { const Selection& selection = m_parent.get_selection(); @@ -126,6 +127,7 @@ void GLGizmoFlatten::on_render_for_picking() glsafe(::glEnable(GL_CULL_FACE)); shader->stop_using(); } +*/ void GLGizmoFlatten::set_flattening_data(const ModelObject* model_object) { diff --git a/src/slic3r/GUI/Gizmos/GLGizmoFlatten.hpp b/src/slic3r/GUI/Gizmos/GLGizmoFlatten.hpp index eb669c74967..f666377ccb1 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoFlatten.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoFlatten.hpp @@ -54,7 +54,6 @@ class GLGizmoFlatten : public GLGizmoBase virtual bool on_is_activable() const override; virtual void on_start_dragging() override; virtual void on_render() override; - virtual void on_render_for_picking() override; virtual void on_set_state() override; virtual CommonGizmosDataID on_get_requirements() const override; }; diff --git a/src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp b/src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp index 733ae7494de..03e12c22dbb 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp @@ -89,18 +89,6 @@ void GLGizmoHollow::on_render() glsafe(::glDisable(GL_BLEND)); } - -void GLGizmoHollow::on_render_for_picking() -{ - const Selection& selection = m_parent.get_selection(); -//#if ENABLE_RENDER_PICKING_PASS -// m_z_shift = selection.get_volume(*selection.get_volume_idxs().begin())->get_sla_shift_z(); -//#endif - - glsafe(::glEnable(GL_DEPTH_TEST)); - render_points(selection, true); -} - void GLGizmoHollow::render_points(const Selection& selection, bool picking) { GLShaderProgram* shader = picking ? wxGetApp().get_shader("flat") : wxGetApp().get_shader("gouraud_light"); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoHollow.hpp b/src/slic3r/GUI/Gizmos/GLGizmoHollow.hpp index fa89e0febc2..e60ece0d526 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoHollow.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoHollow.hpp @@ -40,7 +40,6 @@ class GLGizmoHollow : public GLGizmoBase bool on_init() override; void on_update(const UpdateData& data) override; void on_render() override; - void on_render_for_picking() override; void render_points(const Selection& selection, bool picking = false); void hollow_mesh(bool postpone_error_messages = false); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeshBoolean.hpp b/src/slic3r/GUI/Gizmos/GLGizmoMeshBoolean.hpp index 42fa97eede1..f88ac85c976 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeshBoolean.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeshBoolean.hpp @@ -62,7 +62,6 @@ class GLGizmoMeshBoolean : public GLGizmoBase virtual std::string on_get_name() const override; virtual bool on_is_activable() const override; virtual void on_render() override; - virtual void on_render_for_picking() override {} virtual void on_set_state() override; virtual CommonGizmosDataID on_get_requirements() const override; virtual void on_render_input_window(float x, float y, float bottom_limit); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMove.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMove.cpp index 67fce2f2b74..f22a856718e 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMove.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMove.cpp @@ -182,12 +182,15 @@ void GLGizmoMove3D::on_render() render_grabbers(box); } -void GLGizmoMove3D::on_render_for_picking() +void GLGizmoMove3D::on_register_raycasters_for_picking() { - glsafe(::glDisable(GL_DEPTH_TEST)); + // this gizmo is rendered on top of the scene, so the raytraced picker should take it into account + m_parent.set_raycaster_gizmos_on_top(true); +} - const BoundingBoxf3& box = m_parent.get_selection().get_bounding_box(); - render_grabbers_for_picking(box); +void GLGizmoMove3D::on_unregister_raycasters_for_picking() +{ + m_parent.set_raycaster_gizmos_on_top(false); } //BBS: add input window for move diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMove.hpp b/src/slic3r/GUI/Gizmos/GLGizmoMove.hpp index c8ac84c6e3c..c9623488485 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMove.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMove.hpp @@ -52,7 +52,8 @@ class GLGizmoMove3D : public GLGizmoBase virtual void on_stop_dragging() override; virtual void on_update(const UpdateData& data) override; virtual void on_render() override; - virtual void on_render_for_picking() override; + virtual void on_register_raycasters_for_picking() override; + virtual void on_unregister_raycasters_for_picking() override; //BBS: GUI refactor: add object manipulation virtual void on_render_input_window(float x, float y, float bottom_limit); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.hpp b/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.hpp index 8e0fc1f756a..cd397ab4e21 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.hpp @@ -185,7 +185,6 @@ class GLGizmoPainterBase : public GLGizmoBase ObjectID m_old_mo_id; size_t m_old_volumes_size = 0; void on_render() override {} - void on_render_for_picking() override {} public: GLGizmoPainterBase(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id); virtual ~GLGizmoPainterBase() override; diff --git a/src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp b/src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp index b27b620df12..562bd040778 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp @@ -161,18 +161,6 @@ void GLGizmoRotate::on_render() render_grabber(box); } -void GLGizmoRotate::on_render_for_picking() -{ - const Selection& selection = m_parent.get_selection(); - - glsafe(::glDisable(GL_DEPTH_TEST)); - - m_grabbers.front().matrix = local_transform(selection); - - const BoundingBoxf3& box = selection.get_bounding_box(); - render_grabbers_for_picking(box); -} - //BBS: add input window for move void GLGizmoRotate3D::on_render_input_window(float x, float y, float bottom_limit) { diff --git a/src/slic3r/GUI/Gizmos/GLGizmoRotate.hpp b/src/slic3r/GUI/Gizmos/GLGizmoRotate.hpp index 7432a6584e3..3d454de2bc3 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoRotate.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoRotate.hpp @@ -72,7 +72,6 @@ class GLGizmoRotate : public GLGizmoBase void on_start_dragging() override; void on_update(const UpdateData& data) override; void on_render() override; - void on_render_for_picking() override; private: void render_circle(const ColorRGBA& color, bool radius_changed); @@ -150,11 +149,6 @@ class GLGizmoRotate3D : public GLGizmoBase } } void on_render() override; - void on_render_for_picking() override { - for (GLGizmoRotate& g : m_gizmos) { - g.render_for_picking(); - } - } void on_render_input_window(float x, float y, float bottom_limit) override; diff --git a/src/slic3r/GUI/Gizmos/GLGizmoScale.cpp b/src/slic3r/GUI/Gizmos/GLGizmoScale.cpp index 61f40a3e0ff..f35f1004d43 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoScale.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoScale.cpp @@ -255,12 +255,6 @@ void GLGizmoScale3D::on_render() render_grabbers(grabber_mean_size); } -void GLGizmoScale3D::on_render_for_picking() -{ - glsafe(::glDisable(GL_DEPTH_TEST)); - render_grabbers_for_picking(m_parent.get_selection().get_bounding_box()); -} - void GLGizmoScale3D::render_grabbers_connection(unsigned int id_1, unsigned int id_2, const ColorRGBA& color) { auto grabber_connection = [this](unsigned int id_1, unsigned int id_2) { diff --git a/src/slic3r/GUI/Gizmos/GLGizmoScale.hpp b/src/slic3r/GUI/Gizmos/GLGizmoScale.hpp index b87625a7c1e..f1092be1998 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoScale.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoScale.hpp @@ -72,7 +72,6 @@ class GLGizmoScale3D : public GLGizmoBase virtual void on_start_dragging() override; virtual void on_update(const UpdateData& data) override; virtual void on_render() override; - virtual void on_render_for_picking() override; //BBS: GUI refactor: add object manipulation virtual void on_render_input_window(float x, float y, float bottom_limit); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSimplify.hpp b/src/slic3r/GUI/Gizmos/GLGizmoSimplify.hpp index 39093e14d67..b4be94d2c94 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSimplify.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSimplify.hpp @@ -37,7 +37,6 @@ class GLGizmoSimplify: public GLGizmoBase // must implement virtual bool on_init() override { return true;}; virtual void on_render() override; - virtual void on_render_for_picking() override{}; CommonGizmosDataID on_get_requirements() const override; diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp index 12449eedaf4..ef46c7d0028 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp @@ -108,14 +108,6 @@ void GLGizmoSlaSupports::on_render() glsafe(::glDisable(GL_BLEND)); } - -void GLGizmoSlaSupports::on_render_for_picking() -{ - const Selection& selection = m_parent.get_selection(); - //glsafe(::glEnable(GL_DEPTH_TEST)); - render_points(selection, true); -} - void GLGizmoSlaSupports::render_points(const Selection& selection, bool picking) { const size_t cache_size = m_editing_mode ? m_editing_cache.size() : m_normal_cache.size(); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp index 985b9aeb563..e4e7b8241fc 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp @@ -75,7 +75,6 @@ class GLGizmoSlaSupports : public GLGizmoBase bool on_init() override; void on_update(const UpdateData& data) override; void on_render() override; - void on_render_for_picking() override; void render_points(const Selection& selection, bool picking = false); bool unsaved_changes() const; diff --git a/src/slic3r/GUI/Gizmos/GLGizmoText.cpp b/src/slic3r/GUI/Gizmos/GLGizmoText.cpp index 4c2399dcd58..941f134e781 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoText.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoText.cpp @@ -451,7 +451,7 @@ void GLGizmoText::on_render() GLShaderProgram *shader = wxGetApp().get_shader("gouraud_light"); if (shader != nullptr) { shader->start_using(); - m_grabbers[0].render_for_picking(mean_size); + //m_grabbers[0].render_for_picking(mean_size); shader->stop_using(); } @@ -466,6 +466,7 @@ void GLGizmoText::on_render() plater->update(); } +/* void GLGizmoText::on_render_for_picking() { glsafe(::glDisable(GL_DEPTH_TEST)); @@ -510,6 +511,7 @@ void GLGizmoText::on_render_for_picking() } } } +*/ void GLGizmoText::on_update(const UpdateData &data) { diff --git a/src/slic3r/GUI/Gizmos/GLGizmoText.hpp b/src/slic3r/GUI/Gizmos/GLGizmoText.hpp index 53b792364f2..0eaf1304ca3 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoText.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoText.hpp @@ -91,7 +91,6 @@ class GLGizmoText : public GLGizmoBase virtual std::string on_get_name() const override; virtual bool on_is_activable() const override; virtual void on_render() override; - virtual void on_render_for_picking() override; virtual void on_update(const UpdateData &data) override; void push_combo_style(const float scale); void pop_combo_style(); diff --git a/src/slic3r/GUI/Gizmos/GLGizmosCommon.hpp b/src/slic3r/GUI/Gizmos/GLGizmosCommon.hpp index 6c42052cd5e..5b338f984a0 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosCommon.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosCommon.hpp @@ -80,7 +80,7 @@ enum class CommonGizmosDataID { // by GLGizmoManager, the gizmos keep a pointer to it. class CommonGizmosDataPool { public: - CommonGizmosDataPool(GLCanvas3D* canvas); + explicit CommonGizmosDataPool(GLCanvas3D* canvas); // Update all resources and release what is not used. // Accepts a bitmask of currently required resources. diff --git a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp index 7f13c25c778..51fa667a733 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp @@ -713,15 +713,6 @@ void GLGizmosManager::render_painter_assemble_view() const m_assemble_view_data->model_objects_clipper()->render_cut(); } -void GLGizmosManager::render_current_gizmo_for_picking_pass() const -{ - if (! m_enabled || m_current == Undefined) - - return; - - m_gizmos[m_current]->render_for_picking(); -} - void GLGizmosManager::render_overlay() { if (!m_enabled) @@ -1594,7 +1585,6 @@ bool GLGizmosManager::activate_gizmo(EType type) return true; GLGizmoBase* old_gizmo = m_current == Undefined ? nullptr : m_gizmos[m_current].get(); - GLGizmoBase* new_gizmo = type == Undefined ? nullptr : m_gizmos[type].get(); if (old_gizmo) { //if (m_current == Text) { @@ -1604,6 +1594,8 @@ bool GLGizmosManager::activate_gizmo(EType type) if (old_gizmo->get_state() != GLGizmoBase::Off) return false; // gizmo refused to be turned off, do nothing. + old_gizmo->unregister_raycasters_for_picking(); + if (! m_parent.get_gizmos_manager().is_serializing() && old_gizmo->wants_enter_leave_snapshots()) Plater::TakeSnapshot snapshot(wxGetApp().plater(), @@ -1611,7 +1603,16 @@ bool GLGizmosManager::activate_gizmo(EType type) UndoRedo::SnapshotType::LeavingGizmoWithAction); } - if (new_gizmo && ! m_parent.get_gizmos_manager().is_serializing() + if (type == Undefined) { + // it is deactivation of gizmo + m_current = Undefined; + return true; + } + + // set up new gizmo + GLGizmoBase* new_gizmo = type == Undefined ? nullptr : m_gizmos[type].get(); + + if (new_gizmo && ! m_parent.get_gizmos_manager().is_serializing() && new_gizmo->wants_enter_leave_snapshots()) Plater::TakeSnapshot snapshot(wxGetApp().plater(), new_gizmo->get_gizmo_entering_text(), @@ -1619,12 +1620,14 @@ bool GLGizmosManager::activate_gizmo(EType type) m_current = type; - if (new_gizmo) { - //if (m_current == Text) { - // wxGetApp().imgui()->load_fonts_texture(); - //} - new_gizmo->set_state(GLGizmoBase::On); - } + //if (m_current == Text) { + // wxGetApp().imgui()->load_fonts_texture(); + //} + new_gizmo->set_state(GLGizmoBase::On); + + new_gizmo->register_raycasters_for_picking(); + + // sucessful activation of gizmo return true; } diff --git a/src/slic3r/GUI/Gizmos/GLGizmosManager.hpp b/src/slic3r/GUI/Gizmos/GLGizmosManager.hpp index d95c1693860..3594ab7c483 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosManager.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosManager.hpp @@ -294,7 +294,6 @@ class GLGizmosManager : public Slic3r::ObjectBase void on_change_color_mode(bool is_dark); void render_current_gizmo() const; - void render_current_gizmo_for_picking_pass() const; void render_painter_gizmo(); void render_painter_assemble_view() const; From 6a40d3af166f6602e95e4ebb856044a5604aef7b Mon Sep 17 00:00:00 2001 From: Noisyfox Date: Sat, 28 Oct 2023 23:13:02 +0800 Subject: [PATCH 64/99] Fix volume picking in cut gizmo --- src/slic3r/GUI/GLCanvas3D.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 8667ae9cfd8..e3dd00b08e7 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -6440,7 +6440,11 @@ void GLCanvas3D::_picking_pass() m_hover_volume_idxs.clear(); m_hover_plate_idxs.clear(); - const ClippingPlane clipping_plane = m_gizmos.get_clipping_plane().inverted_normal(); + // Orca: ignore clipping plane if not applying + GLGizmoBase *current_gizmo = m_gizmos.get_current(); + const ClippingPlane clipping_plane = ((!current_gizmo || current_gizmo->apply_clipping_plane()) ? m_gizmos.get_clipping_plane() : + ClippingPlane::ClipsNothing()) + .inverted_normal(); const SceneRaycaster::HitResult hit = m_scene_raycaster.hit(m_mouse.position, wxGetApp().plater()->get_camera(), &clipping_plane); if (hit.is_valid()) { switch (hit.type) From 29be4cc9a3b2f351f53d515ce76de11855a099c1 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Sat, 28 Oct 2023 23:15:24 +0800 Subject: [PATCH 65/99] Tech ENABLE_RAYCAST_PICKING - Raytraced picking of Move, Rotate and Scale Gizmo --- src/slic3r/GUI/Gizmos/GLGizmoBase.cpp | 6 +++--- src/slic3r/GUI/Gizmos/GLGizmoBase.hpp | 9 +++++---- src/slic3r/GUI/Gizmos/GLGizmoMove.cpp | 2 +- src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp | 17 +++++++++++++++++ src/slic3r/GUI/Gizmos/GLGizmoRotate.hpp | 2 ++ src/slic3r/GUI/Gizmos/GLGizmoScale.cpp | 11 +++++++++++ src/slic3r/GUI/Gizmos/GLGizmoScale.hpp | 2 ++ 7 files changed, 41 insertions(+), 8 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoBase.cpp b/src/slic3r/GUI/Gizmos/GLGizmoBase.cpp index 7638ea251da..7469c72257c 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoBase.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoBase.cpp @@ -117,7 +117,7 @@ void GLGizmoBase::Grabber::unregister_raycasters_for_picking() elements_registered_for_picking = false; } -void GLGizmoBase::Grabber::render(float size, const ColorRGBA& render_color, bool picking) +void GLGizmoBase::Grabber::render(float size, const ColorRGBA& render_color) { GLShaderProgram* shader = wxGetApp().get_current_shader(); if (shader == nullptr) @@ -299,10 +299,10 @@ void GLGizmoBase::GizmoImguiSetNextWIndowPos(float &x, float y, int flag, float m_imgui->set_next_window_pos(x, y, flag, pivot_x, pivot_y); } -void GLGizmoBase::register_grabbers_for_picking() +void GLGizmoBase::register_grabbers_for_picking(bool use_group_id) { for (size_t i = 0; i < m_grabbers.size(); ++i) { - m_grabbers[i].register_raycasters_for_picking(i); + m_grabbers[i].register_raycasters_for_picking(use_group_id ? m_group_id : i); } } diff --git a/src/slic3r/GUI/Gizmos/GLGizmoBase.hpp b/src/slic3r/GUI/Gizmos/GLGizmoBase.hpp index 227e96a77bd..f7c4bf2eaae 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoBase.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoBase.hpp @@ -7,6 +7,7 @@ #include "slic3r/GUI/I18N.hpp" #include "slic3r/GUI/GLModel.hpp" #include "slic3r/GUI/MeshUtils.hpp" +#include "slic3r/GUI/SceneRaycaster.hpp" #include @@ -91,7 +92,7 @@ class GLGizmoBase Grabber() = default; ~Grabber(); - void render(bool hover, float size) { render(size, hover ? hover_color : color, false); } + void render(bool hover, float size) { render(size, hover ? hover_color : color); } float get_half_size(float size) const; float get_dragging_half_size(float size) const; @@ -101,7 +102,7 @@ class GLGizmoBase void unregister_raycasters_for_picking(); private: - void render(float size, const ColorRGBA& render_color, bool picking); + void render(float size, const ColorRGBA& render_color); static PickingModel s_cube; static PickingModel s_cone; @@ -211,7 +212,7 @@ class GLGizmoBase int get_count() { return ++count; } std::string get_gizmo_name() { return on_get_name(); } - void register_raycasters_for_picking() { register_grabbers_for_picking(); on_register_raycasters_for_picking(); } + void register_raycasters_for_picking(bool use_group_id = false) { register_grabbers_for_picking(use_group_id); on_register_raycasters_for_picking(); } void unregister_raycasters_for_picking() { unregister_grabbers_for_picking(); on_unregister_raycasters_for_picking(); } protected: @@ -237,7 +238,7 @@ class GLGizmoBase void GizmoImguiEnd(); void GizmoImguiSetNextWIndowPos(float &x, float y, int flag, float pivot_x = 0.0f, float pivot_y = 0.0f); - void register_grabbers_for_picking(); + void register_grabbers_for_picking(bool use_group_id = false); void unregister_grabbers_for_picking(); virtual void on_register_raycasters_for_picking() {} virtual void on_unregister_raycasters_for_picking() {} diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMove.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMove.cpp index f22a856718e..1925cd7fa5e 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMove.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMove.cpp @@ -184,7 +184,7 @@ void GLGizmoMove3D::on_render() void GLGizmoMove3D::on_register_raycasters_for_picking() { - // this gizmo is rendered on top of the scene, so the raytraced picker should take it into account + // the gizmo grabbers are rendered on top of the scene, so the raytraced picker should take it into account m_parent.set_raycaster_gizmos_on_top(true); } diff --git a/src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp b/src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp index 562bd040778..2ecb90641ff 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp @@ -510,6 +510,23 @@ void GLGizmoRotate3D::on_render() m_gizmos[Z].render(); } +void GLGizmoRotate3D::on_register_raycasters_for_picking() +{ + // the gizmo grabbers are rendered on top of the scene, so the raytraced picker should take it into account + m_parent.set_raycaster_gizmos_on_top(true); + for (GLGizmoRotate& g : m_gizmos) { + g.register_raycasters_for_picking(true); + } +} + +void GLGizmoRotate3D::on_unregister_raycasters_for_picking() +{ + for (GLGizmoRotate& g : m_gizmos) { + g.unregister_raycasters_for_picking(); + } + m_parent.set_raycaster_gizmos_on_top(false); +} + GLGizmoRotate3D::RotoptimzeWindow::RotoptimzeWindow(ImGuiWrapper * imgui, State & state, const Alignment &alignment) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoRotate.hpp b/src/slic3r/GUI/Gizmos/GLGizmoRotate.hpp index 3d454de2bc3..cc00409c008 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoRotate.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoRotate.hpp @@ -149,6 +149,8 @@ class GLGizmoRotate3D : public GLGizmoBase } } void on_render() override; + virtual void on_register_raycasters_for_picking() override; + virtual void on_unregister_raycasters_for_picking() override; void on_render_input_window(float x, float y, float bottom_limit) override; diff --git a/src/slic3r/GUI/Gizmos/GLGizmoScale.cpp b/src/slic3r/GUI/Gizmos/GLGizmoScale.cpp index f35f1004d43..f6bbf4c5231 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoScale.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoScale.cpp @@ -255,6 +255,17 @@ void GLGizmoScale3D::on_render() render_grabbers(grabber_mean_size); } +void GLGizmoScale3D::on_register_raycasters_for_picking() +{ + // the gizmo grabbers are rendered on top of the scene, so the raytraced picker should take it into account + m_parent.set_raycaster_gizmos_on_top(true); +} + +void GLGizmoScale3D::on_unregister_raycasters_for_picking() +{ + m_parent.set_raycaster_gizmos_on_top(false); +} + void GLGizmoScale3D::render_grabbers_connection(unsigned int id_1, unsigned int id_2, const ColorRGBA& color) { auto grabber_connection = [this](unsigned int id_1, unsigned int id_2) { diff --git a/src/slic3r/GUI/Gizmos/GLGizmoScale.hpp b/src/slic3r/GUI/Gizmos/GLGizmoScale.hpp index f1092be1998..a4b5a064c15 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoScale.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoScale.hpp @@ -72,6 +72,8 @@ class GLGizmoScale3D : public GLGizmoBase virtual void on_start_dragging() override; virtual void on_update(const UpdateData& data) override; virtual void on_render() override; + virtual void on_register_raycasters_for_picking() override; + virtual void on_unregister_raycasters_for_picking() override; //BBS: GUI refactor: add object manipulation virtual void on_render_input_window(float x, float y, float bottom_limit); From ab090bf20dedf82667ee7f422f6a39ea56c824e7 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Sun, 29 Oct 2023 00:06:43 +0800 Subject: [PATCH 66/99] Tech ENABLE_RAYCAST_PICKING - Refactoring to allow for easier update of raycasters transform (cherry picked from commit prusa3d/PrusaSlicer@9ac5ab857bcd20725b27adcddbc5158f1a42b747) --- src/slic3r/GUI/GLCanvas3D.hpp | 4 +- src/slic3r/GUI/Gizmos/GLGizmoBase.cpp | 36 ++++++------- src/slic3r/GUI/Gizmos/GLGizmoBase.hpp | 11 ++-- src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp | 2 +- src/slic3r/GUI/SceneRaycaster.cpp | 70 +++++++++++-------------- src/slic3r/GUI/SceneRaycaster.hpp | 14 +++-- 6 files changed, 64 insertions(+), 73 deletions(-) diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp index 86c126f8be6..26053a7f8df 100644 --- a/src/slic3r/GUI/GLCanvas3D.hpp +++ b/src/slic3r/GUI/GLCanvas3D.hpp @@ -729,8 +729,8 @@ class GLCanvas3D bool init(); void post_event(wxEvent &&event); - void add_raycaster_for_picking(SceneRaycaster::EType type, PickingId id, const MeshRaycaster& raycaster, const Transform3d& trafo) { - m_scene_raycaster.add_raycaster(type, id, raycaster, trafo); + std::shared_ptr add_raycaster_for_picking(SceneRaycaster::EType type, PickingId id, const MeshRaycaster& raycaster, const Transform3d& trafo) { + return m_scene_raycaster.add_raycaster(type, id, raycaster, trafo); } void remove_raycasters_for_picking(SceneRaycaster::EType type, PickingId id) { m_scene_raycaster.remove_raycasters(type, id); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoBase.cpp b/src/slic3r/GUI/Gizmos/GLGizmoBase.cpp index 7469c72257c..ffb5e92f77c 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoBase.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoBase.cpp @@ -104,17 +104,17 @@ PickingModel &GLGizmoBase::Grabber::get_cube() return s_cube; } -void GLGizmoBase::Grabber::register_raycasters_for_picking(int id) +void GLGizmoBase::Grabber::register_raycasters_for_picking(PickingId id) { picking_id = id; - assert(elements_registered_for_picking == false); + // registration will happen on next call to render() } void GLGizmoBase::Grabber::unregister_raycasters_for_picking() { wxGetApp().plater()->canvas3D()->remove_raycasters_for_picking(SceneRaycaster::EType::Gizmo, picking_id); picking_id = -1; - elements_registered_for_picking = false; + raycasters = { nullptr }; } void GLGizmoBase::Grabber::render(float size, const ColorRGBA& render_color) @@ -150,48 +150,48 @@ void GLGizmoBase::Grabber::render(float size, const ColorRGBA& render_color) const Transform3d& view_matrix = camera.get_view_matrix(); const Matrix3d view_matrix_no_offset = view_matrix.matrix().block(0, 0, 3, 3); - auto render_extension = [&view_matrix, &view_matrix_no_offset, shader, register_for_picking = !elements_registered_for_picking, picking_id = picking_id](PickingModel &model, const Transform3d &model_matrix) { + auto render_extension = [&view_matrix, &view_matrix_no_offset, shader, this](int idx, PickingModel &model, const Transform3d &model_matrix) { shader->set_uniform("view_model_matrix", view_matrix * model_matrix); const Matrix3d view_normal_matrix = view_matrix_no_offset * model_matrix.matrix().block(0, 0, 3, 3).inverse().transpose(); shader->set_uniform("view_normal_matrix", view_normal_matrix); model.model.render(); - if (register_for_picking) { + if (raycasters[idx] == nullptr) { GLCanvas3D &canvas = *wxGetApp().plater()->canvas3D(); - canvas.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, picking_id, *model.mesh_raycaster, model_matrix); + raycasters[idx] = canvas.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, picking_id, *model.mesh_raycaster, model_matrix); + } else { + raycasters[idx]->set_transform(model_matrix); } }; if (extensions == EGrabberExtension::PosZ) { const Transform3d model_matrix = matrix * Geometry::assemble_transform(center, angles, Vec3d(0.75 * extension_size, 0.75 * extension_size, 2.0 * extension_size)); - render_extension(s_cone, model_matrix); + render_extension(0, s_cone, model_matrix); } else { const Transform3d model_matrix = matrix * Geometry::assemble_transform(center, angles, grabber_size * Vec3d::Ones()); - render_extension(s_cube, model_matrix); + render_extension(0, s_cube, model_matrix); const Transform3d extension_model_matrix_base = matrix * Geometry::assemble_transform(center, angles); const Vec3d extension_scale(0.75 * extension_size, 0.75 * extension_size, 3.0 * extension_size); if ((int(extensions) & int(GLGizmoBase::EGrabberExtension::PosX)) != 0) { - render_extension(s_cone, extension_model_matrix_base * Geometry::assemble_transform(2.0 * extension_size * Vec3d::UnitX(), Vec3d(0.0, 0.5 * double(PI), 0.0), extension_scale)); + render_extension(1, s_cone, extension_model_matrix_base * Geometry::assemble_transform(2.0 * extension_size * Vec3d::UnitX(), Vec3d(0.0, 0.5 * double(PI), 0.0), extension_scale)); } if ((int(extensions) & int(GLGizmoBase::EGrabberExtension::NegX)) != 0) { - render_extension(s_cone, extension_model_matrix_base * Geometry::assemble_transform(-2.0 * extension_size * Vec3d::UnitX(), Vec3d(0.0, -0.5 * double(PI), 0.0), extension_scale)); + render_extension(2, s_cone, extension_model_matrix_base * Geometry::assemble_transform(-2.0 * extension_size * Vec3d::UnitX(), Vec3d(0.0, -0.5 * double(PI), 0.0), extension_scale)); } if ((int(extensions) & int(GLGizmoBase::EGrabberExtension::PosY)) != 0) { - render_extension(s_cone, extension_model_matrix_base * Geometry::assemble_transform(2.0 * extension_size * Vec3d::UnitY(), Vec3d(-0.5 * double(PI), 0.0, 0.0), extension_scale)); + render_extension(3, s_cone, extension_model_matrix_base * Geometry::assemble_transform(2.0 * extension_size * Vec3d::UnitY(), Vec3d(-0.5 * double(PI), 0.0, 0.0), extension_scale)); } if ((int(extensions) & int(GLGizmoBase::EGrabberExtension::NegY)) != 0) { - render_extension(s_cone, extension_model_matrix_base * Geometry::assemble_transform(-2.0 * extension_size * Vec3d::UnitY(), Vec3d(0.5 * double(PI), 0.0, 0.0), extension_scale)); + render_extension(4, s_cone, extension_model_matrix_base * Geometry::assemble_transform(-2.0 * extension_size * Vec3d::UnitY(), Vec3d(0.5 * double(PI), 0.0, 0.0), extension_scale)); } if ((int(extensions) & int(GLGizmoBase::EGrabberExtension::PosZ)) != 0) { - render_extension(s_cone, extension_model_matrix_base * Geometry::assemble_transform(2.0 * extension_size * Vec3d::UnitZ(), Vec3d::Zero(), extension_scale)); + render_extension(5, s_cone, extension_model_matrix_base * Geometry::assemble_transform(2.0 * extension_size * Vec3d::UnitZ(), Vec3d::Zero(), extension_scale)); } if ((int(extensions) & int(GLGizmoBase::EGrabberExtension::NegZ)) != 0) { - render_extension(s_cone, extension_model_matrix_base * Geometry::assemble_transform(-2.0 * extension_size * Vec3d::UnitZ(), Vec3d(double(PI), 0.0, 0.0), extension_scale)); + render_extension(6, s_cone, extension_model_matrix_base * Geometry::assemble_transform(-2.0 * extension_size * Vec3d::UnitZ(), Vec3d(double(PI), 0.0, 0.0), extension_scale)); } } - - elements_registered_for_picking = true; } GLGizmoBase::GLGizmoBase(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id) @@ -299,10 +299,10 @@ void GLGizmoBase::GizmoImguiSetNextWIndowPos(float &x, float y, int flag, float m_imgui->set_next_window_pos(x, y, flag, pivot_x, pivot_y); } -void GLGizmoBase::register_grabbers_for_picking(bool use_group_id) +void GLGizmoBase::register_grabbers_for_picking() { for (size_t i = 0; i < m_grabbers.size(); ++i) { - m_grabbers[i].register_raycasters_for_picking(use_group_id ? m_group_id : i); + m_grabbers[i].register_raycasters_for_picking((m_group_id >= 0) ? m_group_id : i); } } diff --git a/src/slic3r/GUI/Gizmos/GLGizmoBase.hpp b/src/slic3r/GUI/Gizmos/GLGizmoBase.hpp index f7c4bf2eaae..6e6ff7efa55 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoBase.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoBase.hpp @@ -37,6 +37,7 @@ class GLGizmoBase // Starting value for ids to avoid clashing with ids used by GLVolumes // (254 is choosen to leave some space for forward compatibility) static const unsigned int BASE_ID = 255 * 255 * 254; + static const unsigned int GRABBER_ELEMENTS_MAX_COUNT = 7; static float INV_ZOOM; @@ -86,8 +87,8 @@ class GLGizmoBase ColorRGBA hover_color{GRABBER_HOVER_COL}; EGrabberExtension extensions{ EGrabberExtension::None }; // the picking id shared by all the elements - int picking_id{ -1 }; - bool elements_registered_for_picking{ false }; + PickingId picking_id{ -1 }; + std::array, GRABBER_ELEMENTS_MAX_COUNT> raycasters = { nullptr }; Grabber() = default; ~Grabber(); @@ -98,7 +99,7 @@ class GLGizmoBase float get_dragging_half_size(float size) const; PickingModel &get_cube(); - void register_raycasters_for_picking(int id); + void register_raycasters_for_picking(PickingId id); void unregister_raycasters_for_picking(); private: @@ -212,7 +213,7 @@ class GLGizmoBase int get_count() { return ++count; } std::string get_gizmo_name() { return on_get_name(); } - void register_raycasters_for_picking(bool use_group_id = false) { register_grabbers_for_picking(use_group_id); on_register_raycasters_for_picking(); } + void register_raycasters_for_picking() { register_grabbers_for_picking(); on_register_raycasters_for_picking(); } void unregister_raycasters_for_picking() { unregister_grabbers_for_picking(); on_unregister_raycasters_for_picking(); } protected: @@ -238,7 +239,7 @@ class GLGizmoBase void GizmoImguiEnd(); void GizmoImguiSetNextWIndowPos(float &x, float y, int flag, float pivot_x = 0.0f, float pivot_y = 0.0f); - void register_grabbers_for_picking(bool use_group_id = false); + void register_grabbers_for_picking(); void unregister_grabbers_for_picking(); virtual void on_register_raycasters_for_picking() {} virtual void on_unregister_raycasters_for_picking() {} diff --git a/src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp b/src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp index 2ecb90641ff..e6a2dd6973b 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp @@ -515,7 +515,7 @@ void GLGizmoRotate3D::on_register_raycasters_for_picking() // the gizmo grabbers are rendered on top of the scene, so the raytraced picker should take it into account m_parent.set_raycaster_gizmos_on_top(true); for (GLGizmoRotate& g : m_gizmos) { - g.register_raycasters_for_picking(true); + g.register_raycasters_for_picking(); } } diff --git a/src/slic3r/GUI/SceneRaycaster.cpp b/src/slic3r/GUI/SceneRaycaster.cpp index 9a4f69b9d43..64bd55f7bc2 100644 --- a/src/slic3r/GUI/SceneRaycaster.cpp +++ b/src/slic3r/GUI/SceneRaycaster.cpp @@ -31,31 +31,22 @@ SceneRaycaster::SceneRaycaster() { #endif // ENABLE_RAYCAST_PICKING_DEBUG } -void SceneRaycaster::add_raycaster(EType type, PickingId id, const MeshRaycaster& raycaster, const Transform3d& trafo) +std::shared_ptr SceneRaycaster::add_raycaster(EType type, PickingId id, const MeshRaycaster& raycaster, const Transform3d& trafo) { switch (type) { - case EType::Bed: { - m_bed.emplace_back(encode_id(type, id), raycaster, trafo); - break; - } - case EType::Volume: { - m_volumes.emplace_back(encode_id(type, id), raycaster, trafo); - break; - } - case EType::Gizmo: { - m_gizmos.emplace_back(encode_id(type, id), raycaster, trafo); - break; - } - default: { break; } + case EType::Bed: { return m_bed.emplace_back(std::make_shared(encode_id(type, id), raycaster, trafo)); } + case EType::Volume: { return m_volumes.emplace_back(std::make_shared(encode_id(type, id), raycaster, trafo)); } + case EType::Gizmo: { return m_gizmos.emplace_back(std::make_shared(encode_id(type, id), raycaster, trafo)); } + default: { assert(false); return nullptr; } }; } void SceneRaycaster::remove_raycasters(EType type, PickingId id) { - std::vector* raycasters = get_raycasters(type); + std::vector>* raycasters = get_raycasters(type); auto it = raycasters->begin(); while (it != raycasters->end()) { - if (it->get_id() == encode_id(type, id)) + if ((*it)->get_id() == encode_id(type, id)) it = raycasters->erase(it); else ++it; @@ -72,24 +63,24 @@ void SceneRaycaster::remove_raycasters(EType type) }; } -void SceneRaycaster::set_raycaster_active_state(EType type, PickingId id, bool active) +void SceneRaycaster::remove_raycaster(std::shared_ptr item) { - std::vector* raycasters = get_raycasters(type); - for (SceneRaycasterItem& item : *raycasters) { - if (item.get_id() == encode_id(type, id)) { - item.set_active(active); - break; + for (auto it = m_bed.begin(); it != m_bed.end(); ++it) { + if (*it == item) { + m_bed.erase(it); + return; } } -} - -void SceneRaycaster::set_raycaster_transform(EType type, PickingId id, const Transform3d& trafo) -{ - std::vector* raycasters = get_raycasters(type); - for (SceneRaycasterItem& item : *raycasters) { - if (item.get_id() == encode_id(type, id)) { - item.set_transform(trafo); - break; + for (auto it = m_volumes.begin(); it != m_volumes.end(); ++it) { + if (*it == item) { + m_volumes.erase(it); + return; + } + } + for (auto it = m_gizmos.begin(); it != m_gizmos.end(); ++it) { + if (*it == item) { + m_gizmos.erase(it); + return; } } } @@ -113,15 +104,15 @@ SceneRaycaster::HitResult SceneRaycaster::hit(const Vec2d& mouse_pos, const Came auto test_raycasters = [&](EType type) { const ClippingPlane* clip_plane = (clipping_plane != nullptr && type == EType::Volume) ? clipping_plane : nullptr; - const std::vector* raycasters = get_raycasters(type); + std::vector>* raycasters = get_raycasters(type); HitResult current_hit = { type }; - for (const SceneRaycasterItem& item : *raycasters) { - if (!item.is_active()) + for (std::shared_ptr item : *raycasters) { + if (!item->is_active()) continue; - current_hit.raycaster_id = item.get_id(); - const Transform3d& trafo = item.get_transform(); - if (item.get_raycaster()->closest_hit(mouse_pos, trafo, camera, current_hit.position, current_hit.normal, clip_plane)) { + current_hit.raycaster_id = item->get_id(); + const Transform3d& trafo = item->get_transform(); + if (item->get_raycaster()->closest_hit(mouse_pos, trafo, camera, current_hit.position, current_hit.normal, clip_plane)) { current_hit.position = (trafo * current_hit.position.cast()).cast(); if (is_closest(camera, current_hit.position)) { const Transform3d matrix = camera.get_view_matrix() * trafo; @@ -180,14 +171,15 @@ void SceneRaycaster::render_hit(const Camera& camera) } #endif // ENABLE_RAYCAST_PICKING_DEBUG -std::vector* SceneRaycaster::get_raycasters(EType type) +std::vector>* SceneRaycaster::get_raycasters(EType type) { - std::vector* ret = nullptr; + std::vector>* ret = nullptr; switch (type) { case EType::Bed: { ret = &m_bed; break; } case EType::Volume: { ret = &m_volumes; break; } case EType::Gizmo: { ret = &m_gizmos; break; } + default: { break; } } assert(ret != nullptr); return ret; diff --git a/src/slic3r/GUI/SceneRaycaster.hpp b/src/slic3r/GUI/SceneRaycaster.hpp index 1832ffc558d..d0b47dbc75a 100644 --- a/src/slic3r/GUI/SceneRaycaster.hpp +++ b/src/slic3r/GUI/SceneRaycaster.hpp @@ -64,9 +64,9 @@ class SceneRaycaster }; private: - std::vector m_bed; - std::vector m_volumes; - std::vector m_gizmos; + std::vector> m_bed; + std::vector> m_volumes; + std::vector> m_gizmos; // When set to true, if checking gizmos returns a valid hit, // the search is not performed on other types @@ -81,12 +81,10 @@ class SceneRaycaster public: SceneRaycaster(); - void add_raycaster(EType type, PickingId picking_id, const MeshRaycaster& raycaster, const Transform3d& trafo); + std::shared_ptr add_raycaster(EType type, PickingId picking_id, const MeshRaycaster& raycaster, const Transform3d& trafo); void remove_raycasters(EType type, PickingId id); void remove_raycasters(EType type); - - void set_raycaster_active_state(EType type, PickingId picking_id, bool active); - void set_raycaster_transform(EType type, PickingId picking_id, const Transform3d& trafo); + void remove_raycaster(std::shared_ptr item); void set_gizmos_on_top(bool value) { m_gizmos_on_top = value; } @@ -101,7 +99,7 @@ class SceneRaycaster #endif // ENABLE_RAYCAST_PICKING_DEBUG private: - std::vector* get_raycasters(EType type); + std::vector>* get_raycasters(EType type); static PickingId encode_id(EType type, PickingId id); static PickingId decode_id(EType type, PickingId id); From 1e7a91e2d56b82bbe09e4fd374a5610723c9e773 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Sun, 29 Oct 2023 00:16:54 +0800 Subject: [PATCH 67/99] Tech ENABLE_RAYCAST_PICKING - Raytraced picking of Gizmo Flatten (cherry picked from commit prusa3d/PrusaSlicer@f5e68a6ac68998ee8d1d8cc43ffd3951557a4cd8) --- src/slic3r/GUI/Gizmos/GLGizmoFlatten.cpp | 50 ++++++++++++++++++------ src/slic3r/GUI/Gizmos/GLGizmoFlatten.hpp | 6 ++- src/slic3r/GUI/Selection.hpp | 1 + 3 files changed, 44 insertions(+), 13 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoFlatten.cpp b/src/slic3r/GUI/Gizmos/GLGizmoFlatten.cpp index 881086881ec..ec5bc3f256b 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoFlatten.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoFlatten.cpp @@ -75,18 +75,18 @@ void GLGizmoFlatten::on_render() glsafe(::glEnable(GL_BLEND)); if (selection.is_single_full_instance()) { - const Transform3d& m = selection.get_volume(*selection.get_volume_idxs().begin())->get_instance_transformation().get_matrix(); + const Transform3d& m = selection.get_first_volume()->get_instance_transformation().get_matrix(); const Camera& camera = wxGetApp().plater()->get_camera(); const Transform3d view_model_matrix = camera.get_view_matrix() * - Geometry::assemble_transform(selection.get_volume(*selection.get_volume_idxs().begin())->get_sla_shift_z() * Vec3d::UnitZ()) * m; + Geometry::assemble_transform(selection.get_first_volume()->get_sla_shift_z() * Vec3d::UnitZ()) * m; shader->set_uniform("view_model_matrix", view_model_matrix); shader->set_uniform("projection_matrix", camera.get_projection_matrix()); if (this->is_plane_update_necessary()) update_planes(); for (int i = 0; i < (int)m_planes.size(); ++i) { - m_planes[i].vbo.set_color(i == m_hover_id ? GLGizmoBase::FLATTEN_HOVER_COLOR : GLGizmoBase::FLATTEN_COLOR); - m_planes[i].vbo.render(); + m_planes[i].vbo.model.set_color(i == m_hover_id ? GLGizmoBase::FLATTEN_HOVER_COLOR : GLGizmoBase::FLATTEN_COLOR); + m_planes[i].vbo.model.render(); } } @@ -95,6 +95,28 @@ void GLGizmoFlatten::on_render() shader->stop_using(); } +void GLGizmoFlatten::on_register_raycasters_for_picking() +{ + // the gizmo grabbers are rendered on top of the scene, so the raytraced picker should take it into account + m_parent.set_raycaster_gizmos_on_top(true); + + if (!m_planes.empty()) { + const Selection& selection = m_parent.get_selection(); + const Transform3d matrix = Geometry::assemble_transform(selection.get_volume(*selection.get_volume_idxs().begin())->get_sla_shift_z() * Vec3d::UnitZ()) * + selection.get_volume(*selection.get_volume_idxs().begin())->get_instance_transformation().get_matrix(); + + for (int i = 0; i < (int)m_planes.size(); ++i) { + m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, i, *m_planes[i].vbo.mesh_raycaster, matrix); + } + } +} + +void GLGizmoFlatten::on_unregister_raycasters_for_picking() +{ + m_parent.remove_raycasters_for_picking(SceneRaycaster::EType::Gizmo); + m_parent.set_raycaster_gizmos_on_top(false); +} + /* void GLGizmoFlatten::on_render_for_picking() { @@ -135,6 +157,7 @@ void GLGizmoFlatten::set_flattening_data(const ModelObject* model_object) if (model_object != m_old_model_object) { m_planes.clear(); m_planes_valid = false; + on_unregister_raycasters_for_picking(); } } @@ -151,6 +174,7 @@ void GLGizmoFlatten::update_planes() } ch = ch.convex_hull_3d(); m_planes.clear(); + on_unregister_raycasters_for_picking(); const Transform3d& inst_matrix = mo->instances.front()->get_matrix(true); // Following constants are used for discarding too small polygons. @@ -343,22 +367,24 @@ void GLGizmoFlatten::update_planes() // And finally create respective VBOs. The polygon is convex with // the vertices in order, so triangulation is trivial. for (auto& plane : m_planes) { - GLModel::Geometry init_data; - init_data.format = { GLModel::Geometry::EPrimitiveType::TriangleFan, GLModel::Geometry::EVertexLayout::P3N3 }; - init_data.reserve_vertices(plane.vertices.size()); - init_data.reserve_indices(plane.vertices.size()); - // vertices + indices + indexed_triangle_set its; + its.vertices.reserve(plane.vertices.size()); + its.indices.reserve(plane.vertices.size() / 3); for (size_t i = 0; i < plane.vertices.size(); ++i) { - init_data.add_vertex((Vec3f)plane.vertices[i].cast(), (Vec3f)plane.normal.cast()); - init_data.add_index((unsigned int)i); + its.vertices.emplace_back((Vec3f)plane.vertices[i].cast()); + } + for (size_t i = 1; i < plane.vertices.size() - 1; ++i) { + its.indices.emplace_back(0, i, i + 1); // triangle fan } - plane.vbo.init_from(std::move(init_data)); + plane.vbo.model.init_from(its); + plane.vbo.mesh_raycaster = std::make_unique(std::make_shared(std::move(its))); // FIXME: vertices should really be local, they need not // persist now when we use VBOs plane.vertices.clear(); plane.vertices.shrink_to_fit(); } + on_register_raycasters_for_picking(); m_planes_valid = true; } diff --git a/src/slic3r/GUI/Gizmos/GLGizmoFlatten.hpp b/src/slic3r/GUI/Gizmos/GLGizmoFlatten.hpp index f666377ccb1..61d34ba492c 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoFlatten.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoFlatten.hpp @@ -3,6 +3,7 @@ #include "GLGizmoBase.hpp" #include "slic3r/GUI/GLModel.hpp" +#include "slic3r/GUI/MeshUtils.hpp" namespace Slic3r { @@ -22,9 +23,10 @@ class GLGizmoFlatten : public GLGizmoBase struct PlaneData { std::vector vertices; // should be in fact local in update_planes() - GLModel vbo; + PickingModel vbo; Vec3d normal; float area; + PickingId picking_id{ -1 }; }; // This holds information to decide whether recalculation is necessary: @@ -54,6 +56,8 @@ class GLGizmoFlatten : public GLGizmoBase virtual bool on_is_activable() const override; virtual void on_start_dragging() override; virtual void on_render() override; + virtual void on_register_raycasters_for_picking() override; + virtual void on_unregister_raycasters_for_picking() override; virtual void on_set_state() override; virtual CommonGizmosDataID on_get_requirements() const override; }; diff --git a/src/slic3r/GUI/Selection.hpp b/src/slic3r/GUI/Selection.hpp index 71c2cf6a1b6..c2eb7e067bd 100644 --- a/src/slic3r/GUI/Selection.hpp +++ b/src/slic3r/GUI/Selection.hpp @@ -323,6 +323,7 @@ class Selection const IndicesList& get_volume_idxs() const { return m_list; } const GLVolume* get_volume(unsigned int volume_idx) const; + const GLVolume* get_first_volume() const { return get_volume(*m_list.begin()); } const ObjectIdxsToInstanceIdxsMap& get_content() const { return m_cache.content; } From f0199159e77e5139e9bfafa41b3e0a96728a3ab1 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Sun, 29 Oct 2023 00:24:19 +0800 Subject: [PATCH 68/99] Removed tech ENABLE_RENDER_PICKING_PASS (cherry picked from commit prusa3d/PrusaSlicer@f45711e7e5cea5d49e1a729be0a397b8d43541d1) --- src/libslic3r/Technologies.hpp | 2 -- src/slic3r/GUI/GLCanvas3D.cpp | 17 ----------------- src/slic3r/GUI/GLCanvas3D.hpp | 4 ---- 3 files changed, 23 deletions(-) diff --git a/src/libslic3r/Technologies.hpp b/src/libslic3r/Technologies.hpp index 40ac478c37f..461e3d8ea3d 100644 --- a/src/libslic3r/Technologies.hpp +++ b/src/libslic3r/Technologies.hpp @@ -12,8 +12,6 @@ #define ENABLE_RENDER_SELECTION_CENTER 0 // Shows an imgui dialog with camera related data #define ENABLE_CAMERA_STATISTICS 0 -// Render the picking pass instead of the main scene (use [T] key to toggle between regular rendering and picking pass only rendering) -#define ENABLE_RENDER_PICKING_PASS 0 // Enable extracting thumbnails from selected gcode and save them as png files #define ENABLE_THUMBNAIL_GENERATOR_DEBUG 0 // Disable synchronization of unselected instances diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index e3dd00b08e7..af0c517f100 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -1125,9 +1125,6 @@ GLCanvas3D::GLCanvas3D(wxGLCanvas* canvas, Bed3D &bed) , m_tab_down(false) , m_cursor_type(Standard) , m_reload_delayed(false) -#if ENABLE_RENDER_PICKING_PASS - , m_show_picking_texture(false) -#endif // ENABLE_RENDER_PICKING_PASS , m_render_sla_auxiliaries(true) , m_labels(*this) , m_slope(m_volumes) @@ -1833,9 +1830,6 @@ void GLCanvas3D::render(bool only_init) } } -#if ENABLE_RENDER_PICKING_PASS - if (!m_picking_enabled || !m_show_picking_texture) { -#endif // ENABLE_RENDER_PICKING_PASS // draw scene glsafe(::glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)); _render_background(); @@ -1900,9 +1894,6 @@ void GLCanvas3D::render(bool only_init) // could be invalidated by the following gizmo render methods _render_selection_sidebar_hints(); _render_current_gizmo(); -#if ENABLE_RENDER_PICKING_PASS - } -#endif // ENABLE_RENDER_PICKING_PASS #if ENABLE_RAYCAST_PICKING_DEBUG if (m_picking_enabled && !m_mouse.dragging) @@ -3192,14 +3183,6 @@ void GLCanvas3D::on_char(wxKeyEvent& evt) //} //case 'O': //case 'o': { _update_camera_zoom(-1.0); break; } -#if ENABLE_RENDER_PICKING_PASS - case 'T': - case 't': { - m_show_picking_texture = !m_show_picking_texture; - m_dirty = true; - break; - } -#endif // ENABLE_RENDER_PICKING_PASS //case 'Z': //case 'z': { // if (!m_selection.is_empty()) diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp index 26053a7f8df..407a2ebb473 100644 --- a/src/slic3r/GUI/GLCanvas3D.hpp +++ b/src/slic3r/GUI/GLCanvas3D.hpp @@ -579,10 +579,6 @@ class GLCanvas3D bool m_reload_delayed; -#if ENABLE_RENDER_PICKING_PASS - bool m_show_picking_texture; -#endif // ENABLE_RENDER_PICKING_PASS - RenderStats m_render_stats; int m_imgui_undo_redo_hovered_pos{ -1 }; From d2d77456ac59aad5418926eb9b76cb5af2b65229 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Sun, 29 Oct 2023 12:05:54 +0800 Subject: [PATCH 69/99] Tech ENABLE_RAYCAST_PICKING - Rendering for rectangle selection made only inside the rectangle, on systems supporting framebuffers Various other refactorings & fixes (cherry picked from commit prusa3d/PrusaSlicer@39b1222b220c5f4aa14354b1c9fff807d8094b1d) --- src/libslic3r/Color.hpp | 46 ++++---- src/slic3r/GUI/3DBed.cpp | 1 - src/slic3r/GUI/Camera.cpp | 113 ++++++++++++++++--- src/slic3r/GUI/Camera.hpp | 12 +- src/slic3r/GUI/GCodeViewer.cpp | 3 +- src/slic3r/GUI/GLCanvas3D.cpp | 135 ++++++++++++++++++++--- src/slic3r/GUI/GLCanvas3D.hpp | 10 +- src/slic3r/GUI/Gizmos/GLGizmoBase.cpp | 2 +- src/slic3r/GUI/Gizmos/GLGizmoBase.hpp | 4 +- src/slic3r/GUI/Gizmos/GLGizmoFlatten.hpp | 2 +- src/slic3r/GUI/SceneRaycaster.cpp | 39 +++---- src/slic3r/GUI/SceneRaycaster.hpp | 27 ++--- 12 files changed, 289 insertions(+), 105 deletions(-) diff --git a/src/libslic3r/Color.hpp b/src/libslic3r/Color.hpp index 183705c4af3..efde3fe4daf 100644 --- a/src/libslic3r/Color.hpp +++ b/src/libslic3r/Color.hpp @@ -133,41 +133,41 @@ class ColorRGBA 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); +ColorRGB operator * (float value, const ColorRGB& other); +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); +ColorRGB lerp(const ColorRGB& a, const ColorRGB& b, float t); +ColorRGBA lerp(const ColorRGBA& a, const ColorRGBA& b, float t); -extern ColorRGB complementary(const ColorRGB& color); -extern ColorRGBA complementary(const ColorRGBA& color); +ColorRGB complementary(const ColorRGB& color); +ColorRGBA complementary(const ColorRGBA& color); -extern ColorRGB saturate(const ColorRGB& color, float factor); -extern ColorRGBA saturate(const ColorRGBA& color, float factor); +ColorRGB saturate(const ColorRGB& color, float factor); +ColorRGBA saturate(const ColorRGBA& color, float factor); -extern ColorRGB opposite(const ColorRGB& color); -extern ColorRGB opposite(const ColorRGB& a, const ColorRGB& b); +ColorRGB opposite(const ColorRGB& color); +ColorRGB opposite(const ColorRGB& a, const ColorRGB& b); -extern bool can_decode_color(const std::string& color); +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); +bool decode_color(const std::string& color_in, ColorRGB& color_out); +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); +bool decode_colors(const std::vector& colors_in, std::vector& colors_out); +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); +std::string encode_color(const ColorRGB& color); +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); +ColorRGB to_rgb(const ColorRGBA& other_rgba); +ColorRGBA to_rgba(const ColorRGB& other_rgb); +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); +ColorRGBA picking_decode(unsigned int id); +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); +unsigned char picking_checksum_alpha_channel(unsigned char red, unsigned char green, unsigned char blue); } // namespace Slic3r diff --git a/src/slic3r/GUI/3DBed.cpp b/src/slic3r/GUI/3DBed.cpp index 202912f3d7b..88c61ac8b12 100644 --- a/src/slic3r/GUI/3DBed.cpp +++ b/src/slic3r/GUI/3DBed.cpp @@ -704,7 +704,6 @@ void Bed3D::render_custom(GLCanvas3D& canvas, const Transform3d& view_matrix, co void Bed3D::render_default(bool bottom, const Transform3d& view_matrix, const Transform3d& projection_matrix) { - bool picking = false; m_texture.reset(); update_bed_triangles(); diff --git a/src/slic3r/GUI/Camera.cpp b/src/slic3r/GUI/Camera.cpp index 420ac15c9ea..7206b5e6c4a 100644 --- a/src/slic3r/GUI/Camera.cpp +++ b/src/slic3r/GUI/Camera.cpp @@ -106,6 +106,78 @@ void Camera::select_view(const std::string& direction) } } +double Camera::get_near_left() const +{ + switch (m_type) + { + case EType::Perspective: + return m_frustrum_zs.first * (m_projection_matrix.matrix()(0, 2) - 1.0) / m_projection_matrix.matrix()(0, 0); + default: + case EType::Ortho: + return -1.0 / m_projection_matrix.matrix()(0, 0) - 0.5 * m_projection_matrix.matrix()(0, 0) * m_projection_matrix.matrix()(0, 3); + } +} + +double Camera::get_near_right() const +{ + switch (m_type) + { + case EType::Perspective: + return m_frustrum_zs.first * (m_projection_matrix.matrix()(0, 2) + 1.0) / m_projection_matrix.matrix()(0, 0); + default: + case EType::Ortho: + return 1.0 / m_projection_matrix.matrix()(0, 0) - 0.5 * m_projection_matrix.matrix()(0, 0) * m_projection_matrix.matrix()(0, 3); + } +} + +double Camera::get_near_top() const +{ + switch (m_type) + { + case EType::Perspective: + return m_frustrum_zs.first * (m_projection_matrix.matrix()(1, 2) + 1.0) / m_projection_matrix.matrix()(1, 1); + default: + case EType::Ortho: + return 1.0 / m_projection_matrix.matrix()(1, 1) - 0.5 * m_projection_matrix.matrix()(1, 1) * m_projection_matrix.matrix()(1, 3); + } +} + +double Camera::get_near_bottom() const +{ + switch (m_type) + { + case EType::Perspective: + return m_frustrum_zs.first * (m_projection_matrix.matrix()(1, 2) - 1.0) / m_projection_matrix.matrix()(1, 1); + default: + case EType::Ortho: + return -1.0 / m_projection_matrix.matrix()(1, 1) - 0.5 * m_projection_matrix.matrix()(1, 1) * m_projection_matrix.matrix()(1, 3); + } +} + +double Camera::get_near_width() const +{ + switch (m_type) + { + case EType::Perspective: + return 2.0 * m_frustrum_zs.first / m_projection_matrix.matrix()(0, 0); + default: + case EType::Ortho: + return 2.0 / m_projection_matrix.matrix()(0, 0); + } +} + +double Camera::get_near_height() const +{ + switch (m_type) + { + case EType::Perspective: + return 2.0 * m_frustrum_zs.first / m_projection_matrix.matrix()(1, 1); + default: + case EType::Ortho: + return 2.0 / m_projection_matrix.matrix()(1, 1); + } +} + double Camera::get_fov() const { switch (m_type) @@ -118,12 +190,16 @@ double Camera::get_fov() const }; } -void Camera::apply_viewport(int x, int y, unsigned int w, unsigned int h) +void Camera::set_viewport(int x, int y, unsigned int w, unsigned int h) { - glsafe(::glViewport(0, 0, w, h)); m_viewport = { 0, 0, int(w), int(h) }; } +void Camera::apply_viewport() const +{ + glsafe(::glViewport(m_viewport[0], m_viewport[1], m_viewport[2], m_viewport[3])); +} + void Camera::apply_projection(const BoundingBoxf3& box, double near_z, double far_z) { double w = 0.0; @@ -163,30 +239,33 @@ void Camera::apply_projection(const BoundingBoxf3& box, double near_z, double fa } } + apply_projection(-w, w, -h, h, m_frustrum_zs.first, m_frustrum_zs.second); +} + +void Camera::apply_projection(double left, double right, double bottom, double top, double near_z, double far_z) +{ + assert(left != right && bottom != top && near_z != far_z); + const double inv_dx = 1.0 / (right - left); + const double inv_dy = 1.0 / (top - bottom); + const double inv_dz = 1.0 / (far_z - near_z); + switch (m_type) { default: case EType::Ortho: { - const double dz = m_frustrum_zs.second - m_frustrum_zs.first; - const double zz = m_frustrum_zs.first + m_frustrum_zs.second; - m_projection_matrix.matrix() << 1.0 / w, 0.0, 0.0, 0.0, - 0.0, 1.0 / h, 0.0, 0.0, - 0.0, 0.0, -2.0 / dz, -zz / dz, - 0.0, 0.0, 0.0, 1.0; + m_projection_matrix.matrix() << 2.0 * inv_dx, 0.0, 0.0, -(left + right) * inv_dx, + 0.0, 2.0 * inv_dy, 0.0, -(bottom + top) * inv_dy, + 0.0, 0.0, -2.0 * inv_dz, -(near_z + far_z) * inv_dz, + 0.0, 0.0, 0.0, 1.0; break; } case EType::Perspective: { - const double n = m_frustrum_zs.first; - const double f = m_frustrum_zs.second; - const double dz = f - n; - const double zz = n + f; - const double fn = n * f; - m_projection_matrix.matrix() << n / w, 0.0, 0.0, 0.0, - 0.0, n / h, 0.0, 0.0, - 0.0, 0.0, -zz / dz, -2.0 * fn / dz, - 0.0, 0.0, -1.0, 0.0; + m_projection_matrix.matrix() << 2.0 * near_z * inv_dx, 0.0, (left + right) * inv_dx, 0.0, + 0.0, 2.0 * near_z * inv_dy, (bottom + top) * inv_dy, 0.0, + 0.0, 0.0, -(near_z + far_z) * inv_dz, -2.0 * near_z * far_z * inv_dz, + 0.0, 0.0, -1.0, 0.0; break; } } diff --git a/src/slic3r/GUI/Camera.hpp b/src/slic3r/GUI/Camera.hpp index 2fdd16461ed..cfed47884cb 100644 --- a/src/slic3r/GUI/Camera.hpp +++ b/src/slic3r/GUI/Camera.hpp @@ -107,13 +107,23 @@ struct Camera double get_far_z() const { return m_frustrum_zs.second; } const std::pair& get_z_range() const { return m_frustrum_zs; } + double get_near_left() const; + double get_near_right() const; + double get_near_top() const; + double get_near_bottom() const; + double get_near_width() const; + double get_near_height() const; + double get_fov() const; - void apply_viewport(int x, int y, unsigned int w, unsigned int h); + void set_viewport(int x, int y, unsigned int w, unsigned int h); + void apply_viewport() const; // Calculates and applies the projection matrix tighting the frustrum z range around the given box. // If larger z span is needed, pass the desired values of near and far z (negative values are ignored) void apply_projection(const BoundingBoxf3& box, double near_z = -1.0, double far_z = -1.0); + void apply_projection(double left, double right, double bottom, double top, double near_z, double far_z); + void zoom_to_box(const BoundingBoxf3& box, double margin_factor = DefaultZoomToBoxMarginFactor); void zoom_to_volumes(const GLVolumePtrs& volumes, double margin_factor = DefaultZoomToVolumesMarginFactor); diff --git a/src/slic3r/GUI/GCodeViewer.cpp b/src/slic3r/GUI/GCodeViewer.cpp index 948632e1591..edb1fade579 100644 --- a/src/slic3r/GUI/GCodeViewer.cpp +++ b/src/slic3r/GUI/GCodeViewer.cpp @@ -1305,7 +1305,8 @@ void GCodeViewer::_render_calibration_thumbnail_internal(ThumbnailData& thumbnai #if 1 Camera camera; - camera.apply_viewport(0,0,thumbnail_data.width, thumbnail_data.height); + camera.set_viewport(0, 0, thumbnail_data.width, thumbnail_data.height); + camera.apply_viewport(); camera.set_scene_box(plate_box); camera.set_type(Camera::EType::Ortho); camera.set_target(center); diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index af0c517f100..5cd88b15345 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -1787,7 +1787,8 @@ void GLCanvas3D::render(bool only_init) // and the viewport was set incorrectly, leading to tripping glAsserts further down // the road (in apply_projection). That's why the minimum size is forced to 10. Camera& camera = wxGetApp().plater()->get_camera(); - camera.apply_viewport(0, 0, std::max(10u, (unsigned int)cnv_size.get_width()), std::max(10u, (unsigned int)cnv_size.get_height())); + camera.set_viewport(0, 0, std::max(10u, (unsigned int)cnv_size.get_width()), std::max(10u, (unsigned int)cnv_size.get_height())); + camera.apply_viewport(); if (camera.requires_zoom_to_bed) { zoom_to_bed(); @@ -1896,7 +1897,7 @@ void GLCanvas3D::render(bool only_init) _render_current_gizmo(); #if ENABLE_RAYCAST_PICKING_DEBUG - if (m_picking_enabled && !m_mouse.dragging) + if (m_picking_enabled && !m_mouse.dragging && !m_gizmos.is_dragging() && !m_rectangle_selection.is_dragging()) m_scene_raycaster.render_hit(camera); #endif // ENABLE_RAYCAST_PICKING_DEBUG @@ -5540,7 +5541,8 @@ void GLCanvas3D::render_thumbnail_internal(ThumbnailData& thumbnail_data, const //BBS modify scene box to plate scene bounding box //plate_build_volume.min(2) = - plate_build_volume.max(2); camera.set_scene_box(plate_build_volume); - camera.apply_viewport(0, 0, thumbnail_data.width, thumbnail_data.height); + camera.set_viewport(0, 0, thumbnail_data.width, thumbnail_data.height); + camera.apply_viewport(); //BoundingBoxf3 plate_box = plate->get_bounding_box(false); //plate_box.min.z() = 0.0; @@ -5911,7 +5913,7 @@ void GLCanvas3D::render_thumbnail_legacy(ThumbnailData& thumbnail_data, unsigned #endif // ENABLE_THUMBNAIL_GENERATOR_DEBUG_OUTPUT // restore the default framebuffer size to avoid flickering on the 3D scene - //wxGetApp().plater()->get_camera().apply_viewport(0, 0, cnv_size.get_width(), cnv_size.get_height()); + //wxGetApp().plater()->get_camera().apply_viewport(); } //BBS: GUI refractor @@ -6412,11 +6414,13 @@ void GLCanvas3D::_refresh_if_shown_on_screen() void GLCanvas3D::_picking_pass() { - if (!m_picking_enabled || m_mouse.dragging || m_mouse.position == Vec2d(DBL_MAX, DBL_MAX)) { + if (!m_picking_enabled || m_mouse.dragging || m_mouse.position == Vec2d(DBL_MAX, DBL_MAX) && !m_gizmos.is_dragging()) { +#if ENABLE_RAYCAST_PICKING_DEBUG ImGuiWrapper& imgui = *wxGetApp().imgui(); imgui.begin(std::string("Hit result"), ImGuiWindowFlags_AlwaysAutoResize); imgui.text("Picking disabled"); imgui.end(); +#endif // ENABLE_RAYCAST_PICKING_DEBUG return; } @@ -6502,6 +6506,7 @@ void GLCanvas3D::_picking_pass() object_type = "Volume"; break; } + default: { break; } } char buf[1024]; if (hit.type != SceneRaycaster::EType::None) { @@ -6536,6 +6541,56 @@ void GLCanvas3D::_rectangular_selection_picking_pass() std::set idxs; if (m_picking_enabled) { + const size_t width = std::max(m_rectangle_selection.get_width(), 1); + const size_t height = std::max(m_rectangle_selection.get_height(), 1); + + const OpenGLManager::EFramebufferType framebuffers_type = OpenGLManager::get_framebuffers_type(); + bool use_framebuffer = framebuffers_type != OpenGLManager::EFramebufferType::Unknown; + + GLuint render_fbo = 0; + GLuint render_tex = 0; + GLuint render_depth = 0; + if (use_framebuffer) { + // setup a framebuffer which covers only the selection rectangle + if (framebuffers_type == OpenGLManager::EFramebufferType::Arb) { + glsafe(::glGenFramebuffers(1, &render_fbo)); + glsafe(::glBindFramebuffer(GL_FRAMEBUFFER, render_fbo)); + } + else { + glsafe(::glGenFramebuffersEXT(1, &render_fbo)); + glsafe(::glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, render_fbo)); + } + glsafe(::glGenTextures(1, &render_tex)); + glsafe(::glBindTexture(GL_TEXTURE_2D, render_tex)); + glsafe(::glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr)); + glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST)); + glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST)); + if (framebuffers_type == OpenGLManager::EFramebufferType::Arb) { + glsafe(::glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, render_tex, 0)); + glsafe(::glGenRenderbuffers(1, &render_depth)); + glsafe(::glBindRenderbuffer(GL_RENDERBUFFER, render_depth)); + glsafe(::glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, width, height)); + glsafe(::glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, render_depth)); + } + else { + glsafe(::glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, render_tex, 0)); + glsafe(::glGenRenderbuffersEXT(1, &render_depth)); + glsafe(::glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, render_depth)); + glsafe(::glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT, width, height)); + glsafe(::glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, render_depth)); + } + const GLenum drawBufs[] = { GL_COLOR_ATTACHMENT0 }; + glsafe(::glDrawBuffers(1, drawBufs)); + if (framebuffers_type == OpenGLManager::EFramebufferType::Arb) { + if (::glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) + use_framebuffer = false; + } + else { + if (::glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT) != GL_FRAMEBUFFER_COMPLETE_EXT) + use_framebuffer = false; + } + } + if (m_multisample_allowed) // This flag is often ignored by NVIDIA drivers if rendering into a screen buffer. glsafe(::glDisable(GL_MULTISAMPLE)); @@ -6545,20 +6600,48 @@ void GLCanvas3D::_rectangular_selection_picking_pass() glsafe(::glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)); - _render_volumes_for_picking(); + Camera& main_camera = wxGetApp().plater()->get_camera(); + Camera framebuffer_camera; + Camera* camera = &main_camera; + if (use_framebuffer) { + // setup a camera which covers only the selection rectangle + const std::array& viewport = camera->get_viewport(); + const double near_left = camera->get_near_left(); + const double near_bottom = camera->get_near_bottom(); + const double near_width = camera->get_near_width(); + const double near_height = camera->get_near_height(); + + const double ratio_x = near_width / double(viewport[2]); + const double ratio_y = near_height / double(viewport[3]); + + const double rect_near_left = near_left + double(m_rectangle_selection.get_left()) * ratio_x; + const double rect_near_bottom = near_bottom + (double(viewport[3]) - double(m_rectangle_selection.get_bottom())) * ratio_y; + double rect_near_right = near_left + double(m_rectangle_selection.get_right()) * ratio_x; + double rect_near_top = near_bottom + (double(viewport[3]) - double(m_rectangle_selection.get_top())) * ratio_y; + + if (rect_near_left == rect_near_right) + rect_near_right = rect_near_left + ratio_x; + if (rect_near_bottom == rect_near_top) + rect_near_top = rect_near_bottom + ratio_y; + + framebuffer_camera.look_at(camera->get_position(), camera->get_target(), camera->get_dir_up()); + framebuffer_camera.apply_projection(rect_near_left, rect_near_right, rect_near_bottom, rect_near_top, camera->get_near_z(), camera->get_far_z()); + framebuffer_camera.set_viewport(0, 0, width, height); + framebuffer_camera.apply_viewport(); + camera = &framebuffer_camera; + } + + _render_volumes_for_picking(*camera); //BBS: remove the bed picking logic //_render_bed_for_picking(!wxGetApp().plater()->get_camera().is_looking_downward()); if (m_multisample_allowed) glsafe(::glEnable(GL_MULTISAMPLE)); - int width = std::max((int)m_rectangle_selection.get_width(), 1); - int height = std::max((int)m_rectangle_selection.get_height(), 1); - int px_count = width * height; + const size_t px_count = width * height; - int left = (int)m_rectangle_selection.get_left(); - int top = get_canvas_size().get_height() - (int)m_rectangle_selection.get_top(); - if (left >= 0 && top >= 0) { + const size_t left = use_framebuffer ? 0 : (size_t)m_rectangle_selection.get_left(); + const size_t top = use_framebuffer ? 0 : (size_t)get_canvas_size().get_height() - (size_t)m_rectangle_selection.get_top(); #define USE_PARALLEL 1 #if USE_PARALLEL struct Pixel @@ -6602,7 +6685,26 @@ void GLCanvas3D::_rectangular_selection_picking_pass() idxs.insert(volume_id); } #endif // USE_PARALLEL - } + if (camera != &main_camera) + main_camera.apply_viewport(); + + if (framebuffers_type == OpenGLManager::EFramebufferType::Arb) { + glsafe(::glBindFramebuffer(GL_FRAMEBUFFER, 0)); + if (render_depth != 0) + glsafe(::glDeleteRenderbuffers(1, &render_depth)); + if (render_fbo != 0) + glsafe(::glDeleteFramebuffers(1, &render_fbo)); + } + else if (framebuffers_type == OpenGLManager::EFramebufferType::Ext) { + glsafe(::glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0)); + if (render_depth != 0) + glsafe(::glDeleteRenderbuffersEXT(1, &render_depth)); + if (render_fbo != 0) + glsafe(::glDeleteFramebuffersEXT(1, &render_fbo)); + } + + if (render_tex != 0) + glsafe(::glDeleteTextures(1, &render_tex)); } m_hover_volume_idxs.assign(idxs.begin(), idxs.end()); @@ -7194,7 +7296,7 @@ void GLCanvas3D::_render_style_editor() ImGui::End(); } -void GLCanvas3D::_render_volumes_for_picking() const +void GLCanvas3D::_render_volumes_for_picking(const Camera& camera) const { GLShaderProgram* shader = wxGetApp().get_shader("flat_clip"); if (shader == nullptr) @@ -7203,7 +7305,7 @@ void GLCanvas3D::_render_volumes_for_picking() const // do not cull backfaces to show broken geometry, if any glsafe(::glDisable(GL_CULL_FACE)); - const Transform3d& view_matrix = wxGetApp().plater()->get_camera().get_view_matrix(); + const Transform3d& view_matrix = camera.get_view_matrix(); for (size_t type = 0; type < 2; ++ type) { GLVolumeWithIdAndZList to_render = volumes_to_render(m_volumes.volumes, (type == 0) ? GLVolumeCollection::ERenderType::Opaque : GLVolumeCollection::ERenderType::Transparent, view_matrix); for (const GLVolumeWithIdAndZ& volume : to_render) @@ -7216,8 +7318,7 @@ void GLCanvas3D::_render_volumes_for_picking() const //const unsigned int id = 1 + volume.second.first; volume.first->model.set_color(picking_decode(id)); shader->start_using(); - const Camera& camera = wxGetApp().plater()->get_camera(); - shader->set_uniform("view_model_matrix", camera.get_view_matrix() * volume.first->world_matrix()); + shader->set_uniform("view_model_matrix", view_matrix * volume.first->world_matrix()); shader->set_uniform("projection_matrix", camera.get_projection_matrix()); shader->set_uniform("volume_world_matrix", volume.first->world_matrix()); shader->set_uniform("z_range", m_volumes.get_z_range()); diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp index 407a2ebb473..db1f004a810 100644 --- a/src/slic3r/GUI/GLCanvas3D.hpp +++ b/src/slic3r/GUI/GLCanvas3D.hpp @@ -725,16 +725,20 @@ class GLCanvas3D bool init(); void post_event(wxEvent &&event); - std::shared_ptr add_raycaster_for_picking(SceneRaycaster::EType type, PickingId id, const MeshRaycaster& raycaster, const Transform3d& trafo) { + std::shared_ptr add_raycaster_for_picking(SceneRaycaster::EType type, int id, const MeshRaycaster& raycaster, const Transform3d& trafo) { return m_scene_raycaster.add_raycaster(type, id, raycaster, trafo); } - void remove_raycasters_for_picking(SceneRaycaster::EType type, PickingId id) { + void remove_raycasters_for_picking(SceneRaycaster::EType type, int id) { m_scene_raycaster.remove_raycasters(type, id); } void remove_raycasters_for_picking(SceneRaycaster::EType type) { m_scene_raycaster.remove_raycasters(type); } + std::vector>* get_raycasters_for_picking(SceneRaycaster::EType type) { + return m_scene_raycaster.get_raycasters(type); + } + void set_raycaster_gizmos_on_top(bool value) { m_scene_raycaster.set_gizmos_on_top(value); } @@ -1144,7 +1148,7 @@ class GLCanvas3D void _check_and_update_toolbar_icon_scale(); void _render_overlays(); void _render_style_editor(); - void _render_volumes_for_picking() const; + void _render_volumes_for_picking(const Camera& camera) const; void _render_current_gizmo() const; void _render_gizmos_overlay(); void _render_main_toolbar(); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoBase.cpp b/src/slic3r/GUI/Gizmos/GLGizmoBase.cpp index ffb5e92f77c..6b3eede5c39 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoBase.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoBase.cpp @@ -104,7 +104,7 @@ PickingModel &GLGizmoBase::Grabber::get_cube() return s_cube; } -void GLGizmoBase::Grabber::register_raycasters_for_picking(PickingId id) +void GLGizmoBase::Grabber::register_raycasters_for_picking(int id) { picking_id = id; // registration will happen on next call to render() diff --git a/src/slic3r/GUI/Gizmos/GLGizmoBase.hpp b/src/slic3r/GUI/Gizmos/GLGizmoBase.hpp index 6e6ff7efa55..d85e5583e4c 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoBase.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoBase.hpp @@ -87,7 +87,7 @@ class GLGizmoBase ColorRGBA hover_color{GRABBER_HOVER_COL}; EGrabberExtension extensions{ EGrabberExtension::None }; // the picking id shared by all the elements - PickingId picking_id{ -1 }; + int picking_id{ -1 }; std::array, GRABBER_ELEMENTS_MAX_COUNT> raycasters = { nullptr }; Grabber() = default; @@ -99,7 +99,7 @@ class GLGizmoBase float get_dragging_half_size(float size) const; PickingModel &get_cube(); - void register_raycasters_for_picking(PickingId id); + void register_raycasters_for_picking(int id); void unregister_raycasters_for_picking(); private: diff --git a/src/slic3r/GUI/Gizmos/GLGizmoFlatten.hpp b/src/slic3r/GUI/Gizmos/GLGizmoFlatten.hpp index 61d34ba492c..b1892e5d062 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoFlatten.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoFlatten.hpp @@ -26,7 +26,7 @@ class GLGizmoFlatten : public GLGizmoBase PickingModel vbo; Vec3d normal; float area; - PickingId picking_id{ -1 }; + int picking_id{ -1 }; }; // This holds information to decide whether recalculation is necessary: diff --git a/src/slic3r/GUI/SceneRaycaster.cpp b/src/slic3r/GUI/SceneRaycaster.cpp index 64bd55f7bc2..faf44a16758 100644 --- a/src/slic3r/GUI/SceneRaycaster.cpp +++ b/src/slic3r/GUI/SceneRaycaster.cpp @@ -31,7 +31,7 @@ SceneRaycaster::SceneRaycaster() { #endif // ENABLE_RAYCAST_PICKING_DEBUG } -std::shared_ptr SceneRaycaster::add_raycaster(EType type, PickingId id, const MeshRaycaster& raycaster, const Transform3d& trafo) +std::shared_ptr SceneRaycaster::add_raycaster(EType type, int id, const MeshRaycaster& raycaster, const Transform3d& trafo) { switch (type) { case EType::Bed: { return m_bed.emplace_back(std::make_shared(encode_id(type, id), raycaster, trafo)); } @@ -41,7 +41,7 @@ std::shared_ptr SceneRaycaster::add_raycaster(EType type, Pi }; } -void SceneRaycaster::remove_raycasters(EType type, PickingId id) +void SceneRaycaster::remove_raycasters(EType type, int id) { std::vector>* raycasters = get_raycasters(type); auto it = raycasters->begin(); @@ -102,7 +102,7 @@ SceneRaycaster::HitResult SceneRaycaster::hit(const Vec2d& mouse_pos, const Came HitResult ret; - auto test_raycasters = [&](EType type) { + auto test_raycasters = [this, is_closest, clipping_plane](EType type, const Vec2d& mouse_pos, const Camera& camera, HitResult& ret) { const ClippingPlane* clip_plane = (clipping_plane != nullptr && type == EType::Volume) ? clipping_plane : nullptr; std::vector>* raycasters = get_raycasters(type); HitResult current_hit = { type }; @@ -115,7 +115,6 @@ SceneRaycaster::HitResult SceneRaycaster::hit(const Vec2d& mouse_pos, const Came if (item->get_raycaster()->closest_hit(mouse_pos, trafo, camera, current_hit.position, current_hit.normal, clip_plane)) { current_hit.position = (trafo * current_hit.position.cast()).cast(); if (is_closest(camera, current_hit.position)) { - const Transform3d matrix = camera.get_view_matrix() * trafo; const Matrix3d normal_matrix = (Matrix3d)trafo.matrix().block(0, 0, 3, 3).inverse().transpose(); current_hit.normal = (normal_matrix * current_hit.normal.cast()).normalized().cast(); ret = current_hit; @@ -125,13 +124,13 @@ SceneRaycaster::HitResult SceneRaycaster::hit(const Vec2d& mouse_pos, const Came }; if (!m_gizmos.empty()) - test_raycasters(EType::Gizmo); + test_raycasters(EType::Gizmo, mouse_pos, camera, ret); if (!m_gizmos_on_top || !ret.is_valid()) { if (camera.is_looking_downward() && !m_bed.empty()) - test_raycasters(EType::Bed); + test_raycasters(EType::Bed, mouse_pos, camera, ret); if (!m_volumes.empty()) - test_raycasters(EType::Volume); + test_raycasters(EType::Volume, mouse_pos, camera, ret); } if (ret.is_valid()) @@ -146,7 +145,7 @@ SceneRaycaster::HitResult SceneRaycaster::hit(const Vec2d& mouse_pos, const Came #if ENABLE_RAYCAST_PICKING_DEBUG void SceneRaycaster::render_hit(const Camera& camera) { - if (!m_last_hit.has_value() || !m_last_hit.value().is_valid()) + if (!m_last_hit.has_value() || !(*m_last_hit).is_valid()) return; GLShaderProgram* shader = wxGetApp().get_shader("flat"); @@ -154,14 +153,14 @@ void SceneRaycaster::render_hit(const Camera& camera) shader->set_uniform("projection_matrix", camera.get_projection_matrix()); - const Transform3d sphere_view_model_matrix = camera.get_view_matrix() * Geometry::translation_transform(m_last_hit.value().position.cast()) * + const Transform3d sphere_view_model_matrix = camera.get_view_matrix() * Geometry::translation_transform((*m_last_hit).position.cast()) * Geometry::scale_transform(4.0 * camera.get_inv_zoom()); shader->set_uniform("view_model_matrix", sphere_view_model_matrix); m_sphere.render(); Eigen::Quaterniond q; Transform3d m = Transform3d::Identity(); - m.matrix().block(0, 0, 3, 3) = q.setFromTwoVectors(Vec3d::UnitZ(), m_last_hit.value().normal.cast()).toRotationMatrix(); + m.matrix().block(0, 0, 3, 3) = q.setFromTwoVectors(Vec3d::UnitZ(), (*m_last_hit).normal.cast()).toRotationMatrix(); const Transform3d line_view_model_matrix = sphere_view_model_matrix * m * Geometry::scale_transform(10.0); shader->set_uniform("view_model_matrix", line_view_model_matrix); @@ -185,28 +184,22 @@ std::vector>* SceneRaycaster::get_raycasters return ret; } -PickingId SceneRaycaster::base_id(EType type) +int SceneRaycaster::base_id(EType type) { switch (type) { - case EType::Bed: { return PickingId(EPickingIdBase::Bed); } - case EType::Volume: { return PickingId(EPickingIdBase::Volume); } - case EType::Gizmo: { return PickingId(EPickingIdBase::Gizmo); } + case EType::Bed: { return int(EIdBase::Bed); } + case EType::Volume: { return int(EIdBase::Volume); } + case EType::Gizmo: { return int(EIdBase::Gizmo); } + default: { break; } }; assert(false); return -1; } -PickingId SceneRaycaster::encode_id(EType type, PickingId id) -{ - return base_id(type) + id; -} - -PickingId SceneRaycaster::decode_id(EType type, PickingId id) -{ - return id - base_id(type); -} +int SceneRaycaster::encode_id(EType type, int id) { return base_id(type) + id; } +int SceneRaycaster::decode_id(EType type, int id) { return id - base_id(type); } } // namespace GUI } // namespace Slic3r diff --git a/src/slic3r/GUI/SceneRaycaster.hpp b/src/slic3r/GUI/SceneRaycaster.hpp index d0b47dbc75a..c4597b6a577 100644 --- a/src/slic3r/GUI/SceneRaycaster.hpp +++ b/src/slic3r/GUI/SceneRaycaster.hpp @@ -3,7 +3,6 @@ #include "MeshUtils.hpp" #include "GLModel.hpp" - #include #include #include @@ -13,21 +12,19 @@ namespace GUI { struct Camera; -using PickingId = int; - class SceneRaycasterItem { - PickingId m_id{ -1 }; + int m_id{ -1 }; bool m_active{ true }; const MeshRaycaster* m_raycaster; Transform3d m_trafo; public: - SceneRaycasterItem(PickingId id, const MeshRaycaster& raycaster, const Transform3d& trafo) + SceneRaycasterItem(int id, const MeshRaycaster& raycaster, const Transform3d& trafo) : m_id(id), m_raycaster(&raycaster), m_trafo(trafo) {} - PickingId get_id() const { return m_id; } + int get_id() const { return m_id; } bool is_active() const { return m_active; } void set_active(bool active) { m_active = active; } const MeshRaycaster* get_raycaster() const { return m_raycaster; } @@ -46,7 +43,7 @@ class SceneRaycaster Gizmo }; - enum class EPickingIdBase + enum class EIdBase { Bed = 0, Volume = 1000, @@ -56,7 +53,7 @@ class SceneRaycaster struct HitResult { EType type{ EType::None }; - PickingId raycaster_id{ -1 }; + int raycaster_id{ -1 }; Vec3f position{ Vec3f::Zero() }; Vec3f normal{ Vec3f::Zero() }; @@ -81,11 +78,13 @@ class SceneRaycaster public: SceneRaycaster(); - std::shared_ptr add_raycaster(EType type, PickingId picking_id, const MeshRaycaster& raycaster, const Transform3d& trafo); - void remove_raycasters(EType type, PickingId id); + std::shared_ptr add_raycaster(EType type, int picking_id, const MeshRaycaster& raycaster, const Transform3d& trafo); + void remove_raycasters(EType type, int id); void remove_raycasters(EType type); void remove_raycaster(std::shared_ptr item); + std::vector>* get_raycasters(EType type); + void set_gizmos_on_top(bool value) { m_gizmos_on_top = value; } HitResult hit(const Vec2d& mouse_pos, const Camera& camera, const ClippingPlane* clipping_plane = nullptr); @@ -99,11 +98,9 @@ class SceneRaycaster #endif // ENABLE_RAYCAST_PICKING_DEBUG private: - std::vector>* get_raycasters(EType type); - - static PickingId encode_id(EType type, PickingId id); - static PickingId decode_id(EType type, PickingId id); - static PickingId base_id(EType type); + static int encode_id(EType type, int id); + static int decode_id(EType type, int id); + static int base_id(EType type); }; } // namespace GUI From e4ec0cfc2ec21a951312a7400dc272aa942ae2af Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Sun, 29 Oct 2023 12:46:58 +0800 Subject: [PATCH 70/99] Tech ENABLE_RAYCAST_PICKING - Method GLCanvas3D::_mouse_to_3d() modified to use the new scene raycaster instead of reading data from the depth buffer (cherry picked from commit prusa3d/PrusaSlicer@a7af73795d5570ed7a0a357c016671a9864e4854) --- src/slic3r/GUI/GLCanvas3D.cpp | 26 +++++++++++--------------- 1 file changed, 11 insertions(+), 15 deletions(-) diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 5cd88b15345..206747ce808 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -8393,21 +8393,17 @@ Vec3d GLCanvas3D::_mouse_to_3d(const Point& mouse_pos, float* z) if (m_canvas == nullptr) return Vec3d(DBL_MAX, DBL_MAX, DBL_MAX); - const Camera& camera = wxGetApp().plater()->get_camera(); - Matrix4d modelview = camera.get_view_matrix().matrix(); - Matrix4d projection= camera.get_projection_matrix().matrix(); - Vec4i viewport(camera.get_viewport().data()); - - GLint y = viewport[3] - (GLint)mouse_pos(1); - GLfloat mouse_z; - if (z == nullptr) - glsafe(::glReadPixels((GLint)mouse_pos(0), y, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, (void*)&mouse_z)); - else - mouse_z = *z; - - Vec3d out; - igl::unproject(Vec3d(mouse_pos(0), y, mouse_z), modelview, projection, viewport, out); - return out; + if (z == nullptr) { + const SceneRaycaster::HitResult hit = m_scene_raycaster.hit(mouse_pos.cast(), wxGetApp().plater()->get_camera(), nullptr); + return hit.is_valid() ? hit.position.cast() : _mouse_to_bed_3d(mouse_pos); + } + else { + const Camera& camera = wxGetApp().plater()->get_camera(); + const Vec4i viewport(camera.get_viewport().data()); + Vec3d out; + igl::unproject(Vec3d(mouse_pos.x(), viewport[3] - mouse_pos.y(), *z), camera.get_view_matrix().matrix(), camera.get_projection_matrix().matrix(), viewport, out); + return out; + } } Vec3d GLCanvas3D::_mouse_to_bed_3d(const Point& mouse_pos) From 094acdb645ab6042584c8abb3a2bf3087e6d5154 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Sun, 29 Oct 2023 15:24:45 +0800 Subject: [PATCH 71/99] Tech ENABLE_RAYCAST_PICKING - Gizmo flatten: fixed update of raycasters transformations (cherry picked from commit prusa3d/PrusaSlicer@2a2d442b2872ad06d4f0db1db2f1d14ef468c107) --- src/slic3r/GUI/GLCanvas3D.hpp | 5 +++-- src/slic3r/GUI/Gizmos/GLGizmoFlatten.cpp | 22 ++++++++++++---------- src/slic3r/GUI/Gizmos/GLGizmoFlatten.hpp | 3 +-- src/slic3r/GUI/SceneRaycaster.cpp | 21 ++++++++++++--------- src/slic3r/GUI/SceneRaycaster.hpp | 9 ++++++--- 5 files changed, 34 insertions(+), 26 deletions(-) diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp index db1f004a810..54c033ebef3 100644 --- a/src/slic3r/GUI/GLCanvas3D.hpp +++ b/src/slic3r/GUI/GLCanvas3D.hpp @@ -725,8 +725,9 @@ class GLCanvas3D bool init(); void post_event(wxEvent &&event); - std::shared_ptr add_raycaster_for_picking(SceneRaycaster::EType type, int id, const MeshRaycaster& raycaster, const Transform3d& trafo) { - return m_scene_raycaster.add_raycaster(type, id, raycaster, trafo); + std::shared_ptr add_raycaster_for_picking(SceneRaycaster::EType type, int id, const MeshRaycaster& raycaster, + const Transform3d& trafo, bool use_back_faces = false) { + return m_scene_raycaster.add_raycaster(type, id, raycaster, trafo, use_back_faces); } void remove_raycasters_for_picking(SceneRaycaster::EType type, int id) { m_scene_raycaster.remove_raycasters(type, id); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoFlatten.cpp b/src/slic3r/GUI/Gizmos/GLGizmoFlatten.cpp index ec5bc3f256b..6b44af03d8e 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoFlatten.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoFlatten.cpp @@ -75,16 +75,17 @@ void GLGizmoFlatten::on_render() glsafe(::glEnable(GL_BLEND)); if (selection.is_single_full_instance()) { - const Transform3d& m = selection.get_first_volume()->get_instance_transformation().get_matrix(); + const Transform3d& inst_matrix = selection.get_first_volume()->get_instance_transformation().get_matrix(); const Camera& camera = wxGetApp().plater()->get_camera(); - const Transform3d view_model_matrix = camera.get_view_matrix() * - Geometry::assemble_transform(selection.get_first_volume()->get_sla_shift_z() * Vec3d::UnitZ()) * m; + const Transform3d model_matrix = Geometry::assemble_transform(selection.get_first_volume()->get_sla_shift_z() * Vec3d::UnitZ()) * inst_matrix; + const Transform3d view_model_matrix = camera.get_view_matrix() * model_matrix; shader->set_uniform("view_model_matrix", view_model_matrix); shader->set_uniform("projection_matrix", camera.get_projection_matrix()); if (this->is_plane_update_necessary()) update_planes(); for (int i = 0; i < (int)m_planes.size(); ++i) { + m_planes_casters[i]->set_transform(model_matrix); m_planes[i].vbo.model.set_color(i == m_hover_id ? GLGizmoBase::FLATTEN_HOVER_COLOR : GLGizmoBase::FLATTEN_COLOR); m_planes[i].vbo.model.render(); } @@ -100,13 +101,15 @@ void GLGizmoFlatten::on_register_raycasters_for_picking() // the gizmo grabbers are rendered on top of the scene, so the raytraced picker should take it into account m_parent.set_raycaster_gizmos_on_top(true); + assert(m_planes_casters.empty()); + if (!m_planes.empty()) { const Selection& selection = m_parent.get_selection(); - const Transform3d matrix = Geometry::assemble_transform(selection.get_volume(*selection.get_volume_idxs().begin())->get_sla_shift_z() * Vec3d::UnitZ()) * - selection.get_volume(*selection.get_volume_idxs().begin())->get_instance_transformation().get_matrix(); + const Transform3d matrix = Geometry::assemble_transform(selection.get_first_volume()->get_sla_shift_z() * Vec3d::UnitZ()) * + selection.get_first_volume()->get_instance_transformation().get_matrix(); for (int i = 0; i < (int)m_planes.size(); ++i) { - m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, i, *m_planes[i].vbo.mesh_raycaster, matrix); + m_planes_casters.emplace_back(m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, i, *m_planes[i].vbo.mesh_raycaster, matrix)); } } } @@ -115,6 +118,7 @@ void GLGizmoFlatten::on_unregister_raycasters_for_picking() { m_parent.remove_raycasters_for_picking(SceneRaycaster::EType::Gizmo); m_parent.set_raycaster_gizmos_on_top(false); + m_planes_casters.clear(); } /* @@ -156,7 +160,6 @@ void GLGizmoFlatten::set_flattening_data(const ModelObject* model_object) m_starting_center = Vec3d::Zero(); if (model_object != m_old_model_object) { m_planes.clear(); - m_planes_valid = false; on_unregister_raycasters_for_picking(); } } @@ -385,7 +388,6 @@ void GLGizmoFlatten::update_planes() } on_register_raycasters_for_picking(); - m_planes_valid = true; } @@ -395,8 +397,8 @@ bool GLGizmoFlatten::is_plane_update_necessary() const if (m_state != On || ! mo || mo->instances.empty()) return false; - if (! m_planes_valid || mo != m_old_model_object - || mo->volumes.size() != m_volumes_matrices.size()) + if (m_planes.empty() || mo != m_old_model_object + || mo->volumes.size() != m_volumes_matrices.size()) return true; // We want to recalculate when the scale changes - some planes could (dis)appear. diff --git a/src/slic3r/GUI/Gizmos/GLGizmoFlatten.hpp b/src/slic3r/GUI/Gizmos/GLGizmoFlatten.hpp index b1892e5d062..73c5d326244 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoFlatten.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoFlatten.hpp @@ -5,7 +5,6 @@ #include "slic3r/GUI/GLModel.hpp" #include "slic3r/GUI/MeshUtils.hpp" - namespace Slic3r { enum class ModelVolumeType : int; @@ -36,7 +35,7 @@ class GLGizmoFlatten : public GLGizmoBase Vec3d m_first_instance_mirror; std::vector m_planes; - bool m_planes_valid = false; + std::vector> m_planes_casters; mutable Vec3d m_starting_center; const ModelObject* m_old_model_object = nullptr; std::vector instances_matrices; diff --git a/src/slic3r/GUI/SceneRaycaster.cpp b/src/slic3r/GUI/SceneRaycaster.cpp index faf44a16758..903c8dc17f7 100644 --- a/src/slic3r/GUI/SceneRaycaster.cpp +++ b/src/slic3r/GUI/SceneRaycaster.cpp @@ -31,13 +31,14 @@ SceneRaycaster::SceneRaycaster() { #endif // ENABLE_RAYCAST_PICKING_DEBUG } -std::shared_ptr SceneRaycaster::add_raycaster(EType type, int id, const MeshRaycaster& raycaster, const Transform3d& trafo) +std::shared_ptr SceneRaycaster::add_raycaster(EType type, int id, const MeshRaycaster& raycaster, + const Transform3d& trafo, bool use_back_faces) { switch (type) { - case EType::Bed: { return m_bed.emplace_back(std::make_shared(encode_id(type, id), raycaster, trafo)); } - case EType::Volume: { return m_volumes.emplace_back(std::make_shared(encode_id(type, id), raycaster, trafo)); } - case EType::Gizmo: { return m_gizmos.emplace_back(std::make_shared(encode_id(type, id), raycaster, trafo)); } - default: { assert(false); return nullptr; } + case EType::Bed: { return m_bed.emplace_back(std::make_shared(encode_id(type, id), raycaster, trafo, use_back_faces)); } + case EType::Volume: { return m_volumes.emplace_back(std::make_shared(encode_id(type, id), raycaster, trafo, use_back_faces)); } + case EType::Gizmo: { return m_gizmos.emplace_back(std::make_shared(encode_id(type, id), raycaster, trafo, use_back_faces)); } + default: { assert(false); return nullptr; } }; } @@ -105,6 +106,7 @@ SceneRaycaster::HitResult SceneRaycaster::hit(const Vec2d& mouse_pos, const Came auto test_raycasters = [this, is_closest, clipping_plane](EType type, const Vec2d& mouse_pos, const Camera& camera, HitResult& ret) { const ClippingPlane* clip_plane = (clipping_plane != nullptr && type == EType::Volume) ? clipping_plane : nullptr; std::vector>* raycasters = get_raycasters(type); + const Vec3f camera_forward = camera.get_dir_forward().cast(); HitResult current_hit = { type }; for (std::shared_ptr item : *raycasters) { if (!item->is_active()) @@ -114,10 +116,11 @@ SceneRaycaster::HitResult SceneRaycaster::hit(const Vec2d& mouse_pos, const Came const Transform3d& trafo = item->get_transform(); if (item->get_raycaster()->closest_hit(mouse_pos, trafo, camera, current_hit.position, current_hit.normal, clip_plane)) { current_hit.position = (trafo * current_hit.position.cast()).cast(); - if (is_closest(camera, current_hit.position)) { - const Matrix3d normal_matrix = (Matrix3d)trafo.matrix().block(0, 0, 3, 3).inverse().transpose(); - current_hit.normal = (normal_matrix * current_hit.normal.cast()).normalized().cast(); - ret = current_hit; + current_hit.normal = (trafo.matrix().block(0, 0, 3, 3).inverse().transpose() * current_hit.normal.cast()).normalized().cast(); + if (item->use_back_faces() || current_hit.normal.dot(camera_forward) < 0.0f){ + if (is_closest(camera, current_hit.position)) { + ret = current_hit; + } } } } diff --git a/src/slic3r/GUI/SceneRaycaster.hpp b/src/slic3r/GUI/SceneRaycaster.hpp index c4597b6a577..e0063659c25 100644 --- a/src/slic3r/GUI/SceneRaycaster.hpp +++ b/src/slic3r/GUI/SceneRaycaster.hpp @@ -16,17 +16,19 @@ class SceneRaycasterItem { int m_id{ -1 }; bool m_active{ true }; + bool m_use_back_faces{ false }; const MeshRaycaster* m_raycaster; Transform3d m_trafo; public: - SceneRaycasterItem(int id, const MeshRaycaster& raycaster, const Transform3d& trafo) - : m_id(id), m_raycaster(&raycaster), m_trafo(trafo) + SceneRaycasterItem(int id, const MeshRaycaster& raycaster, const Transform3d& trafo, bool use_back_faces = false) + : m_id(id), m_raycaster(&raycaster), m_trafo(trafo), m_use_back_faces(use_back_faces) {} int get_id() const { return m_id; } bool is_active() const { return m_active; } void set_active(bool active) { m_active = active; } + bool use_back_faces() const { return m_use_back_faces; } const MeshRaycaster* get_raycaster() const { return m_raycaster; } const Transform3d& get_transform() const { return m_trafo; } void set_transform(const Transform3d& trafo) { m_trafo = trafo; } @@ -78,7 +80,8 @@ class SceneRaycaster public: SceneRaycaster(); - std::shared_ptr add_raycaster(EType type, int picking_id, const MeshRaycaster& raycaster, const Transform3d& trafo); + std::shared_ptr add_raycaster(EType type, int picking_id, const MeshRaycaster& raycaster, + const Transform3d& trafo, bool use_back_faces = false); void remove_raycasters(EType type, int id); void remove_raycasters(EType type); void remove_raycaster(std::shared_ptr item); From da4a70785d74750627e95c23123a1d2adb24469e Mon Sep 17 00:00:00 2001 From: Filip Sykala Date: Sun, 29 Oct 2023 15:57:58 +0800 Subject: [PATCH 72/99] remove unnecessary getting of raw pointer from unique pointer (cherry picked from commit prusa3d/PrusaSlicer@209eda75a04ef99c4f610a888709d8aa89721714) --- src/slic3r/GUI/Gizmos/GLGizmosManager.cpp | 43 ++++++++++------------- src/slic3r/GUI/Gizmos/GLGizmosManager.hpp | 1 - 2 files changed, 18 insertions(+), 26 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp index 51fa667a733..8c62f79a863 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp @@ -1584,48 +1584,41 @@ bool GLGizmosManager::activate_gizmo(EType type) if (m_gizmos.empty() || m_current == type) return true; - GLGizmoBase* old_gizmo = m_current == Undefined ? nullptr : m_gizmos[m_current].get(); - - if (old_gizmo) { - //if (m_current == Text) { - // wxGetApp().imgui()->destroy_fonts_texture(); - //} - old_gizmo->set_state(GLGizmoBase::Off); - if (old_gizmo->get_state() != GLGizmoBase::Off) + if (m_current != Undefined) { + // clean up previous gizmo + GLGizmoBase &old_gizmo = *m_gizmos[m_current]; + old_gizmo.set_state(GLGizmoBase::Off); + if (old_gizmo.get_state() != GLGizmoBase::Off) return false; // gizmo refused to be turned off, do nothing. - old_gizmo->unregister_raycasters_for_picking(); + old_gizmo.unregister_raycasters_for_picking(); - if (! m_parent.get_gizmos_manager().is_serializing() - && old_gizmo->wants_enter_leave_snapshots()) + if (!m_serializing + && old_gizmo.wants_enter_leave_snapshots()) Plater::TakeSnapshot snapshot(wxGetApp().plater(), - old_gizmo->get_gizmo_leaving_text(), + old_gizmo.get_gizmo_leaving_text(), UndoRedo::SnapshotType::LeavingGizmoWithAction); } + // check deactivation of gizmo if (type == Undefined) { - // it is deactivation of gizmo - m_current = Undefined; + m_current = type; return true; } // set up new gizmo - GLGizmoBase* new_gizmo = type == Undefined ? nullptr : m_gizmos[type].get(); - - if (new_gizmo && ! m_parent.get_gizmos_manager().is_serializing() - && new_gizmo->wants_enter_leave_snapshots()) + GLGizmoBase& new_gizmo = *m_gizmos[type]; + if (!m_serializing && new_gizmo.wants_enter_leave_snapshots()) Plater::TakeSnapshot snapshot(wxGetApp().plater(), - new_gizmo->get_gizmo_entering_text(), + new_gizmo.get_gizmo_entering_text(), UndoRedo::SnapshotType::EnteringGizmo); m_current = type; + new_gizmo.set_state(GLGizmoBase::On); + if (new_gizmo.get_state() != GLGizmoBase::On) + return false; // gizmo refused to be turned on. - //if (m_current == Text) { - // wxGetApp().imgui()->load_fonts_texture(); - //} - new_gizmo->set_state(GLGizmoBase::On); - - new_gizmo->register_raycasters_for_picking(); + new_gizmo.register_raycasters_for_picking(); // sucessful activation of gizmo return true; diff --git a/src/slic3r/GUI/Gizmos/GLGizmosManager.hpp b/src/slic3r/GUI/Gizmos/GLGizmosManager.hpp index 3594ab7c483..039cc74cfe0 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosManager.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosManager.hpp @@ -226,7 +226,6 @@ class GLGizmosManager : public Slic3r::ObjectBase void refresh_on_off_state(); void reset_all_states(); - bool is_serializing() const { return m_serializing; } bool open_gizmo(EType type); bool check_gizmos_closed_except(EType) const; From 158bb47af31c28071aebdf5c182bf68130f1fe39 Mon Sep 17 00:00:00 2001 From: Filip Sykala Date: Thu, 19 Oct 2023 14:41:51 +0800 Subject: [PATCH 73/99] Suggestion to detect volume modification instead of check some gizmos during dragging (cherry picked from commit prusa3d/PrusaSlicer@96610ecea98a5be335ed0664d2da9280e9658edb) --- src/slic3r/GUI/GLCanvas3D.cpp | 42 +++++++++++++++-------------------- 1 file changed, 18 insertions(+), 24 deletions(-) diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 206747ce808..d287113a283 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -3900,30 +3900,24 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) m_mouse.set_start_position_3D_as_invalid(); m_mouse.position = pos.cast(); - if (evt.Dragging() && current_printer_technology() == ptFFF && (fff_print()->config().print_sequence == PrintSequence::ByObject)) { - switch (m_gizmos.get_current_type()) - { - case GLGizmosManager::EType::Move: - case GLGizmosManager::EType::Scale: - case GLGizmosManager::EType::Rotate: - { - update_sequential_clearance(); - break; - } - default: { break; } - } - } - else if (evt.Dragging()) { - switch (m_gizmos.get_current_type()) - { - case GLGizmosManager::EType::Move: - case GLGizmosManager::EType::Scale: - case GLGizmosManager::EType::Rotate: - { - show_sinking_contours(); - break; - } - default: { break; } + // It should be detection of volume change + // Not only detection of some modifiers !!! + if (evt.Dragging()) { + if (current_printer_technology() == ptFFF && + (fff_print()->config().print_sequence == PrintSequence::ByObject)) { + switch (m_gizmos.get_current_type()) { + case GLGizmosManager::EType::Move: + case GLGizmosManager::EType::Scale: + case GLGizmosManager::EType::Rotate: + update_sequential_clearance(); + } + } else { + switch (m_gizmos.get_current_type()) { + case GLGizmosManager::EType::Move: + case GLGizmosManager::EType::Scale: + case GLGizmosManager::EType::Rotate: + show_sinking_contours(); + } } } else if (evt.LeftUp() && From 8e2ab660c57efb3540b7beca9c1455f51bb10a46 Mon Sep 17 00:00:00 2001 From: Filip Sykala Date: Sun, 29 Oct 2023 16:04:10 +0800 Subject: [PATCH 74/99] Add virtual function to process mouse_event (cherry picked from commit prusa3d/PrusaSlicer@2ab44546bd5064d7007a95b106de658d01adeb82) --- src/slic3r/GUI/Gizmos/GLGizmoBase.hpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoBase.hpp b/src/slic3r/GUI/Gizmos/GLGizmoBase.hpp index d85e5583e4c..e58eaee6beb 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoBase.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoBase.hpp @@ -152,7 +152,7 @@ class GLGizmoBase GLGizmoBase(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id); - virtual ~GLGizmoBase() {} + virtual ~GLGizmoBase() = default; bool init() { return on_init(); } @@ -213,6 +213,14 @@ class GLGizmoBase int get_count() { return ++count; } std::string get_gizmo_name() { return on_get_name(); } + /// + /// Implement when want to process mouse events in gizmo + /// Click, Right click, move, drag, ... + /// + /// Keep information about mouse click + /// Return True when use the information and don't want to propagate it otherwise False. + virtual bool on_mouse(const wxMouseEvent &mouse_event) { return false; } + void register_raycasters_for_picking() { register_grabbers_for_picking(); on_register_raycasters_for_picking(); } void unregister_raycasters_for_picking() { unregister_grabbers_for_picking(); on_unregister_raycasters_for_picking(); } From 005b83912de2384be368209dc76018602e9ed377 Mon Sep 17 00:00:00 2001 From: Noisyfox Date: Sun, 29 Oct 2023 16:44:23 +0800 Subject: [PATCH 75/99] Do not compile sla related gizmos --- src/slic3r/CMakeLists.txt | 8 +-- src/slic3r/GUI/GLCanvas3D.cpp | 14 ++--- src/slic3r/GUI/Gizmos/GLGizmosManager.cpp | 67 ++++++++++++----------- src/slic3r/GUI/Gizmos/GLGizmosManager.hpp | 6 +- 4 files changed, 49 insertions(+), 46 deletions(-) diff --git a/src/slic3r/CMakeLists.txt b/src/slic3r/CMakeLists.txt index b3d6f514425..4b9a967f9eb 100644 --- a/src/slic3r/CMakeLists.txt +++ b/src/slic3r/CMakeLists.txt @@ -117,16 +117,16 @@ set(SLIC3R_GUI_SOURCES GUI/Gizmos/GLGizmoRotate.hpp GUI/Gizmos/GLGizmoScale.cpp GUI/Gizmos/GLGizmoScale.hpp - GUI/Gizmos/GLGizmoSlaSupports.cpp - GUI/Gizmos/GLGizmoSlaSupports.hpp + #GUI/Gizmos/GLGizmoSlaSupports.cpp + #GUI/Gizmos/GLGizmoSlaSupports.hpp GUI/Gizmos/GLGizmoFdmSupports.cpp GUI/Gizmos/GLGizmoFdmSupports.hpp GUI/Gizmos/GLGizmoFlatten.cpp GUI/Gizmos/GLGizmoFlatten.hpp GUI/Gizmos/GLGizmoAdvancedCut.cpp GUI/Gizmos/GLGizmoAdvancedCut.hpp - GUI/Gizmos/GLGizmoHollow.cpp - GUI/Gizmos/GLGizmoHollow.hpp + #GUI/Gizmos/GLGizmoHollow.cpp + #GUI/Gizmos/GLGizmoHollow.hpp GUI/Gizmos/GLGizmoPainterBase.cpp GUI/Gizmos/GLGizmoPainterBase.hpp GUI/Gizmos/GLGizmoSimplify.cpp diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index d287113a283..6fae6c4976a 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -3443,14 +3443,14 @@ void GLCanvas3D::on_key(wxKeyEvent& evt) if (keyCode == WXK_SHIFT) { translationProcessor.process(evt); - if (m_picking_enabled && (m_gizmos.get_current_type() != GLGizmosManager::SlaSupports)) + if (m_picking_enabled /*&& (m_gizmos.get_current_type() != GLGizmosManager::SlaSupports)*/) { m_mouse.ignore_left_up = false; // set_cursor(Cross); } } else if (keyCode == WXK_ALT) { - if (m_picking_enabled && (m_gizmos.get_current_type() != GLGizmosManager::SlaSupports)) + if (m_picking_enabled /*&& (m_gizmos.get_current_type() != GLGizmosManager::SlaSupports)*/) { m_mouse.ignore_left_up = false; // set_cursor(Cross); @@ -3994,8 +3994,8 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) // BBS: define Alt key to enable volume selection mode m_selection.set_volume_selection_mode(evt.AltDown() ? Selection::Volume : Selection::Instance); if (evt.LeftDown() && evt.ShiftDown() && m_picking_enabled && m_layers_editing.state != LayersEditing::Editing) { - if (m_gizmos.get_current_type() != GLGizmosManager::SlaSupports - && m_gizmos.get_current_type() != GLGizmosManager::FdmSupports + if (/*m_gizmos.get_current_type() != GLGizmosManager::SlaSupports + &&*/ m_gizmos.get_current_type() != GLGizmosManager::FdmSupports && m_gizmos.get_current_type() != GLGizmosManager::Seam && m_gizmos.get_current_type() != GLGizmosManager::MmuSegmentation) { m_rectangle_selection.start_dragging(m_mouse.position, evt.ShiftDown() ? GLSelectionRectangle::Select : GLSelectionRectangle::Deselect); @@ -4266,7 +4266,7 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) // if right clicking on volume, propagate event through callback (shows context menu) int volume_idx = get_first_hover_volume_idx(); if (!m_volumes.volumes[volume_idx]->is_wipe_tower // no context menu for the wipe tower - && m_gizmos.get_current_type() != GLGizmosManager::SlaSupports) // disable context menu when the gizmo is open + /*&& m_gizmos.get_current_type() != GLGizmosManager::SlaSupports*/) // disable context menu when the gizmo is open { // forces the selection of the volume /* m_selection.add(volume_idx); // #et_FIXME_if_needed @@ -7010,8 +7010,8 @@ void GLCanvas3D::_render_sequential_clearance() { case GLGizmosManager::EType::Flatten: case GLGizmosManager::EType::Cut: - case GLGizmosManager::EType::Hollow: - case GLGizmosManager::EType::SlaSupports: + // case GLGizmosManager::EType::Hollow: + // case GLGizmosManager::EType::SlaSupports: case GLGizmosManager::EType::FdmSupports: case GLGizmosManager::EType::Seam: { return; } default: { break; } diff --git a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp index 8c62f79a863..19a38637517 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp @@ -13,12 +13,12 @@ #include "slic3r/GUI/Gizmos/GLGizmoScale.hpp" #include "slic3r/GUI/Gizmos/GLGizmoRotate.hpp" #include "slic3r/GUI/Gizmos/GLGizmoFlatten.hpp" -#include "slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp" +//#include "slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp" #include "slic3r/GUI/Gizmos/GLGizmoFdmSupports.hpp" // BBS #include "slic3r/GUI/Gizmos/GLGizmoAdvancedCut.hpp" //#include "slic3r/GUI/Gizmos/GLGizmoFaceDetector.hpp" -#include "slic3r/GUI/Gizmos/GLGizmoHollow.hpp" +//#include "slic3r/GUI/Gizmos/GLGizmoHollow.hpp" #include "slic3r/GUI/Gizmos/GLGizmoSeam.hpp" #include "slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.hpp" #include "slic3r/GUI/Gizmos/GLGizmoSimplify.hpp" @@ -445,7 +445,7 @@ void GLGizmosManager::update_data() finish_cut_rotation(); ModelObject* model_object = selection.get_model()->objects[selection.get_object_idx()]; set_flattening_data(model_object); - set_sla_support_data(model_object); + //set_sla_support_data(model_object); set_painter_gizmo_data(); } else if (selection.is_single_volume() || selection.is_single_modifier()) @@ -456,7 +456,7 @@ void GLGizmosManager::update_data() // BBS finish_cut_rotation(); set_flattening_data(nullptr); - set_sla_support_data(nullptr); + //set_sla_support_data(nullptr); set_painter_gizmo_data(); } else if (is_wipe_tower) @@ -465,7 +465,7 @@ void GLGizmosManager::update_data() set_scale(Vec3d::Ones()); set_rotation(Vec3d(0., 0., (M_PI/180.) * dynamic_cast(proj_cfg.option("wipe_tower_rotation_angle"))->value)); set_flattening_data(nullptr); - set_sla_support_data(nullptr); + //set_sla_support_data(nullptr); set_painter_gizmo_data(); } else @@ -473,7 +473,7 @@ void GLGizmosManager::update_data() set_scale(Vec3d::Ones()); set_rotation(Vec3d::Zero()); set_flattening_data(selection.is_from_single_object() ? selection.get_model()->objects[selection.get_object_idx()] : nullptr); - set_sla_support_data(selection.is_from_single_instance() ? selection.get_model()->objects[selection.get_object_idx()] : nullptr); + //set_sla_support_data(selection.is_from_single_instance() ? selection.get_model()->objects[selection.get_object_idx()] : nullptr); set_painter_gizmo_data(); } @@ -603,6 +603,7 @@ void GLGizmosManager::set_flattening_data(const ModelObject* model_object) dynamic_cast(m_gizmos[Flatten].get())->set_flattening_data(model_object); } +/* void GLGizmosManager::set_sla_support_data(ModelObject* model_object) { if (! m_enabled @@ -615,6 +616,7 @@ void GLGizmosManager::set_sla_support_data(ModelObject* model_object) gizmo_hollow->set_sla_support_data(model_object, m_parent.get_selection()); gizmo_supports->set_sla_support_data(model_object, m_parent.get_selection()); } +*/ void GLGizmosManager::set_painter_gizmo_data() { @@ -632,11 +634,11 @@ bool GLGizmosManager::gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_p if (!m_enabled || m_gizmos.empty()) return false; - if (m_current == SlaSupports) + /*if (m_current == SlaSupports) return dynamic_cast(m_gizmos[SlaSupports].get())->gizmo_event(action, mouse_position, shift_down, alt_down, control_down); else if (m_current == Hollow) return dynamic_cast(m_gizmos[Hollow].get())->gizmo_event(action, mouse_position, shift_down, alt_down, control_down); - else if (m_current == FdmSupports) + else*/ if (m_current == FdmSupports) return dynamic_cast(m_gizmos[FdmSupports].get())->gizmo_event(action, mouse_position, shift_down, alt_down, control_down); else if (m_current == Seam) return dynamic_cast(m_gizmos[Seam].get())->gizmo_event(action, mouse_position, shift_down, alt_down, control_down); @@ -678,8 +680,9 @@ ClippingPlane GLGizmosManager::get_assemble_view_clipping_plane() const bool GLGizmosManager::wants_reslice_supports_on_undo() const { - return (m_current == SlaSupports - && dynamic_cast(m_gizmos.at(SlaSupports).get())->has_backend_supports()); + return false; + // return (m_current == SlaSupports + // && dynamic_cast(m_gizmos.at(SlaSupports).get())->has_backend_supports()); } void GLGizmosManager::on_change_color_mode(bool is_dark) { @@ -737,7 +740,7 @@ bool GLGizmosManager::on_mouse_wheel(wxMouseEvent& evt) { bool processed = false; - if (m_current == SlaSupports || m_current == Hollow || m_current == FdmSupports || m_current == Seam || m_current == MmuSegmentation) { + if (/*m_current == SlaSupports || m_current == Hollow ||*/ m_current == FdmSupports || m_current == Seam || m_current == MmuSegmentation) { float rot = (float)evt.GetWheelRotation() / (float)evt.GetWheelDelta(); if (gizmo_event((rot > 0.f ? SLAGizmoEventType::MouseWheelUp : SLAGizmoEventType::MouseWheelDown), Vec2d::Zero(), evt.ShiftDown(), evt.AltDown() // BBS @@ -884,7 +887,7 @@ bool GLGizmosManager::on_mouse(wxMouseEvent& evt) m_tooltip.clear(); if (evt.LeftDown() && (!control_down || grabber_contains_mouse())) { - if ((m_current == SlaSupports || m_current == Hollow || m_current == FdmSupports || + if ((/*m_current == SlaSupports || m_current == Hollow ||*/ m_current == FdmSupports || m_current == Seam || m_current == MmuSegmentation || m_current == Text || m_current == Cut || m_current == MeshBoolean) && gizmo_event(SLAGizmoEventType::LeftDown, mouse_pos, evt.ShiftDown(), evt.AltDown())) // the gizmo got the event and took some action, there is no need to do anything more @@ -908,13 +911,13 @@ bool GLGizmosManager::on_mouse(wxMouseEvent& evt) processed = true; } } - else if (evt.RightDown() && selected_object_idx != -1 && (m_current == SlaSupports || m_current == Hollow) - && gizmo_event(SLAGizmoEventType::RightDown, mouse_pos)) { - // we need to set the following right up as processed to avoid showing the context menu if the user release the mouse over the object - pending_right_up = true; - // event was taken care of by the SlaSupports gizmo - processed = true; - } + //else if (evt.RightDown() && selected_object_idx != -1 && (m_current == SlaSupports || m_current == Hollow) + // && gizmo_event(SLAGizmoEventType::RightDown, mouse_pos)) { + // // we need to set the following right up as processed to avoid showing the context menu if the user release the mouse over the object + // pending_right_up = true; + // // event was taken care of by the SlaSupports gizmo + // processed = true; + //} else if (evt.RightDown() && !control_down && selected_object_idx != -1 && (m_current == FdmSupports || m_current == Seam || m_current == MmuSegmentation || m_current == Cut) && gizmo_event(SLAGizmoEventType::RightDown, mouse_pos)) { @@ -922,11 +925,11 @@ bool GLGizmosManager::on_mouse(wxMouseEvent& evt) processed = true; } else if (evt.Dragging() && m_parent.get_move_volume_id() != -1 - && (m_current == SlaSupports || m_current == Hollow || m_current == FdmSupports || m_current == Seam || m_current == MmuSegmentation)) + && (/*m_current == SlaSupports || m_current == Hollow ||*/ m_current == FdmSupports || m_current == Seam || m_current == MmuSegmentation)) // don't allow dragging objects with the Sla gizmo on processed = true; else if (evt.Dragging() && !control_down - && (m_current == SlaSupports || m_current == Hollow || m_current == FdmSupports || m_current == Seam || m_current == MmuSegmentation || m_current == Cut) + && (/*m_current == SlaSupports || m_current == Hollow ||*/ m_current == FdmSupports || m_current == Seam || m_current == MmuSegmentation || m_current == Cut) && gizmo_event(SLAGizmoEventType::Dragging, mouse_pos, evt.ShiftDown(), evt.AltDown())) { // the gizmo got the event and took some action, no need to do anything more here m_parent.set_as_dirty(); @@ -940,7 +943,7 @@ bool GLGizmosManager::on_mouse(wxMouseEvent& evt) gizmo_event(SLAGizmoEventType::RightUp, mouse_pos, evt.ShiftDown(), evt.AltDown(), true); } else if (evt.LeftUp() - && (m_current == SlaSupports || m_current == Hollow || m_current == FdmSupports || m_current == Seam || m_current == MmuSegmentation || m_current == Cut) + && (/*m_current == SlaSupports || m_current == Hollow ||*/ m_current == FdmSupports || m_current == Seam || m_current == MmuSegmentation || m_current == Cut) && !m_parent.is_mouse_dragging() && gizmo_event(SLAGizmoEventType::LeftUp, mouse_pos, evt.ShiftDown(), evt.AltDown(), control_down)) { // in case SLA/FDM gizmo is selected, we just pass the LeftUp event and stop processing - neither @@ -1038,7 +1041,7 @@ bool GLGizmosManager::on_char(wxKeyEvent& evt) { if (m_current != Undefined) { - if ((m_current != SlaSupports) || !gizmo_event(SLAGizmoEventType::DiscardChanges)) + //if ((m_current != SlaSupports) || !gizmo_event(SLAGizmoEventType::DiscardChanges)) reset_all_states(); processed = true; @@ -1149,7 +1152,7 @@ bool GLGizmosManager::on_key(wxKeyEvent& evt) if (evt.GetEventType() == wxEVT_KEY_UP) { - if (m_current == SlaSupports || m_current == Hollow) + /*if (m_current == SlaSupports || m_current == Hollow) { bool is_editing = true; bool is_rectangle_dragging = false; @@ -1182,20 +1185,20 @@ bool GLGizmosManager::on_key(wxKeyEvent& evt) // capture number key processed = true; } - } + }*/ // if (processed) // m_parent.set_cursor(GLCanvas3D::Standard); } else if (evt.GetEventType() == wxEVT_KEY_DOWN) { - if ((m_current == SlaSupports) && ((keyCode == WXK_SHIFT) || (keyCode == WXK_ALT)) + /*if ((m_current == SlaSupports) && ((keyCode == WXK_SHIFT) || (keyCode == WXK_ALT)) && dynamic_cast(get_current())->is_in_editing_mode()) { // m_parent.set_cursor(GLCanvas3D::Cross); processed = true; } - else if (m_current == Cut) + else*/ if (m_current == Cut) { // BBS #if 0 @@ -1265,9 +1268,9 @@ void GLGizmosManager::update_after_undo_redo(const UndoRedo::Snapshot& snapshot) { update_data(); m_serializing = false; - if (m_current == SlaSupports - && snapshot.snapshot_data.flags & UndoRedo::SnapshotData::RECALCULATE_SLA_SUPPORTS) - dynamic_cast(m_gizmos[SlaSupports].get())->reslice_SLA_supports(true); + // if (m_current == SlaSupports + // && snapshot.snapshot_data.flags & UndoRedo::SnapshotData::RECALCULATE_SLA_SUPPORTS) + // dynamic_cast(m_gizmos[SlaSupports].get())->reslice_SLA_supports(true); } void GLGizmosManager::render_background(float left, float top, float right, float bottom, float border_w, float border_h) const @@ -1637,11 +1640,11 @@ bool GLGizmosManager::grabber_contains_mouse() const bool GLGizmosManager::is_in_editing_mode(bool error_notification) const { - if (m_current != SlaSupports || ! dynamic_cast(get_current())->is_in_editing_mode()) + //if (m_current != SlaSupports || ! dynamic_cast(get_current())->is_in_editing_mode()) return false; // BBS: remove SLA editing notification - return true; + //return true; } diff --git a/src/slic3r/GUI/Gizmos/GLGizmosManager.hpp b/src/slic3r/GUI/Gizmos/GLGizmosManager.hpp index 039cc74cfe0..02a88e61575 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosManager.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosManager.hpp @@ -85,10 +85,10 @@ class GLGizmosManager : public Slic3r::ObjectBase Text, MmuSegmentation, Simplify, - SlaSupports, + //SlaSupports, // BBS //FaceRecognition, - Hollow, + //Hollow, Undefined, }; @@ -279,7 +279,7 @@ class GLGizmosManager : public Slic3r::ObjectBase void set_flattening_data(const ModelObject* model_object); - void set_sla_support_data(ModelObject* model_object); + //void set_sla_support_data(ModelObject* model_object); void set_painter_gizmo_data(); From 30af274d447038c35bf88f10931ebc8cce3101db Mon Sep 17 00:00:00 2001 From: Filip Sykala Date: Sun, 29 Oct 2023 22:08:21 +0800 Subject: [PATCH 76/99] Separate GizmoManager on_move into gizmo itself (cherry picked from commit prusa3d/PrusaSlicer@c751d6327db9da594c1f96f27d7df96cf7b5df6a) --- src/slic3r/GUI/GLCanvas3D.cpp | 9 - src/slic3r/GUI/GLCanvas3D.hpp | 1 - src/slic3r/GUI/GUI_App.cpp | 6 + src/slic3r/GUI/GUI_App.hpp | 2 + src/slic3r/GUI/Gizmos/GLGizmoAdvancedCut.cpp | 4 +- src/slic3r/GUI/Gizmos/GLGizmoAdvancedCut.hpp | 22 +- src/slic3r/GUI/Gizmos/GLGizmoBase.cpp | 77 ++- src/slic3r/GUI/Gizmos/GLGizmoBase.hpp | 14 +- src/slic3r/GUI/Gizmos/GLGizmoFlatten.cpp | 79 +--- src/slic3r/GUI/Gizmos/GLGizmoFlatten.hpp | 28 +- src/slic3r/GUI/Gizmos/GLGizmoMeshBoolean.cpp | 21 + src/slic3r/GUI/Gizmos/GLGizmoMeshBoolean.hpp | 11 +- src/slic3r/GUI/Gizmos/GLGizmoMove.cpp | 26 +- src/slic3r/GUI/Gizmos/GLGizmoMove.hpp | 27 +- src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp | 101 ++++ src/slic3r/GUI/Gizmos/GLGizmoPainterBase.hpp | 12 +- src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp | 45 +- src/slic3r/GUI/Gizmos/GLGizmoRotate.hpp | 24 +- src/slic3r/GUI/Gizmos/GLGizmoScale.cpp | 52 +- src/slic3r/GUI/Gizmos/GLGizmoScale.hpp | 13 +- src/slic3r/GUI/Gizmos/GLGizmoText.cpp | 4 +- src/slic3r/GUI/Gizmos/GLGizmoText.hpp | 2 +- src/slic3r/GUI/Gizmos/GLGizmosManager.cpp | 469 +++++-------------- src/slic3r/GUI/Gizmos/GLGizmosManager.hpp | 39 +- 24 files changed, 557 insertions(+), 531 deletions(-) diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 6fae6c4976a..b492d235432 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -4667,15 +4667,6 @@ void GLCanvas3D::do_scale(const std::string& snapshot_type) m_dirty = true; } -void GLCanvas3D::do_flatten(const Vec3d& normal, const std::string& snapshot_type) -{ - if (!snapshot_type.empty()) - wxGetApp().plater()->take_snapshot(snapshot_type); - - m_selection.flattening_rotate(normal); - do_rotate(""); // avoid taking another snapshot -} - void GLCanvas3D::do_center() { if (m_model == nullptr) diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp index 54c033ebef3..b1f73fefab0 100644 --- a/src/slic3r/GUI/GLCanvas3D.hpp +++ b/src/slic3r/GUI/GLCanvas3D.hpp @@ -957,7 +957,6 @@ class GLCanvas3D void do_move(const std::string& snapshot_type); void do_rotate(const std::string& snapshot_type); void do_scale(const std::string& snapshot_type); - void do_flatten(const Vec3d& normal, const std::string& snapshot_type); void do_center(); void do_mirror(const std::string& snapshot_type); diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp index 3e6b699878c..a6847b00fd5 100644 --- a/src/slic3r/GUI/GUI_App.cpp +++ b/src/slic3r/GUI/GUI_App.cpp @@ -5858,6 +5858,12 @@ Sidebar& GUI_App::sidebar() return plater_->sidebar(); } +GizmoObjectManipulation *GUI_App::obj_manipul() +{ + // If this method is called before plater_ has been initialized, return nullptr (to avoid a crash) + return (plater_ != nullptr) ? &plater_->get_view3D_canvas3D()->get_gizmos_manager().get_object_manipulation() : nullptr; +} + ObjectSettings* GUI_App::obj_settings() { return sidebar().obj_settings(); diff --git a/src/slic3r/GUI/GUI_App.hpp b/src/slic3r/GUI/GUI_App.hpp index 44411b361c6..d72a217b93c 100644 --- a/src/slic3r/GUI/GUI_App.hpp +++ b/src/slic3r/GUI/GUI_App.hpp @@ -129,6 +129,7 @@ enum CameraMenuIDs { class Tab; class ConfigWizard; +class GizmoObjectManipulation; static wxString dots("...", wxConvUTF8); @@ -529,6 +530,7 @@ class GUI_App : public wxApp #endif /* __APPLE */ Sidebar& sidebar(); + GizmoObjectManipulation* obj_manipul(); ObjectSettings* obj_settings(); ObjectList* obj_list(); ObjectLayers* obj_layers(); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoAdvancedCut.cpp b/src/slic3r/GUI/Gizmos/GLGizmoAdvancedCut.cpp index a7851318a6c..b3aa8ef8706 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoAdvancedCut.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoAdvancedCut.cpp @@ -434,9 +434,9 @@ void GLGizmoAdvancedCut::on_stop_dragging() } } -void GLGizmoAdvancedCut::on_update(const UpdateData& data) +void GLGizmoAdvancedCut::on_dragging(const UpdateData &data) { - GLGizmoRotate3D::on_update(data); + GLGizmoRotate3D::on_dragging(data); Vec3d rotation; for (int i = 0; i < 3; i++) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoAdvancedCut.hpp b/src/slic3r/GUI/Gizmos/GLGizmoAdvancedCut.hpp index a61fcdc1e1d..007a95e62e3 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoAdvancedCut.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoAdvancedCut.hpp @@ -139,17 +139,17 @@ struct Rotate_data { virtual bool apply_clipping_plane() { return m_connectors_editing; } protected: - virtual bool on_init(); - virtual void on_load(cereal::BinaryInputArchive &ar) override; - virtual void on_save(cereal::BinaryOutputArchive &ar) const override; - virtual std::string on_get_name() const; - virtual void on_set_state(); - virtual bool on_is_activable() const; - virtual CommonGizmosDataID on_get_requirements() const override; - virtual void on_start_dragging() override; - virtual void on_stop_dragging() override; - virtual void on_update(const UpdateData& data); - virtual void on_render(); + bool on_init() override; + void on_load(cereal::BinaryInputArchive &ar) override; + void on_save(cereal::BinaryOutputArchive &ar) const override; + std::string on_get_name() const override; + void on_set_state() override; + bool on_is_activable() const override; + CommonGizmosDataID on_get_requirements() const override; + void on_start_dragging() override; + void on_stop_dragging() override; + void on_dragging(const UpdateData& data) override; + void on_render() override; virtual void on_render_input_window(float x, float y, float bottom_limit); void show_tooltip_information(float x, float y); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoBase.cpp b/src/slic3r/GUI/Gizmos/GLGizmoBase.cpp index 6b3eede5c39..8d59ea819af 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoBase.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoBase.cpp @@ -211,10 +211,15 @@ void GLGizmoBase::set_icon_filename(const std::string &filename) { void GLGizmoBase::set_hover_id(int id) { - if (m_grabbers.empty() || id < (int)m_grabbers.size()) { - m_hover_id = id; - on_set_hover_id(); - } + // do not change hover id during dragging + if (m_dragging) return; + + // allow empty grabbers when not using grabbers but use hover_id - flatten, rotate + if (!m_grabbers.empty() && id >= (int) m_grabbers.size()) + return; + + m_hover_id = id; + on_set_hover_id(); } @@ -260,18 +265,12 @@ void GLGizmoBase::stop_dragging() //BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format("this %1%, m_hover_id=%2%\n")%this %m_hover_id; } -void GLGizmoBase::update(const UpdateData& data) -{ - if (m_hover_id != -1) - on_update(data); -} - bool GLGizmoBase::update_items_state() { bool res = m_dirty; m_dirty = false; return res; -}; +} bool GLGizmoBase::GizmoImguiBegin(const std::string &name, int flags) { @@ -345,6 +344,62 @@ void GLGizmoBase::render_grabbers(float size) const shader->stop_using(); } +// help function to process grabbers +// call start_dragging, stop_dragging, on_dragging +bool GLGizmoBase::use_grabbers(const wxMouseEvent &mouse_event) { + if (mouse_event.Moving()) { + assert(!m_dragging); + // only for sure + if (m_dragging) m_dragging = false; + + return false; + } + if (mouse_event.LeftDown()) { + Selection &selection = m_parent.get_selection(); + if (!selection.is_empty() && m_hover_id != -1) { + selection.start_dragging(); + + start_dragging(); + + // Let the plater know that the dragging started + m_parent.post_event( + SimpleEvent(EVT_GLCANVAS_MOUSE_DRAGGING_STARTED)); + m_parent.set_as_dirty(); + return true; + } + } else if (m_dragging) { + if (mouse_event.Dragging()) { + m_parent.set_mouse_as_dragging(); + + Point mouse_coord(mouse_event.GetX(), mouse_event.GetY()); + UpdateData data{m_parent.mouse_ray(mouse_coord), mouse_coord}; + + on_dragging(data); + + wxGetApp().obj_manipul()->set_dirty(); + m_parent.set_as_dirty(); + return true; + } else if (mouse_event.LeftUp()) { + stop_dragging(); + + m_parent.get_gizmos_manager().update_data(); + wxGetApp().obj_manipul()->set_dirty(); + + // Let the plater know that the dragging finished, so a delayed + // refresh of the scene with the background processing data should + // be performed. + m_parent.post_event( + SimpleEvent(EVT_GLCANVAS_MOUSE_DRAGGING_FINISHED)); + // updates camera target constraints + m_parent.refresh_camera_scene_box(); + return true; + } else if (mouse_event.Leaving()) { + m_dragging = false; + } + } + return false; +} + std::string GLGizmoBase::format(float value, unsigned int decimals) const { return Slic3r::string_printf("%.*f", decimals, value); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoBase.hpp b/src/slic3r/GUI/Gizmos/GLGizmoBase.hpp index e58eaee6beb..8094d36f553 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoBase.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoBase.hpp @@ -199,8 +199,6 @@ class GLGizmoBase bool is_dragging() const { return m_dragging; } - void update(const UpdateData& data); - // returns True when Gizmo changed its state bool update_items_state(); @@ -237,9 +235,12 @@ class GLGizmoBase virtual CommonGizmosDataID on_get_requirements() const { return CommonGizmosDataID(0); } virtual void on_enable_grabber(unsigned int id) {} virtual void on_disable_grabber(unsigned int id) {} + + // called inside use_grabbers virtual void on_start_dragging() {} virtual void on_stop_dragging() {} - virtual void on_update(const UpdateData& data) {} + virtual void on_dragging(const UpdateData& data) {} + virtual void on_render() = 0; virtual void on_render_input_window(float x, float y, float bottom_limit) {} @@ -262,6 +263,13 @@ class GLGizmoBase // Mark gizmo as dirty to Re-Render when idle() void set_dirty(); + + /// + /// + /// + /// + /// + bool use_grabbers(const wxMouseEvent &mouse_event); private: // Flag for dirty visible state of Gizmo // When True then need new rendering diff --git a/src/slic3r/GUI/Gizmos/GLGizmoFlatten.cpp b/src/slic3r/GUI/Gizmos/GLGizmoFlatten.cpp index 6b44af03d8e..2b2b73a1951 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoFlatten.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoFlatten.cpp @@ -18,9 +18,32 @@ namespace GUI { GLGizmoFlatten::GLGizmoFlatten(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id) : GLGizmoBase(parent, icon_filename, sprite_id) - , m_normal(Vec3d::Zero()) - , m_starting_center(Vec3d::Zero()) +{} + +bool GLGizmoFlatten::on_mouse(const wxMouseEvent &mouse_event) { + if (mouse_event.Moving()) { + // only for sure + m_mouse_left_down = false; + + if (m_hover_id != -1) m_parent.set_as_dirty(); + return false; + } + if (mouse_event.LeftDown() && m_hover_id != -1) { + Selection &selection = m_parent.get_selection(); + if (selection.is_single_full_instance()) { + // Rotate the object so the normal points downward: + selection.flattening_rotate(m_planes[m_hover_id].normal); + m_parent.do_rotate(L("Gizmo-Place on Face")); + } + m_mouse_left_down = true; + return true; + } else if (m_mouse_left_down && mouse_event.LeftUp()) { + // responsible for mouse left up + m_mouse_left_down = false; + return true; + } + return false; } bool GLGizmoFlatten::on_init() @@ -51,15 +74,6 @@ bool GLGizmoFlatten::on_is_activable() const return m_parent.get_selection().is_single_full_instance(); } -void GLGizmoFlatten::on_start_dragging() -{ - if (m_hover_id != -1) { - assert(m_planes_valid); - m_normal = m_planes[m_hover_id].normal; - m_starting_center = m_parent.get_selection().get_bounding_box().center(); - } -} - void GLGizmoFlatten::on_render() { const Selection& selection = m_parent.get_selection(); @@ -121,43 +135,8 @@ void GLGizmoFlatten::on_unregister_raycasters_for_picking() m_planes_casters.clear(); } -/* -void GLGizmoFlatten::on_render_for_picking() -{ - const Selection& selection = m_parent.get_selection(); - GLShaderProgram* shader = wxGetApp().get_shader("flat"); - if (shader == nullptr) - return; - - shader->start_using(); - - glsafe(::glDisable(GL_DEPTH_TEST)); - glsafe(::glDisable(GL_BLEND)); - - if (selection.is_single_full_instance() && !wxGetKeyState(WXK_CONTROL)) { - const Transform3d& m = selection.get_volume(*selection.get_volume_idxs().begin())->get_instance_transformation().get_matrix(); - const Camera& camera = wxGetApp().plater()->get_camera(); - const Transform3d view_model_matrix = camera.get_view_matrix() * - Geometry::assemble_transform(selection.get_volume(*selection.get_volume_idxs().begin())->get_sla_shift_z() * Vec3d::UnitZ()) * m; - - shader->set_uniform("view_model_matrix", view_model_matrix); - shader->set_uniform("projection_matrix", camera.get_projection_matrix()); - if (this->is_plane_update_necessary()) - update_planes(); - for (int i = 0; i < (int)m_planes.size(); ++i) { - m_planes[i].vbo.set_color(picking_color_component(i)); - m_planes[i].vbo.render(); - } - } - - glsafe(::glEnable(GL_CULL_FACE)); - shader->stop_using(); -} -*/ - void GLGizmoFlatten::set_flattening_data(const ModelObject* model_object) { - m_starting_center = Vec3d::Zero(); if (model_object != m_old_model_object) { m_planes.clear(); on_unregister_raycasters_for_picking(); @@ -414,13 +393,5 @@ bool GLGizmoFlatten::is_plane_update_necessary() const return false; } -Vec3d GLGizmoFlatten::get_flattening_normal() const -{ - Vec3d out = m_normal; - m_normal = Vec3d::Zero(); - m_starting_center = Vec3d::Zero(); - return out; -} - } // namespace GUI } // namespace Slic3r diff --git a/src/slic3r/GUI/Gizmos/GLGizmoFlatten.hpp b/src/slic3r/GUI/Gizmos/GLGizmoFlatten.hpp index 73c5d326244..54d931577da 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoFlatten.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoFlatten.hpp @@ -18,7 +18,6 @@ class GLGizmoFlatten : public GLGizmoBase // This gizmo does not use grabbers. The m_hover_id relates to polygon managed by the class itself. private: - mutable Vec3d m_normal; struct PlaneData { std::vector vertices; // should be in fact local in update_planes() @@ -36,7 +35,7 @@ class GLGizmoFlatten : public GLGizmoBase std::vector m_planes; std::vector> m_planes_casters; - mutable Vec3d m_starting_center; + bool m_mouse_left_down = false; const ModelObject* m_old_model_object = nullptr; std::vector instances_matrices; @@ -47,18 +46,23 @@ class GLGizmoFlatten : public GLGizmoBase GLGizmoFlatten(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id); void set_flattening_data(const ModelObject* model_object); - Vec3d get_flattening_normal() const; + + /// + /// Apply rotation on select plane + /// + /// Keep information about mouse click + /// Return True when use the information otherwise False. + bool on_mouse(const wxMouseEvent &mouse_event) override; protected: - virtual bool on_init() override; - virtual std::string on_get_name() const override; - virtual bool on_is_activable() const override; - virtual void on_start_dragging() override; - virtual void on_render() override; - virtual void on_register_raycasters_for_picking() override; - virtual void on_unregister_raycasters_for_picking() override; - virtual void on_set_state() override; - virtual CommonGizmosDataID on_get_requirements() const override; + bool on_init() override; + std::string on_get_name() const override; + bool on_is_activable() const override; + void on_render() override; + void on_register_raycasters_for_picking() override; + void on_unregister_raycasters_for_picking() override; + void on_set_state() override; + CommonGizmosDataID on_get_requirements() const override; }; } // namespace GUI diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeshBoolean.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeshBoolean.cpp index df9def7ab47..fb19ff64592 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeshBoolean.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeshBoolean.cpp @@ -84,6 +84,27 @@ bool GLGizmoMeshBoolean::gizmo_event(SLAGizmoEventType action, const Vec2d& mous return true; } +bool GLGizmoMeshBoolean::on_mouse(const wxMouseEvent &mouse_event) +{ + // wxCoord == int --> wx/types.h + Vec2i mouse_coord(mouse_event.GetX(), mouse_event.GetY()); + Vec2d mouse_pos = mouse_coord.cast(); + + // when control is down we allow scene pan and rotation even when clicking + // over some object + bool control_down = mouse_event.CmdDown(); + bool grabber_contains_mouse = (get_hover_id() != -1); + if (mouse_event.LeftDown()) { + if ((!control_down || grabber_contains_mouse) && + gizmo_event(SLAGizmoEventType::LeftDown, mouse_pos, mouse_event.ShiftDown(), mouse_event.AltDown(), false)) + // the gizmo got the event and took some action, there is no need + // to do anything more + return true; + } + + return false; +} + bool GLGizmoMeshBoolean::on_init() { m_shortcut_key = WXK_CONTROL_B; diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeshBoolean.hpp b/src/slic3r/GUI/Gizmos/GLGizmoMeshBoolean.hpp index f88ac85c976..c012a68dca8 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeshBoolean.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeshBoolean.hpp @@ -55,7 +55,16 @@ class GLGizmoMeshBoolean : public GLGizmoBase m_src.reset(); } - bool gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_position, bool shift_down, bool alt_down, bool control_down); + bool gizmo_event(SLAGizmoEventType action, const Vec2d &mouse_position, bool shift_down, bool alt_down, bool control_down); + + /// + /// Implement when want to process mouse events in gizmo + /// Click, Right click, move, drag, ... + /// + /// Keep information about mouse click + /// Return True when use the information and don't want to + /// propagate it otherwise False. + bool on_mouse(const wxMouseEvent &mouse_event) override; protected: virtual bool on_init() override; diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMove.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMove.cpp index 1925cd7fa5e..63857189cd1 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMove.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMove.cpp @@ -43,6 +43,10 @@ std::string GLGizmoMove3D::get_tooltip() const return ""; } +bool GLGizmoMove3D::on_mouse(const wxMouseEvent &mouse_event) { + return use_grabbers(mouse_event); +} + bool GLGizmoMove3D::on_init() { for (int i = 0; i < 3; ++i) { @@ -70,22 +74,23 @@ bool GLGizmoMove3D::on_is_activable() const void GLGizmoMove3D::on_start_dragging() { - if (m_hover_id != -1) { - m_displacement = Vec3d::Zero(); - const BoundingBoxf3& box = m_parent.get_selection().get_bounding_box(); - m_starting_drag_position = m_grabbers[m_hover_id].center; - m_starting_box_center = box.center(); - m_starting_box_bottom_center = box.center(); - m_starting_box_bottom_center(2) = box.min(2); - } + assert(m_hover_id != -1); + + m_displacement = Vec3d::Zero(); + const BoundingBoxf3& box = m_parent.get_selection().get_bounding_box(); + m_starting_drag_position = m_grabbers[m_hover_id].center; + m_starting_box_center = box.center(); + m_starting_box_bottom_center = box.center(); + m_starting_box_bottom_center(2) = box.min(2); } void GLGizmoMove3D::on_stop_dragging() { + m_parent.do_move(L("Gizmo-Move")); m_displacement = Vec3d::Zero(); } -void GLGizmoMove3D::on_update(const UpdateData& data) +void GLGizmoMove3D::on_dragging(const UpdateData& data) { if (m_hover_id == 0) m_displacement.x() = calc_projection(data); @@ -93,6 +98,9 @@ void GLGizmoMove3D::on_update(const UpdateData& data) m_displacement.y() = calc_projection(data); else if (m_hover_id == 2) m_displacement.z() = calc_projection(data); + + Selection &selection = m_parent.get_selection(); + selection.translate(m_displacement); } void GLGizmoMove3D::on_render() diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMove.hpp b/src/slic3r/GUI/Gizmos/GLGizmoMove.hpp index c9623488485..bbe88f5942f 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMove.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMove.hpp @@ -40,20 +40,25 @@ class GLGizmoMove3D : public GLGizmoBase double get_snap_step(double step) const { return m_snap_step; } void set_snap_step(double step) { m_snap_step = step; } - const Vec3d& get_displacement() const { return m_displacement; } - std::string get_tooltip() const override; + /// + /// Postpone to Grabber for move + /// + /// Keep information about mouse click + /// Return True when use the information otherwise False. + bool on_mouse(const wxMouseEvent &mouse_event) override; + protected: - virtual bool on_init() override; - virtual std::string on_get_name() const override; - virtual bool on_is_activable() const override; - virtual void on_start_dragging() override; - virtual void on_stop_dragging() override; - virtual void on_update(const UpdateData& data) override; - virtual void on_render() override; - virtual void on_register_raycasters_for_picking() override; - virtual void on_unregister_raycasters_for_picking() override; + bool on_init() override; + std::string on_get_name() const override; + bool on_is_activable() const override; + void on_start_dragging() override; + void on_stop_dragging() override; + void on_dragging(const UpdateData& data) override; + void on_render() override; + void on_register_raycasters_for_picking() override; + void on_unregister_raycasters_for_picking() override; //BBS: GUI refactor: add object manipulation virtual void on_render_input_window(float x, float y, float bottom_limit); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp b/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp index 4afaf06b492..c9daac5797e 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp @@ -900,7 +900,108 @@ bool GLGizmoPainterBase::gizmo_event(SLAGizmoEventType action, const Vec2d& mous return false; } +bool GLGizmoPainterBase::on_mouse(const wxMouseEvent &mouse_event) +{ + // TODO: distribute implementation into gizmos itself + + GLGizmosManager & mng = m_parent.get_gizmos_manager(); + GLGizmosManager::EType current_type = mng.get_current_type(); + + // wxCoord == int --> wx/types.h + Vec2i mouse_coord(mouse_event.GetX(), mouse_event.GetY()); + Vec2d mouse_pos = mouse_coord.cast(); + + if (mouse_event.Moving()) { + if (current_type == GLGizmosManager::MmuSegmentation || + current_type == GLGizmosManager::FdmSupports || + current_type == GLGizmosManager::Text) + gizmo_event(SLAGizmoEventType::Moving, mouse_pos, + mouse_event.ShiftDown(), mouse_event.AltDown(), + false); + } + + // when control is down we allow scene pan and rotation even when clicking + // over some object + bool control_down = mouse_event.CmdDown(); + bool grabber_contains_mouse = (get_hover_id() != -1); + + const Selection &selection = m_parent.get_selection(); + int selected_object_idx = selection.get_object_idx(); + if (mouse_event.LeftDown() && (!control_down || grabber_contains_mouse)) { + if ((current_type == GLGizmosManager::FdmSupports || + current_type == GLGizmosManager::Seam || + current_type == GLGizmosManager::MmuSegmentation || + current_type == GLGizmosManager::Text || + current_type == GLGizmosManager::Cut || + current_type == GLGizmosManager::MeshBoolean) && + gizmo_event(SLAGizmoEventType::LeftDown, mouse_pos, + mouse_event.ShiftDown(), mouse_event.AltDown(), false)) + // the gizmo got the event and took some action, there is no need + // to do anything more + return true; + } else if (mouse_event.RightDown() && !control_down && selected_object_idx != -1 && + (current_type == GLGizmosManager::FdmSupports || + current_type == GLGizmosManager::Seam || + current_type == GLGizmosManager::MmuSegmentation || + current_type == GLGizmosManager::Cut) && + gizmo_event(SLAGizmoEventType::RightDown, mouse_pos, false, false, false)) { + // event was taken care of by the FdmSupports / Seam / MMUPainting / Cut gizmo + return true; + } else if (mouse_event.Dragging() && + m_parent.get_move_volume_id() != -1 && + (current_type == GLGizmosManager::FdmSupports || + current_type == GLGizmosManager::Seam || + current_type == GLGizmosManager::MmuSegmentation)) + // don't allow dragging objects with the Sla gizmo on + return true; + else if (mouse_event.Dragging() && !control_down && + (current_type == GLGizmosManager::FdmSupports || + current_type == GLGizmosManager::Seam || + current_type == GLGizmosManager::MmuSegmentation || + current_type == GLGizmosManager::Cut) && + gizmo_event(SLAGizmoEventType::Dragging, mouse_pos, + mouse_event.ShiftDown(), mouse_event.AltDown(), false)) { + // the gizmo got the event and took some action, no need to do + // anything more here + m_parent.set_as_dirty(); + return true; + } else if (mouse_event.Dragging() && control_down && + (mouse_event.LeftIsDown() || mouse_event.RightIsDown())) { + // CTRL has been pressed while already dragging -> stop current action + if (mouse_event.LeftIsDown()) + gizmo_event(SLAGizmoEventType::LeftUp, mouse_pos, + mouse_event.ShiftDown(), mouse_event.AltDown(), true); + else if (mouse_event.RightIsDown()) + gizmo_event(SLAGizmoEventType::RightUp, mouse_pos, + mouse_event.ShiftDown(), mouse_event.AltDown(), true); + + } else if (mouse_event.LeftUp() && + (current_type == GLGizmosManager::FdmSupports || + current_type == GLGizmosManager::Seam || + current_type == GLGizmosManager::MmuSegmentation || + current_type == GLGizmosManager::Cut) && + !m_parent.is_mouse_dragging()) { + // in case SLA/FDM gizmo is selected, we just pass the LeftUp event + // and stop processing - neither object moving or selecting is + // suppressed in that case + gizmo_event(SLAGizmoEventType::LeftUp, mouse_pos, + mouse_event.ShiftDown(), mouse_event.AltDown(), + control_down); + return true; + } else if (mouse_event.RightUp() && + (current_type == GLGizmosManager::FdmSupports || + current_type == GLGizmosManager::Seam || + current_type == GLGizmosManager::MmuSegmentation || + current_type == GLGizmosManager::Cut) && + !m_parent.is_mouse_dragging()) { + gizmo_event(SLAGizmoEventType::RightUp, mouse_pos, + mouse_event.ShiftDown(), mouse_event.AltDown(), + control_down); + return true; + } + return false; +} void GLGizmoPainterBase::update_raycast_cache(const Vec2d& mouse_position, const Camera& camera, diff --git a/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.hpp b/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.hpp index cd397ab4e21..15f7c1868d3 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.hpp @@ -206,6 +206,15 @@ class GLGizmoPainterBase : public GLGizmoBase virtual const float get_cursor_height_max() const { return CursorHeightMax; } virtual const float get_cursor_height_step() const { return CursorHeightStep; } + /// + /// Implement when want to process mouse events in gizmo + /// Click, Right click, move, drag, ... + /// + /// Keep information about mouse click + /// Return True when use the information and don't want to + /// propagate it otherwise False. + bool on_mouse(const wxMouseEvent &mouse_event) override; + protected: virtual void render_triangles(const Selection& selection) const; void render_cursor(); @@ -349,9 +358,6 @@ class GLGizmoPainterBase : public GLGizmoBase protected: void on_set_state() override; - void on_start_dragging() override {} - void on_stop_dragging() override {} - virtual void on_opening() = 0; virtual void on_shutdown() = 0; virtual PainterGizmoType get_painter_type() const = 0; diff --git a/src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp b/src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp index e6a2dd6973b..6bc7cbaa5a3 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp @@ -51,6 +51,13 @@ std::string GLGizmoRotate::get_tooltip() const return (m_hover_id == 0 || m_grabbers.front().dragging) ? axis + ": " + format(float(Geometry::rad2deg(m_angle)), 2) : ""; } +bool GLGizmoRotate::on_mouse(const wxMouseEvent &mouse_event) +{ + return use_grabbers(mouse_event); +} + +void GLGizmoRotate::dragging(const UpdateData &data) { on_dragging(data); } + bool GLGizmoRotate::on_init() { m_grabbers.push_back(Grabber()); @@ -69,7 +76,7 @@ void GLGizmoRotate::on_start_dragging() m_snap_fine_out_radius = m_snap_fine_in_radius + m_radius * ScaleLongTooth; } -void GLGizmoRotate::on_update(const UpdateData& data) +void GLGizmoRotate::on_dragging(const UpdateData &data) { const Vec2d mouse_pos = to_2d(mouse_position_in_local_plane(data.mouse_ray, m_parent.get_selection())); @@ -456,16 +463,25 @@ GLGizmoRotate3D::GLGizmoRotate3D(GLCanvas3D& parent, const std::string& icon_fil load_rotoptimize_state(); } +bool GLGizmoRotate3D::on_mouse(const wxMouseEvent &mouse_event) { + + if (mouse_event.Dragging() && m_dragging) { + // Apply new temporary rotations + TransformationType transformation_type( + TransformationType::World_Relative_Joint); + if (mouse_event.AltDown()) transformation_type.set_independent(); + m_parent.get_selection().rotate(get_rotation(), transformation_type); + } + return use_grabbers(mouse_event); +} + bool GLGizmoRotate3D::on_init() { - for (GLGizmoRotate& g : m_gizmos) { - if (!g.init()) - return false; - } + for (GLGizmoRotate& g : m_gizmos) + if (!g.init()) return false; - for (unsigned int i = 0; i < 3; ++i) { + for (unsigned int i = 0; i < 3; ++i) m_gizmos[i].set_highlight_color(AXES_COLOR[i]); - } m_shortcut_key = WXK_CONTROL_R; @@ -486,14 +502,21 @@ bool GLGizmoRotate3D::on_is_activable() const void GLGizmoRotate3D::on_start_dragging() { - if (0 <= m_hover_id && m_hover_id < 3) - m_gizmos[m_hover_id].start_dragging(); + assert(0 <= m_hover_id && m_hover_id < 3); + m_gizmos[m_hover_id].start_dragging(); } void GLGizmoRotate3D::on_stop_dragging() { - if (0 <= m_hover_id && m_hover_id < 3) - m_gizmos[m_hover_id].stop_dragging(); + assert(0 <= m_hover_id && m_hover_id < 3); + m_parent.do_rotate(L("Gizmo-Rotate")); + m_gizmos[m_hover_id].stop_dragging(); +} + +void GLGizmoRotate3D::on_dragging(const UpdateData &data) +{ + assert(0 <= m_hover_id && m_hover_id < 3); + m_gizmos[m_hover_id].dragging(data); } void GLGizmoRotate3D::on_render() diff --git a/src/slic3r/GUI/Gizmos/GLGizmoRotate.hpp b/src/slic3r/GUI/Gizmos/GLGizmoRotate.hpp index cc00409c008..acd2c2876e3 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoRotate.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoRotate.hpp @@ -66,11 +66,19 @@ class GLGizmoRotate : public GLGizmoBase void set_center(const Vec3d &point) { m_custom_center = point; } + /// + /// Postpone to Grabber for move + /// Detect move of object by dragging + /// + /// Keep information about mouse click + /// Return True when use the information otherwise False. + bool on_mouse(const wxMouseEvent &mouse_event) override; + void dragging(const UpdateData &data); protected: bool on_init() override; std::string on_get_name() const override { return ""; } void on_start_dragging() override; - void on_update(const UpdateData& data) override; + void on_dragging(const UpdateData &data) override; void on_render() override; private: @@ -121,6 +129,13 @@ class GLGizmoRotate3D : public GLGizmoBase m_gizmos[Z].set_center(point); } + /// + /// Postpone to Rotation + /// + /// Keep information about mouse click + /// Return True when use the information otherwise False. + bool on_mouse(const wxMouseEvent &mouse_event) override; + protected: bool on_init() override; std::string on_get_name() const override; @@ -143,11 +158,8 @@ class GLGizmoRotate3D : public GLGizmoBase bool on_is_activable() const override; void on_start_dragging() override; void on_stop_dragging() override; - void on_update(const UpdateData& data) override { - for (GLGizmoRotate& g : m_gizmos) { - g.update(data); - } - } + void on_dragging(const UpdateData &data) override; + void on_render() override; virtual void on_register_raycasters_for_picking() override; virtual void on_unregister_raycasters_for_picking() override; diff --git a/src/slic3r/GUI/Gizmos/GLGizmoScale.cpp b/src/slic3r/GUI/Gizmos/GLGizmoScale.cpp index f6bbf4c5231..6215e715253 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoScale.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoScale.cpp @@ -74,6 +74,23 @@ void GLGizmoScale3D::enable_ununiversal_scale(bool enable) m_grabbers[i].enabled = enable; } +bool GLGizmoScale3D::on_mouse(const wxMouseEvent &mouse_event) +{ + if (mouse_event.Dragging()) { + if (m_dragging) { + // Apply new temporary scale factors + TransformationType transformation_type(TransformationType::Local_Absolute_Joint); + if (mouse_event.AltDown()) transformation_type.set_independent(); + + Selection &selection = m_parent.get_selection(); + selection.scale(get_scale(), transformation_type); + if (mouse_event.CmdDown()) selection.translate(m_offset, true); + } + } + return use_grabbers(mouse_event); +} + + bool GLGizmoScale3D::on_init() { for (int i = 0; i < 10; ++i) { @@ -110,24 +127,27 @@ bool GLGizmoScale3D::on_is_activable() const void GLGizmoScale3D::on_start_dragging() { - if (m_hover_id != -1) { - m_starting.drag_position = m_grabbers[m_hover_id].center; - m_starting.plane_center = m_grabbers[4].center; - m_starting.plane_nromal = m_grabbers[5].center - m_grabbers[4].center; - m_starting.ctrl_down = wxGetKeyState(WXK_CONTROL); - m_starting.box = (m_starting.ctrl_down && (m_hover_id < 6)) ? m_box : m_parent.get_selection().get_bounding_box(); - - const Vec3d& center = m_starting.box.center(); - m_starting.pivots[0] = m_transform * Vec3d(m_starting.box.max.x(), center.y(), center.z()); - m_starting.pivots[1] = m_transform * Vec3d(m_starting.box.min.x(), center.y(), center.z()); - m_starting.pivots[2] = m_transform * Vec3d(center.x(), m_starting.box.max.y(), center.z()); - m_starting.pivots[3] = m_transform * Vec3d(center.x(), m_starting.box.min.y(), center.z()); - m_starting.pivots[4] = m_transform * Vec3d(center.x(), center.y(), m_starting.box.max.z()); - m_starting.pivots[5] = m_transform * Vec3d(center.x(), center.y(), m_starting.box.min.z()); - } + assert(m_hover_id != -1); + m_starting.drag_position = m_grabbers[m_hover_id].center; + m_starting.plane_center = m_grabbers[4].center; + m_starting.plane_nromal = m_grabbers[5].center - m_grabbers[4].center; + m_starting.ctrl_down = wxGetKeyState(WXK_CONTROL); + m_starting.box = (m_starting.ctrl_down && (m_hover_id < 6)) ? m_box : m_parent.get_selection().get_bounding_box(); + + const Vec3d& center = m_starting.box.center(); + m_starting.pivots[0] = m_transform * Vec3d(m_starting.box.max.x(), center.y(), center.z()); + m_starting.pivots[1] = m_transform * Vec3d(m_starting.box.min.x(), center.y(), center.z()); + m_starting.pivots[2] = m_transform * Vec3d(center.x(), m_starting.box.max.y(), center.z()); + m_starting.pivots[3] = m_transform * Vec3d(center.x(), m_starting.box.min.y(), center.z()); + m_starting.pivots[4] = m_transform * Vec3d(center.x(), center.y(), m_starting.box.max.z()); + m_starting.pivots[5] = m_transform * Vec3d(center.x(), center.y(), m_starting.box.min.z()); +} + +void GLGizmoScale3D::on_stop_dragging() { + m_parent.do_scale(L("Gizmo-Scale")); } -void GLGizmoScale3D::on_update(const UpdateData& data) +void GLGizmoScale3D::on_dragging(const UpdateData& data) { if (m_hover_id == 0 || m_hover_id == 1) do_scale_along_axis(X, data); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoScale.hpp b/src/slic3r/GUI/Gizmos/GLGizmoScale.hpp index a4b5a064c15..cb504eadb80 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoScale.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoScale.hpp @@ -60,17 +60,24 @@ class GLGizmoScale3D : public GLGizmoBase const Vec3d& get_scale() const { return m_scale; } void set_scale(const Vec3d& scale) { m_starting.scale = scale; m_scale = scale; } - const Vec3d& get_offset() const { return m_offset; } - std::string get_tooltip() const override; void enable_ununiversal_scale(bool enable); + + /// + /// Postpone to Grabber for scale + /// + /// Keep information about mouse click + /// Return True when use the information otherwise False. + bool on_mouse(const wxMouseEvent &mouse_event) override; + protected: virtual bool on_init() override; virtual std::string on_get_name() const override; virtual bool on_is_activable() const override; virtual void on_start_dragging() override; - virtual void on_update(const UpdateData& data) override; + virtual void on_stop_dragging() override; + virtual void on_dragging(const UpdateData& data) override; virtual void on_render() override; virtual void on_register_raycasters_for_picking() override; virtual void on_unregister_raycasters_for_picking() override; diff --git a/src/slic3r/GUI/Gizmos/GLGizmoText.cpp b/src/slic3r/GUI/Gizmos/GLGizmoText.cpp index 941f134e781..518825ca5c1 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoText.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoText.cpp @@ -253,7 +253,7 @@ bool GLGizmoText::gizmo_event(SLAGizmoEventType action, const Vec2d &mouse_posit } else if (action == SLAGizmoEventType::LeftDown) { if (!selection.is_empty() && get_hover_id() != -1) { - start_dragging(); + //start_dragging(); return true; } @@ -513,7 +513,7 @@ void GLGizmoText::on_render_for_picking() } */ -void GLGizmoText::on_update(const UpdateData &data) +void GLGizmoText::on_dragging(const UpdateData &data) { Vec2d mouse_pos = Vec2d(data.mouse_pos.x(), data.mouse_pos.y()); const ModelObject *mo = m_c->selection_info()->model_object(); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoText.hpp b/src/slic3r/GUI/Gizmos/GLGizmoText.hpp index 0eaf1304ca3..801eaddcd77 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoText.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoText.hpp @@ -91,7 +91,7 @@ class GLGizmoText : public GLGizmoBase virtual std::string on_get_name() const override; virtual bool on_is_activable() const override; virtual void on_render() override; - virtual void on_update(const UpdateData &data) override; + virtual void on_dragging(const UpdateData &data) override; void push_combo_style(const float scale); void pop_combo_style(); void push_button_style(bool pressed); diff --git a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp index 19a38637517..3187e426644 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp @@ -45,6 +45,7 @@ GLGizmosManager::GLGizmosManager(GLCanvas3D& parent) , m_enabled(false) , m_icons_texture_dirty(true) , m_current(Undefined) + , m_hover(Undefined) , m_tooltip("") , m_serializing(false) //BBS: GUI refactor: add object manipulation in gizmo @@ -55,6 +56,7 @@ GLGizmosManager::GLGizmosManager(GLCanvas3D& parent) std::vector GLGizmosManager::get_selectable_idxs() const { std::vector out; + out.reserve(m_gizmos.size()); if (m_parent.get_canvas_type() == GLCanvas3D::CanvasAssembleView) { for (size_t i = 0; i < m_gizmos.size(); ++i) if (m_gizmos[i]->get_sprite_id() == (unsigned int)MmuSegmentation) @@ -69,21 +71,19 @@ std::vector GLGizmosManager::get_selectable_idxs() const } //BBS: GUI refactor: GLToolbar&&Gizmo adjust -//when judge the mouse position, {0, 0} is at the left-up corner, and no need to multiply camera_zoom -size_t GLGizmosManager::get_gizmo_idx_from_mouse(const Vec2d& mouse_pos) const +GLGizmosManager::EType GLGizmosManager::get_gizmo_from_mouse(const Vec2d &mouse_pos) const { if (! m_enabled) return Undefined; - float cnv_h = (float)m_parent.get_canvas_size().get_height(); - float height = get_scaled_total_height(); + float cnv_h = (float) m_parent.get_canvas_size().get_height(); + float height = get_scaled_total_height(); float icons_size = m_layout.scaled_icons_size(); - float border = m_layout.scaled_border(); + float border = m_layout.scaled_border(); //BBS: GUI refactor: GLToolbar&&Gizmo adjust float cnv_w = (float)m_parent.get_canvas_size().get_width(); float width = get_scaled_total_width(); -#if BBS_TOOLBAR_ON_TOP //float space_width = GLGizmosManager::Default_Icons_Size * wxGetApp().toolbar_icon_scale();; const float separator_width = m_parent.get_separator_toolbar_width(); float top_x = std::max(0.0f, 0.5f * (cnv_w - (width + separator_width + m_parent.get_main_toolbar_width() - m_parent.get_collapse_toolbar_width() + m_parent.get_assemble_view_toolbar_width()))); @@ -104,31 +104,9 @@ size_t GLGizmosManager::get_gizmo_idx_from_mouse(const Vec2d& mouse_pos) const if ((float)mouse_pos(0) <= top_x + from_left * stride_x + icons_size) { std::vector selectable = get_selectable_idxs(); if (from_left < selectable.size()) - return selectable[from_left]; + return static_cast(selectable[from_left]); } } -#else - //float top_y = 0.5f * (cnv_h - height) + border; - float top_x = cnv_w - width; - float top_y = 0.5f * (cnv_h - height + m_parent.get_main_toolbar_height() - m_parent.get_assemble_view_toolbar_width()) + border; - float stride_y = m_layout.scaled_stride_y(); - - // is mouse horizontally in the area? - //if ((border <= (float)mouse_pos(0) && ((float)mouse_pos(0) <= border + icons_size))) { - if (((top_x + border) <= (float)mouse_pos(0)) && ((float)mouse_pos(0) <= (top_x + border + icons_size))) { - // which icon is it on? - size_t from_top = (size_t)((float)mouse_pos(1) - top_y) / stride_y; - if (from_top < 0) - return Undefined; - // is it really on the icon or already past the border? - if ((float)mouse_pos(1) <= top_y + from_top * stride_y + icons_size) { - std::vector selectable = get_selectable_idxs(); - if (from_top < selectable.size()) - return selectable[from_top]; - } - } -#endif - return Undefined; } @@ -346,9 +324,13 @@ void GLGizmosManager::reset_all_states() bool GLGizmosManager::open_gizmo(EType type) { - int idx = int(type); - if (m_gizmos[idx]->is_activable() - && activate_gizmo(m_current == idx ? Undefined : (EType)idx)) { + int idx = static_cast(type); + + // re-open same type cause closing + if (m_current == type) type = Undefined; + + if (m_gizmos[idx]->is_activable() && activate_gizmo(type)) { + // remove update data into gizmo itself update_data(); #ifdef __WXOSX__ m_parent.post_event(SimpleEvent(wxEVT_PAINT)); @@ -390,16 +372,6 @@ void GLGizmosManager::enable_grabber(EType type, unsigned int id, bool enable) m_gizmos[type]->disable_grabber(id); } -void GLGizmosManager::update(const Linef3& mouse_ray, const Point& mouse_pos) -{ - if (!m_enabled) - return; - - GLGizmoBase* curr = get_current(); - if (curr != nullptr) - curr->update(GLGizmoBase::UpdateData(mouse_ray, mouse_pos)); -} - void GLGizmosManager::update_assemble_view_data() { if (m_assemble_view_data) { @@ -410,6 +382,7 @@ void GLGizmosManager::update_assemble_view_data() } } +// TODO: divide into gizmo: on init + on selection change void GLGizmosManager::update_data() { if (!m_enabled) @@ -534,14 +507,6 @@ void GLGizmosManager::stop_dragging() m_gizmos[m_current]->stop_dragging(); } -Vec3d GLGizmosManager::get_displacement() const -{ - if (!m_enabled) - return Vec3d::Zero(); - - return dynamic_cast(m_gizmos[Move].get())->get_displacement(); -} - Vec3d GLGizmosManager::get_scale() const { if (!m_enabled) @@ -558,14 +523,6 @@ void GLGizmosManager::set_scale(const Vec3d& scale) dynamic_cast(m_gizmos[Scale].get())->set_scale(scale); } -Vec3d GLGizmosManager::get_scale_offset() const -{ - if (!m_enabled || m_gizmos.empty()) - return Vec3d::Zero(); - - return dynamic_cast(m_gizmos[Scale].get())->get_offset(); -} - Vec3d GLGizmosManager::get_rotation() const { if (!m_enabled || m_gizmos.empty()) @@ -587,14 +544,6 @@ void GLGizmosManager::finish_cut_rotation() dynamic_cast(m_gizmos[Cut].get())->finish_rotation(); } -Vec3d GLGizmosManager::get_flattening_normal() const -{ - if (!m_enabled || m_gizmos.empty()) - return Vec3d::Zero(); - - return dynamic_cast(m_gizmos[Flatten].get())->get_flattening_normal(); -} - void GLGizmosManager::set_flattening_data(const ModelObject* model_object) { if (!m_enabled || m_gizmos.empty()) @@ -736,7 +685,7 @@ std::string GLGizmosManager::get_tooltip() const return (curr != nullptr) ? curr->get_tooltip() : ""; } -bool GLGizmosManager::on_mouse_wheel(wxMouseEvent& evt) +bool GLGizmosManager::on_mouse_wheel(const wxMouseEvent &evt) { bool processed = false; @@ -756,253 +705,108 @@ bool GLGizmosManager::on_mouse_wheel(wxMouseEvent& evt) return processed; } -bool GLGizmosManager::on_mouse(wxMouseEvent& evt) -{ - // used to set a right up event as processed when needed - static bool pending_right_up = false; - - Point pos(evt.GetX(), evt.GetY()); - Vec2d mouse_pos((double)evt.GetX(), (double)evt.GetY()); - - Selection& selection = m_parent.get_selection(); - int selected_object_idx = selection.get_object_idx(); - bool processed = false; - - // when control is down we allow scene pan and rotation even when clicking over some object - bool control_down = evt.CmdDown(); - - // mouse anywhere - if (evt.Moving()) { - m_tooltip = update_hover_state(mouse_pos); - if (m_current == MmuSegmentation || m_current == FdmSupports || m_current == Text) - // BBS - gizmo_event(SLAGizmoEventType::Moving, mouse_pos, evt.ShiftDown(), evt.AltDown(), evt.ControlDown()); - } else if (evt.LeftUp()) { - if (m_mouse_capture.left) { - processed = true; - m_mouse_capture.left = false; - } - else if (is_dragging()) { - switch (m_current) { - case Move: { m_parent.do_move(("Tool-Move")); break; } - case Scale: { m_parent.do_scale(("Tool-Scale")); break; } - case Rotate: { m_parent.do_rotate(("Tool-Rotate")); break; } - default: break; - } - - stop_dragging(); - update_data(); - - // BBS - //wxGetApp().obj_manipul()->set_dirty(); - // Let the plater know that the dragging finished, so a delayed refresh - // of the scene with the background processing data should be performed. - m_parent.post_event(SimpleEvent(EVT_GLCANVAS_MOUSE_DRAGGING_FINISHED)); - // updates camera target constraints - m_parent.refresh_camera_scene_box(); - - processed = true; - } -// else -// return false; - } - else if (evt.MiddleUp()) { - if (m_mouse_capture.middle) { - processed = true; - m_mouse_capture.middle = false; +bool GLGizmosManager::gizmos_toolbar_on_mouse(const wxMouseEvent &mouse_event) { + assert(m_enabled); + // keep information about events to process + struct MouseCapture + { + bool left = false; + bool middle = false; + bool right = false; + bool exist_tooltip = false; + MouseCapture() = default; + bool any() const { return left || middle || right; } + void reset() { + left = false; + middle = false; + right = false; } - else + }; + static MouseCapture mc; + + // wxCoord == int --> wx/types.h + Vec2i mouse_coord(mouse_event.GetX(), mouse_event.GetY()); + Vec2d mouse_pos = mouse_coord.cast(); + + EType gizmo = get_gizmo_from_mouse(mouse_pos); + bool selected_gizmo = gizmo != Undefined; + + // fast reaction on move mouse + if (mouse_event.Moving()) { + assert(!mc.any()); + if (selected_gizmo) { + mc.exist_tooltip = true; + update_hover_state(gizmo); + // at this moment is enebled to process mouse move under gizmo + // tools bar e.g. Do not interupt dragging. return false; + } else if (mc.exist_tooltip) { + // first move out of gizmo tool bar - unselect tooltip + mc.exist_tooltip = false; + update_hover_state(Undefined); + return false; + } + return false; } - else if (evt.RightUp()) { - if (pending_right_up) { - pending_right_up = false; + + if (selected_gizmo) { + // mouse is above toolbar + if (mouse_event.LeftDown() || mouse_event.LeftDClick()) { + mc.left = true; + open_gizmo(gizmo); + return true; + } else if (mouse_event.RightDown()) { + mc.right = true; + return true; + } else if (mouse_event.MiddleDown()) { + mc.middle = true; return true; } - if (m_mouse_capture.right) { - processed = true; - m_mouse_capture.right = false; - } -// else -// return false; } - else if (evt.Dragging() && !is_dragging()) { - if (m_mouse_capture.any()) - // if the button down was done on this toolbar, prevent from dragging into the scene - processed = true; -// else -// return false; - } - else if (evt.Dragging() && is_dragging()) { - if (!m_parent.get_wxglcanvas()->HasCapture()) - m_parent.get_wxglcanvas()->CaptureMouse(); - - m_parent.set_mouse_as_dragging(); - update(m_parent.mouse_ray(pos), pos); - switch (m_current) - { - case Move: - { - // Apply new temporary offset - selection.translate(get_displacement()); - // BBS - //wxGetApp().obj_manipul()->set_dirty(); - break; - } - case Scale: - { - // Apply new temporary scale factors - TransformationType transformation_type(TransformationType::Local_Absolute_Joint); - //if (evt.AltDown()) - // transformation_type.set_independent(); - selection.scale(get_scale(), transformation_type); - if (control_down && m_gizmos[m_current].get()->get_hover_id() < 6) - selection.translate(get_scale_offset(), true); - // BBS - //wxGetApp().obj_manipul()->set_dirty(); - break; - } - case Rotate: - { - // Apply new temporary rotations - TransformationType transformation_type(TransformationType::World_Relative_Joint); - if (evt.AltDown()) - transformation_type.set_independent(); - selection.rotate(get_rotation(), transformation_type); - // BBS - //wxGetApp().obj_manipul()->set_dirty(); - break; - } - default: - break; + if (mc.any()) { + // Check if exist release of event started above toolbar? + if (mouse_event.Dragging()) { + if (!selected_gizmo && mc.exist_tooltip) { + // dragging out of gizmo let tooltip disapear + mc.exist_tooltip = false; + update_hover_state(Undefined); + } + // draging start on toolbar so no propagation into scene + return true; + } else if (mc.left && mouse_event.LeftUp()) { + mc.left = false; + return true; + } else if (mc.right && mouse_event.RightUp()) { + mc.right = false; + return true; + } else if (mc.middle && mouse_event.MiddleUp()) { + mc.middle = false; + return true; } - m_parent.set_as_dirty(); - processed = true; + // event out of window is not porocessed + // left down on gizmo -> keep down -> move out of window -> release left + if (mouse_event.Leaving()) mc.reset(); } + return false; +} - if (get_gizmo_idx_from_mouse(mouse_pos) == Undefined) { - // mouse is outside the toolbar - m_tooltip.clear(); +bool GLGizmosManager::on_mouse(const wxMouseEvent &mouse_event) +{ + if (!m_enabled) return false; - if (evt.LeftDown() && (!control_down || grabber_contains_mouse())) { - if ((/*m_current == SlaSupports || m_current == Hollow ||*/ m_current == FdmSupports || - m_current == Seam || m_current == MmuSegmentation || m_current == Text || m_current == Cut || m_current == MeshBoolean) - && gizmo_event(SLAGizmoEventType::LeftDown, mouse_pos, evt.ShiftDown(), evt.AltDown())) - // the gizmo got the event and took some action, there is no need to do anything more - processed = true; - else if (!selection.is_empty() && grabber_contains_mouse()) { - update_data(); - selection.start_dragging(); - start_dragging(); - - // Let the plater know that the dragging started - m_parent.post_event(SimpleEvent(EVT_GLCANVAS_MOUSE_DRAGGING_STARTED)); - - if (m_current == Flatten) { - // Rotate the object so the normal points downward: - m_parent.do_flatten(get_flattening_normal(), L("Tool-Lay on Face")); - // BBS - //wxGetApp().obj_manipul()->set_dirty(); - } + // tool bar wants to use event? + if (gizmos_toolbar_on_mouse(mouse_event)) return true; - m_parent.set_as_dirty(); - processed = true; - } - } - //else if (evt.RightDown() && selected_object_idx != -1 && (m_current == SlaSupports || m_current == Hollow) - // && gizmo_event(SLAGizmoEventType::RightDown, mouse_pos)) { - // // we need to set the following right up as processed to avoid showing the context menu if the user release the mouse over the object - // pending_right_up = true; - // // event was taken care of by the SlaSupports gizmo - // processed = true; - //} - else if (evt.RightDown() && !control_down && selected_object_idx != -1 - && (m_current == FdmSupports || m_current == Seam || m_current == MmuSegmentation || m_current == Cut) - && gizmo_event(SLAGizmoEventType::RightDown, mouse_pos)) { - // event was taken care of by the FdmSupports / Seam / MMUPainting gizmo - processed = true; - } - else if (evt.Dragging() && m_parent.get_move_volume_id() != -1 - && (/*m_current == SlaSupports || m_current == Hollow ||*/ m_current == FdmSupports || m_current == Seam || m_current == MmuSegmentation)) - // don't allow dragging objects with the Sla gizmo on - processed = true; - else if (evt.Dragging() && !control_down - && (/*m_current == SlaSupports || m_current == Hollow ||*/ m_current == FdmSupports || m_current == Seam || m_current == MmuSegmentation || m_current == Cut) - && gizmo_event(SLAGizmoEventType::Dragging, mouse_pos, evt.ShiftDown(), evt.AltDown())) { - // the gizmo got the event and took some action, no need to do anything more here - m_parent.set_as_dirty(); - processed = true; - } - else if (evt.Dragging() && control_down && (evt.LeftIsDown() || evt.RightIsDown())) { - // CTRL has been pressed while already dragging -> stop current action - if (evt.LeftIsDown()) - gizmo_event(SLAGizmoEventType::LeftUp, mouse_pos, evt.ShiftDown(), evt.AltDown(), true); - else if (evt.RightIsDown()) - gizmo_event(SLAGizmoEventType::RightUp, mouse_pos, evt.ShiftDown(), evt.AltDown(), true); - } - else if (evt.LeftUp() - && (/*m_current == SlaSupports || m_current == Hollow ||*/ m_current == FdmSupports || m_current == Seam || m_current == MmuSegmentation || m_current == Cut) - && !m_parent.is_mouse_dragging() - && gizmo_event(SLAGizmoEventType::LeftUp, mouse_pos, evt.ShiftDown(), evt.AltDown(), control_down)) { - // in case SLA/FDM gizmo is selected, we just pass the LeftUp event and stop processing - neither - // object moving or selecting is suppressed in that case - processed = true; - } - else if (evt.LeftUp() && m_current == Flatten && m_gizmos[m_current]->get_hover_id() != -1) { - // to avoid to loose the selection when user clicks an the white faces of a different object while the Flatten gizmo is active - selection.stop_dragging(); - // BBS - //wxGetApp().obj_manipul()->set_dirty(); - processed = true; - } - else if (evt.RightUp() && (m_current == FdmSupports || m_current == Seam || m_current == MmuSegmentation || m_current == Cut) - && !m_parent.is_mouse_dragging() - && gizmo_event(SLAGizmoEventType::RightUp, mouse_pos, evt.ShiftDown(), evt.AltDown(), control_down)) { - processed = true; - } - else if (evt.LeftUp()) { - selection.stop_dragging(); - // BBS - //wxGetApp().obj_manipul()->set_dirty(); - } - } - else { - // mouse inside toolbar - if (evt.LeftDown() || evt.LeftDClick()) { - m_mouse_capture.left = true; - m_mouse_capture.parent = &m_parent; - processed = true; - if (!selection.is_empty()) { - update_on_off_state(mouse_pos); - update_data(); - m_parent.set_as_dirty(); - try { - if ((int)m_hover >= 0 && (int)m_hover < m_gizmos.size()) { - std::string name = get_name_from_gizmo_etype(m_hover); - int count = m_gizmos[m_hover]->get_count(); - NetworkAgent* agent = GUI::wxGetApp().getAgent(); - if (agent) { - agent->track_update_property(name, std::to_string(count)); - } - } - } - catch (...) {} - } - } - else if (evt.MiddleDown()) { - m_mouse_capture.middle = true; - m_mouse_capture.parent = &m_parent; - } - else if (evt.RightDown()) { - m_mouse_capture.right = true; - m_mouse_capture.parent = &m_parent; - return true; - } - } + // current gizmo wants to use event? + if (m_current != Undefined && + // check if gizmo override method could be slower than simple call virtual function + // &m_gizmos[m_current]->on_mouse != &GLGizmoBase::on_mouse && + m_gizmos[m_current]->on_mouse(mouse_event)) + return true; - return processed; + return false; } bool GLGizmosManager::on_char(wxKeyEvent& evt) @@ -1549,43 +1353,26 @@ bool GLGizmosManager::generate_icons_texture() return res; } -void GLGizmosManager::update_on_off_state(const Vec2d& mouse_pos) +void GLGizmosManager::update_hover_state(const EType &type) { - if (!m_enabled) + assert(m_enabled); + if (type == Undefined) { + m_hover = Undefined; + m_tooltip.clear(); return; - - size_t idx = get_gizmo_idx_from_mouse(mouse_pos); - if (idx != Undefined && m_gizmos[idx]->is_activable() && m_hover == idx) { - activate_gizmo(m_current == idx ? Undefined : (EType)idx); - // BBS - wxGetApp().obj_list()->select_object_item((EType) idx <= Scale || (EType) idx == Text); - } -} - -std::string GLGizmosManager::update_hover_state(const Vec2d& mouse_pos) -{ - std::string name = ""; - - if (!m_enabled) - return name; - - m_hover = Undefined; - - size_t idx = get_gizmo_idx_from_mouse(mouse_pos); - if (idx != Undefined) { - name = m_gizmos[idx]->get_name(); - - if (m_gizmos[idx]->is_activable()) - m_hover = (EType)idx; } - return name; + const GLGizmoBase &hovered_gizmo = *m_gizmos[type]; + m_hover = hovered_gizmo.is_activable() ? type : Undefined; + m_tooltip = hovered_gizmo.get_name(); } bool GLGizmosManager::activate_gizmo(EType type) { - if (m_gizmos.empty() || m_current == type) - return true; + assert(!m_gizmos.empty()); + + // already activated + if (m_current == type) return true; if (m_current != Undefined) { // clean up previous gizmo @@ -1596,30 +1383,34 @@ bool GLGizmosManager::activate_gizmo(EType type) old_gizmo.unregister_raycasters_for_picking(); - if (!m_serializing - && old_gizmo.wants_enter_leave_snapshots()) - Plater::TakeSnapshot snapshot(wxGetApp().plater(), - old_gizmo.get_gizmo_leaving_text(), - UndoRedo::SnapshotType::LeavingGizmoWithAction); + if (!m_serializing && old_gizmo.wants_enter_leave_snapshots()) + Plater::TakeSnapshot + snapshot(wxGetApp().plater(), + old_gizmo.get_gizmo_leaving_text(), + UndoRedo::SnapshotType::LeavingGizmoWithAction); } - // check deactivation of gizmo if (type == Undefined) { - m_current = type; + // it is deactivation of gizmo + m_current = Undefined; return true; } // set up new gizmo GLGizmoBase& new_gizmo = *m_gizmos[type]; + if (!new_gizmo.is_activable()) return false; + if (!m_serializing && new_gizmo.wants_enter_leave_snapshots()) Plater::TakeSnapshot snapshot(wxGetApp().plater(), - new_gizmo.get_gizmo_entering_text(), - UndoRedo::SnapshotType::EnteringGizmo); + new_gizmo.get_gizmo_entering_text(), + UndoRedo::SnapshotType::EnteringGizmo); m_current = type; new_gizmo.set_state(GLGizmoBase::On); - if (new_gizmo.get_state() != GLGizmoBase::On) + if (new_gizmo.get_state() != GLGizmoBase::On) { + m_current = Undefined; return false; // gizmo refused to be turned on. + } new_gizmo.register_raycasters_for_picking(); diff --git a/src/slic3r/GUI/Gizmos/GLGizmosManager.hpp b/src/slic3r/GUI/Gizmos/GLGizmosManager.hpp index 02a88e61575..23812c8dca9 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosManager.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosManager.hpp @@ -129,24 +129,10 @@ class GLGizmosManager : public Slic3r::ObjectBase GizmoObjectManipulation m_object_manipulation; std::vector get_selectable_idxs() const; - size_t get_gizmo_idx_from_mouse(const Vec2d& mouse_pos) const; + EType get_gizmo_from_mouse(const Vec2d &mouse_pos) const; bool activate_gizmo(EType type); - struct MouseCapture - { - bool left; - bool middle; - bool right; - GLCanvas3D* parent; - - MouseCapture() { reset(); } - - bool any() const { return left || middle || right; } - void reset() { left = middle = right = false; parent = nullptr; } - }; - - MouseCapture m_mouse_capture; std::string m_tooltip; bool m_serializing; std::unique_ptr m_common_gizmos_data; @@ -155,6 +141,15 @@ class GLGizmosManager : public Slic3r::ObjectBase std::map icon_list; bool m_is_dark = false; + + /// + /// Process mouse event on gizmo toolbar + /// + /// Event descriptor + /// TRUE when take responsibility for event otherwise FALSE. + /// On true, event should not be process by others. + /// On false, event should be process by others. + bool gizmos_toolbar_on_mouse(const wxMouseEvent &mouse_event); public: std::unique_ptr m_assemble_view_data; @@ -232,7 +227,6 @@ class GLGizmosManager : public Slic3r::ObjectBase void set_hover_id(int id); void enable_grabber(EType type, unsigned int id, bool enable); - void update(const Linef3& mouse_ray, const Point& mouse_pos); void update_data(); void update_assemble_view_data(); @@ -248,13 +242,9 @@ class GLGizmosManager : public Slic3r::ObjectBase void start_dragging(); void stop_dragging(); - Vec3d get_displacement() const; - Vec3d get_scale() const; void set_scale(const Vec3d& scale); - Vec3d get_scale_offset() const; - Vec3d get_rotation() const; void set_rotation(const Vec3d& rotation); @@ -275,8 +265,6 @@ class GLGizmosManager : public Slic3r::ObjectBase return nullptr; } - Vec3d get_flattening_normal() const; - void set_flattening_data(const ModelObject* model_object); //void set_sla_support_data(ModelObject* model_object); @@ -302,8 +290,8 @@ class GLGizmosManager : public Slic3r::ObjectBase std::string get_tooltip() const; - bool on_mouse(wxMouseEvent& evt); - bool on_mouse_wheel(wxMouseEvent& evt); + bool on_mouse(const wxMouseEvent &mouse_event); + bool on_mouse_wheel(const wxMouseEvent &evt); bool on_char(wxKeyEvent& evt); bool on_key(wxKeyEvent& evt); @@ -329,8 +317,7 @@ class GLGizmosManager : public Slic3r::ObjectBase bool generate_icons_texture(); - void update_on_off_state(const Vec2d& mouse_pos); - std::string update_hover_state(const Vec2d& mouse_pos); + void update_hover_state(const EType &type); bool grabber_contains_mouse() const; }; From 9dbb2dfe0d5395577a1f86fad7954771d7c77910 Mon Sep 17 00:00:00 2001 From: Filip Sykala Date: Sun, 29 Oct 2023 23:11:10 +0800 Subject: [PATCH 77/99] Various gizmos refactoring --- src/slic3r/GUI/GLCanvas3D.cpp | 26 +-- src/slic3r/GUI/Gizmos/GLGizmoAdvancedCut.cpp | 14 +- src/slic3r/GUI/Gizmos/GLGizmoAdvancedCut.hpp | 24 +-- src/slic3r/GUI/Gizmos/GLGizmoBase.cpp | 108 ++++------- src/slic3r/GUI/Gizmos/GLGizmoBase.hpp | 37 ++-- src/slic3r/GUI/Gizmos/GLGizmoFlatten.cpp | 46 +++-- src/slic3r/GUI/Gizmos/GLGizmoFlatten.hpp | 3 +- .../GUI/Gizmos/GLGizmoMmuSegmentation.cpp | 7 +- .../GUI/Gizmos/GLGizmoMmuSegmentation.hpp | 2 +- src/slic3r/GUI/Gizmos/GLGizmoMove.cpp | 6 + src/slic3r/GUI/Gizmos/GLGizmoMove.hpp | 4 + src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp | 128 +++++-------- src/slic3r/GUI/Gizmos/GLGizmoPainterBase.hpp | 3 +- src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp | 49 ++++- src/slic3r/GUI/Gizmos/GLGizmoRotate.hpp | 29 +-- src/slic3r/GUI/Gizmos/GLGizmoScale.cpp | 26 +++ src/slic3r/GUI/Gizmos/GLGizmoScale.hpp | 7 +- src/slic3r/GUI/Gizmos/GLGizmosManager.cpp | 177 +----------------- src/slic3r/GUI/Gizmos/GLGizmosManager.hpp | 30 +-- .../GUI/Gizmos/GizmoObjectManipulation.cpp | 6 +- src/slic3r/GUI/Selection.cpp | 8 +- src/slic3r/GUI/Selection.hpp | 5 +- 22 files changed, 293 insertions(+), 452 deletions(-) diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index b492d235432..4a87c9746c6 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -3309,7 +3309,7 @@ void GLCanvas3D::on_key(wxKeyEvent& evt) m_dirty = true; }, [this](const Vec3d& direction, bool slow, bool camera_space) { - m_selection.start_dragging(); + m_selection.setup_cache(); double multiplier = slow ? 1.0 : 10.0; Vec3d displacement; @@ -3322,7 +3322,6 @@ void GLCanvas3D::on_key(wxKeyEvent& evt) displacement = multiplier * direction; m_selection.translate(displacement); - m_selection.stop_dragging(); m_dirty = true; } );} @@ -3463,9 +3462,8 @@ void GLCanvas3D::on_key(wxKeyEvent& evt) post_event(SimpleEvent(EVT_GLCANVAS_COLLAPSE_SIDEBAR)); } else if (m_gizmos.is_enabled() && !m_selection.is_empty() && m_canvas_type != CanvasAssembleView) { auto _do_rotate = [this](double angle_z_rad) { - m_selection.start_dragging(); + m_selection.setup_cache(); m_selection.rotate(Vec3d(0.0, 0.0, angle_z_rad), TransformationType(TransformationType::World_Relative_Joint)); - m_selection.stop_dragging(); m_dirty = true; // wxGetApp().obj_manipul()->set_dirty(); }; @@ -3903,21 +3901,18 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) // It should be detection of volume change // Not only detection of some modifiers !!! if (evt.Dragging()) { + GLGizmosManager::EType c = m_gizmos.get_current_type(); if (current_printer_technology() == ptFFF && (fff_print()->config().print_sequence == PrintSequence::ByObject)) { - switch (m_gizmos.get_current_type()) { - case GLGizmosManager::EType::Move: - case GLGizmosManager::EType::Scale: - case GLGizmosManager::EType::Rotate: + if (c == GLGizmosManager::EType::Move || + c == GLGizmosManager::EType::Scale || + c == GLGizmosManager::EType::Rotate ) update_sequential_clearance(); - } } else { - switch (m_gizmos.get_current_type()) { - case GLGizmosManager::EType::Move: - case GLGizmosManager::EType::Scale: - case GLGizmosManager::EType::Rotate: + if (c == GLGizmosManager::EType::Move || + c == GLGizmosManager::EType::Scale || + c == GLGizmosManager::EType::Rotate) show_sinking_contours(); - } } } else if (evt.LeftUp() && @@ -4050,7 +4045,7 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) m_volumes.volumes[volume_idx]->hover = GLVolume::HS_None; // The dragging operation is initiated. m_mouse.drag.move_volume_idx = volume_idx; - m_selection.start_dragging(); + m_selection.setup_cache(); m_mouse.drag.start_position_3D = m_mouse.scene_position; m_sequential_print_clearance_first_displacement = true; m_moving = true; @@ -4218,7 +4213,6 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) m_mouse.position = pos.cast(); if (evt.LeftUp()) { - m_selection.stop_dragging(); m_rotation_center(0) = m_rotation_center(1) = m_rotation_center(2) = 0.f; } diff --git a/src/slic3r/GUI/Gizmos/GLGizmoAdvancedCut.cpp b/src/slic3r/GUI/Gizmos/GLGizmoAdvancedCut.cpp index b3aa8ef8706..70df971f88e 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoAdvancedCut.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoAdvancedCut.cpp @@ -104,13 +104,19 @@ GLGizmoAdvancedCut::GLGizmoAdvancedCut(GLCanvas3D& parent, const std::string& ic for (int i = 0; i < 4; i++) m_cut_plane_points[i] = { 0., 0., 0. }; - set_group_id(m_gizmos.size()); + m_group_id = (m_gizmos.size()); m_rotation.setZero(); //m_current_base_rotation.setZero(); m_rotate_cmds.clear(); m_buffered_rotation.setZero(); } +void GLGizmoAdvancedCut::data_changed() +{ + GLGizmoRotate3D::data_changed(); + finish_rotation(); +} + bool GLGizmoAdvancedCut::gizmo_event(SLAGizmoEventType action, const Vec2d &mouse_position, bool shift_down, bool alt_down, bool control_down) { CutConnectors &connectors = m_c->selection_info()->model_object()->cut_connectors; @@ -126,7 +132,7 @@ bool GLGizmoAdvancedCut::gizmo_event(SLAGizmoEventType action, const Vec2d &mous return false; if (m_hover_id != -1) { - start_dragging(); + //start_dragging(); return true; } @@ -449,7 +455,7 @@ void GLGizmoAdvancedCut::on_dragging(const UpdateData &data) m_rotation = rotation; //m_move_grabber.angles = m_current_base_rotation + m_rotation; - if (m_hover_id == get_group_id()) { + if (m_hover_id == m_group_id) { double move = calc_projection(data.mouse_ray); set_movement(m_start_movement + move); Vec3d plane_normal = get_plane_normal(); @@ -941,7 +947,7 @@ void GLGizmoAdvancedCut::render_cut_plane_and_grabbers() // m_move_grabber.color = GrabberColor; // m_move_grabber.hover_color = GrabberHoverColor; // m_move_grabber.render(m_hover_id == get_group_id(), (float)((box.size()(0) + box.size()(1) + box.size()(2)) / 3.0)); - bool hover = (m_hover_id == get_group_id()); + bool hover = (m_hover_id == m_group_id); ColorRGBA render_color; if (hover) { render_color = GrabberHoverColor; diff --git a/src/slic3r/GUI/Gizmos/GLGizmoAdvancedCut.hpp b/src/slic3r/GUI/Gizmos/GLGizmoAdvancedCut.hpp index 007a95e62e3..4b31176b8d1 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoAdvancedCut.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoAdvancedCut.hpp @@ -138,6 +138,8 @@ struct Rotate_data { virtual bool apply_clipping_plane() { return m_connectors_editing; } + void data_changed() override; + protected: bool on_init() override; void on_load(cereal::BinaryInputArchive &ar) override; @@ -154,28 +156,6 @@ struct Rotate_data { void show_tooltip_information(float x, float y); - virtual void on_enable_grabber(unsigned int id) - { - if (id < 3) - m_gizmos[id].enable_grabber(0); - else if (id == 3) - this->enable_grabber(0); - } - - virtual void on_disable_grabber(unsigned int id) - { - if (id < 3) - m_gizmos[id].disable_grabber(0); - else if (id == 3) - this->disable_grabber(0); - } - - virtual void on_set_hover_id() - { - for (int i = 0; i < 3; ++i) - m_gizmos[i].set_hover_id((m_hover_id == i) ? 0 : -1); - } - private: void perform_cut(const Selection& selection); bool can_perform_cut() const; diff --git a/src/slic3r/GUI/Gizmos/GLGizmoBase.cpp b/src/slic3r/GUI/Gizmos/GLGizmoBase.cpp index 8d59ea819af..5a51304a813 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoBase.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoBase.cpp @@ -200,9 +200,6 @@ GLGizmoBase::GLGizmoBase(GLCanvas3D& parent, const std::string& icon_filename, u , m_sprite_id(sprite_id) , m_imgui(wxGetApp().imgui()) { - m_base_color = DEFAULT_BASE_COLOR; - m_drag_color = DEFAULT_DRAG_COLOR; - m_highlight_color = DEFAULT_HIGHLIGHT_COLOR; } void GLGizmoBase::set_icon_filename(const std::string &filename) { @@ -212,7 +209,7 @@ void GLGizmoBase::set_icon_filename(const std::string &filename) { void GLGizmoBase::set_hover_id(int id) { // do not change hover id during dragging - if (m_dragging) return; + assert(!m_dragging); // allow empty grabbers when not using grabbers but use hover_id - flatten, rotate if (!m_grabbers.empty() && id >= (int) m_grabbers.size()) @@ -222,49 +219,6 @@ void GLGizmoBase::set_hover_id(int id) on_set_hover_id(); } - -void GLGizmoBase::enable_grabber(unsigned int id) -{ - if (id < m_grabbers.size()) - m_grabbers[id].enabled = true; - - on_enable_grabber(id); -} - -void GLGizmoBase::disable_grabber(unsigned int id) -{ - if (id < m_grabbers.size()) - m_grabbers[id].enabled = false; - - on_disable_grabber(id); -} - -void GLGizmoBase::start_dragging() -{ - m_dragging = true; - - for (int i = 0; i < (int)m_grabbers.size(); ++i) - { - m_grabbers[i].dragging = (m_hover_id == i); - } - - on_start_dragging(); - //BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format("this %1%, m_hover_id=%2%\n")%this %m_hover_id; -} - -void GLGizmoBase::stop_dragging() -{ - m_dragging = false; - - for (int i = 0; i < (int)m_grabbers.size(); ++i) - { - m_grabbers[i].dragging = false; - } - - on_stop_dragging(); - //BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format("this %1%, m_hover_id=%2%\n")%this %m_hover_id; -} - bool GLGizmoBase::update_items_state() { bool res = m_dirty; @@ -347,54 +301,72 @@ void GLGizmoBase::render_grabbers(float size) const // help function to process grabbers // call start_dragging, stop_dragging, on_dragging bool GLGizmoBase::use_grabbers(const wxMouseEvent &mouse_event) { + bool is_dragging_finished = false; if (mouse_event.Moving()) { + // it should not happen but for sure assert(!m_dragging); - // only for sure - if (m_dragging) m_dragging = false; + if (m_dragging) is_dragging_finished = true; + else return false; + } - return false; - } if (mouse_event.LeftDown()) { - Selection &selection = m_parent.get_selection(); - if (!selection.is_empty() && m_hover_id != -1) { - selection.start_dragging(); - - start_dragging(); + Selection &selection = m_parent.get_selection(); + if (!selection.is_empty() && m_hover_id != -1 && + (m_grabbers.empty() || m_hover_id < static_cast(m_grabbers.size()))) { + selection.setup_cache(); + + m_dragging = true; + for (auto &grabber : m_grabbers) grabber.dragging = false; + if (!m_grabbers.empty() && m_hover_id < int(m_grabbers.size())) + m_grabbers[m_hover_id].dragging = true; + + // prevent change of hover_id during dragging + m_parent.set_mouse_as_dragging(); + on_start_dragging(); // Let the plater know that the dragging started - m_parent.post_event( - SimpleEvent(EVT_GLCANVAS_MOUSE_DRAGGING_STARTED)); + m_parent.post_event(SimpleEvent(EVT_GLCANVAS_MOUSE_DRAGGING_STARTED)); m_parent.set_as_dirty(); return true; } } else if (m_dragging) { + // when mouse cursor leave window than finish actual dragging operation + bool is_leaving = mouse_event.Leaving(); if (mouse_event.Dragging()) { m_parent.set_mouse_as_dragging(); - - Point mouse_coord(mouse_event.GetX(), mouse_event.GetY()); - UpdateData data{m_parent.mouse_ray(mouse_coord), mouse_coord}; + Point mouse_coord(mouse_event.GetX(), mouse_event.GetY()); + auto ray = m_parent.mouse_ray(mouse_coord); + UpdateData data(ray, mouse_coord); on_dragging(data); wxGetApp().obj_manipul()->set_dirty(); m_parent.set_as_dirty(); return true; - } else if (mouse_event.LeftUp()) { - stop_dragging(); + } else if (mouse_event.LeftUp() || is_leaving || is_dragging_finished) { + for (auto &grabber : m_grabbers) grabber.dragging = false; + m_dragging = false; + + // NOTE: This should be part of GLCanvas3D + // Reset hover_id when leave window + if (is_leaving) m_parent.mouse_up_cleanup(); + + on_stop_dragging(); + + // There is prediction that after draggign, data are changed + // Data are updated twice also by canvas3D::reload_scene. + // Should be fixed. + m_parent.get_gizmos_manager().update_data(); - m_parent.get_gizmos_manager().update_data(); wxGetApp().obj_manipul()->set_dirty(); // Let the plater know that the dragging finished, so a delayed // refresh of the scene with the background processing data should // be performed. - m_parent.post_event( - SimpleEvent(EVT_GLCANVAS_MOUSE_DRAGGING_FINISHED)); + m_parent.post_event(SimpleEvent(EVT_GLCANVAS_MOUSE_DRAGGING_FINISHED)); // updates camera target constraints m_parent.refresh_camera_scene_box(); return true; - } else if (mouse_event.Leaving()) { - m_dragging = false; } } return false; diff --git a/src/slic3r/GUI/Gizmos/GLGizmoBase.hpp b/src/slic3r/GUI/Gizmos/GLGizmoBase.hpp index 8094d36f553..85a8c68a5b1 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoBase.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoBase.hpp @@ -29,7 +29,6 @@ class ImGuiWrapper; class GLCanvas3D; enum class CommonGizmosDataID; class CommonGizmosDataPool; -class Selection; class GLGizmoBase { @@ -137,13 +136,9 @@ class GLGizmoBase unsigned int m_sprite_id; int m_hover_id{ -1 }; bool m_dragging{ false }; - ColorRGBA m_base_color; - ColorRGBA m_drag_color; - ColorRGBA m_highlight_color; mutable std::vector m_grabbers; ImGuiWrapper* m_imgui; bool m_first_input_window_render{ true }; - mutable std::string m_tooltip; CommonGizmosDataPool* m_c{ nullptr }; bool m_is_dark_mode = false; @@ -161,9 +156,6 @@ class GLGizmoBase std::string get_name(bool include_shortcut = true) const; - int get_group_id() const { return m_group_id; } - void set_group_id(int id) { m_group_id = id; } - EState get_state() const { return m_state; } void set_state(EState state) { m_state = state; on_set_state(); } @@ -188,29 +180,30 @@ class GLGizmoBase int get_hover_id() const { return m_hover_id; } void set_hover_id(int id); - - void set_highlight_color(const ColorRGBA& color) { m_highlight_color = color; } - - void enable_grabber(unsigned int id); - void disable_grabber(unsigned int id); - - void start_dragging(); - void stop_dragging(); - + bool is_dragging() const { return m_dragging; } // returns True when Gizmo changed its state bool update_items_state(); - void render() { m_tooltip.clear(); on_render(); } + void render() { on_render(); } void render_input_window(float x, float y, float bottom_limit); virtual void on_change_color_mode(bool is_dark) { m_is_dark_mode = is_dark; } + /// + /// Mouse tooltip text + /// + /// Text to be visible in mouse tooltip virtual std::string get_tooltip() const { return ""; } int get_count() { return ++count; } std::string get_gizmo_name() { return on_get_name(); } + /// + /// Is called when data (Selection) is changed + /// + virtual void data_changed(){}; + /// /// Implement when want to process mouse events in gizmo /// Click, Right click, move, drag, ... @@ -265,10 +258,12 @@ class GLGizmoBase void set_dirty(); /// - /// + /// function which + /// Set up m_dragging and call functions + /// on_start_dragging / on_dragging / on_stop_dragging /// - /// - /// + /// Keep information about mouse click + /// same as on_mouse bool use_grabbers(const wxMouseEvent &mouse_event); private: // Flag for dirty visible state of Gizmo diff --git a/src/slic3r/GUI/Gizmos/GLGizmoFlatten.cpp b/src/slic3r/GUI/Gizmos/GLGizmoFlatten.cpp index 2b2b73a1951..b6eb6b0f855 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoFlatten.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoFlatten.cpp @@ -25,27 +25,47 @@ bool GLGizmoFlatten::on_mouse(const wxMouseEvent &mouse_event) if (mouse_event.Moving()) { // only for sure m_mouse_left_down = false; - - if (m_hover_id != -1) m_parent.set_as_dirty(); return false; } - if (mouse_event.LeftDown() && m_hover_id != -1) { - Selection &selection = m_parent.get_selection(); - if (selection.is_single_full_instance()) { - // Rotate the object so the normal points downward: - selection.flattening_rotate(m_planes[m_hover_id].normal); - m_parent.do_rotate(L("Gizmo-Place on Face")); + if (mouse_event.LeftDown()) { + if (m_hover_id != -1) { + m_mouse_left_down = true; + Selection &selection = m_parent.get_selection(); + if (selection.is_single_full_instance()) { + // Rotate the object so the normal points downward: + selection.flattening_rotate(m_planes[m_hover_id].normal); + m_parent.do_rotate(L("Gizmo-Place on Face")); + } + return true; } - m_mouse_left_down = true; - return true; - } else if (m_mouse_left_down && mouse_event.LeftUp()) { - // responsible for mouse left up + + // fix: prevent restart gizmo when reselect object + // take responsibility for left up + if (m_parent.get_first_hover_volume_idx() >= 0) m_mouse_left_down = true; + + } else if (mouse_event.LeftUp()) { + if (m_mouse_left_down) { + // responsible for mouse left up after selecting plane + m_mouse_left_down = false; + return true; + } + } else if (mouse_event.Leaving()) { m_mouse_left_down = false; - return true; } return false; } +void GLGizmoFlatten::data_changed() +{ + const Selection & selection = m_parent.get_selection(); + const ModelObject *model_object = nullptr; + if (selection.is_single_full_instance() || + selection.is_from_single_object() ) { + model_object = selection.get_model()->objects[selection.get_object_idx()]; + } + set_flattening_data(model_object); +} + bool GLGizmoFlatten::on_init() { // BBS diff --git a/src/slic3r/GUI/Gizmos/GLGizmoFlatten.hpp b/src/slic3r/GUI/Gizmos/GLGizmoFlatten.hpp index 54d931577da..80ae9edd712 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoFlatten.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoFlatten.hpp @@ -35,7 +35,7 @@ class GLGizmoFlatten : public GLGizmoBase std::vector m_planes; std::vector> m_planes_casters; - bool m_mouse_left_down = false; + bool m_mouse_left_down = false; // for detection left_up of this gizmo const ModelObject* m_old_model_object = nullptr; std::vector instances_matrices; @@ -54,6 +54,7 @@ class GLGizmoFlatten : public GLGizmoBase /// Return True when use the information otherwise False. bool on_mouse(const wxMouseEvent &mouse_event) override; + void data_changed() override; protected: bool on_init() override; std::string on_get_name() const override; diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp index e99a7bb34ae..585361d168e 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp @@ -162,11 +162,10 @@ void GLGizmoMmuSegmentation::render_painter_gizmo() glsafe(::glDisable(GL_BLEND)); } -void GLGizmoMmuSegmentation::set_painter_gizmo_data(const Selection &selection) +void GLGizmoMmuSegmentation::data_changed() { - GLGizmoPainterBase::set_painter_gizmo_data(selection); - - if (m_state != On || wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology() != ptFFF || wxGetApp().filaments_cnt() <= 1) + GLGizmoPainterBase::data_changed(); + if (m_state != On || wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology() != ptFFF || wxGetApp().extruders_edited_cnt() <= 1) return; ModelObject* model_object = m_c->selection_info()->model_object(); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.hpp b/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.hpp index ac8238e911a..d9fe8d936b5 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.hpp @@ -70,7 +70,7 @@ class GLGizmoMmuSegmentation : public GLGizmoPainterBase void render_painter_gizmo() override; - void set_painter_gizmo_data(const Selection& selection) override; + void data_changed() override; void render_triangles(const Selection& selection) const override; diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMove.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMove.cpp index 63857189cd1..4846ede7770 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMove.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMove.cpp @@ -47,6 +47,12 @@ bool GLGizmoMove3D::on_mouse(const wxMouseEvent &mouse_event) { return use_grabbers(mouse_event); } +void GLGizmoMove3D::data_changed() { + const Selection &selection = m_parent.get_selection(); + bool is_wipe_tower = selection.is_wipe_tower(); + m_grabbers[2].enabled = !is_wipe_tower; +} + bool GLGizmoMove3D::on_init() { for (int i = 0; i < 3; ++i) { diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMove.hpp b/src/slic3r/GUI/Gizmos/GLGizmoMove.hpp index bbe88f5942f..0650825904f 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMove.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMove.hpp @@ -49,6 +49,10 @@ class GLGizmoMove3D : public GLGizmoBase /// Return True when use the information otherwise False. bool on_mouse(const wxMouseEvent &mouse_event) override; + /// + /// Detect reduction of move for wipetover on selection change + /// + void data_changed() override; protected: bool on_init() override; std::string on_get_name() const override; diff --git a/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp b/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp index c9daac5797e..1c4d5bdefe7 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp @@ -34,13 +34,13 @@ GLGizmoPainterBase::~GLGizmoPainterBase() s_sphere.reset(); } -void GLGizmoPainterBase::set_painter_gizmo_data(const Selection& selection) +void GLGizmoPainterBase::data_changed() { if (m_state != On) return; const ModelObject* mo = m_c->selection_info() ? m_c->selection_info()->model_object() : nullptr; - + const Selection & selection = m_parent.get_selection(); if (mo && selection.is_from_single_instance() && (m_schedule_update || mo->id() != m_old_mo_id || mo->volumes.size() != m_old_volumes_size)) { @@ -902,22 +902,13 @@ bool GLGizmoPainterBase::gizmo_event(SLAGizmoEventType action, const Vec2d& mous bool GLGizmoPainterBase::on_mouse(const wxMouseEvent &mouse_event) { - // TODO: distribute implementation into gizmos itself - - GLGizmosManager & mng = m_parent.get_gizmos_manager(); - GLGizmosManager::EType current_type = mng.get_current_type(); - // wxCoord == int --> wx/types.h Vec2i mouse_coord(mouse_event.GetX(), mouse_event.GetY()); Vec2d mouse_pos = mouse_coord.cast(); if (mouse_event.Moving()) { - if (current_type == GLGizmosManager::MmuSegmentation || - current_type == GLGizmosManager::FdmSupports || - current_type == GLGizmosManager::Text) - gizmo_event(SLAGizmoEventType::Moving, mouse_pos, - mouse_event.ShiftDown(), mouse_event.AltDown(), - false); + gizmo_event(SLAGizmoEventType::Moving, mouse_pos, mouse_event.ShiftDown(), mouse_event.AltDown(), false); + return false; } // when control is down we allow scene pan and rotation even when clicking @@ -927,78 +918,51 @@ bool GLGizmoPainterBase::on_mouse(const wxMouseEvent &mouse_event) const Selection &selection = m_parent.get_selection(); int selected_object_idx = selection.get_object_idx(); - if (mouse_event.LeftDown() && (!control_down || grabber_contains_mouse)) { - if ((current_type == GLGizmosManager::FdmSupports || - current_type == GLGizmosManager::Seam || - current_type == GLGizmosManager::MmuSegmentation || - current_type == GLGizmosManager::Text || - current_type == GLGizmosManager::Cut || - current_type == GLGizmosManager::MeshBoolean) && - gizmo_event(SLAGizmoEventType::LeftDown, mouse_pos, - mouse_event.ShiftDown(), mouse_event.AltDown(), false)) + if (mouse_event.LeftDown()) { + if ((!control_down || grabber_contains_mouse) && + gizmo_event(SLAGizmoEventType::LeftDown, mouse_pos, mouse_event.ShiftDown(), mouse_event.AltDown(), false)) // the gizmo got the event and took some action, there is no need // to do anything more return true; - } else if (mouse_event.RightDown() && !control_down && selected_object_idx != -1 && - (current_type == GLGizmosManager::FdmSupports || - current_type == GLGizmosManager::Seam || - current_type == GLGizmosManager::MmuSegmentation || - current_type == GLGizmosManager::Cut) && - gizmo_event(SLAGizmoEventType::RightDown, mouse_pos, false, false, false)) { - // event was taken care of by the FdmSupports / Seam / MMUPainting / Cut gizmo - return true; - } else if (mouse_event.Dragging() && - m_parent.get_move_volume_id() != -1 && - (current_type == GLGizmosManager::FdmSupports || - current_type == GLGizmosManager::Seam || - current_type == GLGizmosManager::MmuSegmentation)) - // don't allow dragging objects with the Sla gizmo on - return true; - else if (mouse_event.Dragging() && !control_down && - (current_type == GLGizmosManager::FdmSupports || - current_type == GLGizmosManager::Seam || - current_type == GLGizmosManager::MmuSegmentation || - current_type == GLGizmosManager::Cut) && - gizmo_event(SLAGizmoEventType::Dragging, mouse_pos, - mouse_event.ShiftDown(), mouse_event.AltDown(), false)) { - // the gizmo got the event and took some action, no need to do - // anything more here - m_parent.set_as_dirty(); - return true; - } else if (mouse_event.Dragging() && control_down && - (mouse_event.LeftIsDown() || mouse_event.RightIsDown())) { - // CTRL has been pressed while already dragging -> stop current action - if (mouse_event.LeftIsDown()) - gizmo_event(SLAGizmoEventType::LeftUp, mouse_pos, - mouse_event.ShiftDown(), mouse_event.AltDown(), true); - else if (mouse_event.RightIsDown()) - gizmo_event(SLAGizmoEventType::RightUp, mouse_pos, - mouse_event.ShiftDown(), mouse_event.AltDown(), true); - - } else if (mouse_event.LeftUp() && - (current_type == GLGizmosManager::FdmSupports || - current_type == GLGizmosManager::Seam || - current_type == GLGizmosManager::MmuSegmentation || - current_type == GLGizmosManager::Cut) && - !m_parent.is_mouse_dragging()) { - // in case SLA/FDM gizmo is selected, we just pass the LeftUp event - // and stop processing - neither object moving or selecting is - // suppressed in that case - gizmo_event(SLAGizmoEventType::LeftUp, mouse_pos, - mouse_event.ShiftDown(), mouse_event.AltDown(), - control_down); - return true; - } else if (mouse_event.RightUp() && - (current_type == GLGizmosManager::FdmSupports || - current_type == GLGizmosManager::Seam || - current_type == GLGizmosManager::MmuSegmentation || - current_type == GLGizmosManager::Cut) && - !m_parent.is_mouse_dragging()) { - gizmo_event(SLAGizmoEventType::RightUp, mouse_pos, - mouse_event.ShiftDown(), mouse_event.AltDown(), - control_down); - - return true; + } else if (mouse_event.RightDown()){ + if (!control_down && selected_object_idx != -1 && + gizmo_event(SLAGizmoEventType::RightDown, mouse_pos, false, false, false)) + // event was taken care of + return true; + } else if (mouse_event.Dragging()) { + if (m_parent.get_move_volume_id() != -1) + // don't allow dragging objects with the Sla gizmo on + return true; + if (!control_down && gizmo_event(SLAGizmoEventType::Dragging, + mouse_pos, mouse_event.ShiftDown(), + mouse_event.AltDown(), false)) { + // the gizmo got the event and took some action, no need to do + // anything more here + m_parent.set_as_dirty(); + return true; + } + if(control_down && (mouse_event.LeftIsDown() || mouse_event.RightIsDown())) + { + // CTRL has been pressed while already dragging -> stop current action + if (mouse_event.LeftIsDown()) + gizmo_event(SLAGizmoEventType::LeftUp, mouse_pos, mouse_event.ShiftDown(), mouse_event.AltDown(), true); + else if (mouse_event.RightIsDown()) + gizmo_event(SLAGizmoEventType::RightUp, mouse_pos, mouse_event.ShiftDown(), mouse_event.AltDown(), true); + return false; + } + } else if (mouse_event.LeftUp()) { + if (!m_parent.is_mouse_dragging()) { + // in case SLA/FDM gizmo is selected, we just pass the LeftUp + // event and stop processing - neither object moving or selecting + // is suppressed in that case + gizmo_event(SLAGizmoEventType::LeftUp, mouse_pos, mouse_event.ShiftDown(), mouse_event.AltDown(), control_down); + return true; + } + } else if (mouse_event.RightUp()) { + if (!m_parent.is_mouse_dragging()) { + gizmo_event(SLAGizmoEventType::RightUp, mouse_pos, mouse_event.ShiftDown(), mouse_event.AltDown(), control_down); + return true; + } } return false; } diff --git a/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.hpp b/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.hpp index 15f7c1868d3..5aadd0a3ec7 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.hpp @@ -21,6 +21,7 @@ enum class SLAGizmoEventType : unsigned char; class ClippingPlane; struct Camera; class GLGizmoMmuSegmentation; +class Selection; enum class PainterGizmoType { FDM_SUPPORTS, @@ -188,7 +189,7 @@ class GLGizmoPainterBase : public GLGizmoBase public: GLGizmoPainterBase(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id); virtual ~GLGizmoPainterBase() override; - virtual void set_painter_gizmo_data(const Selection& selection); + void data_changed() override; virtual bool gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_position, bool shift_down, bool alt_down, bool control_down); // Following function renders the triangles and cursor. Having this separated diff --git a/src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp b/src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp index 6bc7cbaa5a3..c32e021091a 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp @@ -29,7 +29,16 @@ const float GLGizmoRotate::GrabberOffset = 0.15f; // in percent of radius GLGizmoRotate::GLGizmoRotate(GLCanvas3D& parent, GLGizmoRotate::Axis axis) : GLGizmoBase(parent, "", -1) , m_axis(axis) -{} + , m_drag_color(DEFAULT_DRAG_COLOR) + , m_highlight_color(DEFAULT_HIGHLIGHT_COLOR) +{ + m_group_id = static_cast(axis); +} + +void GLGizmoRotate::set_highlight_color(const ColorRGBA &color) +{ + m_highlight_color = color; +} void GLGizmoRotate::set_angle(double angle) { @@ -58,6 +67,21 @@ bool GLGizmoRotate::on_mouse(const wxMouseEvent &mouse_event) void GLGizmoRotate::dragging(const UpdateData &data) { on_dragging(data); } +void GLGizmoRotate::start_dragging() +{ + m_grabbers[0].dragging = true; + on_start_dragging(); +} + +void GLGizmoRotate::stop_dragging() +{ + m_grabbers[0].dragging = false; + on_stop_dragging(); +} + +void GLGizmoRotate::enable_grabber() { m_grabbers[0].enabled = true; } +void GLGizmoRotate::disable_grabber() { m_grabbers[0].enabled = false; } + bool GLGizmoRotate::on_init() { m_grabbers.push_back(Grabber()); @@ -456,10 +480,6 @@ GLGizmoRotate3D::GLGizmoRotate3D(GLCanvas3D& parent, const std::string& icon_fil //BBS: GUI refactor: add obj manipulation , m_object_manipulation(obj_manipulation) { - for (unsigned int i = 0; i < 3; ++i) { - m_gizmos[i].set_group_id(i); - } - load_rotoptimize_state(); } @@ -475,6 +495,25 @@ bool GLGizmoRotate3D::on_mouse(const wxMouseEvent &mouse_event) { return use_grabbers(mouse_event); } +void GLGizmoRotate3D::data_changed() { + const Selection &selection = m_parent.get_selection(); + bool is_wipe_tower = selection.is_wipe_tower(); + if (is_wipe_tower) { + DynamicPrintConfig& config = wxGetApp().preset_bundle->prints.get_edited_preset().config; + float wipe_tower_rotation_angle = + dynamic_cast( + config.option("wipe_tower_rotation_angle")) + ->value; + set_rotation(Vec3d(0., 0., (M_PI / 180.) * wipe_tower_rotation_angle)); + m_gizmos[0].disable_grabber(); + m_gizmos[1].disable_grabber(); + } else { + set_rotation(Vec3d::Zero()); + m_gizmos[0].enable_grabber(); + m_gizmos[1].enable_grabber(); + } +} + bool GLGizmoRotate3D::on_init() { for (GLGizmoRotate& g : m_gizmos) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoRotate.hpp b/src/slic3r/GUI/Gizmos/GLGizmoRotate.hpp index acd2c2876e3..0a686e701a2 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoRotate.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoRotate.hpp @@ -9,7 +9,7 @@ namespace Slic3r { namespace GUI { - +class Selection; class GLGizmoRotate : public GLGizmoBase { static const float Offset; @@ -24,9 +24,9 @@ class GLGizmoRotate : public GLGizmoBase public: enum Axis : unsigned char { - X, - Y, - Z + X=0, + Y=1, + Z=2 }; private: @@ -39,6 +39,9 @@ class GLGizmoRotate : public GLGizmoBase float m_snap_coarse_out_radius{ 0.0f }; float m_snap_fine_in_radius{ 0.0f }; float m_snap_fine_out_radius{ 0.0f }; + + ColorRGBA m_drag_color; + ColorRGBA m_highlight_color; GLModel m_circle; GLModel m_scale; @@ -66,6 +69,14 @@ class GLGizmoRotate : public GLGizmoBase void set_center(const Vec3d &point) { m_custom_center = point; } + void start_dragging(); + void stop_dragging(); + + void enable_grabber(); + void disable_grabber(); + + void set_highlight_color(const ColorRGBA &color); + /// /// Postpone to Grabber for move /// Detect move of object by dragging @@ -136,6 +147,7 @@ class GLGizmoRotate3D : public GLGizmoBase /// Return True when use the information otherwise False. bool on_mouse(const wxMouseEvent &mouse_event) override; + void data_changed() override; protected: bool on_init() override; std::string on_get_name() const override; @@ -147,14 +159,7 @@ class GLGizmoRotate3D : public GLGizmoBase for (int i = 0; i < 3; ++i) m_gizmos[i].set_hover_id((m_hover_id == i) ? 0 : -1); } - void on_enable_grabber(unsigned int id) override { - if (id < 3) - m_gizmos[id].enable_grabber(0); - } - void on_disable_grabber(unsigned int id) override { - if (id < 3) - m_gizmos[id].disable_grabber(0); - } + bool on_is_activable() const override; void on_start_dragging() override; void on_stop_dragging() override; diff --git a/src/slic3r/GUI/Gizmos/GLGizmoScale.cpp b/src/slic3r/GUI/Gizmos/GLGizmoScale.cpp index 6215e715253..7c3ec6a8964 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoScale.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoScale.cpp @@ -27,6 +27,9 @@ GLGizmoScale3D::GLGizmoScale3D(GLCanvas3D& parent, const std::string& icon_filen : GLGizmoBase(parent, icon_filename, sprite_id) //BBS: GUI refactor: add obj manipulation , m_object_manipulation(obj_manipulation) + , m_base_color(DEFAULT_BASE_COLOR) + , m_drag_color(DEFAULT_DRAG_COLOR) + , m_highlight_color(DEFAULT_HIGHLIGHT_COLOR) { m_grabber_connections[0].grabber_indices = { 0, 1 }; m_grabber_connections[1].grabber_indices = { 2, 3 }; @@ -90,6 +93,29 @@ bool GLGizmoScale3D::on_mouse(const wxMouseEvent &mouse_event) return use_grabbers(mouse_event); } +void GLGizmoScale3D::data_changed() +{ + const Selection &selection = m_parent.get_selection(); + bool enable_scale_xyz = selection.is_single_full_instance() || + selection.is_single_volume() || + selection.is_single_modifier(); + for (unsigned int i = 0; i < 6; ++i) + m_grabbers[i].enabled = enable_scale_xyz; + + if (enable_scale_xyz) { + // all volumes in the selection belongs to the same instance, any of + // them contains the needed data, so we take the first + const GLVolume *volume = selection.get_volume(*selection.get_volume_idxs().begin()); + if (selection.is_single_full_instance()) { + set_scale(volume->get_instance_scaling_factor()); + } else if (selection.is_single_volume() || + selection.is_single_modifier()) { + set_scale(volume->get_volume_scaling_factor()); + } + } else { + set_scale(Vec3d::Ones()); + } +} bool GLGizmoScale3D::on_init() { diff --git a/src/slic3r/GUI/Gizmos/GLGizmoScale.hpp b/src/slic3r/GUI/Gizmos/GLGizmoScale.hpp index cb504eadb80..1b0a47b6baf 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoScale.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoScale.hpp @@ -36,7 +36,11 @@ class GLGizmoScale3D : public GLGizmoBase Vec3d m_offset{ Vec3d::Zero() }; double m_snap_step{ 0.05 }; StartingData m_starting; - + + ColorRGBA m_base_color; + ColorRGBA m_drag_color; + ColorRGBA m_highlight_color; + struct GrabberConnection { GLModel model; @@ -71,6 +75,7 @@ class GLGizmoScale3D : public GLGizmoBase /// Return True when use the information otherwise False. bool on_mouse(const wxMouseEvent &mouse_event) override; + void data_changed() override; protected: virtual bool on_init() override; virtual std::string on_get_name() const override; diff --git a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp index 3187e426644..204e9ebf8e6 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp @@ -308,9 +308,9 @@ void GLGizmosManager::refresh_on_off_state() if (m_serializing || m_current == Undefined || m_gizmos.empty()) return; - if (m_current != Undefined - && ! m_gizmos[m_current]->is_activable() && activate_gizmo(Undefined)) - update_data(); + // FS: Why update data after Undefined gizmo activation? + if (!m_gizmos[m_current]->is_activable() && activate_gizmo(Undefined)) + update_data(); } void GLGizmosManager::reset_all_states() @@ -361,17 +361,6 @@ void GLGizmosManager::set_hover_id(int id) m_gizmos[m_current]->set_hover_id(id); } -void GLGizmosManager::enable_grabber(EType type, unsigned int id, bool enable) -{ - if (!m_enabled || type == Undefined || m_gizmos.empty()) - return; - - if (enable) - m_gizmos[type]->enable_grabber(id); - else - m_gizmos[type]->disable_grabber(id); -} - void GLGizmosManager::update_assemble_view_data() { if (m_assemble_view_data) { @@ -382,73 +371,14 @@ void GLGizmosManager::update_assemble_view_data() } } -// TODO: divide into gizmo: on init + on selection change void GLGizmosManager::update_data() { - if (!m_enabled) - return; - - const Selection& selection = m_parent.get_selection(); - - bool is_wipe_tower = selection.is_wipe_tower(); - enable_grabber(Move, 2, !is_wipe_tower); - enable_grabber(Rotate, 0, !is_wipe_tower); - enable_grabber(Rotate, 1, !is_wipe_tower); - - // BBS: when select multiple objects, uniform scale can be deselected, display the 0-5 grabbers - //bool enable_scale_xyz = selection.is_single_full_instance() || selection.is_single_volume() || selection.is_single_modifier(); - //for (unsigned int i = 0; i < 6; ++i) - //{ - // enable_grabber(Scale, i, enable_scale_xyz); - //} - - if (m_common_gizmos_data) { + if (!m_enabled) return; + if (m_common_gizmos_data) m_common_gizmos_data->update(get_current() - ? get_current()->get_requirements() - : CommonGizmosDataID(0)); - } - - if (selection.is_single_full_instance()) - { - // all volumes in the selection belongs to the same instance, any of them contains the needed data, so we take the first - const GLVolume* volume = selection.get_volume(*selection.get_volume_idxs().begin()); - set_scale(volume->get_instance_scaling_factor()); - set_rotation(Vec3d::Zero()); - // BBS - finish_cut_rotation(); - ModelObject* model_object = selection.get_model()->objects[selection.get_object_idx()]; - set_flattening_data(model_object); - //set_sla_support_data(model_object); - set_painter_gizmo_data(); - } - else if (selection.is_single_volume() || selection.is_single_modifier()) - { - const GLVolume* volume = selection.get_volume(*selection.get_volume_idxs().begin()); - set_scale(volume->get_volume_scaling_factor()); - set_rotation(Vec3d::Zero()); - // BBS - finish_cut_rotation(); - set_flattening_data(nullptr); - //set_sla_support_data(nullptr); - set_painter_gizmo_data(); - } - else if (is_wipe_tower) - { - DynamicPrintConfig& proj_cfg = wxGetApp().preset_bundle->project_config; - set_scale(Vec3d::Ones()); - set_rotation(Vec3d(0., 0., (M_PI/180.) * dynamic_cast(proj_cfg.option("wipe_tower_rotation_angle"))->value)); - set_flattening_data(nullptr); - //set_sla_support_data(nullptr); - set_painter_gizmo_data(); - } - else - { - set_scale(Vec3d::Ones()); - set_rotation(Vec3d::Zero()); - set_flattening_data(selection.is_from_single_object() ? selection.get_model()->objects[selection.get_object_idx()] : nullptr); - //set_sla_support_data(selection.is_from_single_instance() ? selection.get_model()->objects[selection.get_object_idx()] : nullptr); - set_painter_gizmo_data(); - } + ? get_current()->get_requirements() + : CommonGizmosDataID(0)); + if (m_current != Undefined) m_gizmos[m_current]->data_changed(); //BBS: GUI refactor: add object manipulation in gizmo m_object_manipulation.update_ui_from_settings(); @@ -492,91 +422,6 @@ bool GLGizmosManager::is_dragging() const return m_gizmos[m_current]->is_dragging(); } -void GLGizmosManager::start_dragging() -{ - if (! m_enabled || m_current == Undefined) - return; - m_gizmos[m_current]->start_dragging(); -} - -void GLGizmosManager::stop_dragging() -{ - if (! m_enabled || m_current == Undefined) - return; - - m_gizmos[m_current]->stop_dragging(); -} - -Vec3d GLGizmosManager::get_scale() const -{ - if (!m_enabled) - return Vec3d::Ones(); - - return dynamic_cast(m_gizmos[Scale].get())->get_scale(); -} - -void GLGizmosManager::set_scale(const Vec3d& scale) -{ - if (!m_enabled || m_gizmos.empty()) - return; - - dynamic_cast(m_gizmos[Scale].get())->set_scale(scale); -} - -Vec3d GLGizmosManager::get_rotation() const -{ - if (!m_enabled || m_gizmos.empty()) - return Vec3d::Zero(); - - return dynamic_cast(m_gizmos[Rotate].get())->get_rotation(); -} - -void GLGizmosManager::set_rotation(const Vec3d& rotation) -{ - if (!m_enabled || m_gizmos.empty()) - return; - dynamic_cast(m_gizmos[Rotate].get())->set_rotation(rotation); -} - -// BBS -void GLGizmosManager::finish_cut_rotation() -{ - dynamic_cast(m_gizmos[Cut].get())->finish_rotation(); -} - -void GLGizmosManager::set_flattening_data(const ModelObject* model_object) -{ - if (!m_enabled || m_gizmos.empty()) - return; - - dynamic_cast(m_gizmos[Flatten].get())->set_flattening_data(model_object); -} - -/* -void GLGizmosManager::set_sla_support_data(ModelObject* model_object) -{ - if (! m_enabled - || m_gizmos.empty() - || wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology() != ptSLA) - return; - - auto* gizmo_hollow = dynamic_cast(m_gizmos[Hollow].get()); - auto* gizmo_supports = dynamic_cast(m_gizmos[SlaSupports].get()); - gizmo_hollow->set_sla_support_data(model_object, m_parent.get_selection()); - gizmo_supports->set_sla_support_data(model_object, m_parent.get_selection()); -} -*/ - -void GLGizmosManager::set_painter_gizmo_data() -{ - if (!m_enabled || m_gizmos.empty()) - return; - - dynamic_cast(m_gizmos[FdmSupports].get())->set_painter_gizmo_data(m_parent.get_selection()); - dynamic_cast(m_gizmos[Seam].get())->set_painter_gizmo_data(m_parent.get_selection()); - dynamic_cast(m_gizmos[MmuSegmentation].get())->set_painter_gizmo_data(m_parent.get_selection()); -} - // Returns true if the gizmo used the event to do something, false otherwise. bool GLGizmosManager::gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_position, bool shift_down, bool alt_down, bool control_down) { @@ -1446,12 +1291,6 @@ bool GLGizmosManager::is_hiding_instances() const && m_common_gizmos_data->instances_hider()->is_valid()); } - -int GLGizmosManager::get_shortcut_key(GLGizmosManager::EType type) const -{ - return m_gizmos[type]->get_shortcut_key(); -} - std::string get_name_from_gizmo_etype(GLGizmosManager::EType type) { switch (type) { diff --git a/src/slic3r/GUI/Gizmos/GLGizmosManager.hpp b/src/slic3r/GUI/Gizmos/GLGizmosManager.hpp index 23812c8dca9..6d081c59021 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosManager.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosManager.hpp @@ -225,8 +225,11 @@ class GLGizmosManager : public Slic3r::ObjectBase bool check_gizmos_closed_except(EType) const; void set_hover_id(int id); - void enable_grabber(EType type, unsigned int id, bool enable); + /// + /// Distribute information about different data into active gizmo + /// Should be called when selection changed + /// void update_data(); void update_assemble_view_data(); @@ -239,17 +242,6 @@ class GLGizmosManager : public Slic3r::ObjectBase bool handle_shortcut(int key); bool is_dragging() const; - void start_dragging(); - void stop_dragging(); - - Vec3d get_scale() const; - void set_scale(const Vec3d& scale); - - Vec3d get_rotation() const; - void set_rotation(const Vec3d& rotation); - - // BBS - void finish_cut_rotation(); //BBS void* get_icon_texture_id(MENU_ICON_NAME icon) { @@ -265,13 +257,6 @@ class GLGizmosManager : public Slic3r::ObjectBase return nullptr; } - void set_flattening_data(const ModelObject* model_object); - - //void set_sla_support_data(ModelObject* model_object); - - void set_painter_gizmo_data(); - - bool gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_position = Vec2d::Zero(), bool shift_down = false, bool alt_down = false, bool control_down = false); ClippingPlane get_clipping_plane() const; ClippingPlane get_assemble_view_clipping_plane() const; bool wants_reslice_supports_on_undo() const; @@ -298,7 +283,6 @@ class GLGizmosManager : public Slic3r::ObjectBase void update_after_undo_redo(const UndoRedo::Snapshot& snapshot); int get_selectable_icons_cnt() const { return get_selectable_idxs().size(); } - int get_shortcut_key(GLGizmosManager::EType) const; // To end highlight set gizmo = undefined void set_highlight(EType gizmo, bool highlight_shown) { m_highlight = std::pair(gizmo, highlight_shown); } @@ -311,6 +295,12 @@ class GLGizmosManager : public Slic3r::ObjectBase bool get_uniform_scaling() const { return m_object_manipulation.get_uniform_scaling();} private: + bool gizmo_event(SLAGizmoEventType action, + const Vec2d & mouse_position = Vec2d::Zero(), + bool shift_down = false, + bool alt_down = false, + bool control_down = false); + void render_background(float left, float top, float right, float bottom, float border_w, float border_h) const; void do_render_overlay() const; diff --git a/src/slic3r/GUI/Gizmos/GizmoObjectManipulation.cpp b/src/slic3r/GUI/Gizmos/GizmoObjectManipulation.cpp index 2cdd8aac36e..e2be1a7fda7 100644 --- a/src/slic3r/GUI/Gizmos/GizmoObjectManipulation.cpp +++ b/src/slic3r/GUI/Gizmos/GizmoObjectManipulation.cpp @@ -259,7 +259,7 @@ void GizmoObjectManipulation::change_position_value(int axis, double value) position(axis) = value; Selection& selection = m_glcanvas.get_selection(); - selection.start_dragging(); + selection.setup_cache(); selection.translate(position - m_cache.position, selection.requires_local_axes()); m_glcanvas.do_move(L("Set Position")); @@ -287,7 +287,7 @@ void GizmoObjectManipulation::change_rotation_value(int axis, double value) transformation_type.set_local(); } - selection.start_dragging(); + selection.setup_cache(); selection.rotate( (M_PI / 180.0) * (transformation_type.absolute() ? rotation : rotation - m_cache.rotation), transformation_type); @@ -363,7 +363,7 @@ void GizmoObjectManipulation::do_scale(int axis, const Vec3d &scale) const if (m_uniform_scale/* || selection.requires_uniform_scale()*/) scaling_factor = scale(axis) * Vec3d::Ones(); - selection.start_dragging(); + selection.setup_cache(); selection.scale(scaling_factor * 0.01, transformation_type); m_glcanvas.do_scale(L("Set Scale")); } diff --git a/src/slic3r/GUI/Selection.cpp b/src/slic3r/GUI/Selection.cpp index 42e004b8683..36f2294cb51 100644 --- a/src/slic3r/GUI/Selection.cpp +++ b/src/slic3r/GUI/Selection.cpp @@ -117,7 +117,6 @@ Selection::Selection() , m_type(Empty) , m_valid(false) , m_scale_factor(1.0f) - , m_dragging(false) { this->set_bounding_boxes_dirty(); } @@ -812,12 +811,11 @@ const BoundingBoxf3& Selection::get_scaled_instance_bounding_box() const return *m_scaled_instance_bounding_box; } -void Selection::start_dragging() +void Selection::setup_cache() { if (!m_valid) return; - m_dragging = true; set_caches(); } @@ -1166,12 +1164,12 @@ void Selection::scale_to_fit_print_volume(const BuildVolume& volume) type.set_joint(); // apply scale - start_dragging(); + setup_cache(); scale(s * Vec3d::Ones(), type); wxGetApp().plater()->canvas3D()->do_scale(""); // avoid storing another snapshot // center selection on print bed - start_dragging(); + setup_cache(); offset.z() = -get_bounding_box().min.z(); translate(offset); wxGetApp().plater()->canvas3D()->do_move(""); // avoid storing another snapshot diff --git a/src/slic3r/GUI/Selection.hpp b/src/slic3r/GUI/Selection.hpp index c2eb7e067bd..1337bec3866 100644 --- a/src/slic3r/GUI/Selection.hpp +++ b/src/slic3r/GUI/Selection.hpp @@ -229,7 +229,6 @@ class Selection Planes m_planes; float m_scale_factor; - bool m_dragging; // BBS EMode m_volume_selection_mode{ Instance }; @@ -334,9 +333,7 @@ class Selection const BoundingBoxf3& get_unscaled_instance_bounding_box() const; const BoundingBoxf3& get_scaled_instance_bounding_box() const; - void start_dragging(); - void stop_dragging() { m_dragging = false; } - bool is_dragging() const { return m_dragging; } + void setup_cache(); void translate(const Vec3d& displacement, bool local = false); void move_to_center(const Vec3d& displacement, bool local = false); From 049dfd3e08987b546abc288aa7bc53c55686948b Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Mon, 30 Oct 2023 20:12:21 +0800 Subject: [PATCH 78/99] Added method const GLVolume* Selection::get_first_volume() const to simplify client code (cherry picked from commit prusa3d/PrusaSlicer@0e3490620e2b835b7382d23b6d0022205e9293f4) --- src/slic3r/GUI/GUI_ObjectList.cpp | 9 ++++----- src/slic3r/GUI/Gizmos/GLGizmoAdvancedCut.cpp | 2 +- src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp | 2 +- src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp | 4 ++-- src/slic3r/GUI/Gizmos/GLGizmoScale.cpp | 10 +++++----- src/slic3r/GUI/Gizmos/GLGizmoText.cpp | 4 ++-- src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp | 2 +- .../GUI/Gizmos/GizmoObjectManipulation.cpp | 18 +++++++++--------- src/slic3r/GUI/Plater.cpp | 8 ++++---- 9 files changed, 29 insertions(+), 30 deletions(-) diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp index 5e5eee38062..ad885ebb4ee 100644 --- a/src/slic3r/GUI/GUI_ObjectList.cpp +++ b/src/slic3r/GUI/GUI_ObjectList.cpp @@ -1950,7 +1950,7 @@ void ObjectList::load_modifier(const wxArrayString& input_files, ModelObject& mo const BoundingBoxf3 instance_bb = model_object.instance_bounding_box(instance_idx); // First (any) GLVolume of the selected instance. They all share the same instance matrix. - const GLVolume* v = selection.get_volume(*selection.get_volume_idxs().begin()); + const GLVolume* v = selection.get_first_volume(); const Geometry::Transformation inst_transform = v->get_instance_transformation(); const Transform3d inv_inst_transform = inst_transform.get_matrix(true).inverse(); const Vec3d instance_offset = v->get_instance_offset(); @@ -2086,7 +2086,7 @@ void ObjectList::load_generic_subobject(const std::string& type_name, const Mode ModelVolume *new_volume = model_object.add_volume(std::move(mesh), type); // First (any) GLVolume of the selected instance. They all share the same instance matrix. - const GLVolume* v = selection.get_volume(*selection.get_volume_idxs().begin()); + const GLVolume* v = selection.get_first_volume(); // Transform the new modifier to be aligned with the print bed. const BoundingBoxf3 mesh_bb = new_volume->mesh().bounding_box(); new_volume->set_transformation(Geometry::Transformation::volume_to_bed_transformation(v->get_instance_transformation(), mesh_bb)); @@ -4350,7 +4350,7 @@ void ObjectList::update_selections() sels.Add(m_objects_model->GetItemById(selection.get_object_idx())); } else if (selection.is_single_volume() || selection.is_any_modifier()) { - const auto gl_vol = selection.get_volume(*selection.get_volume_idxs().begin()); + const auto gl_vol = selection.get_first_volume(); if (m_objects_model->GetVolumeIdByItem(m_objects_model->GetParent(item)) == gl_vol->volume_idx()) return; } @@ -4426,8 +4426,7 @@ void ObjectList::update_selections() { if (m_selection_mode & smSettings) { - const auto idx = *selection.get_volume_idxs().begin(); - const auto gl_vol = selection.get_volume(idx); + const auto gl_vol = selection.get_first_volume(); if (gl_vol->volume_idx() >= 0) { // Only add GLVolumes with non-negative volume_ids. GLVolumes with negative volume ids // are not associated with ModelVolumes, but they are temporarily generated by the backend diff --git a/src/slic3r/GUI/Gizmos/GLGizmoAdvancedCut.cpp b/src/slic3r/GUI/Gizmos/GLGizmoAdvancedCut.cpp index 70df971f88e..14d351a1a62 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoAdvancedCut.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoAdvancedCut.cpp @@ -621,7 +621,7 @@ void GLGizmoAdvancedCut::perform_cut(const Selection& selection) wxCHECK_RET(instance_idx >= 0 && object_idx >= 0, "GLGizmoAdvancedCut: Invalid object selection"); // m_cut_z is the distance from the bed. Subtract possible SLA elevation. - const GLVolume* first_glvolume = selection.get_volume(*selection.get_volume_idxs().begin()); + const GLVolume* first_glvolume = selection.get_first_volume(); // perform cut { diff --git a/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp b/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp index 1c4d5bdefe7..8831c61abeb 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp @@ -341,7 +341,7 @@ BoundingBoxf3 GLGizmoPainterBase::bounding_box() const void GLGizmoPainterBase::update_contours(const TriangleMesh& vol_mesh, float cursor_z, float max_z, float min_z) const { const Selection& selection = m_parent.get_selection(); - const GLVolume* first_glvolume = selection.get_volume(*selection.get_volume_idxs().begin()); + const GLVolume* first_glvolume = selection.get_first_volume(); const BoundingBoxf3& box = first_glvolume->transformed_convex_hull_bounding_box(); const ModelObject* model_object = wxGetApp().model().objects[selection.get_object_idx()]; diff --git a/src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp b/src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp index c32e021091a..e6a3c9f2354 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp @@ -432,7 +432,7 @@ Transform3d GLGizmoRotate::local_transform(const Selection& selection) const } if (selection.is_single_volume() || selection.is_single_modifier() || selection.requires_local_axes()) - ret = selection.get_volume(*selection.get_volume_idxs().begin())->get_instance_transformation().get_matrix(true, false, true, true) * ret; + ret = selection.get_first_volume()->get_instance_transformation().get_matrix(true, false, true, true) * ret; return Geometry::assemble_transform(m_center) * ret; } @@ -466,7 +466,7 @@ Vec3d GLGizmoRotate::mouse_position_in_local_plane(const Linef3& mouse_ray, cons } if (selection.is_single_volume() || selection.is_single_modifier() || selection.requires_local_axes()) - m = m * selection.get_volume(*selection.get_volume_idxs().begin())->get_instance_transformation().get_matrix(true, false, true, true).inverse(); + m = m * selection.get_first_volume()->get_instance_transformation().get_matrix(true, false, true, true).inverse(); m.translate(-m_center); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoScale.cpp b/src/slic3r/GUI/Gizmos/GLGizmoScale.cpp index 7c3ec6a8964..195368ecf58 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoScale.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoScale.cpp @@ -49,9 +49,9 @@ std::string GLGizmoScale3D::get_tooltip() const Vec3f scale = 100.0f * Vec3f::Ones(); if (single_instance) - scale = 100.0f * selection.get_volume(*selection.get_volume_idxs().begin())->get_instance_scaling_factor().cast(); + scale = 100.0f * selection.get_first_volume()->get_instance_scaling_factor().cast(); else if (single_volume) - scale = 100.0f * selection.get_volume(*selection.get_volume_idxs().begin())->get_volume_scaling_factor().cast(); + scale = 100.0f * selection.get_first_volume()->get_volume_scaling_factor().cast(); if (m_hover_id == 0 || m_hover_id == 1 || m_grabbers[0].dragging || m_grabbers[1].dragging) return "X: " + format(scale.x(), 4) + "%"; @@ -105,7 +105,7 @@ void GLGizmoScale3D::data_changed() if (enable_scale_xyz) { // all volumes in the selection belongs to the same instance, any of // them contains the needed data, so we take the first - const GLVolume *volume = selection.get_volume(*selection.get_volume_idxs().begin()); + const GLVolume *volume = selection.get_first_volume(); if (selection.is_single_full_instance()) { set_scale(volume->get_instance_scaling_factor()); } else if (selection.is_single_volume() || @@ -211,7 +211,7 @@ void GLGizmoScale3D::on_render() } // gets transform from first selected volume - const GLVolume* v = selection.get_volume(*idxs.begin()); + const GLVolume* v = selection.get_first_volume(); m_transform = v->get_instance_transformation().get_matrix(); // gets angles from first selected volume angles = v->get_instance_rotation(); @@ -220,7 +220,7 @@ void GLGizmoScale3D::on_render() m_offsets_transform = offsets_transform; } else if (single_volume) { - const GLVolume* v = selection.get_volume(*selection.get_volume_idxs().begin()); + const GLVolume* v = selection.get_first_volume(); m_box = v->bounding_box(); m_transform = v->world_matrix(); angles = Geometry::extract_euler_angles(m_transform); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoText.cpp b/src/slic3r/GUI/Gizmos/GLGizmoText.cpp index 518825ca5c1..4e28011a29a 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoText.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoText.cpp @@ -652,7 +652,7 @@ void GLGizmoText::on_render_input_window(float x, float y, float bottom_limit) const Selection &selection = m_parent.get_selection(); if (selection.is_single_full_instance() || selection.is_single_full_object()) { - const GLVolume * gl_volume = selection.get_volume(*selection.get_volume_idxs().begin()); + const GLVolume * gl_volume = selection.get_first_volume(); int object_idx = gl_volume->object_idx(); if (object_idx != m_object_idx || (object_idx == m_object_idx && m_volume_idx != -1)) { m_object_idx = object_idx; @@ -917,7 +917,7 @@ ModelVolume *GLGizmoText::get_selected_single_volume(int &out_object_idx, int &o { if (m_parent.get_selection().is_single_volume() || m_parent.get_selection().is_single_modifier()) { const Selection &selection = m_parent.get_selection(); - const GLVolume * gl_volume = selection.get_volume(*selection.get_volume_idxs().begin()); + const GLVolume * gl_volume = selection.get_first_volume(); out_object_idx = gl_volume->object_idx(); ModelObject *model_object = selection.get_model()->objects[out_object_idx]; out_volume_idx = gl_volume->volume_idx(); diff --git a/src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp b/src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp index 09a7cff3ecc..3901b142da7 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp @@ -119,7 +119,7 @@ void SelectionInfo::on_update() const Selection& selection = get_pool()->get_canvas()->get_selection(); if (selection.is_single_full_instance()) { m_model_object = selection.get_model()->objects[selection.get_object_idx()]; - m_z_shift = selection.get_volume(*selection.get_volume_idxs().begin())->get_sla_shift_z(); + m_z_shift = selection.get_first_volume()->get_sla_shift_z(); } else m_model_object = nullptr; diff --git a/src/slic3r/GUI/Gizmos/GizmoObjectManipulation.cpp b/src/slic3r/GUI/Gizmos/GizmoObjectManipulation.cpp index e2be1a7fda7..1a5b891598e 100644 --- a/src/slic3r/GUI/Gizmos/GizmoObjectManipulation.cpp +++ b/src/slic3r/GUI/Gizmos/GizmoObjectManipulation.cpp @@ -86,7 +86,7 @@ void GizmoObjectManipulation::update_settings_value(const Selection& selection) ObjectList* obj_list = wxGetApp().obj_list(); if (selection.is_single_full_instance()) { // all volumes in the selection belongs to the same instance, any of them contains the needed instance data, so we take the first one - const GLVolume* volume = selection.get_volume(*selection.get_volume_idxs().begin()); + const GLVolume* volume = selection.get_first_volume(); m_new_position = volume->get_instance_offset(); if (m_world_coordinates) { @@ -118,7 +118,7 @@ void GizmoObjectManipulation::update_settings_value(const Selection& selection) } else if (selection.is_single_modifier() || selection.is_single_volume()) { // the selection contains a single volume - const GLVolume* volume = selection.get_volume(*selection.get_volume_idxs().begin()); + const GLVolume* volume = selection.get_first_volume(); m_new_position = volume->get_volume_offset(); m_new_rotation = volume->get_volume_rotation() * (180. / M_PI); m_new_scale = volume->get_volume_scaling_factor() * 100.; @@ -217,7 +217,7 @@ void GizmoObjectManipulation::update_reset_buttons_visibility() const Selection& selection = m_glcanvas.get_selection(); if (selection.is_single_full_instance() || selection.is_single_modifier() || selection.is_single_volume()) { - const GLVolume* volume = selection.get_volume(*selection.get_volume_idxs().begin()); + const GLVolume* volume = selection.get_first_volume(); Vec3d rotation; Vec3d scale; double min_z = 0.; @@ -331,14 +331,14 @@ void GizmoObjectManipulation::change_size_value(int axis, double value) Vec3d ref_size = m_cache.size; if (selection.is_single_volume() || selection.is_single_modifier()) { - Vec3d instance_scale = wxGetApp().model().objects[selection.get_volume(*selection.get_volume_idxs().begin())->object_idx()]->instances[0]->get_transformation().get_scaling_factor(); - ref_size = selection.get_volume(*selection.get_volume_idxs().begin())->bounding_box().size(); + Vec3d instance_scale = wxGetApp().model().objects[selection.get_first_volume()->object_idx()]->instances[0]->get_transformation().get_scaling_factor(); + ref_size = selection.get_first_volume()->bounding_box().size(); ref_size = Vec3d(instance_scale[0] * ref_size[0], instance_scale[1] * ref_size[1], instance_scale[2] * ref_size[2]); } else if (selection.is_single_full_instance()) ref_size = m_world_coordinates ? selection.get_unscaled_instance_bounding_box().size() : - wxGetApp().model().objects[selection.get_volume(*selection.get_volume_idxs().begin())->object_idx()]->raw_mesh_bounding_box().size(); + wxGetApp().model().objects[selection.get_first_volume()->object_idx()]->raw_mesh_bounding_box().size(); this->do_scale(axis, 100. * Vec3d(size(0) / ref_size(0), size(1) / ref_size(1), size(2) / ref_size(2))); @@ -391,7 +391,7 @@ void GizmoObjectManipulation::reset_position_value() Selection& selection = m_glcanvas.get_selection(); if (selection.is_single_volume() || selection.is_single_modifier()) { - GLVolume* volume = const_cast(selection.get_volume(*selection.get_volume_idxs().begin())); + GLVolume* volume = const_cast(selection.get_first_volume()); volume->set_volume_offset(Vec3d::Zero()); } else if (selection.is_single_full_instance()) { @@ -414,7 +414,7 @@ void GizmoObjectManipulation::reset_rotation_value() Selection& selection = m_glcanvas.get_selection(); if (selection.is_single_volume() || selection.is_single_modifier()) { - GLVolume* volume = const_cast(selection.get_volume(*selection.get_volume_idxs().begin())); + GLVolume* volume = const_cast(selection.get_first_volume()); volume->set_volume_rotation(Vec3d::Zero()); } else if (selection.is_single_full_instance()) { @@ -450,7 +450,7 @@ void GizmoObjectManipulation::set_uniform_scaling(const bool new_value) if (selection.is_single_full_instance() && m_world_coordinates && !new_value) { // Verify whether the instance rotation is multiples of 90 degrees, so that the scaling in world coordinates is possible. // all volumes in the selection belongs to the same instance, any of them contains the needed instance data, so we take the first one - const GLVolume* volume = selection.get_volume(*selection.get_volume_idxs().begin()); + const GLVolume* volume = selection.get_first_volume(); // Is the angle close to a multiple of 90 degrees? if (! Geometry::is_rotation_ninety_degrees(volume->get_instance_rotation())) { diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 8bd8923d247..4b3aa5d1709 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -4033,7 +4033,7 @@ int Plater::priv::get_selected_volume_idx() const int idx = selection.get_object_idx(); if ((0 > idx) || (idx > 1000)) return-1; - const GLVolume* v = selection.get_volume(*selection.get_volume_idxs().begin()); + const GLVolume* v = selection.get_first_volume(); if (model.objects[idx]->volumes.size() > 1) return v->volume_idx(); return -1; @@ -4844,7 +4844,7 @@ void Plater::priv::replace_with_stl() if (selection.is_wipe_tower() || get_selection().get_volume_idxs().size() != 1) return; - const GLVolume* v = selection.get_volume(*selection.get_volume_idxs().begin()); + const GLVolume* v = selection.get_first_volume(); int object_idx = v->object_idx(); int volume_idx = v->volume_idx(); @@ -7154,7 +7154,7 @@ bool Plater::priv::can_edit_text() const return true; if (selection.is_single_volume()) { - const GLVolume *gl_volume = selection.get_volume(*selection.get_volume_idxs().begin()); + const GLVolume *gl_volume = selection.get_first_volume(); int out_object_idx = gl_volume->object_idx(); ModelObject * model_object = selection.get_model()->objects[out_object_idx]; int out_volume_idx = gl_volume->volume_idx(); @@ -10334,7 +10334,7 @@ void Plater::export_stl(bool extended, bool selection_only) if (selection.get_mode() == Selection::Instance) mesh = mesh_to_export(*model_object, (model_object->instances.size() > 1) ? -1 : selection.get_instance_idx()); else { - const GLVolume* volume = selection.get_volume(*selection.get_volume_idxs().begin()); + const GLVolume* volume = selection.get_first_volume(); mesh = model_object->volumes[volume->volume_idx()]->mesh(); mesh.transform(volume->get_volume_transformation().get_matrix(), true); } From 1561d65712610c8ca23e7e273ddeb04567982f11 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Mon, 30 Oct 2023 23:10:05 +0800 Subject: [PATCH 79/99] Sync most of the gizmos with latest PrusaSlicer --- src/slic3r/GUI/GLCanvas3D.cpp | 41 +- src/slic3r/GUI/GLToolbar.cpp | 45 +-- src/slic3r/GUI/GLToolbar.hpp | 8 +- src/slic3r/GUI/Gizmos/GLGizmoAdvancedCut.cpp | 10 +- src/slic3r/GUI/Gizmos/GLGizmoAdvancedCut.hpp | 2 +- src/slic3r/GUI/Gizmos/GLGizmoBase.cpp | 107 ++--- src/slic3r/GUI/Gizmos/GLGizmoBase.hpp | 24 +- src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp | 4 +- src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.hpp | 2 +- src/slic3r/GUI/Gizmos/GLGizmoFlatten.cpp | 69 ++-- src/slic3r/GUI/Gizmos/GLGizmoFlatten.hpp | 11 +- .../GUI/Gizmos/GLGizmoMmuSegmentation.cpp | 25 +- .../GUI/Gizmos/GLGizmoMmuSegmentation.hpp | 4 +- src/slic3r/GUI/Gizmos/GLGizmoMove.cpp | 21 +- src/slic3r/GUI/Gizmos/GLGizmoMove.hpp | 6 +- src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp | 54 ++- src/slic3r/GUI/Gizmos/GLGizmoPainterBase.hpp | 15 +- src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp | 47 ++- src/slic3r/GUI/Gizmos/GLGizmoRotate.hpp | 9 +- src/slic3r/GUI/Gizmos/GLGizmoScale.cpp | 27 +- src/slic3r/GUI/Gizmos/GLGizmoScale.hpp | 17 +- src/slic3r/GUI/Gizmos/GLGizmoSeam.cpp | 10 +- src/slic3r/GUI/Gizmos/GLGizmoSeam.hpp | 10 +- src/slic3r/GUI/Gizmos/GLGizmoSimplify.cpp | 4 + src/slic3r/GUI/Gizmos/GLGizmoSimplify.hpp | 4 + src/slic3r/GUI/Gizmos/GLGizmoText.cpp | 4 +- src/slic3r/GUI/Gizmos/GLGizmos.hpp | 4 + src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp | 353 +++++------------ src/slic3r/GUI/Gizmos/GLGizmosCommon.hpp | 100 ++--- src/slic3r/GUI/Gizmos/GLGizmosManager.cpp | 87 ++--- src/slic3r/GUI/Gizmos/GLGizmosManager.hpp | 12 +- src/slic3r/GUI/MeshUtils.cpp | 364 +++++++++++++----- src/slic3r/GUI/MeshUtils.hpp | 95 +++-- 33 files changed, 839 insertions(+), 756 deletions(-) diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 4a87c9746c6..b00657faea5 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -1,3 +1,13 @@ +///|/ Copyright (c) Prusa Research 2018 - 2023 Enrico Turri @enricoturri1966, Oleksandra Iushchenko @YuSanka, Tomáš Mészáros @tamasmeszaros, Lukáš Matěna @lukasmatena, Vojtěch Bubník @bubnikv, David Kocík @kocikdav, Filip Sykala @Jony01, Lukáš Hejl @hejllukas, Vojtěch Král @vojtechkral +///|/ Copyright (c) BambuStudio 2023 manch1n @manch1n +///|/ Copyright (c) SuperSlicer 2023 Remi Durand @supermerill +///|/ Copyright (c) 2020 Benjamin Greiner +///|/ Copyright (c) 2019 John Drake @foxox +///|/ Copyright (c) 2019 BeldrothTheGold @BeldrothTheGold +///|/ Copyright (c) 2019 Thomas Moore +///|/ +///|/ PrusaSlicer is released under the terms of the AGPLv3 or higher +///|/ #include "libslic3r/libslic3r.h" #include "GLCanvas3D.hpp" @@ -4505,12 +4515,13 @@ void GLCanvas3D::do_rotate(const std::string& snapshot_type) for (int i = 0; i < static_cast(m_model->objects.size()); ++i) { const ModelObject* obj = m_model->objects[i]; for (int j = 0; j < static_cast(obj->instances.size()); ++j) { - if (snapshot_type.empty() && m_selection.get_object_idx() == i) { + if (snapshot_type == L("Gizmo-Place on Face") && m_selection.get_object_idx() == i) { // This means we are flattening this object. In that case pretend // that it is not sinking (even if it is), so it is placed on bed // later on (whatever is sinking will be left sinking). min_zs[{ i, j }] = SINKING_Z_THRESHOLD; - } else + } + else min_zs[{ i, j }] = obj->instance_bounding_box(j).min.z(); } @@ -5994,21 +6005,12 @@ bool GLCanvas3D::_init_main_toolbar() return true; } // init arrow - BackgroundTexture::Metadata arrow_data; - arrow_data.filename = "toolbar_arrow.svg"; - arrow_data.left = 0; - arrow_data.top = 0; - arrow_data.right = 0; - arrow_data.bottom = 0; - if (!m_main_toolbar.init_arrow(arrow_data)) - { + if (!m_main_toolbar.init_arrow("toolbar_arrow.svg")) BOOST_LOG_TRIVIAL(error) << "Main toolbar failed to load arrow texture."; - } + // m_gizmos is created at constructor, thus we can init arrow here. - if (!m_gizmos.init_arrow(arrow_data)) - { + if (!m_gizmos.init_arrow("toolbar_arrow.svg")) BOOST_LOG_TRIVIAL(error) << "Gizmos manager failed to load arrow texture."; - } m_main_toolbar.set_layout_type(GLToolbar::Layout::Horizontal); //BBS: main toolbar is at the top and left, we don't need the rounded-corner effect at the right side and the top side @@ -6393,7 +6395,7 @@ void GLCanvas3D::_refresh_if_shown_on_screen() void GLCanvas3D::_picking_pass() { - if (!m_picking_enabled || m_mouse.dragging || m_mouse.position == Vec2d(DBL_MAX, DBL_MAX) && !m_gizmos.is_dragging()) { + if (!m_picking_enabled || m_mouse.dragging || m_mouse.position == Vec2d(DBL_MAX, DBL_MAX) || m_gizmos.is_dragging()) { #if ENABLE_RAYCAST_PICKING_DEBUG ImGuiWrapper& imgui = *wxGetApp().imgui(); imgui.begin(std::string("Hit result"), ImGuiWindowFlags_AlwaysAutoResize); @@ -6421,10 +6423,9 @@ void GLCanvas3D::_picking_pass() const GLVolume* volume = m_volumes.volumes[hit.raycaster_id]; if (volume->is_active && !volume->disabled && (volume->composite_id.volume_id >= 0 || m_render_sla_auxiliaries)) { // do not add the volume id if any gizmo is active and CTRL is pressed - if (m_gizmos.get_current_type() == GLGizmosManager::EType::Undefined || !wxGetKeyState(WXK_CONTROL)) { + if (m_gizmos.get_current_type() == GLGizmosManager::EType::Undefined || !wxGetKeyState(WXK_CONTROL)) m_hover_volume_idxs.emplace_back(hit.raycaster_id); - m_gizmos.set_hover_id(-1); - } + m_gizmos.set_hover_id(-1); } } else @@ -6435,8 +6436,8 @@ void GLCanvas3D::_picking_pass() case SceneRaycaster::EType::Gizmo: { const Size& cnv_size = get_canvas_size(); - bool inside = 0 <= m_mouse.position.x() && m_mouse.position.x() < cnv_size.get_width() && - 0 <= m_mouse.position.y() && m_mouse.position.y() < cnv_size.get_height(); + const bool inside = 0 <= m_mouse.position.x() && m_mouse.position.x() < cnv_size.get_width() && + 0 <= m_mouse.position.y() && m_mouse.position.y() < cnv_size.get_height(); m_gizmos.set_hover_id(inside ? hit.raycaster_id : -1); break; } diff --git a/src/slic3r/GUI/GLToolbar.cpp b/src/slic3r/GUI/GLToolbar.cpp index a10177ba9c0..8e99bb1bc27 100644 --- a/src/slic3r/GUI/GLToolbar.cpp +++ b/src/slic3r/GUI/GLToolbar.cpp @@ -1,3 +1,7 @@ +///|/ Copyright (c) Prusa Research 2018 - 2022 Enrico Turri @enricoturri1966, David Kocík @kocikdav, Lukáš Matěna @lukasmatena, Oleksandra Iushchenko @YuSanka, Vojtěch Bubník @bubnikv, Vojtěch Král @vojtechkral +///|/ +///|/ PrusaSlicer is released under the terms of the AGPLv3 or higher +///|/ #include "libslic3r/Point.hpp" #include "libslic3r/libslic3r.h" @@ -281,21 +285,13 @@ bool GLToolbar::init(const BackgroundTexture::Metadata& background_texture) return res; } -bool GLToolbar::init_arrow(const BackgroundTexture::Metadata& arrow_texture) +bool GLToolbar::init_arrow(const std::string& filename) { - if (m_arrow_texture.texture.get_id() != 0) + if (m_arrow_texture.get_id() != 0) return true; - std::string path = resources_dir() + "/images/"; - bool res = false; - - if (!arrow_texture.filename.empty()) { - res = m_arrow_texture.texture.load_from_svg_file(path + arrow_texture.filename, false, false, false, 1000); - } - if (res) - m_arrow_texture.metadata = arrow_texture; - - return res; + const std::string path = resources_dir() + "/images/"; + return (!filename.empty()) ? m_arrow_texture.load_from_svg_file(path + filename, false, false, false, 1000) : false; } GLToolbar::Layout::EType GLToolbar::get_layout_type() const @@ -1300,7 +1296,7 @@ void GLToolbar::render_background(float left, float top, float right, float bott void GLToolbar::render_arrow(const GLCanvas3D& parent, GLToolbarItem* highlighted_item) { // arrow texture not initialized - if (m_arrow_texture.texture.get_id() == 0) + if (m_arrow_texture.get_id() == 0) return; float inv_zoom = (float)wxGetApp().plater()->get_camera().get_inv_zoom(); @@ -1339,27 +1335,24 @@ void GLToolbar::render_arrow(const GLCanvas3D& parent, GLToolbarItem* highlighte top -= separator_stride; float right = left + scaled_icons_size; - unsigned int tex_id = m_arrow_texture.texture.get_id(); + const unsigned int tex_id = m_arrow_texture.get_id(); // arrow width and height - float arr_tex_width = (float)m_arrow_texture.texture.get_width(); - float arr_tex_height = (float)m_arrow_texture.texture.get_height(); - if ((tex_id != 0) && (arr_tex_width > 0) && (arr_tex_height > 0)) { - float inv_tex_width = (arr_tex_width != 0.0f) ? 1.0f / arr_tex_width : 0.0f; - float inv_tex_height = (arr_tex_height != 0.0f) ? 1.0f / arr_tex_height : 0.0f; - + const float arr_tex_width = (float)m_arrow_texture.get_width(); + const float arr_tex_height = (float)m_arrow_texture.get_height(); + if (tex_id != 0 && arr_tex_width > 0.0f && arr_tex_height > 0.0f) { float internal_left = left + border - scaled_icons_size * 1.5f; // add scaled_icons_size for huge arrow float internal_right = right - border + scaled_icons_size * 1.5f; float internal_top = top - border; // bottom is not moving and should be calculated from arrow texture sides ratio - float arrow_sides_ratio = (float)m_arrow_texture.texture.get_height() / (float)m_arrow_texture.texture.get_width(); + float arrow_sides_ratio = (float)m_arrow_texture.get_height() / (float)m_arrow_texture.get_width(); float internal_bottom = internal_top - (internal_right - internal_left) * arrow_sides_ratio ; - float internal_left_uv = (float)m_arrow_texture.metadata.left * inv_tex_width; - float internal_right_uv = 1.0f - (float)m_arrow_texture.metadata.right * inv_tex_width; - float internal_top_uv = 1.0f - (float)m_arrow_texture.metadata.top * inv_tex_height; - float internal_bottom_uv = (float)m_arrow_texture.metadata.bottom * inv_tex_height; + const float left_uv = 0.0f; + const float right_uv = 1.0f; + const float top_uv = 1.0f; + const float bottom_uv = 0.0f; - GLTexture::render_sub_texture(tex_id, internal_left, internal_right, internal_bottom, internal_top, { { internal_left_uv, internal_top_uv }, { internal_right_uv, internal_top_uv }, { internal_right_uv, internal_bottom_uv }, { internal_left_uv, internal_bottom_uv } }); + GLTexture::render_sub_texture(tex_id, internal_left, internal_right, internal_bottom, internal_top, { { left_uv, top_uv }, { right_uv, top_uv }, { right_uv, bottom_uv }, { left_uv, bottom_uv } }); } } diff --git a/src/slic3r/GUI/GLToolbar.hpp b/src/slic3r/GUI/GLToolbar.hpp index 43f81b5abb2..28ad69bb532 100644 --- a/src/slic3r/GUI/GLToolbar.hpp +++ b/src/slic3r/GUI/GLToolbar.hpp @@ -1,3 +1,7 @@ +///|/ Copyright (c) Prusa Research 2018 - 2022 Enrico Turri @enricoturri1966, David Kocík @kocikdav, Oleksandra Iushchenko @YuSanka, Vojtěch Král @vojtechkral, Vojtěch Bubník @bubnikv +///|/ +///|/ PrusaSlicer is released under the terms of the AGPLv3 or higher +///|/ #ifndef slic3r_GLToolbar_hpp_ #define slic3r_GLToolbar_hpp_ @@ -327,7 +331,7 @@ class GLToolbar mutable GLTexture m_images_texture; mutable bool m_images_texture_dirty; BackgroundTexture m_background_texture; - BackgroundTexture m_arrow_texture; + GLTexture m_arrow_texture; Layout m_layout; ItemsList m_items; @@ -354,7 +358,7 @@ class GLToolbar bool init(const BackgroundTexture::Metadata& background_texture); - bool init_arrow(const BackgroundTexture::Metadata& arrow_texture); + bool init_arrow(const std::string& filename); Layout::EType get_layout_type() const; void set_layout_type(Layout::EType type); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoAdvancedCut.cpp b/src/slic3r/GUI/Gizmos/GLGizmoAdvancedCut.cpp index 14d351a1a62..be0c2e15180 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoAdvancedCut.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoAdvancedCut.cpp @@ -17,6 +17,8 @@ #include +#include "slic3r/GUI/CameraUtils.hpp" + namespace Slic3r { namespace GUI { @@ -111,9 +113,9 @@ GLGizmoAdvancedCut::GLGizmoAdvancedCut(GLCanvas3D& parent, const std::string& ic m_buffered_rotation.setZero(); } -void GLGizmoAdvancedCut::data_changed() +void GLGizmoAdvancedCut::data_changed(bool is_serializing) { - GLGizmoRotate3D::data_changed(); + GLGizmoRotate3D::data_changed(is_serializing); finish_rotation(); } @@ -227,7 +229,7 @@ bool GLGizmoAdvancedCut::unproject_on_cut_plane(const Vec2d &mouse_pos, Vec3d &p Vec3d point; Vec3d direction; Vec3d hit; - MeshRaycaster::line_from_mouse_pos_static(mouse_pos, Transform3d::Identity(), camera, point, direction); + CameraUtils::ray_from_screen_pos(camera, mouse_pos, point, direction); Vec3d normal = -cp->get_normal().cast(); double den = normal.dot(direction); if (den != 0.) { @@ -1876,7 +1878,7 @@ bool GLGizmoAdvancedCut::process_cut_line(SLAGizmoEventType action, const Vec2d Vec3d pt; Vec3d dir; - MeshRaycaster::line_from_mouse_pos_static(mouse_position, Transform3d::Identity(), camera, pt, dir); + CameraUtils::ray_from_screen_pos(camera, mouse_position, pt, dir); dir.normalize(); pt += dir; // Move the pt along dir so it is not clipped. diff --git a/src/slic3r/GUI/Gizmos/GLGizmoAdvancedCut.hpp b/src/slic3r/GUI/Gizmos/GLGizmoAdvancedCut.hpp index 4b31176b8d1..d791663ea93 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoAdvancedCut.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoAdvancedCut.hpp @@ -138,7 +138,7 @@ struct Rotate_data { virtual bool apply_clipping_plane() { return m_connectors_editing; } - void data_changed() override; + void data_changed(bool is_serializing) override; protected: bool on_init() override; diff --git a/src/slic3r/GUI/Gizmos/GLGizmoBase.cpp b/src/slic3r/GUI/Gizmos/GLGizmoBase.cpp index 5a51304a813..ed98b81931a 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoBase.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoBase.cpp @@ -1,3 +1,7 @@ +///|/ Copyright (c) Prusa Research 2019 - 2023 Oleksandra Iushchenko @YuSanka, Enrico Turri @enricoturri1966, Lukáš Matěna @lukasmatena, Filip Sykala @Jony01, Vojtěch Bubník @bubnikv +///|/ +///|/ PrusaSlicer is released under the terms of the AGPLv3 or higher +///|/ #include "GLGizmoBase.hpp" #include "slic3r/GUI/GLCanvas3D.hpp" @@ -196,12 +200,21 @@ void GLGizmoBase::Grabber::render(float size, const ColorRGBA& render_color) GLGizmoBase::GLGizmoBase(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id) : m_parent(parent) + , m_group_id(-1) + , m_state(Off) + , m_shortcut_key(NO_SHORTCUT_KEY_VALUE) , m_icon_filename(icon_filename) , m_sprite_id(sprite_id) , m_imgui(wxGetApp().imgui()) { } + +std::string GLGizmoBase::get_action_snapshot_name() const +{ + return "Gizmo action"; +} + void GLGizmoBase::set_icon_filename(const std::string &filename) { m_icon_filename = filename; } @@ -212,8 +225,8 @@ void GLGizmoBase::set_hover_id(int id) assert(!m_dragging); // allow empty grabbers when not using grabbers but use hover_id - flatten, rotate - if (!m_grabbers.empty() && id >= (int) m_grabbers.size()) - return; +// if (!m_grabbers.empty() && id >= (int) m_grabbers.size()) +// return; m_hover_id = id; on_set_hover_id(); @@ -266,15 +279,6 @@ void GLGizmoBase::unregister_grabbers_for_picking() } } -ColorRGBA GLGizmoBase::picking_color_component(unsigned int id) const -{ - id = BASE_ID - id; - if (m_group_id > -1) - id -= m_group_id; - - return picking_decode(id); -} - void GLGizmoBase::render_grabbers(const BoundingBoxf3& box) const { #if ENABLE_FIXED_GRABBER @@ -285,16 +289,23 @@ void GLGizmoBase::render_grabbers(const BoundingBoxf3& box) const } void GLGizmoBase::render_grabbers(float size) const +{ + render_grabbers(0, m_grabbers.size() - 1, size, false); +} + +void GLGizmoBase::render_grabbers(size_t first, size_t last, float size, bool force_hover) const { GLShaderProgram* shader = wxGetApp().get_shader("gouraud_light"); if (shader == nullptr) return; shader->start_using(); shader->set_uniform("emission_factor", 0.1f); - for (int i = 0; i < (int)m_grabbers.size(); ++i) { + glsafe(::glDisable(GL_CULL_FACE)); + for (size_t i = first; i <= last; ++i) { if (m_grabbers[i].enabled) - m_grabbers[i].render(m_hover_id == i, size); + m_grabbers[i].render(force_hover ? true : m_hover_id == (int)i, size); } + glsafe(::glEnable(GL_CULL_FACE)); shader->stop_using(); } @@ -310,18 +321,16 @@ bool GLGizmoBase::use_grabbers(const wxMouseEvent &mouse_event) { } if (mouse_event.LeftDown()) { - Selection &selection = m_parent.get_selection(); - if (!selection.is_empty() && m_hover_id != -1 && - (m_grabbers.empty() || m_hover_id < static_cast(m_grabbers.size()))) { + Selection &selection = m_parent.get_selection(); + if (!selection.is_empty() && m_hover_id != -1 /* && + (m_grabbers.empty() || m_hover_id < static_cast(m_grabbers.size()))*/) { selection.setup_cache(); m_dragging = true; for (auto &grabber : m_grabbers) grabber.dragging = false; - if (!m_grabbers.empty() && m_hover_id < int(m_grabbers.size())) - m_grabbers[m_hover_id].dragging = true; +// if (!m_grabbers.empty() && m_hover_id < int(m_grabbers.size())) +// m_grabbers[m_hover_id].dragging = true; - // prevent change of hover_id during dragging - m_parent.set_mouse_as_dragging(); on_start_dragging(); // Let the plater know that the dragging started @@ -333,7 +342,6 @@ bool GLGizmoBase::use_grabbers(const wxMouseEvent &mouse_event) { // when mouse cursor leave window than finish actual dragging operation bool is_leaving = mouse_event.Leaving(); if (mouse_event.Dragging()) { - m_parent.set_mouse_as_dragging(); Point mouse_coord(mouse_event.GetX(), mouse_event.GetY()); auto ray = m_parent.mouse_ray(mouse_coord); UpdateData data(ray, mouse_coord); @@ -343,33 +351,39 @@ bool GLGizmoBase::use_grabbers(const wxMouseEvent &mouse_event) { wxGetApp().obj_manipul()->set_dirty(); m_parent.set_as_dirty(); return true; - } else if (mouse_event.LeftUp() || is_leaving || is_dragging_finished) { - for (auto &grabber : m_grabbers) grabber.dragging = false; - m_dragging = false; + } + else if (mouse_event.LeftUp() || is_leaving || is_dragging_finished) { + do_stop_dragging(is_leaving); + return true; + } + } + return false; +} - // NOTE: This should be part of GLCanvas3D - // Reset hover_id when leave window - if (is_leaving) m_parent.mouse_up_cleanup(); +void GLGizmoBase::do_stop_dragging(bool perform_mouse_cleanup) +{ + for (auto& grabber : m_grabbers) grabber.dragging = false; + m_dragging = false; - on_stop_dragging(); + // NOTE: This should be part of GLCanvas3D + // Reset hover_id when leave window + if (perform_mouse_cleanup) m_parent.mouse_up_cleanup(); - // There is prediction that after draggign, data are changed - // Data are updated twice also by canvas3D::reload_scene. - // Should be fixed. - m_parent.get_gizmos_manager().update_data(); + on_stop_dragging(); - wxGetApp().obj_manipul()->set_dirty(); + // There is prediction that after draggign, data are changed + // Data are updated twice also by canvas3D::reload_scene. + // Should be fixed. + m_parent.get_gizmos_manager().update_data(); - // Let the plater know that the dragging finished, so a delayed - // refresh of the scene with the background processing data should - // be performed. - m_parent.post_event(SimpleEvent(EVT_GLCANVAS_MOUSE_DRAGGING_FINISHED)); - // updates camera target constraints - m_parent.refresh_camera_scene_box(); - return true; - } - } - return false; + wxGetApp().obj_manipul()->set_dirty(); + + // Let the plater know that the dragging finished, so a delayed + // refresh of the scene with the background processing data should + // be performed. + m_parent.post_event(SimpleEvent(EVT_GLCANVAS_MOUSE_DRAGGING_FINISHED)); + // updates camera target constraints + m_parent.refresh_camera_scene_box(); } std::string GLGizmoBase::format(float value, unsigned int decimals) const @@ -385,9 +399,12 @@ void GLGizmoBase::render_input_window(float x, float y, float bottom_limit) { on_render_input_window(x, y, bottom_limit); if (m_first_input_window_render) { - // for some reason, the imgui dialogs are not shown on screen in the 1st frame where they are rendered, but show up only with the 2nd rendered frame - // so, we forces another frame rendering the first time the imgui window is shown + // imgui windows that don't have an initial size needs to be processed once to get one + // and are not rendered in the first frame + // so, we forces to render another frame the first time the imgui window is shown + // https://github.com/ocornut/imgui/issues/2949 m_parent.set_as_dirty(); + m_parent.request_extra_frame(); m_first_input_window_render = false; } } diff --git a/src/slic3r/GUI/Gizmos/GLGizmoBase.hpp b/src/slic3r/GUI/Gizmos/GLGizmoBase.hpp index 85a8c68a5b1..bcd4f2096f0 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoBase.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoBase.hpp @@ -1,3 +1,7 @@ +///|/ Copyright (c) Prusa Research 2019 - 2023 Oleksandra Iushchenko @YuSanka, Lukáš Matěna @lukasmatena, Enrico Turri @enricoturri1966, Filip Sykala @Jony01, Vojtěch Bubník @bubnikv +///|/ +///|/ PrusaSlicer is released under the terms of the AGPLv3 or higher +///|/ #ifndef slic3r_GLGizmoBase_hpp_ #define slic3r_GLGizmoBase_hpp_ @@ -68,6 +72,9 @@ class GLGizmoBase NegZ = 1 << 5, }; + // Represents NO key(button on keyboard) value + static const int NO_SHORTCUT_KEY_VALUE = 0; + protected: struct Grabber { @@ -129,9 +136,9 @@ class GLGizmoBase protected: GLCanvas3D& m_parent; - int m_group_id{ -1 }; // TODO: remove only for rotate - EState m_state{ Off }; - int m_shortcut_key{ 0 }; + int m_group_id; // TODO: remove only for rotate + EState m_state; + int m_shortcut_key; std::string m_icon_filename; unsigned int m_sprite_id; int m_hover_id{ -1 }; @@ -171,7 +178,7 @@ class GLGizmoBase virtual bool wants_enter_leave_snapshots() const { return false; } virtual std::string get_gizmo_entering_text() const { assert(false); return ""; } virtual std::string get_gizmo_leaving_text() const { assert(false); return ""; } - virtual std::string get_action_snapshot_name() { return "Gizmo action"; } + virtual std::string get_action_snapshot_name() const; void set_common_data_pool(CommonGizmosDataPool* ptr) { m_c = ptr; } virtual bool apply_clipping_plane() { return true; } @@ -202,7 +209,7 @@ class GLGizmoBase /// /// Is called when data (Selection) is changed /// - virtual void data_changed(){}; + virtual void data_changed(bool is_serializing){}; /// /// Implement when want to process mouse events in gizmo @@ -246,11 +253,9 @@ class GLGizmoBase virtual void on_register_raycasters_for_picking() {} virtual void on_unregister_raycasters_for_picking() {} - // Returns the picking color for the given id, based on the BASE_ID constant - // No check is made for clashing with other picking color (i.e. GLVolumes) - ColorRGBA picking_color_component(unsigned int id) const; void render_grabbers(const BoundingBoxf3& box) const; void render_grabbers(float size) const; + void render_grabbers(size_t first, size_t last, float size, bool force_hover) const; std::string format(float value, unsigned int decimals) const; @@ -265,6 +270,9 @@ class GLGizmoBase /// Keep information about mouse click /// same as on_mouse bool use_grabbers(const wxMouseEvent &mouse_event); + + void do_stop_dragging(bool perform_mouse_cleanup); + private: // Flag for dirty visible state of Gizmo // When True then need new rendering diff --git a/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp b/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp index e66e511f52f..1a6ad83ca9c 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp @@ -430,7 +430,7 @@ void GLGizmoFdmSupports::on_render_input_window(float x, float y, float bottom_l else { if (m_imgui->button(m_desc.at("reset_direction"))) { wxGetApp().CallAfter([this]() { - m_c->object_clipper()->set_position(-1., false); + m_c->object_clipper()->set_position_by_ratio(-1., false); }); } } @@ -444,7 +444,7 @@ void GLGizmoFdmSupports::on_render_input_window(float x, float y, float bottom_l ImGui::PushItemWidth(1.5 * slider_icon_width); bool b_drag_input = ImGui::BBLDragFloat("##clp_dist_input", &clp_dist, 0.05f, 0.0f, 0.0f, "%.2f"); - if (b_bbl_slider_float || b_drag_input) m_c->object_clipper()->set_position(clp_dist, true); + if (b_bbl_slider_float || b_drag_input) m_c->object_clipper()->set_position_by_ratio(clp_dist, true); } ImGui::Separator(); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.hpp b/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.hpp index f9a5c375721..306d1f13bb1 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.hpp @@ -40,7 +40,7 @@ class GLGizmoFdmSupports : public GLGizmoPainterBase std::string get_gizmo_entering_text() const override { return "Entering Paint-on supports"; } std::string get_gizmo_leaving_text() const override { return "Leaving Paint-on supports"; } - std::string get_action_snapshot_name() override { return "Paint-on supports editing"; } + std::string get_action_snapshot_name() const override { return "Paint-on supports editing"; } // BBS wchar_t m_current_tool = 0; diff --git a/src/slic3r/GUI/Gizmos/GLGizmoFlatten.cpp b/src/slic3r/GUI/Gizmos/GLGizmoFlatten.cpp index b6eb6b0f855..e4a4f895e66 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoFlatten.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoFlatten.cpp @@ -1,4 +1,7 @@ -// Include GLGizmoBase.hpp before I18N.hpp as it includes some libigl code, which overrides our localization "L" macro. +///|/ Copyright (c) Prusa Research 2019 - 2023 Oleksandra Iushchenko @YuSanka, Lukáš Matěna @lukasmatena, Enrico Turri @enricoturri1966, Filip Sykala @Jony01, Vojtěch Bubník @bubnikv +///|/ +///|/ PrusaSlicer is released under the terms of the AGPLv3 or higher +///|/ #include "GLGizmoFlatten.hpp" #include "slic3r/GUI/GLCanvas3D.hpp" #include "slic3r/GUI/GUI_App.hpp" @@ -22,53 +25,39 @@ GLGizmoFlatten::GLGizmoFlatten(GLCanvas3D& parent, const std::string& icon_filen bool GLGizmoFlatten::on_mouse(const wxMouseEvent &mouse_event) { - if (mouse_event.Moving()) { - // only for sure - m_mouse_left_down = false; - return false; - } if (mouse_event.LeftDown()) { if (m_hover_id != -1) { - m_mouse_left_down = true; Selection &selection = m_parent.get_selection(); if (selection.is_single_full_instance()) { // Rotate the object so the normal points downward: selection.flattening_rotate(m_planes[m_hover_id].normal); m_parent.do_rotate(L("Gizmo-Place on Face")); + wxGetApp().obj_manipul()->set_dirty(); } return true; } - - // fix: prevent restart gizmo when reselect object - // take responsibility for left up - if (m_parent.get_first_hover_volume_idx() >= 0) m_mouse_left_down = true; - - } else if (mouse_event.LeftUp()) { - if (m_mouse_left_down) { - // responsible for mouse left up after selecting plane - m_mouse_left_down = false; - return true; - } - } else if (mouse_event.Leaving()) { - m_mouse_left_down = false; } + else if (mouse_event.LeftUp()) + return m_hover_id != -1; + return false; } -void GLGizmoFlatten::data_changed() +void GLGizmoFlatten::data_changed(bool is_serializing) { const Selection & selection = m_parent.get_selection(); const ModelObject *model_object = nullptr; + int instance_id = -1; if (selection.is_single_full_instance() || selection.is_from_single_object() ) { model_object = selection.get_model()->objects[selection.get_object_idx()]; + instance_id = selection.get_instance_idx(); } - set_flattening_data(model_object); + set_flattening_data(model_object, instance_id); } bool GLGizmoFlatten::on_init() { - // BBS m_shortcut_key = WXK_CONTROL_F; return true; } @@ -111,7 +100,7 @@ void GLGizmoFlatten::on_render() if (selection.is_single_full_instance()) { const Transform3d& inst_matrix = selection.get_first_volume()->get_instance_transformation().get_matrix(); const Camera& camera = wxGetApp().plater()->get_camera(); - const Transform3d model_matrix = Geometry::assemble_transform(selection.get_first_volume()->get_sla_shift_z() * Vec3d::UnitZ()) * inst_matrix; + const Transform3d model_matrix = Geometry::translation_transform(selection.get_first_volume()->get_sla_shift_z() * Vec3d::UnitZ()) * inst_matrix; const Transform3d view_model_matrix = camera.get_view_matrix() * model_matrix; shader->set_uniform("view_model_matrix", view_model_matrix); @@ -119,7 +108,6 @@ void GLGizmoFlatten::on_render() if (this->is_plane_update_necessary()) update_planes(); for (int i = 0; i < (int)m_planes.size(); ++i) { - m_planes_casters[i]->set_transform(model_matrix); m_planes[i].vbo.model.set_color(i == m_hover_id ? GLGizmoBase::FLATTEN_HOVER_COLOR : GLGizmoBase::FLATTEN_COLOR); m_planes[i].vbo.model.render(); } @@ -139,7 +127,7 @@ void GLGizmoFlatten::on_register_raycasters_for_picking() if (!m_planes.empty()) { const Selection& selection = m_parent.get_selection(); - const Transform3d matrix = Geometry::assemble_transform(selection.get_first_volume()->get_sla_shift_z() * Vec3d::UnitZ()) * + const Transform3d matrix = Geometry::translation_transform(selection.get_first_volume()->get_sla_shift_z() * Vec3d::UnitZ()) * selection.get_first_volume()->get_instance_transformation().get_matrix(); for (int i = 0; i < (int)m_planes.size(); ++i) { @@ -155,9 +143,9 @@ void GLGizmoFlatten::on_unregister_raycasters_for_picking() m_planes_casters.clear(); } -void GLGizmoFlatten::set_flattening_data(const ModelObject* model_object) +void GLGizmoFlatten::set_flattening_data(const ModelObject* model_object, int instance_id) { - if (model_object != m_old_model_object) { + if (model_object != m_old_model_object || instance_id != m_old_instance_id) { m_planes.clear(); on_unregister_raycasters_for_picking(); } @@ -237,9 +225,7 @@ void GLGizmoFlatten::update_planes() } // Let's prepare transformation of the normal vector from mesh to instance coordinates. - Geometry::Transformation t(inst_matrix); - Vec3d scaling = t.get_scaling_factor(); - t.set_scaling_factor(Vec3d(1./scaling(0), 1./scaling(1), 1./scaling(2))); + const Matrix3d normal_matrix = inst_matrix.matrix().block(0, 0, 3, 3).inverse().transpose(); // Now we'll go through all the polygons, transform the points into xy plane to process them: for (unsigned int polygon_id=0; polygon_id < m_planes.size(); ++polygon_id) { @@ -247,7 +233,7 @@ void GLGizmoFlatten::update_planes() const Vec3d& normal = m_planes[polygon_id].normal; // transform the normal according to the instance matrix: - Vec3d normal_transformed = t.get_matrix() * normal; + const Vec3d normal_transformed = normal_matrix * normal; // We are going to rotate about z and y to flatten the plane Eigen::Quaterniond q; @@ -260,7 +246,7 @@ void GLGizmoFlatten::update_planes() // And yes, it is a nasty thing to do. Whoever has time is free to refactor. Vec3d bb_size = BoundingBoxf3(polygon).size(); float sf = std::min(1./bb_size(0), 1./bb_size(1)); - Transform3d tr = Geometry::assemble_transform(Vec3d::Zero(), Vec3d::Zero(), Vec3d(sf, sf, 1.f)); + Transform3d tr = Geometry::scale_transform({ sf, sf, 1.f }); polygon = transform(polygon, tr); polygon = Slic3r::Geometry::convex_hull(polygon); polygon = transform(polygon, tr.inverse()); @@ -365,6 +351,7 @@ void GLGizmoFlatten::update_planes() m_first_instance_scale = mo->instances.front()->get_scaling_factor(); m_first_instance_mirror = mo->instances.front()->get_mirror(); m_old_model_object = mo; + m_old_instance_id = m_c->selection_info()->get_active_instance(); // And finally create respective VBOs. The polygon is convex with // the vertices in order, so triangulation is trivial. @@ -378,18 +365,24 @@ void GLGizmoFlatten::update_planes() for (size_t i = 1; i < plane.vertices.size() - 1; ++i) { its.indices.emplace_back(0, i, i + 1); // triangle fan } + plane.vbo.model.init_from(its); + if (Geometry::Transformation(inst_matrix).is_left_handed()) { + // we need to swap face normals in case the object is mirrored + // for the raycaster to work properly + for (stl_triangle_vertex_indices& face : its.indices) { + if (its_face_normal(its, face).cast().dot(plane.normal) < 0.0) + std::swap(face[1], face[2]); + } + } plane.vbo.mesh_raycaster = std::make_unique(std::make_shared(std::move(its))); - // FIXME: vertices should really be local, they need not - // persist now when we use VBOs - plane.vertices.clear(); - plane.vertices.shrink_to_fit(); + // vertices are no more needed, clear memory + plane.vertices = std::vector(); } on_register_raycasters_for_picking(); } - bool GLGizmoFlatten::is_plane_update_necessary() const { const ModelObject* mo = m_c->selection_info()->model_object(); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoFlatten.hpp b/src/slic3r/GUI/Gizmos/GLGizmoFlatten.hpp index 80ae9edd712..027480dbee8 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoFlatten.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoFlatten.hpp @@ -1,3 +1,7 @@ +///|/ Copyright (c) Prusa Research 2019 - 2023 Oleksandra Iushchenko @YuSanka, Lukáš Matěna @lukasmatena, Enrico Turri @enricoturri1966, Filip Sykala @Jony01 +///|/ +///|/ PrusaSlicer is released under the terms of the AGPLv3 or higher +///|/ #ifndef slic3r_GLGizmoFlatten_hpp_ #define slic3r_GLGizmoFlatten_hpp_ @@ -35,9 +39,8 @@ class GLGizmoFlatten : public GLGizmoBase std::vector m_planes; std::vector> m_planes_casters; - bool m_mouse_left_down = false; // for detection left_up of this gizmo const ModelObject* m_old_model_object = nullptr; - std::vector instances_matrices; + int m_old_instance_id{ -1 }; void update_planes(); bool is_plane_update_necessary() const; @@ -45,7 +48,7 @@ class GLGizmoFlatten : public GLGizmoBase public: GLGizmoFlatten(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id); - void set_flattening_data(const ModelObject* model_object); + void set_flattening_data(const ModelObject* model_object, int instance_id); /// /// Apply rotation on select plane @@ -54,7 +57,7 @@ class GLGizmoFlatten : public GLGizmoBase /// Return True when use the information otherwise False. bool on_mouse(const wxMouseEvent &mouse_event) override; - void data_changed() override; + void data_changed(bool is_serializing) override; protected: bool on_init() override; std::string on_get_name() const override; diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp index 585361d168e..d8912b7647d 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp @@ -1,3 +1,8 @@ +///|/ Copyright (c) Prusa Research 2019 - 2023 Oleksandra Iushchenko @YuSanka, Lukáš Matěna @lukasmatena, Enrico Turri @enricoturri1966, Filip Sykala @Jony01, Lukáš Hejl @hejllukas, David Kocík @kocikdav, Vojtěch Bubník @bubnikv +///|/ Copyright (c) 2021 Justin Schuh @jschuh +///|/ +///|/ PrusaSlicer is released under the terms of the AGPLv3 or higher +///|/ #include "GLGizmoMmuSegmentation.hpp" #include "slic3r/GUI/GLCanvas3D.hpp" @@ -162,9 +167,9 @@ void GLGizmoMmuSegmentation::render_painter_gizmo() glsafe(::glDisable(GL_BLEND)); } -void GLGizmoMmuSegmentation::data_changed() +void GLGizmoMmuSegmentation::data_changed(bool is_serializing) { - GLGizmoPainterBase::data_changed(); + GLGizmoPainterBase::data_changed(is_serializing); if (m_state != On || wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology() != ptFFF || wxGetApp().extruders_edited_cnt() <= 1) return; @@ -571,7 +576,7 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott else { if (m_imgui->button(m_desc.at("reset_direction"))) { wxGetApp().CallAfter([this]() { - m_c->object_clipper()->set_position(-1., false); + m_c->object_clipper()->set_position_by_ratio(-1., false); }); } } @@ -584,7 +589,7 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott ImGui::PushItemWidth(1.5 * slider_icon_width); bool b_clp_dist_input = ImGui::BBLDragFloat("##clp_dist_input", &clp_dist, 0.05f, 0.0f, 0.0f, "%.2f"); - if (slider_clp_dist || b_clp_dist_input) { m_c->object_clipper()->set_position(clp_dist, true); } + if (slider_clp_dist || b_clp_dist_input) { m_c->object_clipper()->set_position_by_ratio(clp_dist, true); } } else if (m_current_tool == ImGui::TriangleButtonIcon) { m_cursor_type = TriangleSelector::CursorType::POINTER; @@ -597,7 +602,7 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott else { if (m_imgui->button(m_desc.at("reset_direction"))) { wxGetApp().CallAfter([this]() { - m_c->object_clipper()->set_position(-1., false); + m_c->object_clipper()->set_position_by_ratio(-1., false); }); } } @@ -610,7 +615,7 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott ImGui::PushItemWidth(1.5 * slider_icon_width); bool b_clp_dist_input = ImGui::BBLDragFloat("##clp_dist_input", &clp_dist, 0.05f, 0.0f, 0.0f, "%.2f"); - if (slider_clp_dist || b_clp_dist_input) { m_c->object_clipper()->set_position(clp_dist, true); } + if (slider_clp_dist || b_clp_dist_input) { m_c->object_clipper()->set_position_by_ratio(clp_dist, true); } } else if (m_current_tool == ImGui::FillButtonIcon) { m_cursor_type = TriangleSelector::CursorType::POINTER; @@ -644,7 +649,7 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott else { if (m_imgui->button(m_desc.at("reset_direction"))) { wxGetApp().CallAfter([this]() { - m_c->object_clipper()->set_position(-1., false); + m_c->object_clipper()->set_position_by_ratio(-1., false); }); } } @@ -657,7 +662,7 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott ImGui::PushItemWidth(1.5 * slider_icon_width); bool b_clp_dist_input = ImGui::BBLDragFloat("##clp_dist_input", &clp_dist, 0.05f, 0.0f, 0.0f, "%.2f"); - if (slider_clp_dist || b_clp_dist_input) { m_c->object_clipper()->set_position(clp_dist, true);} + if (slider_clp_dist || b_clp_dist_input) { m_c->object_clipper()->set_position_by_ratio(clp_dist, true);} } else if (m_current_tool == ImGui::HeightRangeIcon) { m_tool_type = ToolType::BRUSH; @@ -680,7 +685,7 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott else { if (m_imgui->button(m_desc.at("reset_direction"))) { wxGetApp().CallAfter([this]() { - m_c->object_clipper()->set_position(-1., false); + m_c->object_clipper()->set_position_by_ratio(-1., false); }); } } @@ -693,7 +698,7 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott ImGui::PushItemWidth(1.5 * slider_icon_width); bool b_clp_dist_input = ImGui::BBLDragFloat("##clp_dist_input", &clp_dist, 0.05f, 0.0f, 0.0f, "%.2f"); - if (slider_clp_dist || b_clp_dist_input) { m_c->object_clipper()->set_position(clp_dist, true); } + if (slider_clp_dist || b_clp_dist_input) { m_c->object_clipper()->set_position_by_ratio(clp_dist, true); } } else if (m_current_tool == ImGui::GapFillIcon) { m_tool_type = ToolType::GAP_FILL; diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.hpp b/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.hpp index d9fe8d936b5..0343c6c3247 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.hpp @@ -70,7 +70,7 @@ class GLGizmoMmuSegmentation : public GLGizmoPainterBase void render_painter_gizmo() override; - void data_changed() override; + void data_changed(bool is_serializing) override; void render_triangles(const Selection& selection) const override; @@ -104,7 +104,7 @@ class GLGizmoMmuSegmentation : public GLGizmoPainterBase std::string get_gizmo_entering_text() const override { return "Entering color painting"; } std::string get_gizmo_leaving_text() const override { return "Leaving color painting"; } - std::string get_action_snapshot_name() override { return "Color painting editing"; } + std::string get_action_snapshot_name() const override { return "Color painting editing"; } // BBS size_t m_selected_extruder_idx = 0; diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMove.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMove.cpp index 4846ede7770..91913914a86 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMove.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMove.cpp @@ -1,4 +1,7 @@ -// Include GLGizmoBase.hpp before I18N.hpp as it includes some libigl code, which overrides our localization "L" macro. +///|/ Copyright (c) Prusa Research 2019 - 2023 Enrico Turri @enricoturri1966, Oleksandra Iushchenko @YuSanka, Lukáš Matěna @lukasmatena, Filip Sykala @Jony01, Vojtěch Bubník @bubnikv +///|/ +///|/ PrusaSlicer is released under the terms of the AGPLv3 or higher +///|/ #include "GLGizmoMove.hpp" #include "slic3r/GUI/GLCanvas3D.hpp" #include "slic3r/GUI/GUI_App.hpp" @@ -47,10 +50,8 @@ bool GLGizmoMove3D::on_mouse(const wxMouseEvent &mouse_event) { return use_grabbers(mouse_event); } -void GLGizmoMove3D::data_changed() { - const Selection &selection = m_parent.get_selection(); - bool is_wipe_tower = selection.is_wipe_tower(); - m_grabbers[2].enabled = !is_wipe_tower; +void GLGizmoMove3D::data_changed(bool is_serializing) { + m_grabbers[2].enabled = !m_parent.get_selection().is_wipe_tower(); } bool GLGizmoMove3D::on_init() @@ -219,17 +220,17 @@ double GLGizmoMove3D::calc_projection(const UpdateData& data) const { double projection = 0.0; - Vec3d starting_vec = m_starting_drag_position - m_starting_box_center; - double len_starting_vec = starting_vec.norm(); + const Vec3d starting_vec = m_starting_drag_position - m_starting_box_center; + const double len_starting_vec = starting_vec.norm(); if (len_starting_vec != 0.0) { - Vec3d mouse_dir = data.mouse_ray.unit_vector(); + const Vec3d mouse_dir = data.mouse_ray.unit_vector(); // finds the intersection of the mouse ray with the plane parallel to the camera viewport and passing throught the starting position // use ray-plane intersection see i.e. https://en.wikipedia.org/wiki/Line%E2%80%93plane_intersection algebric form // in our case plane normal and ray direction are the same (orthogonal view) // when moving to perspective camera the negative z unit axis of the camera needs to be transformed in world space and used as plane normal - Vec3d inters = data.mouse_ray.a + (m_starting_drag_position - data.mouse_ray.a).dot(mouse_dir) / mouse_dir.squaredNorm() * mouse_dir; + const Vec3d inters = data.mouse_ray.a + (m_starting_drag_position - data.mouse_ray.a).dot(mouse_dir) * mouse_dir; // vector from the starting position to the found intersection - Vec3d inters_vec = inters - m_starting_drag_position; + const Vec3d inters_vec = inters - m_starting_drag_position; // finds projection of the vector along the staring direction projection = inters_vec.dot(starting_vec.normalized()); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMove.hpp b/src/slic3r/GUI/Gizmos/GLGizmoMove.hpp index 0650825904f..f4c04c730a7 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMove.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMove.hpp @@ -1,3 +1,7 @@ +///|/ Copyright (c) Prusa Research 2019 - 2023 Lukáš Matěna @lukasmatena, Enrico Turri @enricoturri1966, Oleksandra Iushchenko @YuSanka, Filip Sykala @Jony01 +///|/ +///|/ PrusaSlicer is released under the terms of the AGPLv3 or higher +///|/ #ifndef slic3r_GLGizmoMove_hpp_ #define slic3r_GLGizmoMove_hpp_ @@ -52,7 +56,7 @@ class GLGizmoMove3D : public GLGizmoBase /// /// Detect reduction of move for wipetover on selection change /// - void data_changed() override; + void data_changed(bool is_serializing) override; protected: bool on_init() override; std::string on_get_name() const override; diff --git a/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp b/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp index 8831c61abeb..8b33edfcb8e 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp @@ -1,4 +1,7 @@ -// Include GLGizmoBase.hpp before I18N.hpp as it includes some libigl code, which overrides our localization "L" macro. +///|/ Copyright (c) Prusa Research 2019 - 2023 Oleksandra Iushchenko @YuSanka, Lukáš Matěna @lukasmatena, Enrico Turri @enricoturri1966, Vojtěch Bubník @bubnikv, Filip Sykala @Jony01, Lukáš Hejl @hejllukas +///|/ +///|/ PrusaSlicer is released under the terms of the AGPLv3 or higher +///|/ #include "GLGizmoPainterBase.hpp" #include "slic3r/GUI/GLCanvas3D.hpp" #include "slic3r/GUI/Gizmos/GLGizmosCommon.hpp" @@ -34,7 +37,7 @@ GLGizmoPainterBase::~GLGizmoPainterBase() s_sphere.reset(); } -void GLGizmoPainterBase::data_changed() +void GLGizmoPainterBase::data_changed(bool is_serializing) { if (m_state != On) return; @@ -120,13 +123,11 @@ void GLGizmoPainterBase::render_triangles(const Selection& selection) const shader->set_uniform("volume_world_matrix", trafo_matrix); m_triangle_selectors[mesh_id]->render(m_imgui, trafo_matrix); - if (is_left_handed) glsafe(::glFrontFace(GL_CCW)); } } - void GLGizmoPainterBase::render_cursor() { // First check that the mouse pointer is on an object. @@ -165,11 +166,9 @@ void GLGizmoPainterBase::render_cursor() } } - - void GLGizmoPainterBase::render_cursor_circle() { - const Size cnv_size = m_parent.get_canvas_size(); + const Size cnv_size = m_parent.get_canvas_size(); const float cnv_width = float(cnv_size.get_width()); const float cnv_height = float(cnv_size.get_height()); if (cnv_width == 0.0f || cnv_height == 0.0f) @@ -202,7 +201,7 @@ void GLGizmoPainterBase::render_cursor_circle() init_data.reserve_indices(StepsCount); // vertices + indices - for (unsigned short i = 0; i < StepsCount; ++i) { + for (unsigned int i = 0; i < StepsCount; ++i) { const float angle = float(i * StepSize); init_data.add_vertex(Vec2f(2.0f * ((center.x() + ::cos(angle) * radius) * cnv_inv_width - 0.5f), -2.0f * ((center.y() + ::sin(angle) * radius) * cnv_inv_height - 0.5f))); @@ -220,8 +219,8 @@ void GLGizmoPainterBase::render_cursor_circle() render_color = this->get_cursor_sphere_right_button_color(); m_circle.set_color(render_color); - - GLShaderProgram* shader = wxGetApp().get_shader("flat"); + + GLShaderProgram* shader = GUI::wxGetApp().get_shader("flat"); if (shader != nullptr) { shader->start_using(); shader->set_uniform("view_model_matrix", Transform3d::Identity()); @@ -247,10 +246,6 @@ void GLGizmoPainterBase::render_cursor_sphere(const Transform3d& trafo) const return; const Transform3d complete_scaling_matrix_inverse = Geometry::Transformation(trafo).get_matrix(true, true, false, true).inverse(); - const bool is_left_handed = Geometry::Transformation(trafo).is_left_handed(); - - if (is_left_handed) - glFrontFace(GL_CW); // BBS ColorRGBA render_color = this->get_cursor_hover_color(); @@ -258,6 +253,7 @@ void GLGizmoPainterBase::render_cursor_sphere(const Transform3d& trafo) const render_color = this->get_cursor_sphere_left_button_color(); else if (m_button_down == Button::Right) render_color = this->get_cursor_sphere_right_button_color(); + shader->start_using(); const Camera& camera = wxGetApp().plater()->get_camera(); @@ -268,13 +264,18 @@ void GLGizmoPainterBase::render_cursor_sphere(const Transform3d& trafo) const shader->set_uniform("view_model_matrix", view_model_matrix); shader->set_uniform("projection_matrix", camera.get_projection_matrix()); + const bool is_left_handed = Geometry::Transformation(view_model_matrix).is_left_handed(); + if (is_left_handed) + glsafe(::glFrontFace(GL_CW)); + assert(s_sphere != nullptr); s_sphere->set_color(render_color); s_sphere->render(); - shader->stop_using(); if (is_left_handed) - glFrontFace(GL_CCW); + glsafe(::glFrontFace(GL_CCW)); + + shader->stop_using(); } // BBS @@ -631,13 +632,13 @@ bool GLGizmoPainterBase::gizmo_event(SLAGizmoEventType action, const Vec2d& mous pos = action == SLAGizmoEventType::MouseWheelDown ? std::max(0., pos - 0.01) : std::min(1., pos + 0.01); - m_c->object_clipper()->set_position(pos, true); + m_c->object_clipper()->set_position_by_ratio(pos, true); return true; } } if (action == SLAGizmoEventType::ResetClippingPlane) { - m_c->object_clipper()->set_position(-1., false); + m_c->object_clipper()->set_position_by_ratio(-1., false); return true; } @@ -788,14 +789,13 @@ bool GLGizmoPainterBase::gizmo_event(SLAGizmoEventType action, const Vec2d& mous assert(m_cursor_type == TriangleSelector::CursorType::CIRCLE || m_cursor_type == TriangleSelector::CursorType::SPHERE); if (projected_mouse_positions.size() == 1) { - const ProjectedMousePosition& first_position = projected_mouse_positions.front(); - std::unique_ptr cursor = TriangleSelector::SinglePointCursor::cursor_factory(first_position.mesh_hit, - camera_pos, m_cursor_radius, - m_cursor_type, trafo_matrix, clp); + const ProjectedMousePosition &first_position = projected_mouse_positions.front(); + std::unique_ptr cursor = TriangleSelector::SinglePointCursor::cursor_factory(first_position.mesh_hit, + camera_pos, m_cursor_radius, + m_cursor_type, trafo_matrix, clp); m_triangle_selectors[mesh_idx]->select_patch(int(first_position.facet_idx), std::move(cursor), new_state, trafo_matrix_not_translate, - m_triangle_splitting_enabled, m_paint_on_overhangs_only ? m_highlight_by_angle_threshold_deg : 0.f); - } - else { + m_triangle_splitting_enabled, m_paint_on_overhangs_only ? m_highlight_by_angle_threshold_deg : 0.f); + } else { for (auto first_position_it = projected_mouse_positions.cbegin(); first_position_it != projected_mouse_positions.cend() - 1; ++first_position_it) { auto second_position_it = first_position_it + 1; std::unique_ptr cursor = TriangleSelector::DoublePointCursor::cursor_factory(first_position_it->mesh_hit, second_position_it->mesh_hit, camera_pos, m_cursor_radius, m_cursor_type, trafo_matrix, clp); @@ -1190,10 +1190,6 @@ void TriangleSelectorGUI::update_render_data() static const float offset = 0.001f; for (const Triangle &tr : m_triangles) { - bool is_valid = tr.valid(); - bool is_split = tr.is_split(); - EnforcerBlockerType type = tr.get_state(); - bool is_select_by_seed_fill = tr.is_selected_by_seed_fill(); if (!tr.valid() || tr.is_split() || (tr.get_state() == EnforcerBlockerType::NONE && !tr.is_selected_by_seed_fill())) continue; diff --git a/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.hpp b/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.hpp index 5aadd0a3ec7..4252ae7e0aa 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.hpp @@ -1,3 +1,7 @@ +///|/ Copyright (c) Prusa Research 2019 - 2023 Pavel Mikuš @Godrak, Lukáš Matěna @lukasmatena, Enrico Turri @enricoturri1966, Vojtěch Bubník @bubnikv, Lukáš Hejl @hejllukas, Filip Sykala @Jony01 +///|/ +///|/ PrusaSlicer is released under the terms of the AGPLv3 or higher +///|/ #ifndef slic3r_GLGizmoPainterBase_hpp_ #define slic3r_GLGizmoPainterBase_hpp_ @@ -186,10 +190,11 @@ class GLGizmoPainterBase : public GLGizmoBase ObjectID m_old_mo_id; size_t m_old_volumes_size = 0; void on_render() override {} + public: GLGizmoPainterBase(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id); - virtual ~GLGizmoPainterBase() override; - void data_changed() override; + ~GLGizmoPainterBase() override; + void data_changed(bool is_serializing) override; virtual bool gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_position, bool shift_down, bool alt_down, bool control_down); // Following function renders the triangles and cursor. Having this separated @@ -227,8 +232,8 @@ class GLGizmoPainterBase : public GLGizmoBase virtual void update_model_object() = 0; virtual void update_from_model_object(bool first_update) = 0; - virtual ColorRGBA get_cursor_sphere_left_button_color() const { return {0.f, 0.f, 1.f, 0.25f}; } - virtual ColorRGBA get_cursor_sphere_right_button_color() const { return {1.f, 0.f, 0.f, 0.25f}; } + virtual ColorRGBA get_cursor_sphere_left_button_color() const { return { 0.0f, 0.0f, 1.0f, 0.25f }; } + virtual ColorRGBA get_cursor_sphere_right_button_color() const { return { 1.0f, 0.0f, 0.0f, 0.25f }; } // BBS virtual ColorRGBA get_cursor_hover_color() const { return { 0.f, 0.f, 0.f, 0.25f }; } @@ -339,7 +344,7 @@ class GLGizmoPainterBase : public GLGizmoBase Vec3f hit; size_t facet; }; - mutable RaycastResult m_rr; + mutable RaycastResult m_rr = {Vec2d::Zero(), -1, Vec3f::Zero(), 0}; // BBS struct CutContours diff --git a/src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp b/src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp index e6a3c9f2354..1b412c847cd 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp @@ -1,4 +1,7 @@ -// Include GLGizmoBase.hpp before I18N.hpp as it includes some libigl code, which overrides our localization "L" macro. +///|/ Copyright (c) Prusa Research 2019 - 2023 Oleksandra Iushchenko @YuSanka, Lukáš Matěna @lukasmatena, Enrico Turri @enricoturri1966, Tomáš Mészáros @tamasmeszaros, Filip Sykala @Jony01, Vojtěch Bubník @bubnikv +///|/ +///|/ PrusaSlicer is released under the terms of the AGPLv3 or higher +///|/ #include "GLGizmoRotate.hpp" #include "slic3r/GUI/GLCanvas3D.hpp" #include "slic3r/GUI/ImGuiWrapper.hpp" @@ -235,7 +238,7 @@ void GLGizmoRotate::render_circle(const ColorRGBA& color, bool radius_changed) init_data.reserve_indices(ScaleStepsCount); // vertices + indices - for (unsigned short i = 0; i < ScaleStepsCount; ++i) { + for (unsigned int i = 0; i < ScaleStepsCount; ++i) { const float angle = float(i * ScaleStepRad); init_data.add_vertex(Vec3f(::cos(angle) * m_radius, ::sin(angle) * m_radius, 0.0f)); init_data.add_index(i); @@ -262,7 +265,7 @@ void GLGizmoRotate::render_scale(const ColorRGBA& color, bool radius_changed) init_data.reserve_indices(2 * ScaleStepsCount); // vertices + indices - for (unsigned short i = 0; i < ScaleStepsCount; ++i) { + for (unsigned int i = 0; i < ScaleStepsCount; ++i) { const float angle = float(i * ScaleStepRad); const float cosa = ::cos(angle); const float sina = ::sin(angle); @@ -271,10 +274,12 @@ void GLGizmoRotate::render_scale(const ColorRGBA& color, bool radius_changed) const float out_x = (i % ScaleLongEvery == 0) ? cosa * out_radius_long : cosa * out_radius_short; const float out_y = (i % ScaleLongEvery == 0) ? sina * out_radius_long : sina * out_radius_short; + // vertices init_data.add_vertex(Vec3f(in_x, in_y, 0.0f)); init_data.add_vertex(Vec3f(out_x, out_y, 0.0f)); - init_data.add_index(i * 2); - init_data.add_index(i * 2 + 1); + + // indices + init_data.add_line(i * 2, i * 2 + 1); } m_scale.init_from(std::move(init_data)); @@ -299,7 +304,7 @@ void GLGizmoRotate::render_snap_radii(const ColorRGBA& color, bool radius_change init_data.reserve_indices(2 * ScaleStepsCount); // vertices + indices - for (unsigned short i = 0; i < ScaleStepsCount; ++i) { + for (unsigned int i = 0; i < ScaleStepsCount; ++i) { const float angle = float(i * step); const float cosa = ::cos(angle); const float sina = ::sin(angle); @@ -308,10 +313,12 @@ void GLGizmoRotate::render_snap_radii(const ColorRGBA& color, bool radius_change const float out_x = cosa * out_radius; const float out_y = sina * out_radius; + // vertices init_data.add_vertex(Vec3f(in_x, in_y, 0.0f)); init_data.add_vertex(Vec3f(out_x, out_y, 0.0f)); - init_data.add_index(i * 2); - init_data.add_index(i * 2 + 1); + + // indices + init_data.add_line(i * 2, i * 2 + 1); } m_snap_radii.init_from(std::move(init_data)); @@ -362,7 +369,7 @@ void GLGizmoRotate::render_angle_arc(const ColorRGBA& color, bool radius_changed init_data.reserve_indices(1 + AngleResolution); // vertices + indices - for (unsigned short i = 0; i <= AngleResolution; ++i) { + for (unsigned int i = 0; i <= AngleResolution; ++i) { const float angle = float(i) * step_angle; init_data.add_vertex(Vec3f(::cos(angle) * ex_radius, ::sin(angle) * ex_radius, 0.0f)); init_data.add_index(i); @@ -439,7 +446,7 @@ Transform3d GLGizmoRotate::local_transform(const Selection& selection) const Vec3d GLGizmoRotate::mouse_position_in_local_plane(const Linef3& mouse_ray, const Selection& selection) const { - double half_pi = 0.5 * double(PI); + const double half_pi = 0.5 * double(PI); Transform3d m = Transform3d::Identity(); @@ -470,7 +477,20 @@ Vec3d GLGizmoRotate::mouse_position_in_local_plane(const Linef3& mouse_ray, cons m.translate(-m_center); - return transform(mouse_ray, m).intersect_plane(0.0); + const Linef3 local_mouse_ray = transform(mouse_ray, m); + if (std::abs(local_mouse_ray.vector().dot(Vec3d::UnitZ())) < EPSILON) { + // if the ray is parallel to the plane containing the circle + if (std::abs(local_mouse_ray.vector().dot(Vec3d::UnitY())) > 1.0 - EPSILON) + // if the ray is parallel to grabber direction + return Vec3d::UnitX(); + else { + const Vec3d world_pos = (local_mouse_ray.a.x() >= 0.0) ? mouse_ray.a - m_center : mouse_ray.b - m_center; + m.translate(m_center); + return m * world_pos; + } + } + else + return local_mouse_ray.intersect_plane(0.0); } //BBS: GUI refactor: add obj manipulation @@ -489,13 +509,14 @@ bool GLGizmoRotate3D::on_mouse(const wxMouseEvent &mouse_event) { // Apply new temporary rotations TransformationType transformation_type( TransformationType::World_Relative_Joint); - if (mouse_event.AltDown()) transformation_type.set_independent(); + if (mouse_event.AltDown()) + transformation_type.set_independent(); m_parent.get_selection().rotate(get_rotation(), transformation_type); } return use_grabbers(mouse_event); } -void GLGizmoRotate3D::data_changed() { +void GLGizmoRotate3D::data_changed(bool is_serializing) { const Selection &selection = m_parent.get_selection(); bool is_wipe_tower = selection.is_wipe_tower(); if (is_wipe_tower) { diff --git a/src/slic3r/GUI/Gizmos/GLGizmoRotate.hpp b/src/slic3r/GUI/Gizmos/GLGizmoRotate.hpp index 0a686e701a2..edafc5ae236 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoRotate.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoRotate.hpp @@ -1,3 +1,7 @@ +///|/ Copyright (c) Prusa Research 2019 - 2023 Lukáš Matěna @lukasmatena, Enrico Turri @enricoturri1966, Oleksandra Iushchenko @YuSanka, Filip Sykala @Jony01, Tomáš Mészáros @tamasmeszaros +///|/ +///|/ PrusaSlicer is released under the terms of the AGPLv3 or higher +///|/ #ifndef slic3r_GLGizmoRotate_hpp_ #define slic3r_GLGizmoRotate_hpp_ @@ -85,6 +89,7 @@ class GLGizmoRotate : public GLGizmoBase /// Return True when use the information otherwise False. bool on_mouse(const wxMouseEvent &mouse_event) override; void dragging(const UpdateData &data); + protected: bool on_init() override; std::string on_get_name() const override { return ""; } @@ -122,7 +127,7 @@ class GLGizmoRotate3D : public GLGizmoBase GLGizmoRotate3D(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id, GizmoObjectManipulation* obj_manipulation); Vec3d get_rotation() const { return Vec3d(m_gizmos[X].get_angle(), m_gizmos[Y].get_angle(), m_gizmos[Z].get_angle()); } - void set_rotation(const Vec3d& rotation) { m_gizmos[X].set_angle(rotation(0)); m_gizmos[Y].set_angle(rotation(1)); m_gizmos[Z].set_angle(rotation(2)); } + void set_rotation(const Vec3d& rotation) { m_gizmos[X].set_angle(rotation.x()); m_gizmos[Y].set_angle(rotation.y()); m_gizmos[Z].set_angle(rotation.z()); } std::string get_tooltip() const override { std::string tooltip = m_gizmos[X].get_tooltip(); @@ -147,7 +152,7 @@ class GLGizmoRotate3D : public GLGizmoBase /// Return True when use the information otherwise False. bool on_mouse(const wxMouseEvent &mouse_event) override; - void data_changed() override; + void data_changed(bool is_serializing) override; protected: bool on_init() override; std::string on_get_name() const override; diff --git a/src/slic3r/GUI/Gizmos/GLGizmoScale.cpp b/src/slic3r/GUI/Gizmos/GLGizmoScale.cpp index 195368ecf58..93fbf7d9b33 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoScale.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoScale.cpp @@ -1,4 +1,7 @@ -// Include GLGizmoBase.hpp before I18N.hpp as it includes some libigl code, which overrides our localization "L" macro. +///|/ Copyright (c) Prusa Research 2019 - 2023 Oleksandra Iushchenko @YuSanka, Lukáš Matěna @lukasmatena, Enrico Turri @enricoturri1966, Filip Sykala @Jony01, Vojtěch Bubník @bubnikv +///|/ +///|/ PrusaSlicer is released under the terms of the AGPLv3 or higher +///|/ #include "GLGizmoScale.hpp" #include "slic3r/GUI/GLCanvas3D.hpp" #include "slic3r/GUI/GUI_App.hpp" @@ -83,18 +86,18 @@ bool GLGizmoScale3D::on_mouse(const wxMouseEvent &mouse_event) if (m_dragging) { // Apply new temporary scale factors TransformationType transformation_type(TransformationType::Local_Absolute_Joint); - if (mouse_event.AltDown()) transformation_type.set_independent(); + if (mouse_event.AltDown()) + transformation_type.set_independent(); - Selection &selection = m_parent.get_selection(); - selection.scale(get_scale(), transformation_type); + Selection& selection = m_parent.get_selection(); + selection.scale(m_scale, transformation_type); if (mouse_event.CmdDown()) selection.translate(m_offset, true); } } return use_grabbers(mouse_event); } -void GLGizmoScale3D::data_changed() -{ +void GLGizmoScale3D::data_changed(bool is_serializing) { const Selection &selection = m_parent.get_selection(); bool enable_scale_xyz = selection.is_single_full_instance() || selection.is_single_volume() || @@ -298,7 +301,13 @@ void GLGizmoScale3D::on_render() } // draw grabbers - render_grabbers(grabber_mean_size); + shader = wxGetApp().get_shader("gouraud_light"); + if (shader != nullptr) { + shader->start_using(); + shader->set_uniform("emission_factor", 0.1f); + render_grabbers(grabber_mean_size); + shader->stop_using(); + } } void GLGizmoScale3D::on_register_raycasters_for_picking() @@ -388,9 +397,9 @@ void GLGizmoScale3D::do_scale_along_axis(Axis axis, const UpdateData& data) } } -void GLGizmoScale3D::do_scale_uniform(const UpdateData& data) +void GLGizmoScale3D::do_scale_uniform(const UpdateData & data) { - double ratio = calc_ratio(data); + const double ratio = calc_ratio(data); if (ratio > 0.0) { m_scale = m_starting.scale * ratio; m_offset = Vec3d::Zero(); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoScale.hpp b/src/slic3r/GUI/Gizmos/GLGizmoScale.hpp index 1b0a47b6baf..589b0744915 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoScale.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoScale.hpp @@ -1,3 +1,7 @@ +///|/ Copyright (c) Prusa Research 2019 - 2023 Oleksandra Iushchenko @YuSanka, Lukáš Matěna @lukasmatena, Enrico Turri @enricoturri1966, Filip Sykala @Jony01 +///|/ +///|/ PrusaSlicer is released under the terms of the AGPLv3 or higher +///|/ #ifndef slic3r_GLGizmoScale_hpp_ #define slic3r_GLGizmoScale_hpp_ @@ -28,10 +32,10 @@ class GLGizmoScale3D : public GLGizmoBase StartingData() : scale(Vec3d::Ones()), drag_position(Vec3d::Zero()), ctrl_down(false) { for (int i = 0; i < 5; ++i) { pivots[i] = Vec3d::Zero(); } } }; - mutable BoundingBoxf3 m_box; - mutable Transform3d m_transform; + BoundingBoxf3 m_box; + Transform3d m_transform; // Transforms grabbers offsets to the proper reference system (world for instances, instance for volumes) - mutable Transform3d m_offsets_transform; + Transform3d m_offsets_transform; Vec3d m_scale{ Vec3d::Ones() }; Vec3d m_offset{ Vec3d::Zero() }; double m_snap_step{ 0.05 }; @@ -41,7 +45,7 @@ class GLGizmoScale3D : public GLGizmoBase ColorRGBA m_drag_color; ColorRGBA m_highlight_color; - struct GrabberConnection + struct GrabberConnection { GLModel model; std::pair grabber_indices; @@ -66,8 +70,6 @@ class GLGizmoScale3D : public GLGizmoBase std::string get_tooltip() const override; - void enable_ununiversal_scale(bool enable); - /// /// Postpone to Grabber for scale /// @@ -75,7 +77,8 @@ class GLGizmoScale3D : public GLGizmoBase /// Return True when use the information otherwise False. bool on_mouse(const wxMouseEvent &mouse_event) override; - void data_changed() override; + void data_changed(bool is_serializing) override; + void enable_ununiversal_scale(bool enable); protected: virtual bool on_init() override; virtual std::string on_get_name() const override; diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSeam.cpp b/src/slic3r/GUI/Gizmos/GLGizmoSeam.cpp index 54909592f15..09e999ec520 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSeam.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSeam.cpp @@ -1,3 +1,7 @@ +///|/ Copyright (c) Prusa Research 2020 - 2022 Enrico Turri @enricoturri1966, Lukáš Matěna @lukasmatena, Lukáš Hejl @hejllukas, Oleksandra Iushchenko @YuSanka, Vojtěch Bubník @bubnikv +///|/ +///|/ PrusaSlicer is released under the terms of the AGPLv3 or higher +///|/ #include "GLGizmoSeam.hpp" #include "libslic3r/Model.hpp" @@ -298,8 +302,8 @@ void GLGizmoSeam::on_render_input_window(float x, float y, float bottom_limit) } else { if (m_imgui->button(m_desc.at("reset_direction"))) { - wxGetApp().CallAfter([this]() { - m_c->object_clipper()->set_position(-1., false); + wxGetApp().CallAfter([this](){ + m_c->object_clipper()->set_position_by_ratio(-1., false); }); } } @@ -313,7 +317,7 @@ void GLGizmoSeam::on_render_input_window(float x, float y, float bottom_limit) ImGui::SameLine(drag_left_width); ImGui::PushItemWidth(1.5 * slider_icon_width); bool b_clp_dist_input = ImGui::BBLDragFloat("##clp_dist_input", &clp_dist, 0.05f, 0.0f, 0.0f, "%.2f"); - if (slider_clp_dist || b_clp_dist_input) { m_c->object_clipper()->set_position(clp_dist, true); } + if (slider_clp_dist || b_clp_dist_input) { m_c->object_clipper()->set_position_by_ratio(clp_dist, true); } ImGui::Separator(); m_imgui->bbl_checkbox(_L("Vertical"), m_vertical_only); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSeam.hpp b/src/slic3r/GUI/Gizmos/GLGizmoSeam.hpp index abfd4c28aaf..d5977059922 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSeam.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSeam.hpp @@ -1,3 +1,7 @@ +///|/ Copyright (c) Prusa Research 2019 - 2023 Oleksandra Iushchenko @YuSanka, Enrico Turri @enricoturri1966, Lukáš Matěna @lukasmatena, Lukáš Hejl @hejllukas +///|/ +///|/ PrusaSlicer is released under the terms of the AGPLv3 or higher +///|/ #ifndef slic3r_GLGizmoSeam_hpp_ #define slic3r_GLGizmoSeam_hpp_ @@ -32,9 +36,9 @@ class GLGizmoSeam : public GLGizmoPainterBase wxString handle_snapshot_action_name(bool shift_down, Button button_down) const override; - std::string get_gizmo_entering_text() const override { return "Entering Seam painting"; } - std::string get_gizmo_leaving_text() const override { return "Leaving Seam painting"; } - std::string get_action_snapshot_name() override { return "Paint-on seam editing"; } + std::string get_gizmo_entering_text() const override { return _u8L("Entering Seam painting"); } + std::string get_gizmo_leaving_text() const override { return _u8L("Leaving Seam painting"); } + std::string get_action_snapshot_name() const override { return _u8L("Paint-on seam editing"); } static const constexpr float CursorRadiusMin = 0.05f; // cannot be zero private: diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSimplify.cpp b/src/slic3r/GUI/Gizmos/GLGizmoSimplify.cpp index 4c7042a0059..ca1575bba3d 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSimplify.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSimplify.cpp @@ -1,3 +1,7 @@ +///|/ Copyright (c) Prusa Research 2021 - 2023 Oleksandra Iushchenko @YuSanka, Lukáš Hejl @hejllukas, Enrico Turri @enricoturri1966, David Kocík @kocikdav, Filip Sykala @Jony01, Lukáš Matěna @lukasmatena, Vojtěch Bubník @bubnikv +///|/ +///|/ PrusaSlicer is released under the terms of the AGPLv3 or higher +///|/ #include "GLGizmoSimplify.hpp" #include "slic3r/GUI/GLCanvas3D.hpp" #include "slic3r/GUI/GUI_App.hpp" diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSimplify.hpp b/src/slic3r/GUI/Gizmos/GLGizmoSimplify.hpp index b4be94d2c94..dedcea89716 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSimplify.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSimplify.hpp @@ -1,3 +1,7 @@ +///|/ Copyright (c) Prusa Research 2021 - 2023 Oleksandra Iushchenko @YuSanka, Enrico Turri @enricoturri1966, Vojtěch Bubník @bubnikv, Filip Sykala @Jony01, Lukáš Hejl @hejllukas, Lukáš Matěna @lukasmatena +///|/ +///|/ PrusaSlicer is released under the terms of the AGPLv3 or higher +///|/ #ifndef slic3r_GLGizmoSimplify_hpp_ #define slic3r_GLGizmoSimplify_hpp_ diff --git a/src/slic3r/GUI/Gizmos/GLGizmoText.cpp b/src/slic3r/GUI/Gizmos/GLGizmoText.cpp index 4e28011a29a..5982e269629 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoText.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoText.cpp @@ -445,8 +445,8 @@ void GLGizmoText::on_render() m_grabbers[0].center = m_mouse_position_world; m_grabbers[0].enabled = true; - ColorRGBA color = picking_color_component(0); - m_grabbers[0].color = color; + //ColorRGBA color = picking_color_component(0); + //m_grabbers[0].color = color; GLShaderProgram *shader = wxGetApp().get_shader("gouraud_light"); if (shader != nullptr) { diff --git a/src/slic3r/GUI/Gizmos/GLGizmos.hpp b/src/slic3r/GUI/Gizmos/GLGizmos.hpp index 9751c372328..36435919b7c 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmos.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmos.hpp @@ -1,3 +1,7 @@ +///|/ Copyright (c) Prusa Research 2019 - 2021 Lukáš Hejl @hejllukas, Lukáš Matěna @lukasmatena, Enrico Turri @enricoturri1966 +///|/ +///|/ PrusaSlicer is released under the terms of the AGPLv3 or higher +///|/ #ifndef slic3r_GLGizmos_hpp_ #define slic3r_GLGizmos_hpp_ diff --git a/src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp b/src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp index 3901b142da7..709cd472574 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp @@ -1,3 +1,7 @@ +///|/ Copyright (c) Prusa Research 2020 - 2023 Lukáš Matěna @lukasmatena, Oleksandra Iushchenko @YuSanka, Enrico Turri @enricoturri1966, Tomáš Mészáros @tamasmeszaros, Vojtěch Bubník @bubnikv +///|/ +///|/ PrusaSlicer is released under the terms of the AGPLv3 or higher +///|/ #include "GLGizmosCommon.hpp" #include @@ -23,10 +27,10 @@ CommonGizmosDataPool::CommonGizmosDataPool(GLCanvas3D* canvas) using c = CommonGizmosDataID; m_data[c::SelectionInfo].reset( new SelectionInfo(this)); m_data[c::InstancesHider].reset( new InstancesHider(this)); - m_data[c::HollowedMesh].reset( new HollowedMesh(this)); +// m_data[c::HollowedMesh].reset( new HollowedMesh(this)); m_data[c::Raycaster].reset( new Raycaster(this)); m_data[c::ObjectClipper].reset( new ObjectClipper(this)); - m_data[c::SupportsClipper].reset( new SupportsClipper(this)); + // m_data[c::SupportsClipper].reset( new SupportsClipper(this)); } @@ -59,13 +63,6 @@ InstancesHider* CommonGizmosDataPool::instances_hider() const return inst_hider->is_valid() ? inst_hider : nullptr; } -HollowedMesh* CommonGizmosDataPool::hollowed_mesh() const -{ - HollowedMesh* hol_mesh = dynamic_cast(m_data.at(CommonGizmosDataID::HollowedMesh).get()); - assert(hol_mesh); - return hol_mesh->is_valid() ? hol_mesh : nullptr; -} - Raycaster* CommonGizmosDataPool::raycaster() const { Raycaster* rc = dynamic_cast(m_data.at(CommonGizmosDataID::Raycaster).get()); @@ -81,13 +78,6 @@ ObjectClipper* CommonGizmosDataPool::object_clipper() const return (oc && oc->is_valid()) ? oc : nullptr; } -SupportsClipper* CommonGizmosDataPool::supports_clipper() const -{ - SupportsClipper* sc = dynamic_cast(m_data.at(CommonGizmosDataID::SupportsClipper).get()); - assert(sc); - return sc->is_valid() ? sc : nullptr; -} - #ifndef NDEBUG // Check the required resources one by one and return true if all // dependencies are met. @@ -117,12 +107,13 @@ bool CommonGizmosDataPool::check_dependencies(CommonGizmosDataID required) const void SelectionInfo::on_update() { const Selection& selection = get_pool()->get_canvas()->get_selection(); + + m_model_object = nullptr; + if (selection.is_single_full_instance()) { m_model_object = selection.get_model()->objects[selection.get_object_idx()]; m_z_shift = selection.get_first_volume()->get_sla_shift_z(); } - else - m_model_object = nullptr; } void SelectionInfo::on_release() @@ -132,8 +123,7 @@ void SelectionInfo::on_release() int SelectionInfo::get_active_instance() const { - const Selection& selection = get_pool()->get_canvas()->get_selection(); - return selection.get_instance_idx(); + return get_pool()->get_canvas()->get_selection().get_instance_idx(); } @@ -154,7 +144,7 @@ void InstancesHider::on_update() if (mo && active_inst != -1) { canvas->toggle_model_objects_visibility(false); canvas->toggle_model_objects_visibility(true, mo, active_inst); - canvas->toggle_sla_auxiliaries_visibility(m_show_supports, mo, active_inst); + canvas->toggle_sla_auxiliaries_visibility(false, mo, active_inst); canvas->set_use_clipping_planes(true); // Some objects may be sinking, do not show whatever is below the bed. canvas->set_clipping_plane(0, ClippingPlane(Vec3d::UnitZ(), z_min)); @@ -170,7 +160,7 @@ void InstancesHider::on_update() for (const TriangleMesh* mesh : meshes) { m_clippers.emplace_back(new MeshClipper); m_clippers.back()->set_plane(ClippingPlane(-Vec3d::UnitZ(), z_min)); - m_clippers.back()->set_mesh(*mesh); + m_clippers.back()->set_mesh(mesh->its); } m_old_meshes = meshes; } @@ -187,13 +177,6 @@ void InstancesHider::on_release() m_clippers.clear(); } -void InstancesHider::show_supports(bool show) { - if (m_show_supports != show) { - m_show_supports = show; - on_update(); - } -} - void InstancesHider::render_cut() const { const SelectionInfo* sel_info = get_pool()->selection_info(); @@ -228,104 +211,19 @@ void InstancesHider::render_cut() const } - -void HollowedMesh::on_update() -{ - const ModelObject* mo = get_pool()->selection_info()->model_object(); - bool is_sla = wxGetApp().preset_bundle->printers.get_selected_preset().printer_technology() == ptSLA; - if (! mo || ! is_sla) - return; - - const GLCanvas3D* canvas = get_pool()->get_canvas(); - const PrintObjects& print_objects = canvas->sla_print()->objects(); - const SLAPrintObject* print_object = m_print_object_idx != -1 - ? print_objects[m_print_object_idx] - : nullptr; - - // Find the respective SLAPrintObject. - if (m_print_object_idx < 0 || m_print_objects_count != int(print_objects.size())) { - m_print_objects_count = print_objects.size(); - m_print_object_idx = -1; - for (const SLAPrintObject* po : print_objects) { - ++m_print_object_idx; - if (po->model_object()->id() == mo->id()) { - print_object = po; - break; - } - } - } - - // If there is a valid SLAPrintObject, check state of Hollowing step. - if (print_object) { - if (print_object->is_step_done(slaposDrillHoles) && print_object->has_mesh(slaposDrillHoles)) { - size_t timestamp = print_object->step_state_with_timestamp(slaposDrillHoles).timestamp; - if (timestamp > m_old_hollowing_timestamp) { - const TriangleMesh& backend_mesh = print_object->get_mesh_to_slice(); - if (! backend_mesh.empty()) { - m_hollowed_mesh_transformed.reset(new TriangleMesh(backend_mesh)); - Transform3d trafo_inv = canvas->sla_print()->sla_trafo(*mo).inverse(); - m_hollowed_mesh_transformed->transform(trafo_inv); - m_drainholes = print_object->model_object()->sla_drain_holes; - m_old_hollowing_timestamp = timestamp; - - indexed_triangle_set interior = print_object->hollowed_interior_mesh(); - its_flip_triangles(interior); - m_hollowed_interior_transformed = std::make_unique(std::move(interior)); - m_hollowed_interior_transformed->transform(trafo_inv); - } - else { - m_hollowed_mesh_transformed.reset(nullptr); - } - } - } - else - m_hollowed_mesh_transformed.reset(nullptr); - } -} - - -void HollowedMesh::on_release() -{ - m_hollowed_mesh_transformed.reset(); - m_old_hollowing_timestamp = 0; - m_print_object_idx = -1; -} - - -const TriangleMesh* HollowedMesh::get_hollowed_mesh() const -{ - return m_hollowed_mesh_transformed.get(); -} - -const TriangleMesh* HollowedMesh::get_hollowed_interior() const -{ - return m_hollowed_interior_transformed.get(); -} - - - - void Raycaster::on_update() { wxBusyCursor wait; const ModelObject* mo = get_pool()->selection_info()->model_object(); - if (! mo) + if (mo == nullptr) return; std::vector meshes; const std::vector& mvs = mo->volumes; - if (mvs.size() == 1) { - assert(mvs.front()->is_model_part()); - const HollowedMesh* hollowed_mesh_tracker = get_pool()->hollowed_mesh(); - if (hollowed_mesh_tracker && hollowed_mesh_tracker->get_hollowed_mesh()) - meshes.push_back(hollowed_mesh_tracker->get_hollowed_mesh()); - } - if (meshes.empty()) { - for (const ModelVolume* mv : mvs) { - if (mv->is_model_part()) - meshes.push_back(&mv->mesh()); - } + for (const ModelVolume* mv : mvs) { + if (mv->is_model_part()) + meshes.push_back(&mv->mesh()); } if (meshes != m_old_meshes) { @@ -351,9 +249,6 @@ std::vector Raycaster::raycasters() const } - - - void ObjectClipper::on_update() { const ModelObject* mo = get_pool()->selection_info()->model_object(); @@ -362,24 +257,19 @@ void ObjectClipper::on_update() // which mesh should be cut? std::vector meshes; - bool has_hollowed = get_pool()->hollowed_mesh() && get_pool()->hollowed_mesh()->get_hollowed_mesh(); - if (has_hollowed) - meshes.push_back(get_pool()->hollowed_mesh()->get_hollowed_mesh()); - - if (meshes.empty()) - for (const ModelVolume* mv : mo->volumes) - meshes.push_back(&mv->mesh()); + std::vector trafos; + for (const ModelVolume* mv : mo->volumes) { + meshes.emplace_back(&mv->mesh()); + trafos.emplace_back(mv->get_transformation()); + } if (meshes != m_old_meshes) { m_clippers.clear(); - for (const TriangleMesh* mesh : meshes) { - m_clippers.emplace_back(new MeshClipper); - m_clippers.back()->set_mesh(*mesh); + for (size_t i = 0; i < meshes.size(); ++i) { + m_clippers.emplace_back(new MeshClipper, trafos[i]); + m_clippers.back().first->set_mesh(meshes[i]->its); } - m_old_meshes = meshes; - - if (has_hollowed) - m_clippers.front()->set_negative_mesh(*get_pool()->hollowed_mesh()->get_hollowed_interior()); + m_old_meshes = std::move(meshes); m_active_inst_bb_radius = mo->instance_bounding_box(get_pool()->selection_info()->get_active_instance()).radius(); @@ -396,45 +286,74 @@ void ObjectClipper::on_release() } -void ObjectClipper::render_cut() const +void ObjectClipper::render_cut(const std::vector* ignore_idxs) const { if (m_clp_ratio == 0.) return; const SelectionInfo* sel_info = get_pool()->selection_info(); - const ModelObject* mo = sel_info->model_object(); - Geometry::Transformation inst_trafo; - bool is_assem_cnv = get_pool()->get_canvas()->get_canvas_type() == GLCanvas3D::CanvasAssembleView; - inst_trafo = is_assem_cnv ? - mo->instances[sel_info->get_active_instance()]->get_assemble_transformation() : - mo->instances[sel_info->get_active_instance()]->get_transformation(); - auto offset_to_assembly = mo->instances[0]->get_offset_to_assembly(); + const Geometry::Transformation inst_trafo = sel_info->model_object()->instances[sel_info->get_active_instance()]->get_transformation(); + + std::vector ignore_idxs_local = ignore_idxs ? *ignore_idxs : std::vector(); - size_t clipper_id = 0; - for (const ModelVolume* mv : mo->volumes) { - const Geometry::Transformation vol_trafo = mv->get_transformation(); - Geometry::Transformation trafo = inst_trafo * vol_trafo; - if (is_assem_cnv) { - trafo.set_offset(trafo.get_offset() + offset_to_assembly * (GLVolume::explosion_ratio - 1.0) + vol_trafo.get_offset() * (GLVolume::explosion_ratio - 1.0)); - } - else { - trafo.set_offset(trafo.get_offset() + Vec3d(0., 0., sel_info->get_sla_shift())); - } - auto& clipper = m_clippers[clipper_id]; - clipper->set_plane(*m_clp); - clipper->set_transformation(trafo); - if (is_assem_cnv) - clipper->set_limiting_plane(ClippingPlane(Vec3d::UnitZ(), std::numeric_limits::max())); - else - clipper->set_limiting_plane(ClippingPlane(Vec3d::UnitZ(), -SINKING_Z_THRESHOLD)); - // BBS - clipper->render_cut({ 0.25f, 0.25f, 0.25f, 1.0f }); + for (auto& clipper : m_clippers) { + Geometry::Transformation trafo = inst_trafo * clipper.second; + trafo.set_offset(trafo.get_offset() + Vec3d(0., 0., sel_info->get_sla_shift())); + clipper.first->set_plane(*m_clp); + clipper.first->set_transformation(trafo); + clipper.first->set_limiting_plane(ClippingPlane(Vec3d::UnitZ(), -SINKING_Z_THRESHOLD)); + // BBS + clipper.first->render_cut({ 0.25f, 0.25f, 0.25f, 1.0f }, &ignore_idxs_local); + clipper.first->render_contour({ 1.f, 1.f, 1.f, 1.f }, &ignore_idxs_local); + + // Now update the ignore idxs. Find the first element belonging to the next clipper, + // and remove everything before it and decrement everything by current number of contours. + const int num_of_contours = clipper.first->get_number_of_contours(); + ignore_idxs_local.erase(ignore_idxs_local.begin(), std::find_if(ignore_idxs_local.begin(), ignore_idxs_local.end(), [num_of_contours](size_t idx) { return idx >= size_t(num_of_contours); } )); + for (size_t& idx : ignore_idxs_local) + idx -= num_of_contours; + } +} - ++clipper_id; + +int ObjectClipper::get_number_of_contours() const +{ + int sum = 0; + for (const auto& [clipper, trafo] : m_clippers) + sum += clipper->get_number_of_contours(); + return sum; +} + +int ObjectClipper::is_projection_inside_cut(const Vec3d& point) const +{ + if (m_clp_ratio == 0.) + return -1; + int idx_offset = 0; + for (const auto& [clipper, trafo] : m_clippers) { + if (int idx = clipper->is_projection_inside_cut(point); idx != -1) + return idx_offset + idx; + idx_offset += clipper->get_number_of_contours(); } + return -1; } +bool ObjectClipper::has_valid_contour() const +{ + return m_clp_ratio != 0. && std::any_of(m_clippers.begin(), m_clippers.end(), [](const auto& cl) { return cl.first->has_valid_contour(); }); +} -void ObjectClipper::set_position(double pos, bool keep_normal) +std::vector ObjectClipper::point_per_contour() const +{ + std::vector pts; + + for (const auto& clipper : m_clippers) { + const std::vector pts_clipper = clipper.first->point_per_contour(); + pts.insert(pts.end(), pts_clipper.begin(), pts_clipper.end());; + } + return pts; +} + + +void ObjectClipper::set_position_by_ratio(double pos, bool keep_normal) { const ModelObject* mo = get_pool()->selection_info()->model_object(); int active_inst = get_pool()->selection_info()->get_active_instance(); @@ -469,114 +388,26 @@ void ObjectClipper::set_position(double pos, bool keep_normal) get_pool()->get_canvas()->set_as_dirty(); } -void ObjectClipper::set_range_and_pos(const Vec3d &cpl_normal, double cpl_offset, double pos) +void ObjectClipper::set_range_and_pos(const Vec3d& cpl_normal, double cpl_offset, double pos) { m_clp.reset(new ClippingPlane(cpl_normal, cpl_offset)); m_clp_ratio = pos; get_pool()->get_canvas()->set_as_dirty(); } -bool ObjectClipper::is_projection_inside_cut(const Vec3d &point) const +const ClippingPlane* ObjectClipper::get_clipping_plane(bool ignore_hide_clipped) const { - return m_clp_ratio != 0. && std::any_of(m_clippers.begin(), m_clippers.end(), [point](const auto &cl) { - return cl->is_projection_inside_cut(point); - }); + static const ClippingPlane no_clip = ClippingPlane::ClipsNothing(); + return (ignore_hide_clipped || m_hide_clipped) ? m_clp.get() : &no_clip; } -bool ObjectClipper::has_valid_contour() const +void ObjectClipper::set_behavior(bool hide_clipped, bool fill_cut, double contour_width) { - return m_clp_ratio != 0. && std::any_of(m_clippers.begin(), m_clippers.end(), [](const auto &cl) { - return cl->has_valid_contour(); - }); + m_hide_clipped = hide_clipped; + for (auto& clipper : m_clippers) + clipper.first->set_behaviour(fill_cut, contour_width); } -void SupportsClipper::on_update() -{ - const ModelObject* mo = get_pool()->selection_info()->model_object(); - bool is_sla = wxGetApp().preset_bundle->printers.get_selected_preset().printer_technology() == ptSLA; - if (! mo || ! is_sla) - return; - - const GLCanvas3D* canvas = get_pool()->get_canvas(); - const PrintObjects& print_objects = canvas->sla_print()->objects(); - const SLAPrintObject* print_object = m_print_object_idx != -1 - ? print_objects[m_print_object_idx] - : nullptr; - - // Find the respective SLAPrintObject. - if (m_print_object_idx < 0 || m_print_objects_count != int(print_objects.size())) { - m_print_objects_count = print_objects.size(); - m_print_object_idx = -1; - for (const SLAPrintObject* po : print_objects) { - ++m_print_object_idx; - if (po->model_object()->id() == mo->id()) { - print_object = po; - break; - } - } - } - - if (print_object - && print_object->is_step_done(slaposSupportTree) - && ! print_object->support_mesh().empty()) - { - // If the supports are already calculated, save the timestamp of the respective step - // so we can later tell they were recalculated. - size_t timestamp = print_object->step_state_with_timestamp(slaposSupportTree).timestamp; - if (! m_clipper || timestamp != m_old_timestamp) { - // The timestamp has changed. - m_clipper.reset(new MeshClipper); - // The mesh should already have the shared vertices calculated. - m_clipper->set_mesh(print_object->support_mesh()); - m_old_timestamp = timestamp; - } - } - else - // The supports are not valid. We better dump the cached data. - m_clipper.reset(); -} - - -void SupportsClipper::on_release() -{ - m_clipper.reset(); - m_old_timestamp = 0; - m_print_object_idx = -1; -} - -void SupportsClipper::render_cut() const -{ - const CommonGizmosDataObjects::ObjectClipper* ocl = get_pool()->object_clipper(); - if (ocl->get_position() == 0. - || ! get_pool()->instances_hider()->are_supports_shown() - || ! m_clipper) - return; - - const SelectionInfo* sel_info = get_pool()->selection_info(); - const ModelObject* mo = sel_info->model_object(); - const Geometry::Transformation inst_trafo = mo->instances[sel_info->get_active_instance()]->get_transformation(); - //Geometry::Transformation vol_trafo = mo->volumes.front()->get_transformation(); - Geometry::Transformation trafo = inst_trafo;// * vol_trafo; - trafo.set_offset(trafo.get_offset() + Vec3d(0., 0., sel_info->get_sla_shift())); - - - // Get transformation of supports - Geometry::Transformation supports_trafo = trafo; - supports_trafo.set_scaling_factor(Vec3d::Ones()); - supports_trafo.set_offset(Vec3d(trafo.get_offset()(0), trafo.get_offset()(1), sel_info->get_sla_shift())); - supports_trafo.set_rotation(Vec3d(0., 0., trafo.get_rotation()(2))); - // I don't know why, but following seems to be correct. - supports_trafo.set_mirror(Vec3d(trafo.get_mirror()(0) * trafo.get_mirror()(1) * trafo.get_mirror()(2), - 1, - 1.)); - - m_clipper->set_plane(*ocl->get_clipping_plane()); - m_clipper->set_transformation(supports_trafo); - - m_clipper->render_cut({ 1.0f, 0.f, 0.37f, 1.0f }); -} - - using namespace AssembleViewDataObjects; AssembleViewDataPool::AssembleViewDataPool(GLCanvas3D* canvas) @@ -683,7 +514,7 @@ void ModelObjectsClipper::on_update() m_clippers.clear(); for (const TriangleMesh* mesh : meshes) { m_clippers.emplace_back(new MeshClipper); - m_clippers.back()->set_mesh(*mesh); + m_clippers.back()->set_mesh(mesh->its); } m_old_meshes = meshes; diff --git a/src/slic3r/GUI/Gizmos/GLGizmosCommon.hpp b/src/slic3r/GUI/Gizmos/GLGizmosCommon.hpp index 5b338f984a0..a0631671256 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosCommon.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosCommon.hpp @@ -1,3 +1,7 @@ +///|/ Copyright (c) Prusa Research 2020 - 2023 Lukáš Matěna @lukasmatena, Oleksandra Iushchenko @YuSanka, Enrico Turri @enricoturri1966, Tomáš Mészáros @tamasmeszaros, Lukáš Hejl @hejllukas +///|/ +///|/ PrusaSlicer is released under the terms of the AGPLv3 or higher +///|/ #ifndef slic3r_GUI_GLGizmosCommon_hpp_ #define slic3r_GUI_GLGizmosCommon_hpp_ @@ -6,12 +10,13 @@ #include "slic3r/GUI/3DScene.hpp" #include "slic3r/GUI/MeshUtils.hpp" -#include "libslic3r/SLA/Hollowing.hpp" namespace Slic3r { class ModelObject; - +class ModelInstance; +class SLAPrintObject; +class ModelVolume; namespace GUI { @@ -67,10 +72,8 @@ enum class CommonGizmosDataID { None = 0, SelectionInfo = 1 << 0, InstancesHider = 1 << 1, - HollowedMesh = 1 << 2, Raycaster = 1 << 3, ObjectClipper = 1 << 4, - SupportsClipper = 1 << 5, }; @@ -89,10 +92,10 @@ class CommonGizmosDataPool { // Getters for the data that need to be accessed from the gizmos directly. CommonGizmosDataObjects::SelectionInfo* selection_info() const; CommonGizmosDataObjects::InstancesHider* instances_hider() const; - CommonGizmosDataObjects::HollowedMesh* hollowed_mesh() const; +// CommonGizmosDataObjects::HollowedMesh* hollowed_mesh() const; CommonGizmosDataObjects::Raycaster* raycaster() const; CommonGizmosDataObjects::ObjectClipper* object_clipper() const; - CommonGizmosDataObjects::SupportsClipper* supports_clipper() const; + // CommonGizmosDataObjects::SupportsClipper* supports_clipper() const; GLCanvas3D* get_canvas() const { return m_canvas; } @@ -141,7 +144,6 @@ class CommonGizmosDataBase { virtual void on_update() = 0; CommonGizmosDataPool* get_pool() const { return m_common; } - private: bool m_is_valid = false; CommonGizmosDataPool* m_common = nullptr; @@ -185,8 +187,6 @@ class InstancesHider : public CommonGizmosDataBase CommonGizmosDataID get_dependencies() const override { return CommonGizmosDataID::SelectionInfo; } #endif // NDEBUG - void show_supports(bool show); - bool are_supports_shown() const { return m_show_supports; } void render_cut() const; protected: @@ -194,42 +194,12 @@ class InstancesHider : public CommonGizmosDataBase void on_release() override; private: - bool m_show_supports = false; std::vector m_old_meshes; std::vector> m_clippers; }; -class HollowedMesh : public CommonGizmosDataBase -{ -public: - explicit HollowedMesh(CommonGizmosDataPool* cgdp) - : CommonGizmosDataBase(cgdp) {} -#ifndef NDEBUG - CommonGizmosDataID get_dependencies() const override { return CommonGizmosDataID::SelectionInfo; } -#endif // NDEBUG - - const sla::DrainHoles &get_drainholes() const { return m_drainholes; } - - const TriangleMesh* get_hollowed_mesh() const; - const TriangleMesh* get_hollowed_interior() const; - -protected: - void on_update() override; - void on_release() override; - -private: - std::unique_ptr m_hollowed_mesh_transformed; - std::unique_ptr m_hollowed_interior_transformed; - size_t m_old_hollowing_timestamp = 0; - int m_print_object_idx = -1; - int m_print_objects_count = 0; - sla::DrainHoles m_drainholes; -}; - - - class Raycaster : public CommonGizmosDataBase { public: @@ -261,57 +231,31 @@ class ObjectClipper : public CommonGizmosDataBase #ifndef NDEBUG CommonGizmosDataID get_dependencies() const override { return CommonGizmosDataID::SelectionInfo; } #endif // NDEBUG - - void set_position(double pos, bool keep_normal); double get_position() const { return m_clp_ratio; } - ClippingPlane* get_clipping_plane() const { return m_clp.get(); } - void render_cut() const; - - void set_range_and_pos(const Vec3d &cpl_normal, double cpl_offset, double pos); - - bool is_projection_inside_cut(const Vec3d &point_in) const; + const ClippingPlane* get_clipping_plane(bool ignore_hide_clipped = false) const; + void render_cut(const std::vector* ignore_idxs = nullptr) const; + void set_position_by_ratio(double pos, bool keep_normal); + void set_range_and_pos(const Vec3d& cpl_normal, double cpl_offset, double pos); + void set_behavior(bool hide_clipped, bool fill_cut, double contour_width); + + int get_number_of_contours() const; + std::vector point_per_contour() const; + + int is_projection_inside_cut(const Vec3d& point_in) const; bool has_valid_contour() const; + protected: void on_update() override; void on_release() override; private: std::vector m_old_meshes; - std::vector> m_clippers; + std::vector, Geometry::Transformation>> m_clippers; std::unique_ptr m_clp; double m_clp_ratio = 0.; double m_active_inst_bb_radius = 0.; -}; - - - -class SupportsClipper : public CommonGizmosDataBase -{ -public: - explicit SupportsClipper(CommonGizmosDataPool* cgdp) - : CommonGizmosDataBase(cgdp) {} -#ifndef NDEBUG - CommonGizmosDataID get_dependencies() const override { - return CommonGizmosDataID( - int(CommonGizmosDataID::SelectionInfo) - | int(CommonGizmosDataID::ObjectClipper) - ); - } -#endif // NDEBUG - - void render_cut() const; - - -protected: - void on_update() override; - void on_release() override; - -private: - size_t m_old_timestamp = 0; - int m_print_object_idx = -1; - int m_print_objects_count = 0; - std::unique_ptr m_clipper; + bool m_hide_clipped = true; }; } // namespace CommonGizmosDataObjects diff --git a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp index 204e9ebf8e6..7b5735d8030 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp @@ -1,3 +1,8 @@ +///|/ Copyright (c) Prusa Research 2019 - 2023 Oleksandra Iushchenko @YuSanka, Enrico Turri @enricoturri1966, Lukáš Matěna @lukasmatena, David Kocík @kocikdav, Filip Sykala @Jony01, Vojtěch Bubník @bubnikv, Lukáš Hejl @hejllukas +///|/ Copyright (c) 2019 John Drake @foxox +///|/ +///|/ PrusaSlicer is released under the terms of the AGPLv3 or higher +///|/ #include "libslic3r/libslic3r.h" #include "GLGizmosManager.hpp" #include "slic3r/GUI/GLCanvas3D.hpp" @@ -269,20 +274,13 @@ float GLGizmosManager::get_layout_scale() return m_layout.scale; } -bool GLGizmosManager::init_arrow(const BackgroundTexture::Metadata& arrow_texture) +bool GLGizmosManager::init_arrow(const std::string& filename) { - if (m_arrow_texture.texture.get_id() != 0) + if (m_arrow_texture.get_id() != 0) return true; - std::string path = resources_dir() + "/images/"; - bool res = false; - - if (!arrow_texture.filename.empty()) - res = m_arrow_texture.texture.load_from_svg_file(path + arrow_texture.filename, false, false, false, 1000); - if (res) - m_arrow_texture.metadata = arrow_texture; - - return res; + const std::string path = resources_dir() + "/images/"; + return (!filename.empty()) ? m_arrow_texture.load_from_svg_file(path + filename, false, false, false, 1000) : false; } void GLGizmosManager::set_overlay_icon_size(float size) @@ -378,7 +376,7 @@ void GLGizmosManager::update_data() m_common_gizmos_data->update(get_current() ? get_current()->get_requirements() : CommonGizmosDataID(0)); - if (m_current != Undefined) m_gizmos[m_current]->data_changed(); + if (m_current != Undefined) m_gizmos[m_current]->data_changed(m_serializing); //BBS: GUI refactor: add object manipulation in gizmo m_object_manipulation.update_ui_from_settings(); @@ -600,10 +598,12 @@ bool GLGizmosManager::gizmos_toolbar_on_mouse(const wxMouseEvent &mouse_event) { mc.left = true; open_gizmo(gizmo); return true; - } else if (mouse_event.RightDown()) { + } + else if (mouse_event.RightDown()) { mc.right = true; return true; - } else if (mouse_event.MiddleDown()) { + } + else if (mouse_event.MiddleDown()) { mc.middle = true; return true; } @@ -618,18 +618,21 @@ bool GLGizmosManager::gizmos_toolbar_on_mouse(const wxMouseEvent &mouse_event) { update_hover_state(Undefined); } // draging start on toolbar so no propagation into scene - return true; - } else if (mc.left && mouse_event.LeftUp()) { + return true; + } + else if (mc.left && mouse_event.LeftUp()) { mc.left = false; return true; - } else if (mc.right && mouse_event.RightUp()) { + } + else if (mc.right && mouse_event.RightUp()) { mc.right = false; return true; - } else if (mc.middle && mouse_event.MiddleUp()) { + } + else if (mc.middle && mouse_event.MiddleUp()) { mc.middle = false; return true; } - + // event out of window is not porocessed // left down on gizmo -> keep down -> move out of window -> release left if (mouse_event.Leaving()) mc.reset(); @@ -650,7 +653,7 @@ bool GLGizmosManager::on_mouse(const wxMouseEvent &mouse_event) // &m_gizmos[m_current]->on_mouse != &GLGizmoBase::on_mouse && m_gizmos[m_current]->on_mouse(mouse_event)) return true; - + return false; } @@ -662,8 +665,7 @@ bool GLGizmosManager::on_char(wxKeyEvent& evt) bool processed = false; - if ((evt.GetModifiers() & ctrlMask) != 0) - { + if ((evt.GetModifiers() & ctrlMask) != 0) { switch (keyCode) { #ifdef __APPLE__ @@ -681,8 +683,7 @@ bool GLGizmosManager::on_char(wxKeyEvent& evt) } } } - else if (!evt.HasModifiers()) - { + else if (!evt.HasModifiers()) { switch (keyCode) { // key ESC @@ -775,8 +776,7 @@ bool GLGizmosManager::on_char(wxKeyEvent& evt) } } - if (!processed && !evt.HasModifiers()) - { + if (!processed && !evt.HasModifiers()) { if (handle_shortcut(keyCode)) processed = true; } @@ -792,15 +792,7 @@ bool GLGizmosManager::on_key(wxKeyEvent& evt) const int keyCode = evt.GetKeyCode(); bool processed = false; - // todo: zhimin Each gizmo should handle key event in it own on_key() function - if (m_current == Cut) { - if (GLGizmoAdvancedCut *gizmo_cut = dynamic_cast(get_current())) { - return gizmo_cut->on_key(evt); - } - } - - if (evt.GetEventType() == wxEVT_KEY_UP) - { + if (evt.GetEventType() == wxEVT_KEY_UP) { /*if (m_current == SlaSupports || m_current == Hollow) { bool is_editing = true; @@ -987,7 +979,7 @@ void GLGizmosManager::render_background(float left, float top, float right, floa void GLGizmosManager::render_arrow(const GLCanvas3D& parent, EType highlighted_type) const { - std::vector selectable_idxs = get_selectable_idxs(); + const std::vector selectable_idxs = get_selectable_idxs(); if (selectable_idxs.empty()) return; float cnv_w = (float)m_parent.get_canvas_size().get_width(); @@ -1006,18 +998,18 @@ void GLGizmosManager::render_arrow(const GLCanvas3D& parent, EType highlighted_t if (idx == highlighted_type) { int tex_width = m_icons_texture.get_width(); int tex_height = m_icons_texture.get_height(); - unsigned int tex_id = m_arrow_texture.texture.get_id(); + unsigned int tex_id = m_arrow_texture.get_id(); float inv_tex_width = (tex_width != 0.0f) ? 1.0f / tex_width : 0.0f; float inv_tex_height = (tex_height != 0.0f) ? 1.0f / tex_height : 0.0f; - float internal_left_uv = (float)m_arrow_texture.metadata.left * inv_tex_width; - float internal_right_uv = 1.0f - (float)m_arrow_texture.metadata.right * inv_tex_width; - float internal_top_uv = 1.0f - (float)m_arrow_texture.metadata.top * inv_tex_height; - float internal_bottom_uv = (float)m_arrow_texture.metadata.bottom * inv_tex_height; + const float left_uv = 0.0f; + const float right_uv = 1.0f; + const float top_uv = 1.0f; + const float bottom_uv = 0.0f; - float arrow_sides_ratio = (float)m_arrow_texture.texture.get_height() / (float)m_arrow_texture.texture.get_width(); + float arrow_sides_ratio = (float)m_arrow_texture.get_height() / (float)m_arrow_texture.get_width(); - GLTexture::render_sub_texture(tex_id, zoomed_top_x + zoomed_icons_size * 1.2f, zoomed_top_x + zoomed_icons_size * 1.2f + zoomed_icons_size * 2.2f * arrow_sides_ratio, zoomed_top_y - zoomed_icons_size * 1.6f , zoomed_top_y + zoomed_icons_size * 0.6f, { { internal_left_uv, internal_bottom_uv }, { internal_left_uv, internal_top_uv }, { internal_right_uv, internal_top_uv }, { internal_right_uv, internal_bottom_uv } }); + GLTexture::render_sub_texture(tex_id, zoomed_top_x + zoomed_icons_size * 1.2f, zoomed_top_x + zoomed_icons_size * 1.2f + zoomed_icons_size * 2.2f * arrow_sides_ratio, zoomed_top_y - zoomed_icons_size * 1.6f , zoomed_top_y + zoomed_icons_size * 0.6f, { { left_uv, bottom_uv }, { left_uv, top_uv }, { right_uv, top_uv }, { right_uv, bottom_uv } }); break; } zoomed_top_y -= zoomed_stride_y; @@ -1170,9 +1162,12 @@ bool GLGizmosManager::generate_icons_texture() { std::string path = resources_dir() + "/images/"; std::vector filenames; - for (size_t idx = 0; idxget_icon_filename(); + for (size_t idx=0; idxget_icon_filename(); if (!icon_filename.empty()) filenames.push_back(path + icon_filename); } diff --git a/src/slic3r/GUI/Gizmos/GLGizmosManager.hpp b/src/slic3r/GUI/Gizmos/GLGizmosManager.hpp index 6d081c59021..a2a9b2f3a9b 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosManager.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosManager.hpp @@ -1,3 +1,7 @@ +///|/ Copyright (c) Prusa Research 2019 - 2022 Enrico Turri @enricoturri1966, Lukáš Matěna @lukasmatena, Oleksandra Iushchenko @YuSanka, Filip Sykala @Jony01, David Kocík @kocikdav, Lukáš Hejl @hejllukas, Vojtěch Bubník @bubnikv +///|/ +///|/ PrusaSlicer is released under the terms of the AGPLv3 or higher +///|/ #ifndef slic3r_GUI_GLGizmosManager_hpp_ #define slic3r_GUI_GLGizmosManager_hpp_ @@ -116,10 +120,10 @@ class GLGizmosManager : public Slic3r::ObjectBase GLCanvas3D& m_parent; bool m_enabled; std::vector> m_gizmos; - mutable GLTexture m_icons_texture; - mutable bool m_icons_texture_dirty; + GLTexture m_icons_texture; + bool m_icons_texture_dirty; BackgroundTexture m_background_texture; - BackgroundTexture m_arrow_texture; + GLTexture m_arrow_texture; Layout m_layout; EType m_current; EType m_hover; @@ -175,7 +179,7 @@ class GLGizmosManager : public Slic3r::ObjectBase float get_layout_scale(); - bool init_arrow(const BackgroundTexture::Metadata& arrow_texture); + bool init_arrow(const std::string& filename); template void load(Archive& ar) diff --git a/src/slic3r/GUI/MeshUtils.cpp b/src/slic3r/GUI/MeshUtils.cpp index 878aa3a1cd0..18a86fb8ff1 100644 --- a/src/slic3r/GUI/MeshUtils.cpp +++ b/src/slic3r/GUI/MeshUtils.cpp @@ -1,3 +1,7 @@ +///|/ Copyright (c) Prusa Research 2019 - 2023 Lukáš Matěna @lukasmatena, Oleksandra Iushchenko @YuSanka, Enrico Turri @enricoturri1966, Tomáš Mészáros @tamasmeszaros, Filip Sykala @Jony01, Lukáš Hejl @hejllukas, Vojtěch Bubník @bubnikv +///|/ +///|/ PrusaSlicer is released under the terms of the AGPLv3 or higher +///|/ #include "MeshUtils.hpp" #include "libslic3r/Tesselate.hpp" @@ -5,25 +9,39 @@ #include "libslic3r/TriangleMeshSlicer.hpp" #include "libslic3r/ClipperUtils.hpp" #include "libslic3r/Model.hpp" +#include "libslic3r/CSGMesh/SliceCSGMesh.hpp" #include "slic3r/GUI/GUI_App.hpp" -#include "slic3r/GUI/Camera.hpp" #include "slic3r/GUI/Plater.hpp" +#include "slic3r/GUI/Camera.hpp" +#include "slic3r/GUI/CameraUtils.hpp" + #include #include -#include "CameraUtils.hpp" + +#include namespace Slic3r { namespace GUI { +void MeshClipper::set_behaviour(bool fill_cut, double contour_width) +{ + if (fill_cut != m_fill_cut || ! is_approx(contour_width, m_contour_width)) + m_result.reset(); + m_fill_cut = fill_cut; + m_contour_width = contour_width; +} + + + void MeshClipper::set_plane(const ClippingPlane& plane) { if (m_plane != plane) { m_plane = plane; - m_triangles_valid = false; + m_result.reset(); } } @@ -32,27 +50,41 @@ void MeshClipper::set_limiting_plane(const ClippingPlane& plane) { if (m_limiting_plane != plane) { m_limiting_plane = plane; - m_triangles_valid = false; + m_result.reset(); } } -void MeshClipper::set_mesh(const TriangleMesh& mesh) +void MeshClipper::set_mesh(const indexed_triangle_set& mesh) { - if (m_mesh != &mesh) { + if (m_mesh.get() != &mesh) { m_mesh = &mesh; - m_triangles_valid = false; - m_triangles2d.resize(0); + m_result.reset(); + } +} + +void MeshClipper::set_mesh(AnyPtr &&ptr) +{ + if (m_mesh.get() != ptr.get()) { + m_mesh = std::move(ptr); + m_result.reset(); } } -void MeshClipper::set_negative_mesh(const TriangleMesh& mesh) +void MeshClipper::set_negative_mesh(const indexed_triangle_set& mesh) { - if (m_negative_mesh != &mesh) { + if (m_negative_mesh.get() != &mesh) { m_negative_mesh = &mesh; - m_triangles_valid = false; - m_triangles2d.resize(0); + m_result.reset(); + } +} + +void MeshClipper::set_negative_mesh(AnyPtr &&ptr) +{ + if (m_negative_mesh.get() != ptr.get()) { + m_negative_mesh = std::move(ptr); + m_result.reset(); } } @@ -62,21 +94,44 @@ void MeshClipper::set_transformation(const Geometry::Transformation& trafo) { if (! m_trafo.get_matrix().isApprox(trafo.get_matrix())) { m_trafo = trafo; - m_triangles_valid = false; - m_triangles2d.resize(0); + m_result.reset(); } } +void MeshClipper::render_cut(const ColorRGBA& color, const std::vector* ignore_idxs) +{ + if (! m_result) + recalculate_triangles(); + GLShaderProgram* curr_shader = wxGetApp().get_current_shader(); + if (curr_shader != nullptr) + curr_shader->stop_using(); + + GLShaderProgram* shader = wxGetApp().get_shader("flat"); + if (shader != nullptr) { + shader->start_using(); + const Camera& camera = wxGetApp().plater()->get_camera(); + shader->set_uniform("view_model_matrix", camera.get_view_matrix()); + shader->set_uniform("projection_matrix", camera.get_projection_matrix()); + for (size_t i=0; icut_islands.size(); ++i) { + if (ignore_idxs && std::binary_search(ignore_idxs->begin(), ignore_idxs->end(), i)) + continue; + CutIsland& isl = m_result->cut_islands[i]; + isl.model.set_color(isl.disabled ? ColorRGBA(0.5f, 0.5f, 0.5f, 1.f) : color); + isl.model.render(); + } + shader->stop_using(); + } + + if (curr_shader != nullptr) + curr_shader->start_using(); +} -void MeshClipper::render_cut(const ColorRGBA& color) +void MeshClipper::render_contour(const ColorRGBA& color, const std::vector* ignore_idxs) { - if (! m_triangles_valid) + if (! m_result) recalculate_triangles(); - if (m_model.vertices_count() == 0 || m_model.indices_count() == 0) - return; - GLShaderProgram* curr_shader = wxGetApp().get_current_shader(); if (curr_shader != nullptr) curr_shader->stop_using(); @@ -87,8 +142,13 @@ void MeshClipper::render_cut(const ColorRGBA& color) const Camera& camera = wxGetApp().plater()->get_camera(); shader->set_uniform("view_model_matrix", camera.get_view_matrix()); shader->set_uniform("projection_matrix", camera.get_projection_matrix()); - m_model.set_color(color); - m_model.render(); + for (size_t i=0; icut_islands.size(); ++i) { + if (ignore_idxs && std::binary_search(ignore_idxs->begin(), ignore_idxs->end(), i)) + continue; + CutIsland& isl = m_result->cut_islands[i]; + isl.model_expanded.set_color(isl.disabled ? ColorRGBA(1.f, 0.f, 0.f, 1.f) : color); + isl.model_expanded.render(); + } shader->stop_using(); } @@ -96,45 +156,95 @@ void MeshClipper::render_cut(const ColorRGBA& color) curr_shader->start_using(); } -bool MeshClipper::is_projection_inside_cut(const Vec3d &point_in) const +int MeshClipper::is_projection_inside_cut(const Vec3d& point_in) const { if (!m_result || m_result->cut_islands.empty()) - return false; + return -1; Vec3d point = m_result->trafo.inverse() * point_in; Point pt_2d = Point::new_scale(Vec2d(point.x(), point.y())); - for (const CutIsland &isl : m_result->cut_islands) { + for (int i=0; icut_islands.size()); ++i) { + const CutIsland& isl = m_result->cut_islands[i]; if (isl.expoly_bb.contains(pt_2d) && isl.expoly.contains(pt_2d)) - return true; + return i; // TODO: handle intersecting contours } - return false; + return -1; } bool MeshClipper::has_valid_contour() const { - return m_result && std::any_of(m_result->cut_islands.begin(), m_result->cut_islands.end(), [](const CutIsland &isl) { return !isl.expoly.empty(); }); + return m_result && std::any_of(m_result->cut_islands.begin(), m_result->cut_islands.end(), [](const CutIsland& isl) { return !isl.expoly.empty(); }); +} + +std::vector MeshClipper::point_per_contour() const +{ + assert(m_result); + std::vector out; + + for (const CutIsland& isl : m_result->cut_islands) { + assert(isl.expoly.contour.size() > 2); + // Now return a point lying inside the contour but not in a hole. + // We do this by taking a point lying close to the edge, repeating + // this several times for different edges and distances from them. + // (We prefer point not extremely close to the border. + bool done = false; + Vec2d p; + size_t i = 1; + while (i < isl.expoly.contour.size()) { + const Vec2d& a = unscale(isl.expoly.contour.points[i-1]); + const Vec2d& b = unscale(isl.expoly.contour.points[i]); + Vec2d n = (b-a).normalized(); + std::swap(n.x(), n.y()); + n.x() = -1 * n.x(); + double f = 10.; + while (f > 0.05) { + p = (0.5*(b+a)) + f * n; + if (isl.expoly.contains(Point::new_scale(p))) { + done = true; + break; + } + f = f/10.; + } + if (done) + break; + i += std::max(size_t(2), isl.expoly.contour.size() / 5); + } + // If the above failed, just return the centroid, regardless of whether + // it is inside the contour or in a hole (we must return something). + Vec2d c = done ? p : unscale(isl.expoly.contour.centroid()); + out.emplace_back(m_result->trafo * Vec3d(c.x(), c.y(), 0.)); + } + return out; } + void MeshClipper::recalculate_triangles() { - const Transform3f& instance_matrix_no_translation_no_scaling = m_trafo.get_matrix(true,false,true).cast(); - // Calculate clipping plane normal in mesh coordinates. - const Vec3f up_noscale = instance_matrix_no_translation_no_scaling.inverse() * m_plane.get_normal().cast(); - const Vec3d up = up_noscale.cast().cwiseProduct(m_trafo.get_scaling_factor()); - // Calculate distance from mesh origin to the clipping plane (in mesh coordinates). - const float height_mesh = m_plane.distance(m_trafo.get_offset()) * (up_noscale.norm()/up.norm()); + m_result = ClipResult(); + + auto plane_mesh = Eigen::Hyperplane(m_plane.get_normal(), -m_plane.distance(Vec3d::Zero())).transform(m_trafo.get_matrix().inverse()); + const Vec3d up = plane_mesh.normal(); + const float height_mesh = -plane_mesh.offset(); // Now do the cutting MeshSlicingParams slicing_params; slicing_params.trafo.rotate(Eigen::Quaternion::FromTwoVectors(up, Vec3d::UnitZ())); - ExPolygons expolys = union_ex(slice_mesh(m_mesh->its, height_mesh, slicing_params)); + ExPolygons expolys; - if (m_negative_mesh && !m_negative_mesh->empty()) { - const ExPolygons neg_expolys = union_ex(slice_mesh(m_negative_mesh->its, height_mesh, slicing_params)); - expolys = diff_ex(expolys, neg_expolys); + if (m_csgmesh.empty()) { + if (m_mesh) + expolys = union_ex(slice_mesh(*m_mesh, height_mesh, slicing_params)); + + if (m_negative_mesh && !m_negative_mesh->empty()) { + const ExPolygons neg_expolys = union_ex(slice_mesh(*m_negative_mesh, height_mesh, slicing_params)); + expolys = diff_ex(expolys, neg_expolys); + } + } else { + expolys = std::move(csg::slice_csgmesh_ex(range(m_csgmesh), {height_mesh}, MeshSlicingParamsEx{slicing_params}).front()); } + // Triangulate and rotate the cut into world coords: Eigen::Quaterniond q; q.setFromTwoVectors(Vec3d::UnitZ(), up); @@ -142,7 +252,6 @@ void MeshClipper::recalculate_triangles() tr.rotate(q); tr = m_trafo.get_matrix() * tr; - m_result = ClipResult(); m_result->trafo = tr; if (m_limiting_plane != ClippingPlane::ClipsNothing()) @@ -190,7 +299,7 @@ void MeshClipper::recalculate_triangles() // it so it lies on our line. This will be the figure to subtract // from the cut. The coordinates must not overflow after the transform, // make the rectangle a bit smaller. - const coord_t size = (std::numeric_limits::max() - scale_(std::max(std::abs(e*a), std::abs(e*b)))) / 4; + const coord_t size = (std::numeric_limits::max()/2 - scale_(std::max(std::abs(e * a), std::abs(e * b)))) / 4; Polygons ep {Polygon({Point(-size, 0), Point(size, 0), Point(size, 2*size), Point(-size, 2*size)})}; ep.front().rotate(angle); ep.front().translate(scale_(-e * a), scale_(-e * b)); @@ -198,37 +307,107 @@ void MeshClipper::recalculate_triangles() } } - for (const ExPolygon &exp : expolys) { + tr.pretranslate(0.001 * m_plane.get_normal().normalized()); // to avoid z-fighting + Transform3d tr2 = tr; + tr2.pretranslate(0.002 * m_plane.get_normal().normalized()); + + + std::vector triangles2d; + + for (const ExPolygon& exp : expolys) { + triangles2d.clear(); + m_result->cut_islands.push_back(CutIsland()); - CutIsland &isl = m_result->cut_islands.back(); - isl.expoly = std::move(exp); - isl.expoly_bb = get_extents(exp); - } + CutIsland& isl = m_result->cut_islands.back(); + + if (m_fill_cut) { + triangles2d = triangulate_expolygon_2f(exp, m_trafo.get_matrix().matrix().determinant() < 0.); + GLModel::Geometry init_data; + init_data.format = { GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3N3 }; + init_data.reserve_vertices(triangles2d.size()); + init_data.reserve_indices(triangles2d.size()); + + // vertices + indices + for (auto it = triangles2d.cbegin(); it != triangles2d.cend(); it = it + 3) { + init_data.add_vertex((Vec3f)(tr * Vec3d((*(it + 0)).x(), (*(it + 0)).y(), height_mesh)).cast(), (Vec3f)up.cast()); + init_data.add_vertex((Vec3f)(tr * Vec3d((*(it + 1)).x(), (*(it + 1)).y(), height_mesh)).cast(), (Vec3f)up.cast()); + init_data.add_vertex((Vec3f)(tr * Vec3d((*(it + 2)).x(), (*(it + 2)).y(), height_mesh)).cast(), (Vec3f)up.cast()); + const size_t idx = it - triangles2d.cbegin(); + init_data.add_triangle((unsigned int)idx, (unsigned int)idx + 1, (unsigned int)idx + 2); + } - m_triangles2d = triangulate_expolygons_2f(expolys, m_trafo.get_matrix().matrix().determinant() < 0.); + if (!init_data.is_empty()) + isl.model.init_from(std::move(init_data)); + } - tr.pretranslate(0.001 * m_plane.get_normal().normalized()); // to avoid z-fighting + if (m_contour_width != 0. && ! exp.contour.empty()) { + triangles2d.clear(); + + // The contours must not scale with the object. Check the scale factor + // in the respective directions, create a scaled copy of the ExPolygon + // offset it and then unscale the result again. + + Transform3d t = tr; + t.translation() = Vec3d::Zero(); + double scale_x = (t * Vec3d::UnitX()).norm(); + double scale_y = (t * Vec3d::UnitY()).norm(); + + // To prevent overflow after scaling, downscale the input if needed: + double extra_scale = 1.; + int32_t limit = int32_t(std::min(std::numeric_limits::max() / (2. * std::max(1., scale_x)), std::numeric_limits::max() / (2. * std::max(1., scale_y)))); + int32_t max_coord = 0; + for (const Point& pt : exp.contour) + max_coord = std::max(max_coord, std::max(std::abs(pt.x()), std::abs(pt.y()))); + if (max_coord + m_contour_width >= limit) + extra_scale = 0.9 * double(limit) / max_coord; + + ExPolygon exp_copy = exp; + if (extra_scale != 1.) + exp_copy.scale(extra_scale); + exp_copy.scale(scale_x, scale_y); + + ExPolygons expolys_exp = offset_ex(exp_copy, scale_(m_contour_width)); + expolys_exp = diff_ex(expolys_exp, ExPolygons({exp_copy})); + + for (ExPolygon& e : expolys_exp) { + e.scale(1./scale_x, 1./scale_y); + if (extra_scale != 1.) + e.scale(1./extra_scale); + } - m_model.reset(); - GLModel::Geometry init_data; - init_data.format = { GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3N3 }; - init_data.reserve_vertices(m_triangles2d.size()); - init_data.reserve_indices(m_triangles2d.size()); + triangles2d = triangulate_expolygons_2f(expolys_exp, m_trafo.get_matrix().matrix().determinant() < 0.); + GLModel::Geometry init_data = GLModel::Geometry(); + init_data.format = { GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3N3 }; + init_data.reserve_vertices(triangles2d.size()); + init_data.reserve_indices(triangles2d.size()); - // vertices + indices - for (auto it = m_triangles2d.cbegin(); it != m_triangles2d.cend(); it = it + 3) { - init_data.add_vertex((Vec3f)(tr * Vec3d((*(it + 0)).x(), (*(it + 0)).y(), height_mesh)).cast(), (Vec3f)up.cast()); - init_data.add_vertex((Vec3f)(tr * Vec3d((*(it + 1)).x(), (*(it + 1)).y(), height_mesh)).cast(), (Vec3f)up.cast()); - init_data.add_vertex((Vec3f)(tr * Vec3d((*(it + 2)).x(), (*(it + 2)).y(), height_mesh)).cast(), (Vec3f)up.cast()); - const size_t idx = it - m_triangles2d.cbegin(); - init_data.add_triangle((unsigned int)idx, (unsigned int)idx + 1, (unsigned int)idx + 2); - } + // vertices + indices + for (auto it = triangles2d.cbegin(); it != triangles2d.cend(); it = it + 3) { + init_data.add_vertex((Vec3f)(tr2 * Vec3d((*(it + 0)).x(), (*(it + 0)).y(), height_mesh)).cast(), (Vec3f)up.cast()); + init_data.add_vertex((Vec3f)(tr2 * Vec3d((*(it + 1)).x(), (*(it + 1)).y(), height_mesh)).cast(), (Vec3f)up.cast()); + init_data.add_vertex((Vec3f)(tr2 * Vec3d((*(it + 2)).x(), (*(it + 2)).y(), height_mesh)).cast(), (Vec3f)up.cast()); + const size_t idx = it - triangles2d.cbegin(); + init_data.add_triangle((unsigned short)idx, (unsigned short)idx + 1, (unsigned short)idx + 2); + } - if (!init_data.is_empty()) - m_model.init_from(std::move(init_data)); + if (!init_data.is_empty()) + isl.model_expanded.init_from(std::move(init_data)); + } + + isl.expoly = std::move(exp); + isl.expoly_bb = get_extents(isl.expoly); + + Point centroid_scaled = isl.expoly.contour.centroid(); + Vec3d centroid_world = m_result->trafo * Vec3d(unscale(centroid_scaled).x(), unscale(centroid_scaled).y(), 0.); + isl.hash = isl.expoly.contour.size() + size_t(std::abs(100.*centroid_world.x())) + size_t(std::abs(100.*centroid_world.y())) + size_t(std::abs(100.*centroid_world.z())); + } - m_triangles_valid = true; + // Now sort the islands so they are in defined order. This is a hack needed by cut gizmo, which sometimes + // flips the normal of the cut, in which case the contours stay the same but their order may change. + std::sort(m_result->cut_islands.begin(), m_result->cut_islands.end(), [](const CutIsland& a, const CutIsland& b) { + return a.hash < b.hash; + }); } @@ -237,46 +416,26 @@ Vec3f MeshRaycaster::get_triangle_normal(size_t facet_idx) const return m_normals[facet_idx]; } -void MeshRaycaster::line_from_mouse_pos_static(const Vec2d &mouse_pos, const Transform3d &trafo, const Camera &camera, Vec3d &point, Vec3d &direction) +void MeshRaycaster::line_from_mouse_pos(const Vec2d& mouse_pos, const Transform3d& trafo, const Camera& camera, Vec3d& point, Vec3d& direction) { CameraUtils::ray_from_screen_pos(camera, mouse_pos, point, direction); Transform3d inv = trafo.inverse(); - point = inv * point; - direction = inv.linear() * direction; -} - -void MeshRaycaster::line_from_mouse_pos(const Vec2d& mouse_pos, const Transform3d& trafo, const Camera& camera, - Vec3d& point, Vec3d& direction) const -{ - Matrix4d modelview = camera.get_view_matrix().matrix(); - Matrix4d projection= camera.get_projection_matrix().matrix(); - Vec4i viewport(camera.get_viewport().data()); - - Vec3d pt1; - Vec3d pt2; - igl::unproject(Vec3d(mouse_pos(0), viewport[3] - mouse_pos(1), 0.), - modelview, projection, viewport, pt1); - igl::unproject(Vec3d(mouse_pos(0), viewport[3] - mouse_pos(1), 1.), - modelview, projection, viewport, pt2); - - Transform3d inv = trafo.inverse(); - pt1 = inv * pt1; - pt2 = inv * pt2; - - point = pt1; - direction = pt2-pt1; + point = inv*point; + direction = inv.linear()*direction; } - bool MeshRaycaster::unproject_on_mesh(const Vec2d& mouse_pos, const Transform3d& trafo, const Camera& camera, Vec3f& position, Vec3f& normal, const ClippingPlane* clipping_plane, size_t* facet_idx, bool sinking_limit) const { Vec3d point; Vec3d direction; - line_from_mouse_pos(mouse_pos, trafo, camera, point, direction); + CameraUtils::ray_from_screen_pos(camera, mouse_pos, point, direction); + Transform3d inv = trafo.inverse(); + point = inv*point; + direction = inv.linear()*direction; - std::vector hits = m_emesh.query_ray_hits(point, direction); + std::vector hits = m_emesh.query_ray_hits(point, direction); if (hits.empty()) return false; // no intersection found @@ -309,6 +468,21 @@ bool MeshRaycaster::unproject_on_mesh(const Vec2d& mouse_pos, const Transform3d& } + +bool MeshRaycaster::intersects_line(Vec3d point, Vec3d direction, const Transform3d& trafo) const +{ + Transform3d trafo_inv = trafo.inverse(); + Vec3d to = trafo_inv * (point + direction); + point = trafo_inv * point; + direction = (to-point).normalized(); + + std::vector hits = m_emesh.query_ray_hits(point, direction); + std::vector neg_hits = m_emesh.query_ray_hits(point, -direction); + + return !hits.empty() || !neg_hits.empty(); +} + + std::vector MeshRaycaster::get_unobscured_idxs(const Geometry::Transformation& trafo, const Camera& camera, const std::vector& points, const ClippingPlane* clipping_plane) const { @@ -327,7 +501,7 @@ std::vector MeshRaycaster::get_unobscured_idxs(const Geometry::Transfo bool is_obscured = false; // Cast a ray in the direction of the camera and look for intersection with the mesh: - std::vector hits; + std::vector hits; // Offset the start of the ray by EPSILON to account for numerical inaccuracies. hits = m_emesh.query_ray_hits((inverse_trafo * pt.cast() + direction_to_camera_mesh * EPSILON), direction_to_camera_mesh); @@ -364,7 +538,7 @@ bool MeshRaycaster::closest_hit(const Vec2d& mouse_pos, const Transform3d& trafo Vec3d direction; line_from_mouse_pos(mouse_pos, trafo, camera, point, direction); - const std::vector hits = m_emesh.query_ray_hits(point, direction.normalized()); + const std::vector hits = m_emesh.query_ray_hits(point, direction.normalized()); if (hits.empty()) return false; // no intersection found @@ -379,7 +553,7 @@ bool MeshRaycaster::closest_hit(const Vec2d& mouse_pos, const Transform3d& trafo if (hit_id == hits.size()) return false; // all points are obscured or cut by the clipping plane. - const sla::IndexedMesh::hit_result& hit = hits[hit_id]; + const AABBMesh::hit_result& hit = hits[hit_id]; position = hit.position().cast(); normal = hit.normal().cast(); @@ -394,8 +568,10 @@ Vec3f MeshRaycaster::get_closest_point(const Vec3f& point, Vec3f* normal) const { int idx = 0; Vec3d closest_point; - m_emesh.squared_distance(point.cast(), idx, closest_point); + Vec3d pointd = point.cast(); + m_emesh.squared_distance(pointd, idx, closest_point); if (normal) + // TODO: consider: get_normal(m_emesh, pointd).cast(); *normal = m_normals[idx]; return closest_point.cast(); diff --git a/src/slic3r/GUI/MeshUtils.hpp b/src/slic3r/GUI/MeshUtils.hpp index b387966961c..c3e0b4247d2 100644 --- a/src/slic3r/GUI/MeshUtils.hpp +++ b/src/slic3r/GUI/MeshUtils.hpp @@ -1,18 +1,25 @@ +///|/ Copyright (c) Prusa Research 2019 - 2023 Lukáš Matěna @lukasmatena, Oleksandra Iushchenko @YuSanka, Tomáš Mészáros @tamasmeszaros, Enrico Turri @enricoturri1966, Lukáš Hejl @hejllukas, Filip Sykala @Jony01, Vojtěch Bubník @bubnikv +///|/ +///|/ PrusaSlicer is released under the terms of the AGPLv3 or higher +///|/ #ifndef slic3r_MeshUtils_hpp_ #define slic3r_MeshUtils_hpp_ #include "libslic3r/Point.hpp" #include "libslic3r/Geometry.hpp" -#include "libslic3r/SLA/IndexedMesh.hpp" +#include "libslic3r/TriangleMesh.hpp" +#include "libslic3r/AABBMesh.hpp" +#include "libslic3r/CSGMesh/TriangleMeshAdapter.hpp" +#include "libslic3r/CSGMesh/CSGMeshCopy.hpp" #include "admesh/stl.h" #include "slic3r/GUI/GLModel.hpp" #include +#include #include namespace Slic3r { - namespace GUI { struct Camera; @@ -71,6 +78,10 @@ class ClippingPlane class MeshClipper { public: + // Set whether the cut should be triangulated and whether a cut + // contour should be calculated and shown. + void set_behaviour(bool fill_cut, double contour_width); + // Inform MeshClipper about which plane we want to use to cut the mesh // This is supposed to be in world coordinates. void set_plane(const ClippingPlane& plane); @@ -82,9 +93,25 @@ class MeshClipper // Which mesh to cut. MeshClipper remembers const * to it, caller // must make sure that it stays valid. - void set_mesh(const TriangleMesh& mesh); + void set_mesh(const indexed_triangle_set& mesh); + void set_mesh(AnyPtr &&ptr); + + void set_negative_mesh(const indexed_triangle_set &mesh); + void set_negative_mesh(AnyPtr &&ptr); - void set_negative_mesh(const TriangleMesh &mesh); + template + void set_mesh(const Range &csgrange, bool copy_meshes = false) + { + if (! csg::is_same(range(m_csgmesh), csgrange)) { + m_csgmesh.clear(); + if (copy_meshes) + csg::copy_csgrange_deep(csgrange, std::back_inserter(m_csgmesh)); + else + csg::copy_csgrange_shallow(csgrange, std::back_inserter(m_csgmesh)); + + m_result.reset(); + } + } // Inform the MeshClipper about the transformation that transforms the mesh // into world coordinates. @@ -92,34 +119,41 @@ class MeshClipper // Render the triangulated cut. Transformation matrices should // be set in world coords. - void render_cut(const ColorRGBA& color); + void render_cut(const ColorRGBA& color, const std::vector* ignore_idxs = nullptr); + void render_contour(const ColorRGBA& color, const std::vector* ignore_idxs = nullptr); - bool is_projection_inside_cut(const Vec3d &point) const; + // Returns index of the contour which was clicked, -1 otherwise. + int is_projection_inside_cut(const Vec3d& point) const; bool has_valid_contour() const; + int get_number_of_contours() const { return m_result ? m_result->cut_islands.size() : 0; } + std::vector point_per_contour() const; private: void recalculate_triangles(); Geometry::Transformation m_trafo; - const TriangleMesh* m_mesh = nullptr; - const TriangleMesh* m_negative_mesh = nullptr; + AnyPtr m_mesh; + AnyPtr m_negative_mesh; + std::vector m_csgmesh; + ClippingPlane m_plane; ClippingPlane m_limiting_plane = ClippingPlane::ClipsNothing(); - std::vector m_triangles2d; - GLModel m_model; - bool m_triangles_valid = false; - struct CutIsland - { - ExPolygon expoly; + struct CutIsland { + GLModel model; + GLModel model_expanded; + ExPolygon expoly; BoundingBox expoly_bb; + bool disabled = false; + size_t hash; }; - struct ClipResult - { + struct ClipResult { std::vector cut_islands; - Transform3d trafo; // this rotates the cut into world coords + Transform3d trafo; // this rotates the cut into world coords }; - std::optional m_result; // the cut plane + std::optional m_result; + bool m_fill_cut = true; + double m_contour_width = 0.; }; @@ -129,17 +163,20 @@ class MeshClipper class MeshRaycaster { public: explicit MeshRaycaster(std::shared_ptr mesh) - : m_mesh(mesh) - , m_emesh(*mesh, true) // calculate epsilon for triangle-ray intersection from an average edge length - , m_normals(its_face_normals(mesh->its)) + : m_mesh(std::move(mesh)) + , m_emesh(*m_mesh, true) // calculate epsilon for triangle-ray intersection from an average edge length + , m_normals(its_face_normals(m_mesh->its)) { + assert(m_mesh); } - static void line_from_mouse_pos_static(const Vec2d &mouse_pos, const Transform3d &trafo, - const Camera &camera, Vec3d &point, Vec3d &direction); + explicit MeshRaycaster(const TriangleMesh &mesh) + : MeshRaycaster(std::make_unique(mesh)) + {} - void line_from_mouse_pos(const Vec2d& mouse_pos, const Transform3d& trafo, const Camera& camera, - Vec3d& point, Vec3d& direction) const; + // DEPRICATED - use CameraUtils::ray_from_screen_pos + static void line_from_mouse_pos(const Vec2d& mouse_pos, const Transform3d& trafo, const Camera& camera, + Vec3d& point, Vec3d& direction); // Given a mouse position, this returns true in case it is on the mesh. bool unproject_on_mesh( @@ -152,6 +189,12 @@ class MeshRaycaster { size_t* facet_idx = nullptr, // index of the facet hit bool sinking_limit = true ) const; + + const AABBMesh &get_aabb_mesh() const { return m_emesh; } + + // Given a point and direction in world coords, returns whether the respective line + // intersects the mesh if it is transformed into world by trafo. + bool intersects_line(Vec3d point, Vec3d direction, const Transform3d& trafo) const; // Given a vector of points in woorld coordinates, this returns vector // of indices of points that are visible (i.e. not cut by clipping plane @@ -188,7 +231,7 @@ class MeshRaycaster { private: std::shared_ptr m_mesh; - sla::IndexedMesh m_emesh; + AABBMesh m_emesh; std::vector m_normals; }; From f72d42f920334a05b0efa01f18eb4cc066809c00 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Tue, 31 Oct 2023 11:43:04 +0800 Subject: [PATCH 80/99] Measure: Initial porting of Measure Gizmo --- resources/images/copy_menu.svg | 37 + resources/images/measure.svg | 93 + src/imgui/imconfig.h | 1 + src/libslic3r/CMakeLists.txt | 4 + src/libslic3r/Geometry.hpp | 15 + src/libslic3r/Geometry/Circle.cpp | 8 +- src/libslic3r/Geometry/Circle.hpp | 6 +- src/libslic3r/Measure.cpp | 1255 ++++++++++++ src/libslic3r/Measure.hpp | 200 ++ src/libslic3r/MeasureUtils.hpp | 390 ++++ src/libslic3r/SurfaceMesh.hpp | 167 ++ src/slic3r/CMakeLists.txt | 13 + src/slic3r/GUI/3DScene.hpp | 11 + src/slic3r/GUI/GLCanvas3D.cpp | 110 +- src/slic3r/GUI/GLCanvas3D.hpp | 9 +- src/slic3r/GUI/GLModel.cpp | 204 ++ src/slic3r/GUI/GLModel.hpp | 18 + src/slic3r/GUI/GUI_Geometry.cpp | 13 + src/slic3r/GUI/GUI_Geometry.hpp | 82 + src/slic3r/GUI/GUI_Utils.hpp | 14 + src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 2154 +++++++++++++++++++++ src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp | 190 ++ src/slic3r/GUI/Gizmos/GLGizmosCommon.hpp | 4 + src/slic3r/GUI/Gizmos/GLGizmosManager.cpp | 31 +- src/slic3r/GUI/Gizmos/GLGizmosManager.hpp | 1 + src/slic3r/GUI/ImGuiWrapper.cpp | 149 +- src/slic3r/GUI/ImGuiWrapper.hpp | 13 +- src/slic3r/GUI/SceneRaycaster.cpp | 134 +- src/slic3r/GUI/SceneRaycaster.hpp | 22 +- src/slic3r/GUI/Selection.cpp | 15 + src/slic3r/GUI/Selection.hpp | 59 +- 31 files changed, 5276 insertions(+), 146 deletions(-) create mode 100644 resources/images/copy_menu.svg create mode 100644 resources/images/measure.svg create mode 100644 src/libslic3r/Measure.cpp create mode 100644 src/libslic3r/Measure.hpp create mode 100644 src/libslic3r/MeasureUtils.hpp create mode 100644 src/libslic3r/SurfaceMesh.hpp create mode 100644 src/slic3r/GUI/GUI_Geometry.cpp create mode 100644 src/slic3r/GUI/GUI_Geometry.hpp create mode 100644 src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp create mode 100644 src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp diff --git a/resources/images/copy_menu.svg b/resources/images/copy_menu.svg new file mode 100644 index 00000000000..0d1af6a0a7c --- /dev/null +++ b/resources/images/copy_menu.svg @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/resources/images/measure.svg b/resources/images/measure.svg new file mode 100644 index 00000000000..3ea137a1ed9 --- /dev/null +++ b/resources/images/measure.svg @@ -0,0 +1,93 @@ + + + + + + + + + + + + + + + + diff --git a/src/imgui/imconfig.h b/src/imgui/imconfig.h index 1774eb28ac5..be78d7cd40b 100644 --- a/src/imgui/imconfig.h +++ b/src/imgui/imconfig.h @@ -161,6 +161,7 @@ namespace ImGui const wchar_t ClippyMarker = 0x0802; const wchar_t InfoMarker = 0x0803; const wchar_t SliderFloatEditBtnIcon = 0x0804; + const wchar_t ClipboardBtnIcon = 0x0805; // BBS const wchar_t CircleButtonIcon = 0x0810; diff --git a/src/libslic3r/CMakeLists.txt b/src/libslic3r/CMakeLists.txt index 0a840db87f3..c5d6463a39f 100644 --- a/src/libslic3r/CMakeLists.txt +++ b/src/libslic3r/CMakeLists.txt @@ -208,6 +208,9 @@ set(lisbslic3r_sources ModelArrange.cpp MultiMaterialSegmentation.cpp MultiMaterialSegmentation.hpp + Measure.hpp + Measure.cpp + MeasureUtils.hpp CustomGCode.cpp CustomGCode.hpp Arrange.hpp @@ -307,6 +310,7 @@ set(lisbslic3r_sources Surface.hpp SurfaceCollection.cpp SurfaceCollection.hpp + SurfaceMesh.hpp SVG.cpp SVG.hpp Technologies.hpp diff --git a/src/libslic3r/Geometry.hpp b/src/libslic3r/Geometry.hpp index bafed3b9cf3..0a3dcad7d51 100644 --- a/src/libslic3r/Geometry.hpp +++ b/src/libslic3r/Geometry.hpp @@ -1,3 +1,18 @@ +///|/ Copyright (c) Prusa Research 2016 - 2023 Vojtěch Bubník @bubnikv, Enrico Turri @enricoturri1966, Tomáš Mészáros @tamasmeszaros, Lukáš Matěna @lukasmatena, Filip Sykala @Jony01, Lukáš Hejl @hejllukas +///|/ Copyright (c) 2017 Eyal Soha @eyal0 +///|/ Copyright (c) Slic3r 2013 - 2016 Alessandro Ranellucci @alranel +///|/ +///|/ ported from lib/Slic3r/Geometry.pm: +///|/ Copyright (c) Prusa Research 2017 - 2022 Vojtěch Bubník @bubnikv +///|/ Copyright (c) Slic3r 2011 - 2015 Alessandro Ranellucci @alranel +///|/ Copyright (c) 2013 Jose Luis Perez Diez +///|/ Copyright (c) 2013 Anders Sundman +///|/ Copyright (c) 2013 Jesse Vincent +///|/ Copyright (c) 2012 Mike Sheldrake @mesheldrake +///|/ Copyright (c) 2012 Mark Hindess +///|/ +///|/ PrusaSlicer is released under the terms of the AGPLv3 or higher +///|/ #ifndef slic3r_Geometry_hpp_ #define slic3r_Geometry_hpp_ diff --git a/src/libslic3r/Geometry/Circle.cpp b/src/libslic3r/Geometry/Circle.cpp index 4d7c38ccc23..012b240f8a3 100644 --- a/src/libslic3r/Geometry/Circle.cpp +++ b/src/libslic3r/Geometry/Circle.cpp @@ -1,3 +1,7 @@ +///|/ Copyright (c) Prusa Research 2021 - 2022 Lukáš Matěna @lukasmatena, Filip Sykala @Jony01, Vojtěch Bubník @bubnikv +///|/ +///|/ PrusaSlicer is released under the terms of the AGPLv3 or higher +///|/ #include "Circle.hpp" #include "../Polygon.hpp" @@ -108,7 +112,7 @@ Circled circle_taubin_newton(const Vec2ds& input, size_t cycles) return out; } -Circled circle_ransac(const Vec2ds& input, size_t iterations) +Circled circle_ransac(const Vec2ds& input, size_t iterations, double* min_error) { if (input.size() < 3) return Circled::make_invalid(); @@ -132,6 +136,8 @@ Circled circle_ransac(const Vec2ds& input, size_t iterations) circle_best = c; } } + if (min_error) + *min_error = err_min; return circle_best; } diff --git a/src/libslic3r/Geometry/Circle.hpp b/src/libslic3r/Geometry/Circle.hpp index 39973d916d9..a192cc2fd61 100644 --- a/src/libslic3r/Geometry/Circle.hpp +++ b/src/libslic3r/Geometry/Circle.hpp @@ -1,3 +1,7 @@ +///|/ Copyright (c) Prusa Research 2021 - 2022 Lukáš Matěna @lukasmatena, Filip Sykala @Jony01, Vojtěch Bubník @bubnikv, Enrico Turri @enricoturri1966 +///|/ +///|/ PrusaSlicer is released under the terms of the AGPLv3 or higher +///|/ #ifndef slic3r_Geometry_Circle_hpp_ #define slic3r_Geometry_Circle_hpp_ @@ -102,7 +106,7 @@ inline Vec2d circle_center_taubin_newton(const Vec2ds& input, size_t cycles = 20 Circled circle_taubin_newton(const Vec2ds& input, size_t cycles = 20); // Find circle using RANSAC randomized algorithm. -Circled circle_ransac(const Vec2ds& input, size_t iterations = 20); +Circled circle_ransac(const Vec2ds& input, size_t iterations = 20, double* min_error = nullptr); // Randomized algorithm by Emo Welzl, working with squared radii for efficiency. The returned circle radius is inflated by epsilon. template diff --git a/src/libslic3r/Measure.cpp b/src/libslic3r/Measure.cpp new file mode 100644 index 00000000000..2e6156a88e3 --- /dev/null +++ b/src/libslic3r/Measure.cpp @@ -0,0 +1,1255 @@ +///|/ Copyright (c) Prusa Research 2022 - 2023 Lukáš Matěna @lukasmatena, Enrico Turri @enricoturri1966, Vojtěch Bubník @bubnikv, Pavel Mikuš @Godrak +///|/ +///|/ PrusaSlicer is released under the terms of the AGPLv3 or higher +///|/ +#include "libslic3r/libslic3r.h" +#include "Measure.hpp" +#include "MeasureUtils.hpp" + +#include "libslic3r/Geometry/Circle.hpp" +#include "libslic3r/SurfaceMesh.hpp" + + +#include +#include + +#define DEBUG_EXTRACT_ALL_FEATURES_AT_ONCE 0 + +namespace Slic3r { +namespace Measure { + + +constexpr double feature_hover_limit = 0.5; // how close to a feature the mouse must be to highlight it + +static std::tuple get_center_and_radius(const std::vector& points, const Transform3d& trafo, const Transform3d& trafo_inv) +{ + Vec2ds out; + double z = 0.; + for (const Vec3d& pt : points) { + Vec3d pt_transformed = trafo * pt; + z = pt_transformed.z(); + out.emplace_back(pt_transformed.x(), pt_transformed.y()); + } + + const int iter = points.size() < 10 ? 2 : + points.size() < 100 ? 4 : + 6; + + double error = std::numeric_limits::max(); + auto circle = Geometry::circle_ransac(out, iter, &error); + + return std::make_tuple(trafo.inverse() * Vec3d(circle.center.x(), circle.center.y(), z), circle.radius, error); +} + + + +static std::array orthonormal_basis(const Vec3d& v) +{ + std::array ret; + ret[2] = v.normalized(); + int index; + ret[2].cwiseAbs().maxCoeff(&index); + switch (index) + { + case 0: { ret[0] = Vec3d(ret[2].y(), -ret[2].x(), 0.0).normalized(); break; } + case 1: { ret[0] = Vec3d(0.0, ret[2].z(), -ret[2].y()).normalized(); break; } + case 2: { ret[0] = Vec3d(-ret[2].z(), 0.0, ret[2].x()).normalized(); break; } + } + ret[1] = ret[2].cross(ret[0]).normalized(); + return ret; +} + + + +class MeasuringImpl { +public: + explicit MeasuringImpl(const indexed_triangle_set& its); + struct PlaneData { + std::vector facets; + std::vector> borders; // FIXME: should be in fact local in update_planes() + std::vector surface_features; + Vec3d normal; + float area; + bool features_extracted = false; + }; + + std::optional get_feature(size_t face_idx, const Vec3d& point); + int get_num_of_planes() const; + const std::vector& get_plane_triangle_indices(int idx) const; + const std::vector& get_plane_features(unsigned int plane_id); + const indexed_triangle_set& get_its() const; + +private: + void update_planes(); + void extract_features(int plane_idx); + + std::vector m_planes; + std::vector m_face_to_plane; + indexed_triangle_set m_its; +}; + + + + + + +MeasuringImpl::MeasuringImpl(const indexed_triangle_set& its) +: m_its(its) +{ + update_planes(); + + // Extracting features will be done as needed. + // To extract all planes at once, run the following: +#if DEBUG_EXTRACT_ALL_FEATURES_AT_ONCE + for (int i=0; i face_normals = its_face_normals(m_its); + const std::vector face_neighbors = its_face_neighbors(m_its); + std::vector facet_queue(num_of_facets, 0); + int facet_queue_cnt = 0; + const stl_normal* normal_ptr = nullptr; + size_t seed_facet_idx = 0; + + auto is_same_normal = [](const stl_normal& a, const stl_normal& b) -> bool { + return (std::abs(a(0) - b(0)) < 0.001 && std::abs(a(1) - b(1)) < 0.001 && std::abs(a(2) - b(2)) < 0.001); + }; + + m_planes.clear(); + m_planes.reserve(num_of_facets / 5); // empty plane data object is quite lightweight, let's save the initial reallocations + + + // First go through all the triangles and fill in m_planes vector. For each "plane" + // detected on the model, it will contain list of facets that are part of it. + // We will also fill in m_face_to_plane, which contains index into m_planes + // for each of the source facets. + while (1) { + // Find next unvisited triangle: + for (; seed_facet_idx < num_of_facets; ++ seed_facet_idx) + if (m_face_to_plane[seed_facet_idx] == size_t(-1)) { + facet_queue[facet_queue_cnt ++] = seed_facet_idx; + normal_ptr = &face_normals[seed_facet_idx]; + m_face_to_plane[seed_facet_idx] = m_planes.size(); + m_planes.emplace_back(); + break; + } + if (seed_facet_idx == num_of_facets) + break; // Everything was visited already + + while (facet_queue_cnt > 0) { + int facet_idx = facet_queue[-- facet_queue_cnt]; + const stl_normal& this_normal = face_normals[facet_idx]; + if (is_same_normal(this_normal, *normal_ptr)) { +// const Vec3i& face = m_its.indices[facet_idx]; + + m_face_to_plane[facet_idx] = m_planes.size() - 1; + m_planes.back().facets.emplace_back(facet_idx); + for (int j = 0; j < 3; ++ j) + if (int neighbor_idx = face_neighbors[facet_idx][j]; neighbor_idx >= 0 && m_face_to_plane[neighbor_idx] == size_t(-1)) + facet_queue[facet_queue_cnt ++] = neighbor_idx; + } + } + + m_planes.back().normal = normal_ptr->cast(); + std::sort(m_planes.back().facets.begin(), m_planes.back().facets.end()); + } + + // Check that each facet is part of one of the planes. + assert(std::none_of(m_face_to_plane.begin(), m_face_to_plane.end(), [](size_t val) { return val == size_t(-1); })); + + // Now we will walk around each of the planes and save vertices which form the border. + const SurfaceMesh sm(m_its); + + const auto& face_to_plane = m_face_to_plane; + auto& planes = m_planes; + + tbb::parallel_for(tbb::blocked_range(0, m_planes.size()), + [&planes, &face_to_plane, &face_neighbors, &sm](const tbb::blocked_range& range) { + for (size_t plane_id = range.begin(); plane_id != range.end(); ++plane_id) { + + const auto& facets = planes[plane_id].facets; + planes[plane_id].borders.clear(); + std::vector> visited(facets.size(), {false, false, false}); + + for (int face_id=0; face_id& last_border = planes[plane_id].borders.back(); + last_border.reserve(4); + last_border.emplace_back(sm.point(sm.source(he)).cast()); + //Vertex_index target = sm.target(he); + const Halfedge_index he_start = he; + + Face_index fi = he.face(); + auto face_it = std::lower_bound(facets.begin(), facets.end(), int(fi)); + assert(face_it != facets.end()); + assert(*face_it == int(fi)); + visited[face_it - facets.begin()][he.side()] = true; + + do { + const Halfedge_index he_orig = he; + he = sm.next_around_target(he); + if (he.is_invalid()) + goto PLANE_FAILURE; + + // For broken meshes, the iteration might never get back to he_orig. + // Remember all halfedges we saw to break out of such infinite loops. + boost::container::small_vector he_seen; + + while ( face_to_plane[sm.face(he)] == plane_id && he != he_orig) { + he_seen.emplace_back(he); + he = sm.next_around_target(he); + if (he.is_invalid() || std::find(he_seen.begin(), he_seen.end(), he) != he_seen.end()) + goto PLANE_FAILURE; + } + he = sm.opposite(he); + if (he.is_invalid()) + goto PLANE_FAILURE; + + Face_index fi = he.face(); + auto face_it = std::lower_bound(facets.begin(), facets.end(), int(fi)); + if (face_it == facets.end() || *face_it != int(fi)) // This indicates a broken mesh. + goto PLANE_FAILURE; + + if (visited[face_it - facets.begin()][he.side()] && he != he_start) { + last_border.resize(1); + break; + } + visited[face_it - facets.begin()][he.side()] = true; + + last_border.emplace_back(sm.point(sm.source(he)).cast()); + + // In case of broken meshes, this loop might be infinite. Break + // out in case it is clearly going bad. + if (last_border.size() > 3*facets.size()+1) + goto PLANE_FAILURE; + + } while (he != he_start); + + if (last_border.size() == 1) + planes[plane_id].borders.pop_back(); + else { + assert(last_border.front() == last_border.back()); + last_border.pop_back(); + } + } + } + continue; // There was no failure. + + PLANE_FAILURE: + planes[plane_id].borders.clear(); + }}); + m_planes.shrink_to_fit(); +} + + + + + + +void MeasuringImpl::extract_features(int plane_idx) +{ + assert(! m_planes[plane_idx].features_extracted); + + PlaneData& plane = m_planes[plane_idx]; + plane.surface_features.clear(); + const Vec3d& normal = plane.normal; + + Eigen::Quaterniond q; + q.setFromTwoVectors(plane.normal, Vec3d::UnitZ()); + Transform3d trafo = Transform3d::Identity(); + trafo.rotate(q); + const Transform3d trafo_inv = trafo.inverse(); + + std::vector angles; // placed in outer scope to prevent reallocations + std::vector lengths; + + for (const std::vector& border : plane.borders) { + if (border.size() <= 1) + continue; + + bool done = false; + + if (border.size() > 4) { + const auto& [center, radius, err] = get_center_and_radius(border, trafo, trafo_inv); + + if (err < 0.05) { + // The whole border is one circle. Just add it into the list of features + // and we are done. + + bool is_polygon = border.size()>4 && border.size()<=8; + bool lengths_match = std::all_of(border.begin()+2, border.end(), [is_polygon](const Vec3d& pt) { + return Slic3r::is_approx((pt - *((&pt)-1)).squaredNorm(), (*((&pt)-1) - *((&pt)-2)).squaredNorm(), is_polygon ? 0.01 : 0.01); + }); + + if (lengths_match && (is_polygon || border.size() > 8)) { + if (is_polygon) { + // This is a polygon, add the separate edges with the center. + for (int j=0; j int { + assert(std::abs(offset) < border_size); + int out = idx+offset; + if (out >= border_size) + out = out - border_size; + else if (out < 0) + out = border_size + out; + + return out; + }; + + // First calculate angles at all the vertices. + angles.clear(); + lengths.clear(); + int first_different_angle_idx = 0; + for (int i=0; i M_PI) + angle = 2*M_PI - angle; + + angles.push_back(angle); + lengths.push_back(v2.norm()); + if (first_different_angle_idx == 0 && angles.size() > 1) { + if (! are_angles_same(angles.back(), angles[angles.size()-2])) + first_different_angle_idx = angles.size()-1; + } + } + assert(border.size() == angles.size()); + assert(border.size() == lengths.size()); + + // First go around the border and pick what might be circular segments. + // Save pair of indices to where such potential segments start and end. + // Also remember the length of these segments. + int start_idx = -1; + bool circle = false; + bool first_iter = true; + std::vector circles; + std::vector edges; + std::vector> circles_idxs; + //std::vector circles_lengths; + std::vector single_circle; // could be in loop-scope, but reallocations + double single_circle_length = 0.; + int first_pt_idx = offset_to_index(first_different_angle_idx, 1); + int i = first_pt_idx; + while (i != first_pt_idx || first_iter) { + if (are_angles_same(angles[i], angles[offset_to_index(i,-1)]) + && i != offset_to_index(first_pt_idx, -1) // not the last point + && i != start_idx ) { + // circle + if (! circle) { + circle = true; + single_circle.clear(); + single_circle_length = 0.; + start_idx = offset_to_index(i, -2); + single_circle = { border[start_idx], border[offset_to_index(start_idx,1)] }; + single_circle_length += lengths[offset_to_index(i, -1)]; + } + single_circle.emplace_back(border[i]); + single_circle_length += lengths[i]; + } else { + if (circle && single_circle.size() >= 5) { // Less than 5 vertices? Not a circle. + single_circle.emplace_back(border[i]); + single_circle_length += lengths[i]; + + bool accept_circle = true; + { + // Check that lengths of internal (!!!) edges match. + int j = offset_to_index(start_idx, 3); + while (j != i) { + if (! are_lengths_same(lengths[offset_to_index(j,-1)], lengths[j])) { + accept_circle = false; + break; + } + j = offset_to_index(j, 1); + } + } + + if (accept_circle) { + const auto& [center, radius, err] = get_center_and_radius(single_circle, trafo, trafo_inv); + + // Check that the fit went well. The tolerance is high, only to + // reject complete failures. + accept_circle &= err < 0.05; + + // If the segment subtends less than 90 degrees, throw it away. + accept_circle &= single_circle_length / radius > 0.9*M_PI/2.; + + if (accept_circle) { + // Add the circle and remember indices into borders. + circles_idxs.emplace_back(start_idx, i); + circles.emplace_back(SurfaceFeature(SurfaceFeatureType::Circle, center, plane.normal, std::nullopt, radius)); + } + } + } + circle = false; + } + // Take care of the wrap around. + first_iter = false; + i = offset_to_index(i, 1); + } + + // We have the circles. Now go around again and pick edges, while jumping over circles. + if (circles_idxs.empty()) { + // Just add all edges. + for (int i=1; i 1 || circles_idxs.front().first != circles_idxs.front().second) { + // There is at least one circular segment. Start at its end and add edges until the start of the next one. + int i = circles_idxs.front().second; + int circle_idx = 1; + while (true) { + i = offset_to_index(i, 1); + edges.emplace_back(SurfaceFeature(SurfaceFeatureType::Edge, border[offset_to_index(i,-1)], border[i])); + if (circle_idx < int(circles_idxs.size()) && i == circles_idxs[circle_idx].first) { + i = circles_idxs[circle_idx].second; + ++circle_idx; + } + if (i == circles_idxs.front().first) + break; + } + } + + // Merge adjacent edges where needed. + assert(std::all_of(edges.begin(), edges.end(), + [](const SurfaceFeature& f) { return f.get_type() == SurfaceFeatureType::Edge; })); + for (int i=edges.size()-1; i>=0; --i) { + const auto& [first_start, first_end] = edges[i==0 ? edges.size()-1 : i-1].get_edge(); + const auto& [second_start, second_end] = edges[i].get_edge(); + + if (Slic3r::is_approx(first_end, second_start) + && Slic3r::is_approx((first_end-first_start).normalized().dot((second_end-second_start).normalized()), 1.)) { + // The edges have the same direction and share a point. Merge them. + edges[i==0 ? edges.size()-1 : i-1] = SurfaceFeature(SurfaceFeatureType::Edge, first_start, second_end); + edges.erase(edges.begin() + i); + } + } + + // Now move the circles and edges into the feature list for the plane. + assert(std::all_of(circles.begin(), circles.end(), [](const SurfaceFeature& f) { + return f.get_type() == SurfaceFeatureType::Circle; + })); + assert(std::all_of(edges.begin(), edges.end(), [](const SurfaceFeature& f) { + return f.get_type() == SurfaceFeatureType::Edge; + })); + plane.surface_features.insert(plane.surface_features.end(), std::make_move_iterator(circles.begin()), + std::make_move_iterator(circles.end())); + plane.surface_features.insert(plane.surface_features.end(), std::make_move_iterator(edges.begin()), + std::make_move_iterator(edges.end())); + } + } + + // The last surface feature is the plane itself. + Vec3d cog = Vec3d::Zero(); + size_t counter = 0; + for (const std::vector& b : plane.borders) { + for (size_t i = 1; i < b.size(); ++i) { + cog += b[i]; + ++counter; + } + } + cog /= double(counter); + plane.surface_features.emplace_back(SurfaceFeature(SurfaceFeatureType::Plane, + plane.normal, cog, std::optional(), plane_idx + 0.0001)); + + plane.borders.clear(); + plane.borders.shrink_to_fit(); + + plane.features_extracted = true; +} + + + + + + + + +std::optional MeasuringImpl::get_feature(size_t face_idx, const Vec3d& point) +{ + if (face_idx >= m_face_to_plane.size()) + return std::optional(); + + const PlaneData& plane = m_planes[m_face_to_plane[face_idx]]; + + if (! plane.features_extracted) + extract_features(m_face_to_plane[face_idx]); + + size_t closest_feature_idx = size_t(-1); + double min_dist = std::numeric_limits::max(); + + MeasurementResult res; + SurfaceFeature point_sf(point); + + assert(plane.surface_features.empty() || plane.surface_features.back().get_type() == SurfaceFeatureType::Plane); + + for (size_t i=0; idist; + if (dist < feature_hover_limit && dist < min_dist) { + min_dist = std::min(dist, min_dist); + closest_feature_idx = i; + } + } + } + + if (closest_feature_idx != size_t(-1)) { + const SurfaceFeature& f = plane.surface_features[closest_feature_idx]; + if (f.get_type() == SurfaceFeatureType::Edge) { + // If this is an edge, check if we are not close to the endpoint. If so, + // we will include the endpoint as well. Close = 10% of the lenghth of + // the edge, clamped between 0.025 and 0.5 mm. + const auto& [sp, ep] = f.get_edge(); + double len_sq = (ep-sp).squaredNorm(); + double limit_sq = std::max(0.025*0.025, std::min(0.5*0.5, 0.1 * 0.1 * len_sq)); + + if ((point-sp).squaredNorm() < limit_sq) + return std::make_optional(SurfaceFeature(sp)); + if ((point-ep).squaredNorm() < limit_sq) + return std::make_optional(SurfaceFeature(ep)); + } + return std::make_optional(f); + } + + // Nothing detected, return the plane as a whole. + assert(plane.surface_features.back().get_type() == SurfaceFeatureType::Plane); + return std::make_optional(plane.surface_features.back()); +} + + + + + +int MeasuringImpl::get_num_of_planes() const +{ + return (m_planes.size()); +} + + + +const std::vector& MeasuringImpl::get_plane_triangle_indices(int idx) const +{ + assert(idx >= 0 && idx < int(m_planes.size())); + return m_planes[idx].facets; +} + +const std::vector& MeasuringImpl::get_plane_features(unsigned int plane_id) +{ + assert(plane_id < m_planes.size()); + if (! m_planes[plane_id].features_extracted) + extract_features(plane_id); + return m_planes[plane_id].surface_features; +} + +const indexed_triangle_set& MeasuringImpl::get_its() const +{ + return this->m_its; +} + + + + + + + + + + + +Measuring::Measuring(const indexed_triangle_set& its) +: priv{std::make_unique(its)} +{} + +Measuring::~Measuring() {} + + + +std::optional Measuring::get_feature(size_t face_idx, const Vec3d& point) const +{ + return priv->get_feature(face_idx, point); +} + + +int Measuring::get_num_of_planes() const +{ + return priv->get_num_of_planes(); +} + + +const std::vector& Measuring::get_plane_triangle_indices(int idx) const +{ + return priv->get_plane_triangle_indices(idx); +} + +const std::vector& Measuring::get_plane_features(unsigned int plane_id) const +{ + return priv->get_plane_features(plane_id); +} + +const indexed_triangle_set& Measuring::get_its() const +{ + return priv->get_its(); +} + +const AngleAndEdges AngleAndEdges::Dummy = { 0.0, Vec3d::Zero(), { Vec3d::Zero(), Vec3d::Zero() }, { Vec3d::Zero(), Vec3d::Zero() }, 0.0, true }; + +static AngleAndEdges angle_edge_edge(const std::pair& e1, const std::pair& e2) +{ + if (are_parallel(e1, e2)) + return AngleAndEdges::Dummy; + + Vec3d e1_unit = edge_direction(e1.first, e1.second); + Vec3d e2_unit = edge_direction(e2.first, e2.second); + + // project edges on the plane defined by them + Vec3d normal = e1_unit.cross(e2_unit).normalized(); + const Eigen::Hyperplane plane(normal, e1.first); + Vec3d e11_proj = plane.projection(e1.first); + Vec3d e12_proj = plane.projection(e1.second); + Vec3d e21_proj = plane.projection(e2.first); + Vec3d e22_proj = plane.projection(e2.second); + + const bool coplanar = (e2.first - e21_proj).norm() < EPSILON && (e2.second - e22_proj).norm() < EPSILON; + + // rotate the plane to become the XY plane + auto qp = Eigen::Quaternion::FromTwoVectors(normal, Vec3d::UnitZ()); + auto qp_inverse = qp.inverse(); + const Vec3d e11_rot = qp * e11_proj; + const Vec3d e12_rot = qp * e12_proj; + const Vec3d e21_rot = qp * e21_proj; + const Vec3d e22_rot = qp * e22_proj; + + // discard Z + const Vec2d e11_rot_2d = Vec2d(e11_rot.x(), e11_rot.y()); + const Vec2d e12_rot_2d = Vec2d(e12_rot.x(), e12_rot.y()); + const Vec2d e21_rot_2d = Vec2d(e21_rot.x(), e21_rot.y()); + const Vec2d e22_rot_2d = Vec2d(e22_rot.x(), e22_rot.y()); + + // find intersection (arc center) of edges in XY plane + const Eigen::Hyperplane e1_rot_2d_line = Eigen::Hyperplane::Through(e11_rot_2d, e12_rot_2d); + const Eigen::Hyperplane e2_rot_2d_line = Eigen::Hyperplane::Through(e21_rot_2d, e22_rot_2d); + const Vec2d center_rot_2d = e1_rot_2d_line.intersection(e2_rot_2d_line); + + // arc center in original coordinate + const Vec3d center = qp_inverse * Vec3d(center_rot_2d.x(), center_rot_2d.y(), e11_rot.z()); + + // ensure the edges are pointing away from the center + std::pair out_e1 = e1; + std::pair out_e2 = e2; + if ((center_rot_2d - e11_rot_2d).squaredNorm() > (center_rot_2d - e12_rot_2d).squaredNorm()) { + std::swap(e11_proj, e12_proj); + std::swap(out_e1.first, out_e1.second); + e1_unit = -e1_unit; + } + if ((center_rot_2d - e21_rot_2d).squaredNorm() > (center_rot_2d - e22_rot_2d).squaredNorm()) { + std::swap(e21_proj, e22_proj); + std::swap(out_e2.first, out_e2.second); + e2_unit = -e2_unit; + } + + // arc angle + const double angle = std::acos(std::clamp(e1_unit.dot(e2_unit), -1.0, 1.0)); + // arc radius + const Vec3d e1_proj_mid = 0.5 * (e11_proj + e12_proj); + const Vec3d e2_proj_mid = 0.5 * (e21_proj + e22_proj); + const double radius = std::min((center - e1_proj_mid).norm(), (center - e2_proj_mid).norm()); + + return { angle, center, out_e1, out_e2, radius, coplanar }; +} + +static AngleAndEdges angle_edge_plane(const std::pair& e, const std::tuple& p) +{ + const auto& [idx, normal, origin] = p; + Vec3d e1e2_unit = edge_direction(e); + if (are_perpendicular(e1e2_unit, normal)) + return AngleAndEdges::Dummy; + + // ensure the edge is pointing away from the intersection + // 1st calculate instersection between edge and plane + const Eigen::Hyperplane plane(normal, origin); + const Eigen::ParametrizedLine line = Eigen::ParametrizedLine::Through(e.first, e.second); + const Vec3d inters = line.intersectionPoint(plane); + + // then verify edge direction and revert it, if needed + Vec3d e1 = e.first; + Vec3d e2 = e.second; + if ((e1 - inters).squaredNorm() > (e2 - inters).squaredNorm()) { + std::swap(e1, e2); + e1e2_unit = -e1e2_unit; + } + + if (are_parallel(e1e2_unit, normal)) { + const std::array basis = orthonormal_basis(e1e2_unit); + const double radius = (0.5 * (e1 + e2) - inters).norm(); + const Vec3d edge_on_plane_dir = (basis[1].dot(origin - inters) >= 0.0) ? basis[1] : -basis[1]; + std::pair edge_on_plane = std::make_pair(inters, inters + radius * edge_on_plane_dir); + if (!inters.isApprox(e1)) { + edge_on_plane.first += radius * edge_on_plane_dir; + edge_on_plane.second += radius * edge_on_plane_dir; + } + return AngleAndEdges(0.5 * double(PI), inters, std::make_pair(e1, e2), edge_on_plane, radius, inters.isApprox(e1)); + } + + const Vec3d e1e2 = e2 - e1; + const double e1e2_len = e1e2.norm(); + + // calculate 2nd edge (on the plane) + const Vec3d temp = normal.cross(e1e2); + const Vec3d edge_on_plane_unit = normal.cross(temp).normalized(); + std::pair edge_on_plane = { origin, origin + e1e2_len * edge_on_plane_unit }; + + // ensure the 2nd edge is pointing in the correct direction + const Vec3d test_edge = (edge_on_plane.second - edge_on_plane.first).cross(e1e2); + if (test_edge.dot(temp) < 0.0) + edge_on_plane = { origin, origin - e1e2_len * edge_on_plane_unit }; + + AngleAndEdges ret = angle_edge_edge({ e1, e2 }, edge_on_plane); + ret.radius = (inters - 0.5 * (e1 + e2)).norm(); + return ret; +} + +static AngleAndEdges angle_plane_plane(const std::tuple& p1, const std::tuple& p2) +{ + const auto& [idx1, normal1, origin1] = p1; + const auto& [idx2, normal2, origin2] = p2; + + // are planes parallel ? + if (are_parallel(normal1, normal2)) + return AngleAndEdges::Dummy; + + auto intersection_plane_plane = [](const Vec3d& n1, const Vec3d& o1, const Vec3d& n2, const Vec3d& o2) { + Eigen::MatrixXd m(2, 3); + m << n1.x(), n1.y(), n1.z(), n2.x(), n2.y(), n2.z(); + Eigen::VectorXd b(2); + b << o1.dot(n1), o2.dot(n2); + Eigen::VectorXd x = m.colPivHouseholderQr().solve(b); + return std::make_pair(n1.cross(n2).normalized(), Vec3d(x(0), x(1), x(2))); + }; + + // Calculate intersection line between planes + const auto [intersection_line_direction, intersection_line_origin] = intersection_plane_plane(normal1, origin1, normal2, origin2); + + // Project planes' origin on intersection line + const Eigen::ParametrizedLine intersection_line = Eigen::ParametrizedLine(intersection_line_origin, intersection_line_direction); + const Vec3d origin1_proj = intersection_line.projection(origin1); + const Vec3d origin2_proj = intersection_line.projection(origin2); + + // Calculate edges on planes + const Vec3d edge_on_plane1_unit = (origin1 - origin1_proj).normalized(); + const Vec3d edge_on_plane2_unit = (origin2 - origin2_proj).normalized(); + const double radius = std::max(10.0, std::max((origin1 - origin1_proj).norm(), (origin2 - origin2_proj).norm())); + const std::pair edge_on_plane1 = { origin1_proj + radius * edge_on_plane1_unit, origin1_proj + 2.0 * radius * edge_on_plane1_unit }; + const std::pair edge_on_plane2 = { origin2_proj + radius * edge_on_plane2_unit, origin2_proj + 2.0 * radius * edge_on_plane2_unit }; + + AngleAndEdges ret = angle_edge_edge(edge_on_plane1, edge_on_plane2); + ret.radius = radius; + return ret; +} + + + + + + + +MeasurementResult get_measurement(const SurfaceFeature& a, const SurfaceFeature& b, const Measuring* measuring) +{ + assert(a.get_type() != SurfaceFeatureType::Undef && b.get_type() != SurfaceFeatureType::Undef); + + const bool swap = int(a.get_type()) > int(b.get_type()); + const SurfaceFeature& f1 = swap ? b : a; + const SurfaceFeature& f2 = swap ? a : b; + + MeasurementResult result; + + /////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////// + if (f1.get_type() == SurfaceFeatureType::Point) { + if (f2.get_type() == SurfaceFeatureType::Point) { + Vec3d diff = (f2.get_point() - f1.get_point()); + result.distance_strict = std::make_optional(DistAndPoints{diff.norm(), f1.get_point(), f2.get_point()}); + result.distance_xyz = diff.cwiseAbs(); + + /////////////////////////////////////////////////////////////////////////// + } else if (f2.get_type() == SurfaceFeatureType::Edge) { + const auto [s,e] = f2.get_edge(); + const Eigen::ParametrizedLine line(s, (e-s).normalized()); + const double dist_inf = line.distance(f1.get_point()); + const Vec3d proj = line.projection(f1.get_point()); + const double len_sq = (e-s).squaredNorm(); + const double dist_start_sq = (proj-s).squaredNorm(); + const double dist_end_sq = (proj-e).squaredNorm(); + if (dist_start_sq < len_sq && dist_end_sq < len_sq) { + // projection falls on the line - the strict distance is the same as infinite + result.distance_strict = std::make_optional(DistAndPoints{dist_inf, f1.get_point(), proj}); + } else { // the result is the closer of the endpoints + const bool s_is_closer = dist_start_sq < dist_end_sq; + result.distance_strict = std::make_optional(DistAndPoints{std::sqrt(std::min(dist_start_sq, dist_end_sq) + sqr(dist_inf)), f1.get_point(), s_is_closer ? s : e}); + } + result.distance_infinite = std::make_optional(DistAndPoints{dist_inf, f1.get_point(), proj}); + /////////////////////////////////////////////////////////////////////////// + } else if (f2.get_type() == SurfaceFeatureType::Circle) { + // Find a plane containing normal, center and the point. + const auto [c, radius, n] = f2.get_circle(); + const Eigen::Hyperplane circle_plane(n, c); + const Vec3d proj = circle_plane.projection(f1.get_point()); + if (proj.isApprox(c)) { + const Vec3d p_on_circle = c + radius * get_orthogonal(n, true); + result.distance_strict = std::make_optional(DistAndPoints{ radius, c, p_on_circle }); + } + else { + const Eigen::Hyperplane circle_plane(n, c); + const Vec3d proj = circle_plane.projection(f1.get_point()); + const double dist = std::sqrt(std::pow((proj - c).norm() - radius, 2.) + + (f1.get_point() - proj).squaredNorm()); + + const Vec3d p_on_circle = c + radius * (proj - c).normalized(); + result.distance_strict = std::make_optional(DistAndPoints{ dist, f1.get_point(), p_on_circle }); // TODO + } + /////////////////////////////////////////////////////////////////////////// + } else if (f2.get_type() == SurfaceFeatureType::Plane) { + const auto [idx, normal, pt] = f2.get_plane(); + Eigen::Hyperplane plane(normal, pt); + result.distance_infinite = std::make_optional(DistAndPoints{plane.absDistance(f1.get_point()), f1.get_point(), plane.projection(f1.get_point())}); // TODO + // TODO: result.distance_strict = + } + /////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////// + } + else if (f1.get_type() == SurfaceFeatureType::Edge) { + if (f2.get_type() == SurfaceFeatureType::Edge) { + std::vector distances; + + auto add_point_edge_distance = [&distances](const Vec3d& v, const std::pair& e) { + const MeasurementResult res = get_measurement(SurfaceFeature(v), SurfaceFeature(SurfaceFeatureType::Edge, e.first, e.second)); + double distance = res.distance_strict->dist; + Vec3d v2 = res.distance_strict->to; + + const Vec3d e1e2 = e.second - e.first; + const Vec3d e1v2 = v2 - e.first; + if (e1v2.dot(e1e2) >= 0.0 && e1v2.norm() < e1e2.norm()) + distances.emplace_back(distance, v, v2); + }; + + std::pair e1 = f1.get_edge(); + std::pair e2 = f2.get_edge(); + + distances.emplace_back((e2.first - e1.first).norm(), e1.first, e2.first); + distances.emplace_back((e2.second - e1.first).norm(), e1.first, e2.second); + distances.emplace_back((e2.first - e1.second).norm(), e1.second, e2.first); + distances.emplace_back((e2.second - e1.second).norm(), e1.second, e2.second); + add_point_edge_distance(e1.first, e2); + add_point_edge_distance(e1.second, e2); + add_point_edge_distance(e2.first, e1); + add_point_edge_distance(e2.second, e1); + auto it = std::min_element(distances.begin(), distances.end(), + [](const DistAndPoints& item1, const DistAndPoints& item2) { + return item1.dist < item2.dist; + }); + result.distance_infinite = std::make_optional(*it); + + result.angle = angle_edge_edge(f1.get_edge(), f2.get_edge()); + /////////////////////////////////////////////////////////////////////////// + } else if (f2.get_type() == SurfaceFeatureType::Circle) { + const std::pair e = f1.get_edge(); + const auto& [center, radius, normal] = f2.get_circle(); + const Vec3d e1e2 = (e.second - e.first); + const Vec3d e1e2_unit = e1e2.normalized(); + + std::vector distances; + distances.emplace_back(*get_measurement(SurfaceFeature(e.first), f2).distance_strict); + distances.emplace_back(*get_measurement(SurfaceFeature(e.second), f2).distance_strict); + + const Eigen::Hyperplane plane(e1e2_unit, center); + const Eigen::ParametrizedLine line = Eigen::ParametrizedLine::Through(e.first, e.second); + const Vec3d inter = line.intersectionPoint(plane); + const Vec3d e1inter = inter - e.first; + if (e1inter.dot(e1e2) >= 0.0 && e1inter.norm() < e1e2.norm()) + distances.emplace_back(*get_measurement(SurfaceFeature(inter), f2).distance_strict); + + auto it = std::min_element(distances.begin(), distances.end(), + [](const DistAndPoints& item1, const DistAndPoints& item2) { + return item1.dist < item2.dist; + }); + result.distance_infinite = std::make_optional(DistAndPoints{it->dist, it->from, it->to}); + /////////////////////////////////////////////////////////////////////////// + } else if (f2.get_type() == SurfaceFeatureType::Plane) { + assert(measuring != nullptr); + + const auto [from, to] = f1.get_edge(); + const auto [idx, normal, origin] = f2.get_plane(); + + const Vec3d edge_unit = (to - from).normalized(); + if (are_perpendicular(edge_unit, normal)) { + std::vector distances; + const Eigen::Hyperplane plane(normal, origin); + distances.push_back(DistAndPoints{ plane.absDistance(from), from, plane.projection(from) }); + distances.push_back(DistAndPoints{ plane.absDistance(to), to, plane.projection(to) }); + auto it = std::min_element(distances.begin(), distances.end(), + [](const DistAndPoints& item1, const DistAndPoints& item2) { + return item1.dist < item2.dist; + }); + result.distance_infinite = std::make_optional(DistAndPoints{ it->dist, it->from, it->to }); + } + else { + const std::vector& plane_features = measuring->get_plane_features(idx); + std::vector distances; + for (const SurfaceFeature& sf : plane_features) { + if (sf.get_type() == SurfaceFeatureType::Edge) { + const auto m = get_measurement(sf, f1); + if (!m.distance_infinite.has_value()) { + distances.clear(); + break; + } + else + distances.push_back(*m.distance_infinite); + } + } + if (!distances.empty()) { + auto it = std::min_element(distances.begin(), distances.end(), + [](const DistAndPoints& item1, const DistAndPoints& item2) { + return item1.dist < item2.dist; + }); + result.distance_infinite = std::make_optional(DistAndPoints{ it->dist, it->from, it->to }); + } + } + result.angle = angle_edge_plane(f1.get_edge(), f2.get_plane()); + } + /////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////// + } else if (f1.get_type() == SurfaceFeatureType::Circle) { + if (f2.get_type() == SurfaceFeatureType::Circle) { + const auto [c0, r0, n0] = f1.get_circle(); + const auto [c1, r1, n1] = f2.get_circle(); + + // The following code is an adaptation of the algorithm found in: + // https://github.com/davideberly/GeometricTools/blob/master/GTE/Mathematics/DistCircle3Circle3.h + // and described in: + // https://www.geometrictools.com/Documentation/DistanceToCircle3.pdf + + struct ClosestInfo + { + double sqrDistance{ 0.0 }; + Vec3d circle0Closest{ Vec3d::Zero() }; + Vec3d circle1Closest{ Vec3d::Zero() }; + + inline bool operator < (const ClosestInfo& other) const { return sqrDistance < other.sqrDistance; } + }; + std::array candidates{}; + + const double zero = 0.0; + + const Vec3d D = c1 - c0; + + if (!are_parallel(n0, n1)) { + // Get parameters for constructing the degree-8 polynomial phi. + const double one = 1.0; + const double two = 2.0; + const double r0sqr = sqr(r0); + const double r1sqr = sqr(r1); + + // Compute U1 and V1 for the plane of circle1. + const std::array basis = orthonormal_basis(n1); + const Vec3d U1 = basis[0]; + const Vec3d V1 = basis[1]; + + // Construct the polynomial phi(cos(theta)). + const Vec3d N0xD = n0.cross(D); + const Vec3d N0xU1 = n0.cross(U1); + const Vec3d N0xV1 = n0.cross(V1); + const double a0 = r1 * D.dot(U1); + const double a1 = r1 * D.dot(V1); + const double a2 = N0xD.dot(N0xD); + const double a3 = r1 * N0xD.dot(N0xU1); + const double a4 = r1 * N0xD.dot(N0xV1); + const double a5 = r1sqr * N0xU1.dot(N0xU1); + const double a6 = r1sqr * N0xU1.dot(N0xV1); + const double a7 = r1sqr * N0xV1.dot(N0xV1); + Polynomial1 p0{ a2 + a7, two * a3, a5 - a7 }; + Polynomial1 p1{ two * a4, two * a6 }; + Polynomial1 p2{ zero, a1 }; + Polynomial1 p3{ -a0 }; + Polynomial1 p4{ -a6, a4, two * a6 }; + Polynomial1 p5{ -a3, a7 - a5 }; + Polynomial1 tmp0{ one, zero, -one }; + Polynomial1 tmp1 = p2 * p2 + tmp0 * p3 * p3; + Polynomial1 tmp2 = two * p2 * p3; + Polynomial1 tmp3 = p4 * p4 + tmp0 * p5 * p5; + Polynomial1 tmp4 = two * p4 * p5; + Polynomial1 p6 = p0 * tmp1 + tmp0 * p1 * tmp2 - r0sqr * tmp3; + Polynomial1 p7 = p0 * tmp2 + p1 * tmp1 - r0sqr * tmp4; + + // Parameters for polynomial root finding. The roots[] array + // stores the roots. We need only the unique ones, which is + // the responsibility of the set uniqueRoots. The pairs[] + // array stores the (cosine,sine) information mentioned in the + // PDF. TODO: Choose the maximum number of iterations for root + // finding based on specific polynomial data? + const uint32_t maxIterations = 128; + int32_t degree = 0; + size_t numRoots = 0; + std::array roots{}; + std::set uniqueRoots{}; + size_t numPairs = 0; + std::array, 16> pairs{}; + double temp = zero; + double sn = zero; + + if (p7.GetDegree() > 0 || p7[0] != zero) { + // H(cs,sn) = p6(cs) + sn * p7(cs) + Polynomial1 phi = p6 * p6 - tmp0 * p7 * p7; + degree = static_cast(phi.GetDegree()); + assert(degree > 0); + numRoots = RootsPolynomial::Find(degree, &phi[0], maxIterations, roots.data()); + for (size_t i = 0; i < numRoots; ++i) { + uniqueRoots.insert(roots[i]); + } + + for (auto const& cs : uniqueRoots) { + if (std::fabs(cs) <= one) { + temp = p7(cs); + if (temp != zero) { + sn = -p6(cs) / temp; + pairs[numPairs++] = std::make_pair(cs, sn); + } + else { + temp = std::max(one - sqr(cs), zero); + sn = std::sqrt(temp); + pairs[numPairs++] = std::make_pair(cs, sn); + if (sn != zero) + pairs[numPairs++] = std::make_pair(cs, -sn); + } + } + } + } + else { + // H(cs,sn) = p6(cs) + degree = static_cast(p6.GetDegree()); + assert(degree > 0); + numRoots = RootsPolynomial::Find(degree, &p6[0], maxIterations, roots.data()); + for (size_t i = 0; i < numRoots; ++i) { + uniqueRoots.insert(roots[i]); + } + + for (auto const& cs : uniqueRoots) { + if (std::fabs(cs) <= one) { + temp = std::max(one - sqr(cs), zero); + sn = std::sqrt(temp); + pairs[numPairs++] = std::make_pair(cs, sn); + if (sn != zero) + pairs[numPairs++] = std::make_pair(cs, -sn); + } + } + } + + for (size_t i = 0; i < numPairs; ++i) { + ClosestInfo& info = candidates[i]; + Vec3d delta = D + r1 * (pairs[i].first * U1 + pairs[i].second * V1); + info.circle1Closest = c0 + delta; + const double N0dDelta = n0.dot(delta); + const double lenN0xDelta = n0.cross(delta).norm(); + if (lenN0xDelta > 0.0) { + const double diff = lenN0xDelta - r0; + info.sqrDistance = sqr(N0dDelta) + sqr(diff); + delta -= N0dDelta * n0; + delta.normalize(); + info.circle0Closest = c0 + r0 * delta; + } + else { + const Vec3d r0U0 = r0 * get_orthogonal(n0, true); + const Vec3d diff = delta - r0U0; + info.sqrDistance = diff.dot(diff); + info.circle0Closest = c0 + r0U0; + } + } + + std::sort(candidates.begin(), candidates.begin() + numPairs); + } + else { + ClosestInfo& info = candidates[0]; + + const double N0dD = n0.dot(D); + const Vec3d normProj = N0dD * n0; + const Vec3d compProj = D - normProj; + Vec3d U = compProj; + const double d = U.norm(); + U.normalize(); + + // The configuration is determined by the relative location of the + // intervals of projection of the circles on to the D-line. + // Circle0 projects to [-r0,r0] and circle1 projects to + // [d-r1,d+r1]. + const double dmr1 = d - r1; + double distance; + if (dmr1 >= r0) { + // d >= r0 + r1 + // The circles are separated (d > r0 + r1) or tangent with one + // outside the other (d = r0 + r1). + distance = dmr1 - r0; + info.circle0Closest = c0 + r0 * U; + info.circle1Closest = c1 - r1 * U; + } + else { + // d < r0 + r1 + // The cases implicitly use the knowledge that d >= 0. + const double dpr1 = d + r1; + if (dpr1 <= r0) { + // Circle1 is inside circle0. + distance = r0 - dpr1; + if (d > 0.0) { + info.circle0Closest = c0 + r0 * U; + info.circle1Closest = c1 + r1 * U; + } + else { + // The circles are concentric, so U = (0,0,0). + // Construct a vector perpendicular to N0 to use for + // closest points. + U = get_orthogonal(n0, true); + info.circle0Closest = c0 + r0 * U; + info.circle1Closest = c1 + r1 * U; + } + } + else if (dmr1 <= -r0) { + // Circle0 is inside circle1. + distance = -r0 - dmr1; + if (d > 0.0) { + info.circle0Closest = c0 - r0 * U; + info.circle1Closest = c1 - r1 * U; + } + else { + // The circles are concentric, so U = (0,0,0). + // Construct a vector perpendicular to N0 to use for + // closest points. + U = get_orthogonal(n0, true); + info.circle0Closest = c0 + r0 * U; + info.circle1Closest = c1 + r1 * U; + } + } + else { + distance = (c1 - c0).norm(); + info.circle0Closest = c0; + info.circle1Closest = c1; + } + } + + info.sqrDistance = distance * distance + N0dD * N0dD; + } + + result.distance_infinite = std::make_optional(DistAndPoints{ std::sqrt(candidates[0].sqrDistance), candidates[0].circle0Closest, candidates[0].circle1Closest }); // TODO + /////////////////////////////////////////////////////////////////////////// + } else if (f2.get_type() == SurfaceFeatureType::Plane) { + assert(measuring != nullptr); + + const auto [center, radius, normal1] = f1.get_circle(); + const auto [idx2, normal2, origin2] = f2.get_plane(); + + const bool coplanar = are_parallel(normal1, normal2) && Eigen::Hyperplane(normal1, center).absDistance(origin2) < EPSILON; + if (!coplanar) { + const std::vector& plane_features = measuring->get_plane_features(idx2); + std::vector distances; + for (const SurfaceFeature& sf : plane_features) { + if (sf.get_type() == SurfaceFeatureType::Edge) { + const auto m = get_measurement(sf, f1); + if (!m.distance_infinite.has_value()) { + distances.clear(); + break; + } + else + distances.push_back(*m.distance_infinite); + } + } + if (!distances.empty()) { + auto it = std::min_element(distances.begin(), distances.end(), + [](const DistAndPoints& item1, const DistAndPoints& item2) { + return item1.dist < item2.dist; + }); + result.distance_infinite = std::make_optional(DistAndPoints{ it->dist, it->from, it->to }); + } + } + } + /////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////// + } else if (f1.get_type() == SurfaceFeatureType::Plane) { + const auto [idx1, normal1, pt1] = f1.get_plane(); + const auto [idx2, normal2, pt2] = f2.get_plane(); + + if (are_parallel(normal1, normal2)) { + // The planes are parallel, calculate distance. + const Eigen::Hyperplane plane(normal1, pt1); + result.distance_infinite = std::make_optional(DistAndPoints{ plane.absDistance(pt2), pt2, plane.projection(pt2) }); // TODO + } + else + result.angle = angle_plane_plane(f1.get_plane(), f2.get_plane()); + } + + return result; +} + + + + + + + + +} // namespace Measure +} // namespace Slic3r + diff --git a/src/libslic3r/Measure.hpp b/src/libslic3r/Measure.hpp new file mode 100644 index 00000000000..dcccafb70d6 --- /dev/null +++ b/src/libslic3r/Measure.hpp @@ -0,0 +1,200 @@ +///|/ Copyright (c) Prusa Research 2022 - 2023 Lukáš Matěna @lukasmatena, Enrico Turri @enricoturri1966, Vojtěch Bubník @bubnikv +///|/ +///|/ PrusaSlicer is released under the terms of the AGPLv3 or higher +///|/ +#ifndef Slic3r_Measure_hpp_ +#define Slic3r_Measure_hpp_ + +#include +#include + +#include "Point.hpp" + + +struct indexed_triangle_set; + + + +namespace Slic3r { + +class TriangleMesh; + +namespace Measure { + + +enum class SurfaceFeatureType : int { + Undef = 0, + Point = 1 << 0, + Edge = 1 << 1, + Circle = 1 << 2, + Plane = 1 << 3 +}; + +class SurfaceFeature { +public: + SurfaceFeature(SurfaceFeatureType type, const Vec3d& pt1, const Vec3d& pt2, std::optional pt3 = std::nullopt, double value = 0.0) + : m_type(type), m_pt1(pt1), m_pt2(pt2), m_pt3(pt3), m_value(value) {} + + explicit SurfaceFeature(const Vec3d& pt) + : m_type{SurfaceFeatureType::Point}, m_pt1{pt} {} + + // Get type of this feature. + SurfaceFeatureType get_type() const { return m_type; } + + // For points, return the point. + Vec3d get_point() const { assert(m_type == SurfaceFeatureType::Point); return m_pt1; } + + // For edges, return start and end. + std::pair get_edge() const { assert(m_type == SurfaceFeatureType::Edge); return std::make_pair(m_pt1, m_pt2); } + + // For circles, return center, radius and normal. + std::tuple get_circle() const { assert(m_type == SurfaceFeatureType::Circle); return std::make_tuple(m_pt1, m_value, m_pt2); } + + // For planes, return index into vector provided by Measuring::get_plane_triangle_indices, normal and point. + std::tuple get_plane() const { assert(m_type == SurfaceFeatureType::Plane); return std::make_tuple(int(m_value), m_pt1, m_pt2); } + + // For anything, return an extra point that should also be considered a part of this. + std::optional get_extra_point() const { assert(m_type != SurfaceFeatureType::Undef); return m_pt3; } + + bool operator == (const SurfaceFeature& other) const { + if (this->m_type != other.m_type) return false; + switch (this->m_type) + { + case SurfaceFeatureType::Undef: { break; } + case SurfaceFeatureType::Point: { return (this->m_pt1.isApprox(other.m_pt1)); } + case SurfaceFeatureType::Edge: { + return (this->m_pt1.isApprox(other.m_pt1) && this->m_pt2.isApprox(other.m_pt2)) || + (this->m_pt1.isApprox(other.m_pt2) && this->m_pt2.isApprox(other.m_pt1)); + } + case SurfaceFeatureType::Plane: + case SurfaceFeatureType::Circle: { + return (this->m_pt1.isApprox(other.m_pt1) && this->m_pt2.isApprox(other.m_pt2) && std::abs(this->m_value - other.m_value) < EPSILON); + } + } + + return false; + } + + bool operator != (const SurfaceFeature& other) const { + return !operator == (other); + } + +private: + SurfaceFeatureType m_type{ SurfaceFeatureType::Undef }; + Vec3d m_pt1{ Vec3d::Zero() }; + Vec3d m_pt2{ Vec3d::Zero() }; + std::optional m_pt3; + double m_value{ 0.0 }; +}; + + + +class MeasuringImpl; + + +class Measuring { +public: + // Construct the measurement object on a given its. + explicit Measuring(const indexed_triangle_set& its); + ~Measuring(); + + + // Given a face_idx where the mouse cursor points, return a feature that + // should be highlighted (if any). + std::optional get_feature(size_t face_idx, const Vec3d& point) const; + + // Return total number of planes. + int get_num_of_planes() const; + + // Returns a list of triangle indices for given plane. + const std::vector& get_plane_triangle_indices(int idx) const; + + // Returns the surface features of the plane with the given index + const std::vector& get_plane_features(unsigned int plane_id) const; + + // Returns the mesh used for measuring + const indexed_triangle_set& get_its() const; + +private: + std::unique_ptr priv; +}; + + +struct DistAndPoints { + DistAndPoints(double dist_, Vec3d from_, Vec3d to_) : dist(dist_), from(from_), to(to_) {} + double dist; + Vec3d from; + Vec3d to; +}; + +struct AngleAndEdges { + AngleAndEdges(double angle_, const Vec3d& center_, const std::pair& e1_, const std::pair& e2_, double radius_, bool coplanar_) + : angle(angle_), center(center_), e1(e1_), e2(e2_), radius(radius_), coplanar(coplanar_) {} + double angle; + Vec3d center; + std::pair e1; + std::pair e2; + double radius; + bool coplanar; + + static const AngleAndEdges Dummy; +}; + +struct MeasurementResult { + std::optional angle; + std::optional distance_infinite; + std::optional distance_strict; + std::optional distance_xyz; + + bool has_distance_data() const { + return distance_infinite.has_value() || distance_strict.has_value(); + } + + bool has_any_data() const { + return angle.has_value() || distance_infinite.has_value() || distance_strict.has_value() || distance_xyz.has_value(); + } +}; + +// Returns distance/angle between two SurfaceFeatures. +MeasurementResult get_measurement(const SurfaceFeature& a, const SurfaceFeature& b, const Measuring* measuring = nullptr); + +inline Vec3d edge_direction(const Vec3d& from, const Vec3d& to) { return (to - from).normalized(); } +inline Vec3d edge_direction(const std::pair& e) { return edge_direction(e.first, e.second); } +inline Vec3d edge_direction(const SurfaceFeature& edge) { + assert(edge.get_type() == SurfaceFeatureType::Edge); + return edge_direction(edge.get_edge()); +} + +inline Vec3d plane_normal(const SurfaceFeature& plane) { + assert(plane.get_type() == SurfaceFeatureType::Plane); + return std::get<1>(plane.get_plane()); +} + +inline bool are_parallel(const Vec3d& v1, const Vec3d& v2) { return std::abs(std::abs(v1.dot(v2)) - 1.0) < EPSILON; } +inline bool are_perpendicular(const Vec3d& v1, const Vec3d& v2) { return std::abs(v1.dot(v2)) < EPSILON; } + +inline bool are_parallel(const std::pair& e1, const std::pair& e2) { + return are_parallel(e1.second - e1.first, e2.second - e2.first); +} +inline bool are_parallel(const SurfaceFeature& f1, const SurfaceFeature& f2) { + if (f1.get_type() == SurfaceFeatureType::Edge && f2.get_type() == SurfaceFeatureType::Edge) + return are_parallel(edge_direction(f1), edge_direction(f2)); + else if (f1.get_type() == SurfaceFeatureType::Edge && f2.get_type() == SurfaceFeatureType::Plane) + return are_perpendicular(edge_direction(f1), plane_normal(f2)); + else + return false; +} + +inline bool are_perpendicular(const SurfaceFeature& f1, const SurfaceFeature& f2) { + if (f1.get_type() == SurfaceFeatureType::Edge && f2.get_type() == SurfaceFeatureType::Edge) + return are_perpendicular(edge_direction(f1), edge_direction(f2)); + else if (f1.get_type() == SurfaceFeatureType::Edge && f2.get_type() == SurfaceFeatureType::Plane) + return are_parallel(edge_direction(f1), plane_normal(f2)); + else + return false; +} + +} // namespace Measure +} // namespace Slic3r + +#endif // Slic3r_Measure_hpp_ diff --git a/src/libslic3r/MeasureUtils.hpp b/src/libslic3r/MeasureUtils.hpp new file mode 100644 index 00000000000..8a63de5a1f4 --- /dev/null +++ b/src/libslic3r/MeasureUtils.hpp @@ -0,0 +1,390 @@ +///|/ Copyright (c) Prusa Research 2022 Enrico Turri @enricoturri1966 +///|/ +///|/ PrusaSlicer is released under the terms of the AGPLv3 or higher +///|/ +#ifndef Slic3r_MeasureUtils_hpp_ +#define Slic3r_MeasureUtils_hpp_ + +#include + +namespace Slic3r { +namespace Measure { + +// Utility class used to calculate distance circle-circle +// Adaptation of code found in: +// https://github.com/davideberly/GeometricTools/blob/master/GTE/Mathematics/Polynomial1.h + +class Polynomial1 +{ +public: + Polynomial1(std::initializer_list values) + { + // C++ 11 will call the default constructor for + // Polynomial1 p{}, so it is guaranteed that + // values.size() > 0. + m_coefficient.resize(values.size()); + std::copy(values.begin(), values.end(), m_coefficient.begin()); + EliminateLeadingZeros(); + } + + // Construction and destruction. The first constructor creates a + // polynomial of the specified degree but sets all coefficients to + // zero (to ensure initialization). You are responsible for setting + // the coefficients, presumably with the degree-term set to a nonzero + // number. In the second constructor, the degree is the number of + // initializers plus 1, but then adjusted so that coefficient[degree] + // is not zero (unless all initializer values are zero). + explicit Polynomial1(uint32_t degree) + : m_coefficient(static_cast(degree) + 1, 0.0) + {} + + // Eliminate any leading zeros in the polynomial, except in the case + // the degree is 0 and the coefficient is 0. The elimination is + // necessary when arithmetic operations cause a decrease in the degree + // of the result. For example, (1 + x + x^2) + (1 + 2*x - x^2) = + // (2 + 3*x). The inputs both have degree 2, so the result is created + // with degree 2. After the addition we find that the degree is in + // fact 1 and resize the array of coefficients. This function is + // called internally by the arithmetic operators, but it is exposed in + // the public interface in case you need it for your own purposes. + void EliminateLeadingZeros() + { + const size_t size = m_coefficient.size(); + if (size > 1) { + const double zero = 0.0; + int32_t leading; + for (leading = static_cast(size) - 1; leading > 0; --leading) { + if (m_coefficient[leading] != zero) + break; + } + + m_coefficient.resize(++leading); + } + } + + // Set all coefficients to the specified value. + void SetCoefficients(double value) + { + std::fill(m_coefficient.begin(), m_coefficient.end(), value); + } + + inline uint32_t GetDegree() const + { + // By design, m_coefficient.size() > 0. + return static_cast(m_coefficient.size() - 1); + } + + inline const double& operator[](uint32_t i) const { return m_coefficient[i]; } + inline double& operator[](uint32_t i) { return m_coefficient[i]; } + + // Evaluate the polynomial. If the polynomial is invalid, the + // function returns zero. + double operator()(double t) const + { + int32_t i = static_cast(m_coefficient.size()); + double result = m_coefficient[--i]; + for (--i; i >= 0; --i) { + result *= t; + result += m_coefficient[i]; + } + return result; + } + +protected: + // The class is designed so that m_coefficient.size() >= 1. + std::vector m_coefficient; +}; + +inline Polynomial1 operator * (const Polynomial1& p0, const Polynomial1& p1) +{ + const uint32_t p0Degree = p0.GetDegree(); + const uint32_t p1Degree = p1.GetDegree(); + Polynomial1 result(p0Degree + p1Degree); + result.SetCoefficients(0.0); + for (uint32_t i0 = 0; i0 <= p0Degree; ++i0) { + for (uint32_t i1 = 0; i1 <= p1Degree; ++i1) { + result[i0 + i1] += p0[i0] * p1[i1]; + } + } + return result; +} + +inline Polynomial1 operator + (const Polynomial1& p0, const Polynomial1& p1) +{ + const uint32_t p0Degree = p0.GetDegree(); + const uint32_t p1Degree = p1.GetDegree(); + uint32_t i; + if (p0Degree >= p1Degree) { + Polynomial1 result(p0Degree); + for (i = 0; i <= p1Degree; ++i) { + result[i] = p0[i] + p1[i]; + } + for (/**/; i <= p0Degree; ++i) { + result[i] = p0[i]; + } + result.EliminateLeadingZeros(); + return result; + } + else { + Polynomial1 result(p1Degree); + for (i = 0; i <= p0Degree; ++i) { + result[i] = p0[i] + p1[i]; + } + for (/**/; i <= p1Degree; ++i) { + result[i] = p1[i]; + } + result.EliminateLeadingZeros(); + return result; + } +} + +inline Polynomial1 operator - (const Polynomial1& p0, const Polynomial1& p1) +{ + const uint32_t p0Degree = p0.GetDegree(); + const uint32_t p1Degree = p1.GetDegree(); + uint32_t i; + if (p0Degree >= p1Degree) { + Polynomial1 result(p0Degree); + for (i = 0; i <= p1Degree; ++i) { + result[i] = p0[i] - p1[i]; + } + for (/**/; i <= p0Degree; ++i) { + result[i] = p0[i]; + } + result.EliminateLeadingZeros(); + return result; + } + else { + Polynomial1 result(p1Degree); + for (i = 0; i <= p0Degree; ++i) { + result[i] = p0[i] - p1[i]; + } + for (/**/; i <= p1Degree; ++i) { + result[i] = -p1[i]; + } + result.EliminateLeadingZeros(); + return result; + } +} + +inline Polynomial1 operator * (double scalar, const Polynomial1& p) +{ + const uint32_t degree = p.GetDegree(); + Polynomial1 result(degree); + for (uint32_t i = 0; i <= degree; ++i) { + result[i] = scalar * p[i]; + } + return result; +} + +// Utility class used to calculate distance circle-circle +// Adaptation of code found in: +// https://github.com/davideberly/GeometricTools/blob/master/GTE/Mathematics/RootsPolynomial.h + +class RootsPolynomial +{ +public: + // General equations: sum_{i=0}^{d} c(i)*t^i = 0. The input array 'c' + // must have at least d+1 elements and the output array 'root' must + // have at least d elements. + + // Find the roots on (-infinity,+infinity). + static int32_t Find(int32_t degree, const double* c, uint32_t maxIterations, double* roots) + { + if (degree >= 0 && c != nullptr) { + const double zero = 0.0; + while (degree >= 0 && c[degree] == zero) { + --degree; + } + + if (degree > 0) { + // Compute the Cauchy bound. + const double one = 1.0; + const double invLeading = one / c[degree]; + double maxValue = zero; + for (int32_t i = 0; i < degree; ++i) { + const double value = std::fabs(c[i] * invLeading); + if (value > maxValue) + maxValue = value; + } + const double bound = one + maxValue; + + return FindRecursive(degree, c, -bound, bound, maxIterations, roots); + } + else if (degree == 0) + // The polynomial is a nonzero constant. + return 0; + else { + // The polynomial is identically zero. + roots[0] = zero; + return 1; + } + } + else + // Invalid degree or c. + return 0; + } + + // If you know that p(tmin) * p(tmax) <= 0, then there must be at + // least one root in [tmin, tmax]. Compute it using bisection. + static bool Find(int32_t degree, const double* c, double tmin, double tmax, uint32_t maxIterations, double& root) + { + const double zero = 0.0; + double pmin = Evaluate(degree, c, tmin); + if (pmin == zero) { + root = tmin; + return true; + } + double pmax = Evaluate(degree, c, tmax); + if (pmax == zero) { + root = tmax; + return true; + } + + if (pmin * pmax > zero) + // It is not known whether the interval bounds a root. + return false; + + if (tmin >= tmax) + // Invalid ordering of interval endpoitns. + return false; + + for (uint32_t i = 1; i <= maxIterations; ++i) { + root = 0.5 * (tmin + tmax); + + // This test is designed for 'float' or 'double' when tmin + // and tmax are consecutive floating-point numbers. + if (root == tmin || root == tmax) + break; + + const double p = Evaluate(degree, c, root); + const double product = p * pmin; + if (product < zero) { + tmax = root; + pmax = p; + } + else if (product > zero) { + tmin = root; + pmin = p; + } + else + break; + } + + return true; + } + + // Support for the Find functions. + static int32_t FindRecursive(int32_t degree, double const* c, double tmin, double tmax, uint32_t maxIterations, double* roots) + { + // The base of the recursion. + const double zero = 0.0; + double root = zero; + if (degree == 1) { + int32_t numRoots; + if (c[1] != zero) { + root = -c[0] / c[1]; + numRoots = 1; + } + else if (c[0] == zero) { + root = zero; + numRoots = 1; + } + else + numRoots = 0; + + if (numRoots > 0 && tmin <= root && root <= tmax) { + roots[0] = root; + return 1; + } + return 0; + } + + // Find the roots of the derivative polynomial scaled by 1/degree. + // The scaling avoids the factorial growth in the coefficients; + // for example, without the scaling, the high-order term x^d + // becomes (d!)*x through multiple differentiations. With the + // scaling we instead get x. This leads to better numerical + // behavior of the root finder. + const int32_t derivDegree = degree - 1; + std::vector derivCoeff(static_cast(derivDegree) + 1); + std::vector derivRoots(derivDegree); + for (int32_t i = 0, ip1 = 1; i <= derivDegree; ++i, ++ip1) { + derivCoeff[i] = c[ip1] * (double)(ip1) / (double)degree; + } + const int32_t numDerivRoots = FindRecursive(degree - 1, &derivCoeff[0], tmin, tmax, maxIterations, &derivRoots[0]); + + int32_t numRoots = 0; + if (numDerivRoots > 0) { + // Find root on [tmin,derivRoots[0]]. + if (Find(degree, c, tmin, derivRoots[0], maxIterations, root)) + roots[numRoots++] = root; + + // Find root on [derivRoots[i],derivRoots[i+1]]. + for (int32_t i = 0, ip1 = 1; i <= numDerivRoots - 2; ++i, ++ip1) { + if (Find(degree, c, derivRoots[i], derivRoots[ip1], maxIterations, root)) + roots[numRoots++] = root; + } + + // Find root on [derivRoots[numDerivRoots-1],tmax]. + if (Find(degree, c, derivRoots[static_cast(numDerivRoots) - 1], tmax, maxIterations, root)) + roots[numRoots++] = root; + } + else { + // The polynomial is monotone on [tmin,tmax], so has at most one root. + if (Find(degree, c, tmin, tmax, maxIterations, root)) + roots[numRoots++] = root; + } + return numRoots; + } + + static double Evaluate(int32_t degree, const double* c, double t) + { + int32_t i = degree; + double result = c[i]; + while (--i >= 0) { + result = t * result + c[i]; + } + return result; + } +}; + +// Adaptation of code found in: +// https://github.com/davideberly/GeometricTools/blob/master/GTE/Mathematics/Vector.h + +// Construct a single vector orthogonal to the nonzero input vector. If +// the maximum absolute component occurs at index i, then the orthogonal +// vector U has u[i] = v[i+1], u[i+1] = -v[i], and all other components +// zero. The index addition i+1 is computed modulo N. +inline Vec3d get_orthogonal(const Vec3d& v, bool unitLength) +{ + double cmax = std::fabs(v[0]); + int32_t imax = 0; + for (int32_t i = 1; i < 3; ++i) { + double c = std::fabs(v[i]); + if (c > cmax) { + cmax = c; + imax = i; + } + } + + Vec3d result = Vec3d::Zero(); + int32_t inext = imax + 1; + if (inext == 3) + inext = 0; + + result[imax] = v[inext]; + result[inext] = -v[imax]; + if (unitLength) { + const double sqrDistance = result[imax] * result[imax] + result[inext] * result[inext]; + const double invLength = 1.0 / std::sqrt(sqrDistance); + result[imax] *= invLength; + result[inext] *= invLength; + } + return result; +} + +} // namespace Slic3r +} // namespace Measure + +#endif // Slic3r_MeasureUtils_hpp_ diff --git a/src/libslic3r/SurfaceMesh.hpp b/src/libslic3r/SurfaceMesh.hpp new file mode 100644 index 00000000000..976387c21f6 --- /dev/null +++ b/src/libslic3r/SurfaceMesh.hpp @@ -0,0 +1,167 @@ +///|/ Copyright (c) Prusa Research 2022 Lukáš Matěna @lukasmatena +///|/ +///|/ PrusaSlicer is released under the terms of the AGPLv3 or higher +///|/ +#ifndef slic3r_SurfaceMesh_hpp_ +#define slic3r_SurfaceMesh_hpp_ + +#include +#include + +#include "boost/container/small_vector.hpp" + +namespace Slic3r { + +class TriangleMesh; + + + +enum Face_index : int; + +class Halfedge_index { + friend class SurfaceMesh; + +public: + Halfedge_index() : m_face(Face_index(-1)), m_side(0) {} + Face_index face() const { return m_face; } + unsigned char side() const { return m_side; } + bool is_invalid() const { return int(m_face) < 0; } + bool operator!=(const Halfedge_index& rhs) const { return ! ((*this) == rhs); } + bool operator==(const Halfedge_index& rhs) const { return m_face == rhs.m_face && m_side == rhs.m_side; } + +private: + Halfedge_index(int face_idx, unsigned char side_idx) : m_face(Face_index(face_idx)), m_side(side_idx) {} + + Face_index m_face; + unsigned char m_side; +}; + + + +class Vertex_index { + friend class SurfaceMesh; + +public: + Vertex_index() : m_face(Face_index(-1)), m_vertex_idx(0) {} + bool is_invalid() const { return int(m_face) < 0; } + bool operator==(const Vertex_index& rhs) const = delete; // Use SurfaceMesh::is_same_vertex. + +private: + Vertex_index(int face_idx, unsigned char vertex_idx) : m_face(Face_index(face_idx)), m_vertex_idx(vertex_idx) {} + + Face_index m_face; + unsigned char m_vertex_idx; +}; + + + +class SurfaceMesh { +public: + explicit SurfaceMesh(const indexed_triangle_set& its) + : m_its(its), + m_face_neighbors(its_face_neighbors_par(its)) + {} + SurfaceMesh(const SurfaceMesh&) = delete; + SurfaceMesh& operator=(const SurfaceMesh&) = delete; + + Vertex_index source(Halfedge_index h) const { assert(! h.is_invalid()); return Vertex_index(h.m_face, h.m_side); } + Vertex_index target(Halfedge_index h) const { assert(! h.is_invalid()); return Vertex_index(h.m_face, h.m_side == 2 ? 0 : h.m_side + 1); } + Face_index face(Halfedge_index h) const { assert(! h.is_invalid()); return h.m_face; } + + Halfedge_index next(Halfedge_index h) const { assert(! h.is_invalid()); h.m_side = (h.m_side + 1) % 3; return h; } + Halfedge_index prev(Halfedge_index h) const { assert(! h.is_invalid()); h.m_side = (h.m_side == 0 ? 2 : h.m_side - 1); return h; } + Halfedge_index halfedge(Vertex_index v) const { return Halfedge_index(v.m_face, (v.m_vertex_idx == 0 ? 2 : v.m_vertex_idx - 1)); } + Halfedge_index halfedge(Face_index f) const { return Halfedge_index(f, 0); } + Halfedge_index opposite(Halfedge_index h) const { + if (h.is_invalid()) + return h; + + int face_idx = m_face_neighbors[h.m_face][h.m_side]; + Halfedge_index h_candidate = halfedge(Face_index(face_idx)); + + if (h_candidate.is_invalid()) + return Halfedge_index(); // invalid + + for (int i=0; i<3; ++i) { + if (is_same_vertex(source(h_candidate), target(h))) { + // Meshes in PrusaSlicer should be fixed enough for the following not to happen. + assert(is_same_vertex(target(h_candidate), source(h))); + return h_candidate; + } + h_candidate = next(h_candidate); + } + return Halfedge_index(); // invalid + } + + Halfedge_index next_around_target(Halfedge_index h) const { return opposite(next(h)); } + Halfedge_index prev_around_target(Halfedge_index h) const { Halfedge_index op = opposite(h); return (op.is_invalid() ? Halfedge_index() : prev(op)); } + Halfedge_index next_around_source(Halfedge_index h) const { Halfedge_index op = opposite(h); return (op.is_invalid() ? Halfedge_index() : next(op)); } + Halfedge_index prev_around_source(Halfedge_index h) const { return opposite(prev(h)); } + Halfedge_index halfedge(Vertex_index source, Vertex_index target) const + { + Halfedge_index hi(source.m_face, source.m_vertex_idx); + assert(! hi.is_invalid()); + + const Vertex_index orig_target = this->target(hi); + Vertex_index current_target = orig_target; + + while (! is_same_vertex(current_target, target)) { + hi = next_around_source(hi); + if (hi.is_invalid()) + break; + current_target = this->target(hi); + if (is_same_vertex(current_target, orig_target)) + return Halfedge_index(); // invalid + } + + return hi; + } + + const stl_vertex& point(Vertex_index v) const { return m_its.vertices[m_its.indices[v.m_face][v.m_vertex_idx]]; } + + size_t degree(Vertex_index v) const + { + // In case the mesh is broken badly, the loop might end up to be infinite, + // never getting back to the first halfedge. Remember list of all half-edges + // and trip if any is encountered for the second time. + Halfedge_index h_first = halfedge(v); + boost::container::small_vector he_visited; + Halfedge_index h = next_around_target(h_first); + size_t degree = 2; + while (! h.is_invalid() && h != h_first) { + he_visited.emplace_back(h); + h = next_around_target(h); + if (std::find(he_visited.begin(), he_visited.end(), h) == he_visited.end()) + return 0; + ++degree; + } + return h.is_invalid() ? 0 : degree - 1; + } + + size_t degree(Face_index f) const { + size_t total = 0; + for (unsigned char i=0; i<3; ++i) { + size_t d = degree(Vertex_index(f, i)); + if (d == 0) + return 0; + total += d; + } + assert(total - 6 >= 0); + return total - 6; // we counted 3 halfedges from f, and one more for each neighbor + } + + bool is_border(Halfedge_index h) const { return m_face_neighbors[h.m_face][h.m_side] == -1; } + + bool is_same_vertex(const Vertex_index& a, const Vertex_index& b) const { return m_its.indices[a.m_face][a.m_vertex_idx] == m_its.indices[b.m_face][b.m_vertex_idx]; } + Vec3i get_face_neighbors(Face_index face_id) const { assert(int(face_id) < int(m_face_neighbors.size())); return m_face_neighbors[face_id]; } + + + +private: + const std::vector m_face_neighbors; + const indexed_triangle_set& m_its; +}; + +} //namespace Slic3r + +#endif // slic3r_SurfaceMesh_hpp_ diff --git a/src/slic3r/CMakeLists.txt b/src/slic3r/CMakeLists.txt index 4b9a967f9eb..e1404b09a5f 100644 --- a/src/slic3r/CMakeLists.txt +++ b/src/slic3r/CMakeLists.txt @@ -1,3 +1,12 @@ +#/|/ Copyright (c) Prusa Research 2018 - 2023 Tomáš Mészáros @tamasmeszaros, David Kocík @kocikdav, Lukáš Matěna @lukasmatena, Enrico Turri @enricoturri1966, Vojtěch Bubník @bubnikv, Pavel Mikuš @Godrak, Filip Sykala @Jony01, Oleksandra Iushchenko @YuSanka, Lukáš Hejl @hejllukas, Vojtěch Král @vojtechkral +#/|/ Copyright (c) 2023 Pedro Lamas @PedroLamas +#/|/ Copyright (c) 2020 Sergey Kovalev @RandoMan70 +#/|/ Copyright (c) 2021 Boleslaw Ciesielski +#/|/ Copyright (c) 2019 Spencer Owen @spuder +#/|/ Copyright (c) 2019 Stephan Reichhelm @stephanr +#/|/ +#/|/ PrusaSlicer is released under the terms of the AGPLv3 or higher +#/|/ cmake_minimum_required(VERSION 3.13) project(libslic3r_gui) @@ -135,6 +144,8 @@ set(SLIC3R_GUI_SOURCES GUI/Gizmos/GLGizmoMmuSegmentation.hpp #GUI/Gizmos/GLGizmoFaceDetector.cpp #GUI/Gizmos/GLGizmoFaceDetector.hpp + GUI/Gizmos/GLGizmoMeasure.cpp + GUI/Gizmos/GLGizmoMeasure.hpp GUI/Gizmos/GLGizmoSeam.cpp GUI/Gizmos/GLGizmoSeam.hpp GUI/Gizmos/GLGizmoText.cpp @@ -175,6 +186,8 @@ set(SLIC3R_GUI_SOURCES GUI/GUI_App.hpp GUI/GUI_Utils.cpp GUI/GUI_Utils.hpp + GUI/GUI_Geometry.cpp + GUI/GUI_Geometry.hpp GUI/I18N.cpp GUI/I18N.hpp GUI/MainFrame.cpp diff --git a/src/slic3r/GUI/3DScene.hpp b/src/slic3r/GUI/3DScene.hpp index e04e71ab45f..0d52ba48821 100644 --- a/src/slic3r/GUI/3DScene.hpp +++ b/src/slic3r/GUI/3DScene.hpp @@ -1,3 +1,14 @@ +///|/ Copyright (c) Prusa Research 2017 - 2023 Lukáš Matěna @lukasmatena, Enrico Turri @enricoturri1966, Oleksandra Iushchenko @YuSanka, Tomáš Mészáros @tamasmeszaros, Filip Sykala @Jony01, Vojtěch Bubník @bubnikv, David Kocík @kocikdav, Vojtěch Král @vojtechkral +///|/ Copyright (c) 2017 Eyal Soha @eyal0 +///|/ Copyright (c) Slic3r 2015 Alessandro Ranellucci @alranel +///|/ +///|/ ported from lib/Slic3r/GUI/3DScene.pm: +///|/ Copyright (c) Prusa Research 2016 - 2019 Vojtěch Bubník @bubnikv, Enrico Turri @enricoturri1966, Oleksandra Iushchenko @YuSanka +///|/ Copyright (c) Slic3r 2013 - 2016 Alessandro Ranellucci @alranel +///|/ Copyright (c) 2013 Guillaume Seguin @iXce +///|/ +///|/ PrusaSlicer is released under the terms of the AGPLv3 or higher +///|/ #ifndef slic3r_3DScene_hpp_ #define slic3r_3DScene_hpp_ diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index b00657faea5..dcf2713fb5d 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -2189,15 +2189,11 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re if (!m_initialized) return; - + _set_current(); m_hover_volume_idxs.clear(); - GLGizmoBase* curr_gizmo = m_gizmos.get_current(); - if (curr_gizmo != nullptr) - curr_gizmo->unregister_raycasters_for_picking(); - struct ModelVolumeState { ModelVolumeState(const GLVolume* volume) : model_volume(nullptr), geometry_id(volume->geometry_id), volume_idx(-1) {} @@ -2656,6 +2652,8 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re else m_selection.volumes_changed(map_glvolume_old_to_new); + // @Enrico suggest this solution to preven accessing pointer on caster without data + m_scene_raycaster.remove_raycasters(SceneRaycaster::EType::Volume); m_gizmos.update_data(); m_gizmos.update_assemble_view_data(); m_gizmos.refresh_on_off_state(); @@ -2663,9 +2661,7 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re // Update the toolbar //BBS: notify the PartPlateList to reload all objects if (update_object_list) - { post_event(SimpleEvent(EVT_GLCANVAS_OBJECT_SELECT)); - } //BBS:exclude the assmble view if (m_canvas_type != ECanvasType::CanvasAssembleView) { @@ -2711,14 +2707,19 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re } // refresh volume raycasters for picking - m_scene_raycaster.remove_raycasters(SceneRaycaster::EType::Volume); for (size_t i = 0; i < m_volumes.volumes.size(); ++i) { - assert(m_volumes.volumes[i]->mesh_raycaster != nullptr); - add_raycaster_for_picking(SceneRaycaster::EType::Volume, i, *m_volumes.volumes[i]->mesh_raycaster, m_volumes.volumes[i]->world_matrix()); + const GLVolume* v = m_volumes.volumes[i]; + assert(v->mesh_raycaster != nullptr); + std::shared_ptr raycaster = add_raycaster_for_picking(SceneRaycaster::EType::Volume, i, *v->mesh_raycaster, v->world_matrix()); + raycaster->set_active(v->is_active); } // refresh gizmo elements raycasters for picking + GLGizmoBase* curr_gizmo = m_gizmos.get_current(); + if (curr_gizmo != nullptr) + curr_gizmo->unregister_raycasters_for_picking(); m_scene_raycaster.remove_raycasters(SceneRaycaster::EType::Gizmo); + m_scene_raycaster.remove_raycasters(SceneRaycaster::EType::FallbackGizmo); if (curr_gizmo != nullptr && !m_selection.is_empty()) curr_gizmo->register_raycasters_for_picking(); @@ -6434,6 +6435,7 @@ void GLCanvas3D::_picking_pass() break; } case SceneRaycaster::EType::Gizmo: + case SceneRaycaster::EType::FallbackGizmo: { const Size& cnv_size = get_canvas_size(); const bool inside = 0 <= m_mouse.position.x() && m_mouse.position.x() < cnv_size.get_width() && @@ -6474,42 +6476,94 @@ void GLCanvas3D::_picking_pass() { case SceneRaycaster::EType::Bed: { object_type = "Bed"; break; } case SceneRaycaster::EType::Gizmo: { object_type = "Gizmo element"; break; } + case SceneRaycaster::EType::FallbackGizmo: { object_type = "Gizmo2 element"; break; } case SceneRaycaster::EType::Volume: { if (m_volumes.volumes[hit.raycaster_id]->is_wipe_tower) - object_type = "Wipe tower"; + object_type = "Volume (Wipe tower)"; else if (m_volumes.volumes[hit.raycaster_id]->volume_idx() == -int(slaposPad)) - object_type = "SLA pad"; + object_type = "Volume (SLA pad)"; else if (m_volumes.volumes[hit.raycaster_id]->volume_idx() == -int(slaposSupportTree)) - object_type = "SLA supports"; + object_type = "Volume (SLA supports)"; + else if (m_volumes.volumes[hit.raycaster_id]->is_modifier) + object_type = "Volume (Modifier)"; else - object_type = "Volume"; + object_type = "Volume (Part)"; break; } default: { break; } } + + auto add_strings_row_to_table = [&imgui](const std::string& col_1, const ImVec4& col_1_color, const std::string& col_2, const ImVec4& col_2_color, + const std::string& col_3 = "", const ImVec4& col_3_color = ImGui::GetStyleColorVec4(ImGuiCol_Text)) { + ImGui::TableNextRow(); + ImGui::TableSetColumnIndex(0); + imgui.text_colored(col_1_color, col_1.c_str()); + ImGui::TableSetColumnIndex(1); + imgui.text_colored(col_2_color, col_2.c_str()); + if (!col_3.empty()) { + ImGui::TableSetColumnIndex(2); + imgui.text_colored(col_3_color, col_3.c_str()); + } + }; + char buf[1024]; if (hit.type != SceneRaycaster::EType::None) { - sprintf(buf, "Object ID: %d", hit.raycaster_id); - imgui.text(std::string(buf)); - sprintf(buf, "Type: %s", object_type.c_str()); - imgui.text(std::string(buf)); - sprintf(buf, "Position: %.3f, %.3f, %.3f", hit.position.x(), hit.position.y(), hit.position.z()); - imgui.text(std::string(buf)); - sprintf(buf, "Normal: %.3f, %.3f, %.3f", hit.normal.x(), hit.normal.y(), hit.normal.z()); - imgui.text(std::string(buf)); + if (ImGui::BeginTable("Hit", 2)) { + add_strings_row_to_table("Object ID", ImGuiWrapper::COL_ORANGE_LIGHT, std::to_string(hit.raycaster_id), ImGui::GetStyleColorVec4(ImGuiCol_Text)); + add_strings_row_to_table("Type", ImGuiWrapper::COL_ORANGE_LIGHT, object_type, ImGui::GetStyleColorVec4(ImGuiCol_Text)); + sprintf(buf, "%.3f, %.3f, %.3f", hit.position.x(), hit.position.y(), hit.position.z()); + add_strings_row_to_table("Position", ImGuiWrapper::COL_ORANGE_LIGHT, std::string(buf), ImGui::GetStyleColorVec4(ImGuiCol_Text)); + sprintf(buf, "%.3f, %.3f, %.3f", hit.normal.x(), hit.normal.y(), hit.normal.z()); + add_strings_row_to_table("Normal", ImGuiWrapper::COL_ORANGE_LIGHT, std::string(buf), ImGui::GetStyleColorVec4(ImGuiCol_Text)); + ImGui::EndTable(); + } } else imgui.text("NO HIT"); ImGui::Separator(); imgui.text("Registered for picking:"); - sprintf(buf, "Beds: %d", (int)m_scene_raycaster.beds_count()); - imgui.text(std::string(buf)); - sprintf(buf, "Volumes: %d", (int)m_scene_raycaster.volumes_count()); - imgui.text(std::string(buf)); - sprintf(buf, "Gizmo elements: %d", (int)m_scene_raycaster.gizmos_count()); - imgui.text(std::string(buf)); + if (ImGui::BeginTable("Raycasters", 2)) { + sprintf(buf, "%d (%d)", (int)m_scene_raycaster.beds_count(), (int)m_scene_raycaster.active_beds_count()); + add_strings_row_to_table("Beds", ImGuiWrapper::COL_ORANGE_LIGHT, std::string(buf), ImGui::GetStyleColorVec4(ImGuiCol_Text)); + sprintf(buf, "%d (%d)", (int)m_scene_raycaster.volumes_count(), (int)m_scene_raycaster.active_volumes_count()); + add_strings_row_to_table("Volumes", ImGuiWrapper::COL_ORANGE_LIGHT, std::string(buf), ImGui::GetStyleColorVec4(ImGuiCol_Text)); + sprintf(buf, "%d (%d)", (int)m_scene_raycaster.gizmos_count(), (int)m_scene_raycaster.active_gizmos_count()); + add_strings_row_to_table("Gizmo elements", ImGuiWrapper::COL_ORANGE_LIGHT, std::string(buf), ImGui::GetStyleColorVec4(ImGuiCol_Text)); + sprintf(buf, "%d (%d)", (int)m_scene_raycaster.fallback_gizmos_count(), (int)m_scene_raycaster.active_fallback_gizmos_count()); + add_strings_row_to_table("Gizmo2 elements", ImGuiWrapper::COL_ORANGE_LIGHT, std::string(buf), ImGui::GetStyleColorVec4(ImGuiCol_Text)); + ImGui::EndTable(); + } + + std::vector>* gizmo_raycasters = m_scene_raycaster.get_raycasters(SceneRaycaster::EType::Gizmo); + if (gizmo_raycasters != nullptr && !gizmo_raycasters->empty()) { + ImGui::Separator(); + imgui.text("Gizmo raycasters IDs:"); + if (ImGui::BeginTable("GizmoRaycasters", 3)) { + for (size_t i = 0; i < gizmo_raycasters->size(); ++i) { + add_strings_row_to_table(std::to_string(i), ImGuiWrapper::COL_ORANGE_LIGHT, + std::to_string(SceneRaycaster::decode_id(SceneRaycaster::EType::Gizmo, (*gizmo_raycasters)[i]->get_id())), ImGui::GetStyleColorVec4(ImGuiCol_Text), + to_string(Geometry::Transformation((*gizmo_raycasters)[i]->get_transform()).get_offset()), ImGui::GetStyleColorVec4(ImGuiCol_Text)); + } + ImGui::EndTable(); + } + } + + std::vector>* gizmo2_raycasters = m_scene_raycaster.get_raycasters(SceneRaycaster::EType::FallbackGizmo); + if (gizmo2_raycasters != nullptr && !gizmo2_raycasters->empty()) { + ImGui::Separator(); + imgui.text("Gizmo2 raycasters IDs:"); + if (ImGui::BeginTable("Gizmo2Raycasters", 3)) { + for (size_t i = 0; i < gizmo2_raycasters->size(); ++i) { + add_strings_row_to_table(std::to_string(i), ImGuiWrapper::COL_ORANGE_LIGHT, + std::to_string(SceneRaycaster::decode_id(SceneRaycaster::EType::FallbackGizmo, (*gizmo2_raycasters)[i]->get_id())), ImGui::GetStyleColorVec4(ImGuiCol_Text), + to_string(Geometry::Transformation((*gizmo2_raycasters)[i]->get_transform()).get_offset()), ImGui::GetStyleColorVec4(ImGuiCol_Text)); + } + ImGui::EndTable(); + } + } + imgui.end(); #endif // ENABLE_RAYCAST_PICKING_DEBUG } diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp index b1f73fefab0..afcd5bdcb8b 100644 --- a/src/slic3r/GUI/GLCanvas3D.hpp +++ b/src/slic3r/GUI/GLCanvas3D.hpp @@ -1,3 +1,8 @@ +///|/ Copyright (c) Prusa Research 2018 - 2023 Enrico Turri @enricoturri1966, Tomáš Mészáros @tamasmeszaros, Lukáš Matěna @lukasmatena, Oleksandra Iushchenko @YuSanka, Filip Sykala @Jony01, Vojtěch Bubník @bubnikv, Lukáš Hejl @hejllukas, David Kocík @kocikdav, Vojtěch Král @vojtechkral +///|/ Copyright (c) BambuStudio 2023 manch1n @manch1n +///|/ +///|/ PrusaSlicer is released under the terms of the AGPLv3 or higher +///|/ #ifndef slic3r_GLCanvas3D_hpp_ #define slic3r_GLCanvas3D_hpp_ @@ -724,9 +729,9 @@ class GLCanvas3D bool init(); void post_event(wxEvent &&event); - + std::shared_ptr add_raycaster_for_picking(SceneRaycaster::EType type, int id, const MeshRaycaster& raycaster, - const Transform3d& trafo, bool use_back_faces = false) { + const Transform3d& trafo = Transform3d::Identity(), bool use_back_faces = false) { return m_scene_raycaster.add_raycaster(type, id, raycaster, trafo, use_back_faces); } void remove_raycasters_for_picking(SceneRaycaster::EType type, int id) { diff --git a/src/slic3r/GUI/GLModel.cpp b/src/slic3r/GUI/GLModel.cpp index 97ef65978fb..959c9aa9ac6 100644 --- a/src/slic3r/GUI/GLModel.cpp +++ b/src/slic3r/GUI/GLModel.cpp @@ -1,3 +1,7 @@ +///|/ Copyright (c) Prusa Research 2020 - 2023 Enrico Turri @enricoturri1966, Vojtěch Bubník @bubnikv, Filip Sykala @Jony01 +///|/ +///|/ PrusaSlicer is released under the terms of the AGPLv3 or higher +///|/ #include "libslic3r/libslic3r.h" #include "GLModel.hpp" @@ -247,6 +251,21 @@ void GLModel::Geometry::remove_vertex(size_t id) } } +indexed_triangle_set GLModel::Geometry::get_as_indexed_triangle_set() const +{ + indexed_triangle_set its; + its.vertices.reserve(vertices_count()); + for (size_t i = 0; i < vertices_count(); ++i) { + its.vertices.emplace_back(extract_position_3(i)); + } + its.indices.reserve(indices_count() / 3); + for (size_t i = 0; i < indices_count() / 3; ++i) { + const size_t tri_id = i * 3; + its.indices.emplace_back(extract_index(tri_id), extract_index(tri_id + 1), extract_index(tri_id + 2)); + } + return its; +} + size_t GLModel::Geometry::vertex_stride_floats(const Format& format) { switch (format.vertex_layout) @@ -1212,5 +1231,190 @@ GLModel::Geometry diamond(unsigned int resolution) return data; } +GLModel::Geometry smooth_sphere(unsigned int resolution, float radius) +{ + resolution = std::max(4, resolution); + + const unsigned int sectorCount = resolution; + const unsigned int stackCount = resolution; + + const float sectorStep = float(2.0 * M_PI / sectorCount); + const float stackStep = float(M_PI / stackCount); + + GLModel::Geometry data; + data.format = { GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3N3 }; + data.reserve_vertices((stackCount - 1) * sectorCount + 2); + data.reserve_indices((2 * (stackCount - 1) * sectorCount) * 3); + + // vertices + for (unsigned int i = 0; i <= stackCount; ++i) { + // from pi/2 to -pi/2 + const double stackAngle = 0.5 * M_PI - stackStep * i; + const double xy = double(radius) * ::cos(stackAngle); + const double z = double(radius) * ::sin(stackAngle); + if (i == 0 || i == stackCount) { + const Vec3f v(float(xy), 0.0f, float(z)); + data.add_vertex(v, (Vec3f)v.normalized()); + } + else { + for (unsigned int j = 0; j < sectorCount; ++j) { + // from 0 to 2pi + const double sectorAngle = sectorStep * j; + const Vec3f v(float(xy * std::cos(sectorAngle)), float(xy * std::sin(sectorAngle)), float(z)); + data.add_vertex(v, (Vec3f)v.normalized()); + } + } + } + + // triangles + for (unsigned int i = 0; i < stackCount; ++i) { + // Beginning of current stack. + unsigned int k1 = (i == 0) ? 0 : (1 + (i - 1) * sectorCount); + const unsigned int k1_first = k1; + // Beginning of next stack. + unsigned int k2 = (i == 0) ? 1 : (k1 + sectorCount); + const unsigned int k2_first = k2; + for (unsigned int j = 0; j < sectorCount; ++j) { + // 2 triangles per sector excluding first and last stacks + unsigned int k1_next = k1; + unsigned int k2_next = k2; + if (i != 0) { + k1_next = (j + 1 == sectorCount) ? k1_first : (k1 + 1); + data.add_triangle(k1, k2, k1_next); + } + if (i + 1 != stackCount) { + k2_next = (j + 1 == sectorCount) ? k2_first : (k2 + 1); + data.add_triangle(k1_next, k2, k2_next); + } + k1 = k1_next; + k2 = k2_next; + } + } + + return data; +} + +GLModel::Geometry smooth_cylinder(unsigned int resolution, float radius, float height) +{ + resolution = std::max(4, resolution); + + const unsigned int sectorCount = resolution; + const float sectorStep = 2.0f * float(M_PI) / float(sectorCount); + + GLModel::Geometry data; + data.format = { GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3N3 }; + data.reserve_vertices(sectorCount * 4 + 2); + data.reserve_indices(sectorCount * 4 * 3); + + auto generate_vertices_on_circle = [sectorCount, sectorStep](float radius) { + std::vector ret; + ret.reserve(sectorCount); + for (unsigned int i = 0; i < sectorCount; ++i) { + // from 0 to 2pi + const float sectorAngle = sectorStep * i; + ret.emplace_back(radius * std::cos(sectorAngle), radius * std::sin(sectorAngle), 0.0f); + } + return ret; + }; + + const std::vector base_vertices = generate_vertices_on_circle(radius); + const Vec3f h = height * Vec3f::UnitZ(); + + // stem vertices + for (unsigned int i = 0; i < sectorCount; ++i) { + const Vec3f& v = base_vertices[i]; + const Vec3f n = v.normalized(); + data.add_vertex(v, n); + data.add_vertex(v + h, n); + } + + // stem triangles + for (unsigned int i = 0; i < sectorCount; ++i) { + unsigned int v1 = i * 2; + unsigned int v2 = (i < sectorCount - 1) ? v1 + 2 : 0; + unsigned int v3 = v2 + 1; + unsigned int v4 = v1 + 1; + data.add_triangle(v1, v2, v3); + data.add_triangle(v1, v3, v4); + } + + // bottom cap vertices + Vec3f cap_center = Vec3f::Zero(); + unsigned int cap_center_id = data.vertices_count(); + Vec3f normal = -Vec3f::UnitZ(); + + data.add_vertex(cap_center, normal); + for (unsigned int i = 0; i < sectorCount; ++i) { + data.add_vertex(base_vertices[i], normal); + } + + // bottom cap triangles + for (unsigned int i = 0; i < sectorCount; ++i) { + data.add_triangle(cap_center_id, (i < sectorCount - 1) ? cap_center_id + i + 2 : cap_center_id + 1, cap_center_id + i + 1); + } + + // top cap vertices + cap_center += h; + cap_center_id = data.vertices_count(); + normal = -normal; + + data.add_vertex(cap_center, normal); + for (unsigned int i = 0; i < sectorCount; ++i) { + data.add_vertex(base_vertices[i] + h, normal); + } + + // top cap triangles + for (unsigned int i = 0; i < sectorCount; ++i) { + data.add_triangle(cap_center_id, cap_center_id + i + 1, (i < sectorCount - 1) ? cap_center_id + i + 2 : cap_center_id + 1); + } + + return data; +} + +GLModel::Geometry smooth_torus(unsigned int primary_resolution, unsigned int secondary_resolution, float radius, float thickness) +{ + const unsigned int torus_sector_count = std::max(4, primary_resolution); + const float torus_sector_step = 2.0f * float(M_PI) / float(torus_sector_count); + const unsigned int section_sector_count = std::max(4, secondary_resolution); + const float section_sector_step = 2.0f * float(M_PI) / float(section_sector_count); + + GLModel::Geometry data; + data.format = { GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3N3 }; + data.reserve_vertices(torus_sector_count * section_sector_count); + data.reserve_indices(torus_sector_count * section_sector_count * 2 * 3); + + // vertices + for (unsigned int i = 0; i < torus_sector_count; ++i) { + const float section_angle = torus_sector_step * i; + const float csa = std::cos(section_angle); + const float ssa = std::sin(section_angle); + const Vec3f section_center(radius * csa, radius * ssa, 0.0f); + for (unsigned int j = 0; j < section_sector_count; ++j) { + const float circle_angle = section_sector_step * j; + const float thickness_xy = thickness * std::cos(circle_angle); + const float thickness_z = thickness * std::sin(circle_angle); + const Vec3f v(thickness_xy * csa, thickness_xy * ssa, thickness_z); + data.add_vertex(section_center + v, (Vec3f)v.normalized()); + } + } + + // triangles + for (unsigned int i = 0; i < torus_sector_count; ++i) { + const unsigned int ii = i * section_sector_count; + const unsigned int ii_next = ((i + 1) % torus_sector_count) * section_sector_count; + for (unsigned int j = 0; j < section_sector_count; ++j) { + const unsigned int j_next = (j + 1) % section_sector_count; + const unsigned int i0 = ii + j; + const unsigned int i1 = ii_next + j; + const unsigned int i2 = ii_next + j_next; + const unsigned int i3 = ii + j_next; + data.add_triangle(i0, i1, i2); + data.add_triangle(i0, i2, i3); + } + } + + return data; +} + } // namespace GUI } // namespace Slic3r diff --git a/src/slic3r/GUI/GLModel.hpp b/src/slic3r/GUI/GLModel.hpp index 7089f11e15a..e90c263eced 100644 --- a/src/slic3r/GUI/GLModel.hpp +++ b/src/slic3r/GUI/GLModel.hpp @@ -1,3 +1,7 @@ +///|/ Copyright (c) Prusa Research 2020 - 2023 Enrico Turri @enricoturri1966, Vojtěch Bubník @bubnikv, Filip Sykala @Jony01, Lukáš Matěna @lukasmatena +///|/ +///|/ PrusaSlicer is released under the terms of the AGPLv3 or higher +///|/ #ifndef slic3r_GLModel_hpp_ #define slic3r_GLModel_hpp_ @@ -101,6 +105,8 @@ namespace GUI { size_t vertices_size_bytes() const { return vertices_size_floats() * sizeof(float); } size_t indices_size_bytes() const { return indices.size() * index_stride_bytes(*this); } + indexed_triangle_set get_as_indexed_triangle_set() const; + static size_t vertex_stride_floats(const Format& format); static size_t vertex_stride_bytes(const Format& format) { return vertex_stride_floats(format) * sizeof(float); } @@ -233,6 +239,18 @@ namespace GUI { // the diamond is contained into a box with size [1, 1, 1] GLModel::Geometry diamond(unsigned int resolution); + // create a sphere with smooth normals + // the origin of the sphere is in its center + GLModel::Geometry smooth_sphere(unsigned int resolution, float radius); + // create a cylinder with smooth normals + // the axis of the cylinder is the Z axis + // the origin of the cylinder is the center of its bottom cap face + GLModel::Geometry smooth_cylinder(unsigned int resolution, float radius, float height); + // create a torus with smooth normals + // the axis of the torus is the Z axis + // the origin of the torus is in its center + GLModel::Geometry smooth_torus(unsigned int primary_resolution, unsigned int secondary_resolution, float radius, float thickness); + } // namespace GUI } // namespace Slic3r diff --git a/src/slic3r/GUI/GUI_Geometry.cpp b/src/slic3r/GUI/GUI_Geometry.cpp new file mode 100644 index 00000000000..3cee023e122 --- /dev/null +++ b/src/slic3r/GUI/GUI_Geometry.cpp @@ -0,0 +1,13 @@ +///|/ Copyright (c) Prusa Research 2021 Enrico Turri @enricoturri1966 +///|/ +///|/ PrusaSlicer is released under the terms of the AGPLv3 or higher +///|/ +#include "libslic3r/libslic3r.h" +#include "GUI_Geometry.hpp" + +namespace Slic3r { +namespace GUI { + + +} // namespace Slic3r +} // namespace GUI diff --git a/src/slic3r/GUI/GUI_Geometry.hpp b/src/slic3r/GUI/GUI_Geometry.hpp new file mode 100644 index 00000000000..ed89af649c3 --- /dev/null +++ b/src/slic3r/GUI/GUI_Geometry.hpp @@ -0,0 +1,82 @@ +///|/ Copyright (c) Prusa Research 2021 - 2023 Enrico Turri @enricoturri1966 +///|/ +///|/ PrusaSlicer is released under the terms of the AGPLv3 or higher +///|/ +#ifndef slic3r_GUI_Geometry_hpp_ +#define slic3r_GUI_Geometry_hpp_ + +namespace Slic3r { +namespace GUI { + +enum class ECoordinatesType : unsigned char +{ + World, + Instance, + Local +}; + +class TransformationType +{ +public: + enum Enum { + // Transforming in a world coordinate system + World = 0, + // Transforming in a instance coordinate system + Instance = 1, + // Transforming in a local coordinate system + Local = 2, + // Absolute transformations, allowed in local coordinate system only. + Absolute = 0, + // Relative transformations, allowed in both local and world coordinate system. + Relative = 4, + // For group selection, the transformation is performed as if the group made a single solid body. + Joint = 0, + // For group selection, the transformation is performed on each object independently. + Independent = 8, + + World_Relative_Joint = World | Relative | Joint, + World_Relative_Independent = World | Relative | Independent, + Instance_Absolute_Joint = Instance | Absolute | Joint, + Instance_Absolute_Independent = Instance | Absolute | Independent, + Instance_Relative_Joint = Instance | Relative | Joint, + Instance_Relative_Independent = Instance | Relative | Independent, + Local_Absolute_Joint = Local | Absolute | Joint, + Local_Absolute_Independent = Local | Absolute | Independent, + Local_Relative_Joint = Local | Relative | Joint, + Local_Relative_Independent = Local | Relative | Independent, + }; + + TransformationType() : m_value(World) {} + TransformationType(Enum value) : m_value(value) {} + TransformationType& operator=(Enum value) { m_value = value; return *this; } + + Enum operator()() const { return m_value; } + bool has(Enum v) const { return ((unsigned int)m_value & (unsigned int)v) != 0; } + + void set_world() { this->remove(Instance); this->remove(Local); } + void set_instance() { this->remove(Local); this->add(Instance); } + void set_local() { this->remove(Instance); this->add(Local); } + void set_absolute() { this->remove(Relative); } + void set_relative() { this->add(Relative); } + void set_joint() { this->remove(Independent); } + void set_independent() { this->add(Independent); } + + bool world() const { return !this->has(Instance) && !this->has(Local); } + bool instance() const { return this->has(Instance); } + bool local() const { return this->has(Local); } + bool absolute() const { return !this->has(Relative); } + bool relative() const { return this->has(Relative); } + bool joint() const { return !this->has(Independent); } + bool independent() const { return this->has(Independent); } + +private: + void add(Enum v) { m_value = Enum((unsigned int)m_value | (unsigned int)v); } + void remove(Enum v) { m_value = Enum((unsigned int)m_value & (~(unsigned int)v)); } + + Enum m_value; +}; + +} // namespace Slic3r +} // namespace GUI + +#endif // slic3r_GUI_Geometry_hpp_ diff --git a/src/slic3r/GUI/GUI_Utils.hpp b/src/slic3r/GUI/GUI_Utils.hpp index ab3d2fd7946..6fbec69ba79 100644 --- a/src/slic3r/GUI/GUI_Utils.hpp +++ b/src/slic3r/GUI/GUI_Utils.hpp @@ -1,3 +1,7 @@ +///|/ Copyright (c) Prusa Research 2018 - 2023 Oleksandra Iushchenko @YuSanka, Enrico Turri @enricoturri1966, Lukáš Matěna @lukasmatena, Vojtěch Bubník @bubnikv, Vojtěch Král @vojtechkral +///|/ +///|/ PrusaSlicer is released under the terms of the AGPLv3 or higher +///|/ #ifndef slic3r_GUI_Utils_hpp_ #define slic3r_GUI_Utils_hpp_ @@ -463,6 +467,16 @@ class TaskTimer ~TaskTimer(); }; +class KeyAutoRepeatFilter +{ + size_t m_count{ 0 }; + +public: + void increase_count() { ++m_count; } + void reset_count() { m_count = 0; } + bool is_first() const { return m_count == 0; } +}; + /* Image Generator */ #define _3MF_COVER_SIZE wxSize(240, 240) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp new file mode 100644 index 00000000000..5b4d3bd9321 --- /dev/null +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -0,0 +1,2154 @@ +///|/ Copyright (c) Prusa Research 2019 - 2023 Lukáš Matěna @lukasmatena, Oleksandra Iushchenko @YuSanka, Enrico Turri @enricoturri1966, Vojtěch Bubník @bubnikv, Filip Sykala @Jony01 +///|/ +///|/ PrusaSlicer is released under the terms of the AGPLv3 or higher +///|/ +#include "GLGizmoMeasure.hpp" +#include "slic3r/GUI/GLCanvas3D.hpp" +#include "slic3r/GUI/GUI_App.hpp" +#include "slic3r/GUI/Plater.hpp" +#include "slic3r/GUI/Gizmos/GizmoObjectManipulation.hpp" + + +#include "libslic3r/PresetBundle.hpp" +#include "libslic3r/MeasureUtils.hpp" + +#include + +#include + +#include + +#include + +#include + +namespace Slic3r { +namespace GUI { + +static const Slic3r::ColorRGBA SELECTED_1ST_COLOR = { 0.25f, 0.75f, 0.75f, 1.0f }; +static const Slic3r::ColorRGBA SELECTED_2ND_COLOR = { 0.75f, 0.25f, 0.75f, 1.0f }; +static const Slic3r::ColorRGBA NEUTRAL_COLOR = {0.5f, 0.5f, 0.5f, 1.0f}; +static const Slic3r::ColorRGBA HOVER_COLOR = ColorRGBA::GREEN(); + +static const int POINT_ID = 100; +static const int EDGE_ID = 200; +static const int CIRCLE_ID = 300; +static const int PLANE_ID = 400; +static const int SEL_SPHERE_1_ID = 501; +static const int SEL_SPHERE_2_ID = 502; + +static const float TRIANGLE_BASE = 10.0f; +static const float TRIANGLE_HEIGHT = TRIANGLE_BASE * 1.618033f; + +static const std::string CTRL_STR = +#ifdef __APPLE__ +"⌘" +#else +"Ctrl" +#endif //__APPLE__ +; + +static std::string format_double(double value) +{ + char buf[1024]; + sprintf(buf, "%.3f", value); + return std::string(buf); +} + +static std::string format_vec3(const Vec3d& v) +{ + char buf[1024]; + sprintf(buf, "X: %.3f, Y: %.3f, Z: %.3f", v.x(), v.y(), v.z()); + return std::string(buf); +} + +static std::string surface_feature_type_as_string(Measure::SurfaceFeatureType type) +{ + switch (type) + { + default: + case Measure::SurfaceFeatureType::Undef: { return ("No feature"); } + case Measure::SurfaceFeatureType::Point: { return _u8L("Vertex"); } + case Measure::SurfaceFeatureType::Edge: { return _u8L("Edge"); } + case Measure::SurfaceFeatureType::Circle: { return _u8L("Circle"); } + case Measure::SurfaceFeatureType::Plane: { return _u8L("Plane"); } + } +} + +static std::string point_on_feature_type_as_string(Measure::SurfaceFeatureType type, int hover_id) +{ + std::string ret; + switch (type) { + case Measure::SurfaceFeatureType::Point: { ret = _u8L("Vertex"); break; } + case Measure::SurfaceFeatureType::Edge: { ret = _u8L("Point on edge"); break; } + case Measure::SurfaceFeatureType::Circle: { ret = _u8L("Point on circle"); break; } + case Measure::SurfaceFeatureType::Plane: { ret = _u8L("Point on plane"); break; } + default: { assert(false); break; } + } + return ret; +} + +static std::string center_on_feature_type_as_string(Measure::SurfaceFeatureType type) +{ + std::string ret; + switch (type) { + case Measure::SurfaceFeatureType::Edge: { ret = _u8L("Center of edge"); break; } + case Measure::SurfaceFeatureType::Circle: { ret = _u8L("Center of circle"); break; } + default: { assert(false); break; } + } + return ret; +} + +static GLModel::Geometry init_plane_data(const indexed_triangle_set& its, const std::vector& triangle_indices) +{ + GLModel::Geometry init_data; + init_data.format = { GUI::GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3N3 }; + init_data.reserve_indices(3 * triangle_indices.size()); + init_data.reserve_vertices(3 * triangle_indices.size()); + unsigned int i = 0; + for (int idx : triangle_indices) { + const Vec3f& v0 = its.vertices[its.indices[idx][0]]; + const Vec3f& v1 = its.vertices[its.indices[idx][1]]; + const Vec3f& v2 = its.vertices[its.indices[idx][2]]; + + const Vec3f n = (v1 - v0).cross(v2 - v0).normalized(); + init_data.add_vertex(v0, n); + init_data.add_vertex(v1, n); + init_data.add_vertex(v2, n); + init_data.add_triangle(i, i + 1, i + 2); + i += 3; + } + + return init_data; +} + +static GLModel::Geometry init_torus_data(unsigned int primary_resolution, unsigned int secondary_resolution, const Vec3f& center, + float radius, float thickness, const Vec3f& model_axis, const Transform3f& world_trafo) +{ + const unsigned int torus_sector_count = std::max(4, primary_resolution); + const unsigned int section_sector_count = std::max(4, secondary_resolution); + const float torus_sector_step = 2.0f * float(M_PI) / float(torus_sector_count); + const float section_sector_step = 2.0f * float(M_PI) / float(section_sector_count); + + GLModel::Geometry data; + data.format = { GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3N3 }; + data.reserve_vertices(torus_sector_count * section_sector_count); + data.reserve_indices(torus_sector_count * section_sector_count * 2 * 3); + + // vertices + const Transform3f local_to_world_matrix = world_trafo * Geometry::translation_transform(center.cast()).cast() * + Eigen::Quaternion::FromTwoVectors(Vec3f::UnitZ(), model_axis); + for (unsigned int i = 0; i < torus_sector_count; ++i) { + const float section_angle = torus_sector_step * i; + const Vec3f radius_dir(std::cos(section_angle), std::sin(section_angle), 0.0f); + const Vec3f local_section_center = radius * radius_dir; + const Vec3f world_section_center = local_to_world_matrix * local_section_center; + const Vec3f local_section_normal = local_section_center.normalized().cross(Vec3f::UnitZ()).normalized(); + const Vec3f world_section_normal = (Vec3f)(local_to_world_matrix.matrix().block(0, 0, 3, 3) * local_section_normal).normalized(); + const Vec3f base_v = thickness * radius_dir; + for (unsigned int j = 0; j < section_sector_count; ++j) { + const Vec3f v = Eigen::AngleAxisf(section_sector_step * j, world_section_normal) * base_v; + data.add_vertex(world_section_center + v, (Vec3f)v.normalized()); + } + } + + // triangles + for (unsigned int i = 0; i < torus_sector_count; ++i) { + const unsigned int ii = i * section_sector_count; + const unsigned int ii_next = ((i + 1) % torus_sector_count) * section_sector_count; + for (unsigned int j = 0; j < section_sector_count; ++j) { + const unsigned int j_next = (j + 1) % section_sector_count; + const unsigned int i0 = ii + j; + const unsigned int i1 = ii_next + j; + const unsigned int i2 = ii_next + j_next; + const unsigned int i3 = ii + j_next; + data.add_triangle(i0, i1, i2); + data.add_triangle(i0, i2, i3); + } + } + + return data; +} + +static bool is_feature_with_center(const Measure::SurfaceFeature& feature) +{ + const Measure::SurfaceFeatureType type = feature.get_type(); + return (type == Measure::SurfaceFeatureType::Circle || (type == Measure::SurfaceFeatureType::Edge && feature.get_extra_point().has_value())); +} + +static Vec3d get_feature_offset(const Measure::SurfaceFeature& feature) +{ + Vec3d ret; + switch (feature.get_type()) + { + case Measure::SurfaceFeatureType::Circle: + { + const auto [center, radius, normal] = feature.get_circle(); + ret = center; + break; + } + case Measure::SurfaceFeatureType::Edge: + { + std::optional p = feature.get_extra_point(); + assert(p.has_value()); + ret = *p; + break; + } + case Measure::SurfaceFeatureType::Point: + { + ret = feature.get_point(); + break; + } + default: { assert(false); } + } + + return ret; +} + +class TransformHelper +{ + struct Cache + { + std::array viewport; + Matrix4d ndc_to_ss_matrix; + Transform3d ndc_to_ss_matrix_inverse; + }; + + static Cache s_cache; + +public: + static Vec3d model_to_world(const Vec3d& model, const Transform3d& world_matrix) { + return world_matrix * model; + } + + static Vec4d world_to_clip(const Vec3d& world, const Matrix4d& projection_view_matrix) { + return projection_view_matrix * Vec4d(world.x(), world.y(), world.z(), 1.0); + } + + static Vec3d clip_to_ndc(const Vec4d& clip) { + return Vec3d(clip.x(), clip.y(), clip.z()) / clip.w(); + } + + static Vec2d ndc_to_ss(const Vec3d& ndc, const std::array& viewport) { + const double half_w = 0.5 * double(viewport[2]); + const double half_h = 0.5 * double(viewport[3]); + return { half_w * ndc.x() + double(viewport[0]) + half_w, half_h * ndc.y() + double(viewport[1]) + half_h }; + }; + + static Vec4d model_to_clip(const Vec3d& model, const Transform3d& world_matrix, const Matrix4d& projection_view_matrix) { + return world_to_clip(model_to_world(model, world_matrix), projection_view_matrix); + } + + static Vec3d model_to_ndc(const Vec3d& model, const Transform3d& world_matrix, const Matrix4d& projection_view_matrix) { + return clip_to_ndc(world_to_clip(model_to_world(model, world_matrix), projection_view_matrix)); + } + + static Vec2d model_to_ss(const Vec3d& model, const Transform3d& world_matrix, const Matrix4d& projection_view_matrix, const std::array& viewport) { + return ndc_to_ss(clip_to_ndc(world_to_clip(model_to_world(model, world_matrix), projection_view_matrix)), viewport); + } + + static Vec2d world_to_ss(const Vec3d& world, const Matrix4d& projection_view_matrix, const std::array& viewport) { + return ndc_to_ss(clip_to_ndc(world_to_clip(world, projection_view_matrix)), viewport); + } + + static const Matrix4d& ndc_to_ss_matrix(const std::array& viewport) { + update(viewport); + return s_cache.ndc_to_ss_matrix; + } + + static const Transform3d ndc_to_ss_matrix_inverse(const std::array& viewport) { + update(viewport); + return s_cache.ndc_to_ss_matrix_inverse; + } + +private: + static void update(const std::array& viewport) { + if (s_cache.viewport == viewport) + return; + + const double half_w = 0.5 * double(viewport[2]); + const double half_h = 0.5 * double(viewport[3]); + s_cache.ndc_to_ss_matrix << half_w, 0.0, 0.0, double(viewport[0]) + half_w, + 0.0, half_h, 0.0, double(viewport[1]) + half_h, + 0.0, 0.0, 1.0, 0.0, + 0.0, 0.0, 0.0, 1.0; + + s_cache.ndc_to_ss_matrix_inverse = s_cache.ndc_to_ss_matrix.inverse(); + s_cache.viewport = viewport; + } +}; + +TransformHelper::Cache TransformHelper::s_cache = { { 0, 0, 0, 0 }, Matrix4d::Identity(), Transform3d::Identity() }; + +GLGizmoMeasure::GLGizmoMeasure(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id) +: GLGizmoBase(parent, icon_filename, sprite_id) +{ + GLModel::Geometry sphere_geometry = smooth_sphere(16, 7.5f); + m_sphere.mesh_raycaster = std::make_unique(std::make_shared(sphere_geometry.get_as_indexed_triangle_set())); + m_sphere.model.init_from(std::move(sphere_geometry)); + + GLModel::Geometry cylinder_geometry = smooth_cylinder(16, 5.0f, 1.0f); + m_cylinder.mesh_raycaster = std::make_unique(std::make_shared(cylinder_geometry.get_as_indexed_triangle_set())); + m_cylinder.model.init_from(std::move(cylinder_geometry)); +} + +bool GLGizmoMeasure::on_mouse(const wxMouseEvent &mouse_event) +{ + m_mouse_pos = { double(mouse_event.GetX()), double(mouse_event.GetY()) }; + + if (mouse_event.Moving()) { + // only for sure + m_mouse_left_down = false; + return false; + } + else if (mouse_event.Dragging()) { + // Enable/Disable panning/rotating the 3D scene + // Ctrl is pressed or the mouse is not hovering a selected volume + bool unlock_dragging = mouse_event.CmdDown() || (m_hover_id == -1 && !m_parent.get_selection().contains_volume(m_parent.get_first_hover_volume_idx())); + // mode is not center selection or mouse is not hovering a center + unlock_dragging &= !mouse_event.ShiftDown() || (m_hover_id != SEL_SPHERE_1_ID && m_hover_id != SEL_SPHERE_2_ID && m_hover_id != POINT_ID); + return !unlock_dragging; + } + else if (mouse_event.LeftDown()) { + // let the event pass through to allow panning/rotating the 3D scene + if (mouse_event.CmdDown()) + return false; + + if (m_hover_id != -1) { + m_mouse_left_down = true; + + auto detect_current_item = [this]() { + SelectedFeatures::Item item; + if (m_hover_id == SEL_SPHERE_1_ID) { + if (m_selected_features.first.is_center) + // mouse is hovering over a selected center + item = { true, m_selected_features.first.source, { Measure::SurfaceFeature(get_feature_offset(*m_selected_features.first.source)) } }; + else if (is_feature_with_center(*m_selected_features.first.feature)) + // mouse is hovering over a unselected center + item = { true, m_selected_features.first.feature, { Measure::SurfaceFeature(get_feature_offset(*m_selected_features.first.feature)) } }; + else + // mouse is hovering over a point + item = m_selected_features.first; + } + else if (m_hover_id == SEL_SPHERE_2_ID) { + if (m_selected_features.second.is_center) + // mouse is hovering over a selected center + item = { true, m_selected_features.second.source, { Measure::SurfaceFeature(get_feature_offset(*m_selected_features.second.source)) } }; + else if (is_feature_with_center(*m_selected_features.second.feature)) + // mouse is hovering over a center + item = { true, m_selected_features.second.feature, { Measure::SurfaceFeature(get_feature_offset(*m_selected_features.second.feature)) } }; + else + // mouse is hovering over a point + item = m_selected_features.second; + } + else { + switch (m_mode) + { + case EMode::FeatureSelection: { item = { false, m_curr_feature, m_curr_feature }; break; } + case EMode::PointSelection: { item = { false, m_curr_feature, Measure::SurfaceFeature(*m_curr_point_on_feature_position) }; break; } + } + } + return item; + }; + + auto requires_sphere_raycaster_for_picking = [this](const SelectedFeatures::Item& item) { + if (m_mode == EMode::PointSelection || item.feature->get_type() == Measure::SurfaceFeatureType::Point) + return true; + else if (m_mode == EMode::FeatureSelection) { + if (is_feature_with_center(*item.feature)) + return true; + } + return false; + }; + + if (m_selected_features.first.feature.has_value()) { + const SelectedFeatures::Item item = detect_current_item(); + if (m_selected_features.first != item) { + bool processed = false; + if (item.is_center) { + if (item.source == m_selected_features.first.feature) { + // switch 1st selection from feature to its center + m_selected_features.first = item; + processed = true; + } + else if (item.source == m_selected_features.second.feature) { + // switch 2nd selection from feature to its center + m_selected_features.second = item; + processed = true; + } + } + else if (is_feature_with_center(*item.feature)) { + if (m_selected_features.first.is_center && m_selected_features.first.source == item.feature) { + // switch 1st selection from center to its feature + m_selected_features.first = item; + processed = true; + } + else if (m_selected_features.second.is_center && m_selected_features.second.source == item.feature) { + // switch 2nd selection from center to its feature + m_selected_features.second = item; + processed = true; + } + } + + if (!processed) { + remove_selected_sphere_raycaster(SEL_SPHERE_2_ID); + if (m_selected_features.second == item) + // 2nd feature deselection + m_selected_features.second.reset(); + else { + // 2nd feature selection + m_selected_features.second = item; + if (requires_sphere_raycaster_for_picking(item)) + m_selected_sphere_raycasters.push_back(m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, SEL_SPHERE_2_ID, *m_sphere.mesh_raycaster)); + } + } + } + else { + remove_selected_sphere_raycaster(SEL_SPHERE_1_ID); + if (m_selected_features.second.feature.has_value()) { + // promote 2nd feature to 1st feature + remove_selected_sphere_raycaster(SEL_SPHERE_2_ID); + m_selected_features.first = m_selected_features.second; + if (requires_sphere_raycaster_for_picking(m_selected_features.first)) + m_selected_sphere_raycasters.push_back(m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, SEL_SPHERE_1_ID, *m_sphere.mesh_raycaster)); + m_selected_features.second.reset(); + } + else + // 1st feature deselection + m_selected_features.first.reset(); + } + } + else { + // 1st feature selection + const SelectedFeatures::Item item = detect_current_item(); + m_selected_features.first = item; + if (requires_sphere_raycaster_for_picking(item)) + m_selected_sphere_raycasters.push_back(m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, SEL_SPHERE_1_ID, *m_sphere.mesh_raycaster)); + } + + update_measurement_result(); + + m_imgui->set_requires_extra_frame(); + + return true; + } + else + // if the mouse pointer is on any volume, filter out the event to prevent the user to move it + // equivalent tp: return (m_parent.get_first_hover_volume_idx() != -1); + return m_curr_feature.has_value(); + + // fix: prevent restart gizmo when reselect object + // take responsibility for left up + if (m_parent.get_first_hover_volume_idx() >= 0) + m_mouse_left_down = true; + } + else if (mouse_event.LeftUp()) { + if (m_mouse_left_down) { + // responsible for mouse left up after selecting plane + m_mouse_left_down = false; + return true; + } + if (m_hover_id == -1 && !m_parent.is_mouse_dragging()) + // avoid closing the gizmo if the user clicks outside of any volume + return true; + } + else if (mouse_event.RightDown()) { + // let the event pass through to allow panning/rotating the 3D scene + if (mouse_event.CmdDown()) + return false; + } + else if (mouse_event.Leaving()) + m_mouse_left_down = false; + + return false; +} + +void GLGizmoMeasure::data_changed(bool is_serializing) +{ + m_parent.toggle_sla_auxiliaries_visibility(false, nullptr, -1); + + update_if_needed(); + + m_last_inv_zoom = 0.0f; + m_last_plane_idx = -1; + if (m_pending_scale) { + update_measurement_result(); + m_pending_scale = false; + } + else + m_selected_features.reset(); + m_selected_sphere_raycasters.clear(); + m_editing_distance = false; + m_is_editing_distance_first_frame = true; +} + +bool GLGizmoMeasure::gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_position, bool shift_down, bool alt_down, bool control_down) +{ + if (action == SLAGizmoEventType::ShiftDown) { + if (m_shift_kar_filter.is_first()) { + m_mode = EMode::PointSelection; + disable_scene_raycasters(); + } + m_shift_kar_filter.increase_count(); + } + else if (action == SLAGizmoEventType::ShiftUp) { + m_shift_kar_filter.reset_count(); + m_mode = EMode::FeatureSelection; + restore_scene_raycasters_state(); + } + else if (action == SLAGizmoEventType::Delete) { + m_selected_features.reset(); + m_selected_sphere_raycasters.clear(); + m_parent.request_extra_frame(); + } + else if (action == SLAGizmoEventType::Escape) { + if (!m_selected_features.first.feature.has_value()) { + update_measurement_result(); + return false; + } + else { + if (m_selected_features.second.feature.has_value()) { + remove_selected_sphere_raycaster(SEL_SPHERE_2_ID); + m_selected_features.second.feature.reset(); + } + else { + remove_selected_sphere_raycaster(SEL_SPHERE_1_ID); + m_selected_features.first.feature.reset(); + } + + update_measurement_result(); + } + } + + return true; +} + +bool GLGizmoMeasure::on_init() +{ + m_shortcut_key = WXK_CONTROL_U; + return true; +} + +void GLGizmoMeasure::on_set_state() +{ + if (m_state == Off) { + m_parent.toggle_sla_auxiliaries_visibility(true, nullptr, -1); + m_shift_kar_filter.reset_count(); + m_curr_feature.reset(); + m_curr_point_on_feature_position.reset(); + restore_scene_raycasters_state(); + m_editing_distance = false; + m_is_editing_distance_first_frame = true; + m_measuring.reset(); + m_raycaster.reset(); + } + else { + m_mode = EMode::FeatureSelection; + // store current state of scene raycaster for later use + m_scene_raycasters.clear(); + auto scene_raycasters = m_parent.get_raycasters_for_picking(SceneRaycaster::EType::Volume); + if (scene_raycasters != nullptr) { + m_scene_raycasters.reserve(scene_raycasters->size()); + for (auto r : *scene_raycasters) { + SceneRaycasterState state = { r, r->is_active() }; + m_scene_raycasters.emplace_back(state); + } + } + } +} + +std::string GLGizmoMeasure::on_get_name() const +{ + return _u8L("Measure"); +} + +bool GLGizmoMeasure::on_is_activable() const +{ + const Selection& selection = m_parent.get_selection(); + bool res = (wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology() == ptSLA) ? + selection.is_single_full_instance() : + selection.is_single_full_instance() || selection.is_single_volume() || selection.is_single_modifier(); + if (res) + res &= !selection.contains_sinking_volumes(); + + return res; +} + +void GLGizmoMeasure::on_render() +{ +#if ENABLE_MEASURE_GIZMO_DEBUG + render_debug_dialog(); +#endif // ENABLE_MEASURE_GIZMO_DEBUG + +// // do not render if the user is panning/rotating the 3d scene +// if (m_parent.is_mouse_dragging()) +// return; + + update_if_needed(); + + const Camera& camera = wxGetApp().plater()->get_camera(); + const float inv_zoom = (float)camera.get_inv_zoom(); + + Vec3f position_on_model; + Vec3f normal_on_model; + size_t model_facet_idx; + const bool mouse_on_object = m_raycaster->unproject_on_mesh(m_mouse_pos, Transform3d::Identity(), camera, position_on_model, normal_on_model, nullptr, &model_facet_idx); + const bool is_hovering_on_feature = m_mode == EMode::PointSelection && m_hover_id != -1; + + auto update_circle = [this, inv_zoom]() { + if (m_last_inv_zoom != inv_zoom || m_last_circle != m_curr_feature) { + m_last_inv_zoom = inv_zoom; + m_last_circle = m_curr_feature; + m_circle.reset(); + const auto [center, radius, normal] = m_curr_feature->get_circle(); + GLModel::Geometry circle_geometry = init_torus_data(64, 16, center.cast(), float(radius), 5.0f * inv_zoom, normal.cast(), Transform3f::Identity()); + m_circle.mesh_raycaster = std::make_unique(std::make_shared(circle_geometry.get_as_indexed_triangle_set())); + m_circle.model.init_from(std::move(circle_geometry)); + return true; + } + return false; + }; + + if (m_mode == EMode::FeatureSelection || m_mode == EMode::PointSelection) { + if (m_hover_id == SEL_SPHERE_1_ID || m_hover_id == SEL_SPHERE_2_ID) { + // Skip feature detection if hovering on a selected point/center + m_parent.remove_raycasters_for_picking(SceneRaycaster::EType::Gizmo, POINT_ID); + m_parent.remove_raycasters_for_picking(SceneRaycaster::EType::Gizmo, EDGE_ID); + m_parent.remove_raycasters_for_picking(SceneRaycaster::EType::Gizmo, PLANE_ID); + m_parent.remove_raycasters_for_picking(SceneRaycaster::EType::Gizmo, CIRCLE_ID); + m_curr_feature.reset(); + m_curr_point_on_feature_position.reset(); + } + else { + std::optional curr_feature = wxGetMouseState().LeftIsDown() ? m_curr_feature : + mouse_on_object ? m_measuring->get_feature(model_facet_idx, position_on_model.cast()) : std::nullopt; + + if (m_curr_feature != curr_feature || + (curr_feature.has_value() && curr_feature->get_type() == Measure::SurfaceFeatureType::Circle && (m_curr_feature != curr_feature || m_last_inv_zoom != inv_zoom))) { + m_parent.remove_raycasters_for_picking(SceneRaycaster::EType::Gizmo, POINT_ID); + m_parent.remove_raycasters_for_picking(SceneRaycaster::EType::Gizmo, EDGE_ID); + m_parent.remove_raycasters_for_picking(SceneRaycaster::EType::Gizmo, PLANE_ID); + m_parent.remove_raycasters_for_picking(SceneRaycaster::EType::Gizmo, CIRCLE_ID); + m_raycasters.clear(); + m_curr_feature = curr_feature; + if (!m_curr_feature.has_value()) + return; + + switch (m_curr_feature->get_type()) { + default: { assert(false); break; } + case Measure::SurfaceFeatureType::Point: + { + m_raycasters.insert({ POINT_ID, m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, POINT_ID, *m_sphere.mesh_raycaster) }); + break; + } + case Measure::SurfaceFeatureType::Edge: + { + m_raycasters.insert({ EDGE_ID, m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, EDGE_ID, *m_cylinder.mesh_raycaster) }); + break; + } + case Measure::SurfaceFeatureType::Circle: + { + update_circle(); + m_raycasters.insert({ CIRCLE_ID, m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, CIRCLE_ID, *m_circle.mesh_raycaster) }); + break; + } + case Measure::SurfaceFeatureType::Plane: + { + const auto [idx, normal, point] = m_curr_feature->get_plane(); + if (m_last_plane_idx != idx) { + m_last_plane_idx = idx; + const indexed_triangle_set& its = m_measuring->get_its(); + const std::vector& plane_triangles = m_measuring->get_plane_triangle_indices(idx); + GLModel::Geometry init_data = init_plane_data(its, plane_triangles); + m_plane.reset(); + m_plane.mesh_raycaster = std::make_unique(std::make_shared(init_data.get_as_indexed_triangle_set())); + } + + m_raycasters.insert({ PLANE_ID, m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, PLANE_ID, *m_plane.mesh_raycaster) }); + break; + } + } + } + } + } + + if (m_mode != EMode::PointSelection) + m_curr_point_on_feature_position.reset(); + else if (is_hovering_on_feature) { + auto position_on_feature = [this](int feature_type_id, const Camera& camera, std::function callback = nullptr) -> Vec3d { + auto it = m_raycasters.find(feature_type_id); + if (it != m_raycasters.end() && it->second != nullptr) { + Vec3f p; + Vec3f n; + const Transform3d& trafo = it->second->get_transform(); + bool res = it->second->get_raycaster()->closest_hit(m_mouse_pos, trafo, camera, p, n); + if (res) { + if (callback) + p = callback(p); + return trafo * p.cast(); + } + } + return Vec3d(DBL_MAX, DBL_MAX, DBL_MAX); + }; + + if (m_curr_feature.has_value()) { + switch (m_curr_feature->get_type()) + { + default: { assert(false); break; } + case Measure::SurfaceFeatureType::Point: + { + m_curr_point_on_feature_position = m_curr_feature->get_point(); + break; + } + case Measure::SurfaceFeatureType::Edge: + { + const std::optional extra = m_curr_feature->get_extra_point(); + if (extra.has_value() && m_hover_id == POINT_ID) + m_curr_point_on_feature_position = *extra; + else { + const Vec3d pos = position_on_feature(EDGE_ID, camera, [](const Vec3f& v) { return Vec3f(0.0f, 0.0f, v.z()); }); + if (!pos.isApprox(Vec3d(DBL_MAX, DBL_MAX, DBL_MAX))) + m_curr_point_on_feature_position = pos; + } + break; + } + case Measure::SurfaceFeatureType::Plane: + { + m_curr_point_on_feature_position = position_on_feature(PLANE_ID, camera); + break; + } + case Measure::SurfaceFeatureType::Circle: + { + const auto [center, radius, normal] = m_curr_feature->get_circle(); + if (m_hover_id == POINT_ID) + m_curr_point_on_feature_position = center; + else { + const Vec3d world_pof = position_on_feature(CIRCLE_ID, camera, [](const Vec3f& v) { return v; }); + const Eigen::Hyperplane plane(normal, center); + const Transform3d local_to_model_matrix = Geometry::translation_transform(center) * Eigen::Quaternion::FromTwoVectors(Vec3d::UnitZ(), normal); + const Vec3d local_proj = local_to_model_matrix.inverse() * plane.projection(world_pof); + double angle = std::atan2(local_proj.y(), local_proj.x()); + if (angle < 0.0) + angle += 2.0 * double(M_PI); + + const Vec3d local_pos = radius * Vec3d(std::cos(angle), std::sin(angle), 0.0); + m_curr_point_on_feature_position = local_to_model_matrix * local_pos; + } + break; + } + } + } + } + else { + m_curr_point_on_feature_position.reset(); + if (m_curr_feature.has_value() && m_curr_feature->get_type() == Measure::SurfaceFeatureType::Circle) { + if (update_circle()) { + m_parent.remove_raycasters_for_picking(SceneRaycaster::EType::Gizmo, CIRCLE_ID); + auto it = m_raycasters.find(CIRCLE_ID); + if (it != m_raycasters.end()) + m_raycasters.erase(it); + m_raycasters.insert({ CIRCLE_ID, m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, CIRCLE_ID, *m_circle.mesh_raycaster) }); + } + } + } + + if (!m_curr_feature.has_value() && !m_selected_features.first.feature.has_value()) + return; + + GLShaderProgram* shader = wxGetApp().get_shader("gouraud_light"); + if (shader == nullptr) + return; + + shader->start_using(); + shader->set_uniform("projection_matrix", camera.get_projection_matrix()); + + glsafe(::glClear(GL_DEPTH_BUFFER_BIT)); + glsafe(::glEnable(GL_DEPTH_TEST)); + const bool old_cullface = ::glIsEnabled(GL_CULL_FACE); + glsafe(::glDisable(GL_CULL_FACE)); + + const Transform3d& view_matrix = camera.get_view_matrix(); + + auto set_matrix_uniforms = [shader, &view_matrix](const Transform3d& model_matrix) { + const Transform3d view_model_matrix = view_matrix * model_matrix; + shader->set_uniform("view_model_matrix", view_model_matrix); + const Matrix3d view_normal_matrix = view_matrix.matrix().block(0, 0, 3, 3) * model_matrix.matrix().block(0, 0, 3, 3).inverse().transpose(); + shader->set_uniform("view_normal_matrix", view_normal_matrix); + }; + + auto set_emission_uniform = [shader](const ColorRGBA& color, bool hover) { + shader->set_uniform("emission_factor", /*(color == GLVolume::SELECTED_COLOR) ? 0.0f :*/ + hover ? 0.5f : 0.25f); + }; + + auto render_feature = [this, set_matrix_uniforms, set_emission_uniform](const Measure::SurfaceFeature& feature, const std::vector& colors, + float inv_zoom, bool hover, bool update_raycasters_transform) { + switch (feature.get_type()) + { + default: { assert(false); break; } + case Measure::SurfaceFeatureType::Point: + { + const Transform3d feature_matrix = Geometry::translation_transform(feature.get_point()) * Geometry::scale_transform(inv_zoom); + set_matrix_uniforms(feature_matrix); + set_emission_uniform(colors.front(), hover); + m_sphere.model.set_color(colors.front()); + m_sphere.model.render(); + if (update_raycasters_transform) { + auto it = m_raycasters.find(POINT_ID); + if (it != m_raycasters.end() && it->second != nullptr) + it->second->set_transform(feature_matrix); + } + break; + } + case Measure::SurfaceFeatureType::Circle: + { + const auto& [center, radius, normal] = feature.get_circle(); + // render circle + const Transform3d circle_matrix = Transform3d::Identity(); + set_matrix_uniforms(circle_matrix); + if (update_raycasters_transform) { + set_emission_uniform(colors.front(), hover); + m_circle.model.set_color(colors.front()); + m_circle.model.render(); + auto it = m_raycasters.find(CIRCLE_ID); + if (it != m_raycasters.end() && it->second != nullptr) + it->second->set_transform(circle_matrix); + } + else { + GLModel circle; + GLModel::Geometry circle_geometry = init_torus_data(64, 16, center.cast(), float(radius), 5.0f * inv_zoom, normal.cast(), Transform3f::Identity()); + circle.init_from(std::move(circle_geometry)); + set_emission_uniform(colors.front(), hover); + circle.set_color(colors.front()); + circle.render(); + } + // render center + if (colors.size() > 1) { + const Transform3d center_matrix = Geometry::translation_transform(center) * Geometry::scale_transform(inv_zoom); + set_matrix_uniforms(center_matrix); + set_emission_uniform(colors.back(), hover); + m_sphere.model.set_color(colors.back()); + m_sphere.model.render(); + auto it = m_raycasters.find(POINT_ID); + if (it != m_raycasters.end() && it->second != nullptr) + it->second->set_transform(center_matrix); + } + break; + } + case Measure::SurfaceFeatureType::Edge: + { + const auto& [from, to] = feature.get_edge(); + // render edge + const Transform3d edge_matrix = Geometry::translation_transform(from) * + Eigen::Quaternion::FromTwoVectors(Vec3d::UnitZ(), to - from) * + Geometry::scale_transform({ (double)inv_zoom, (double)inv_zoom, (to - from).norm() }); + set_matrix_uniforms(edge_matrix); + set_emission_uniform(colors.front(), hover); + m_cylinder.model.set_color(colors.front()); + m_cylinder.model.render(); + if (update_raycasters_transform) { + auto it = m_raycasters.find(EDGE_ID); + if (it != m_raycasters.end() && it->second != nullptr) + it->second->set_transform(edge_matrix); + } + + // render extra point + if (colors.size() > 1) { + const std::optional extra = feature.get_extra_point(); + if (extra.has_value()) { + const Transform3d point_matrix = Geometry::translation_transform(*extra) * Geometry::scale_transform(inv_zoom); + set_matrix_uniforms(point_matrix); + set_emission_uniform(colors.back(), hover); + m_sphere.model.set_color(colors.back()); + m_sphere.model.render(); + auto it = m_raycasters.find(POINT_ID); + if (it != m_raycasters.end() && it->second != nullptr) + it->second->set_transform(point_matrix); + } + } + break; + } + case Measure::SurfaceFeatureType::Plane: + { + const auto& [idx, normal, pt] = feature.get_plane(); + assert(idx < m_plane_models_cache.size()); + set_matrix_uniforms(Transform3d::Identity()); + set_emission_uniform(colors.front(), hover); + m_plane_models_cache[idx].set_color(colors.front()); + m_plane_models_cache[idx].render(); + if (update_raycasters_transform) { + auto it = m_raycasters.find(PLANE_ID); + if (it != m_raycasters.end() && it->second != nullptr) + it->second->set_transform(Transform3d::Identity()); + } + break; + } + } + }; + + auto hover_selection_color = [this]() { + return ((m_mode == EMode::PointSelection && !m_selected_features.first.feature.has_value()) || + (m_mode != EMode::PointSelection && (!m_selected_features.first.feature.has_value() || *m_curr_feature == *m_selected_features.first.feature))) ? + SELECTED_1ST_COLOR : SELECTED_2ND_COLOR; + }; + + auto hovering_color = [this, hover_selection_color]() { + return (m_mode == EMode::PointSelection) ? HOVER_COLOR : hover_selection_color(); + }; + + if (m_curr_feature.has_value()) { + // render hovered feature + + std::vector colors; + if (m_selected_features.first.feature.has_value() && *m_curr_feature == *m_selected_features.first.feature) { + // hovering over the 1st selected feature + if (m_selected_features.first.is_center) + // hovering over a center + colors = { NEUTRAL_COLOR, hovering_color() }; + else if (is_feature_with_center(*m_selected_features.first.feature)) + // hovering over a feature with center + colors = { hovering_color(), NEUTRAL_COLOR }; + else + colors = { hovering_color() }; + } + else if (m_selected_features.second.feature.has_value() && *m_curr_feature == *m_selected_features.second.feature) { + // hovering over the 2nd selected feature + if (m_selected_features.second.is_center) + // hovering over a center + colors = { NEUTRAL_COLOR, hovering_color() }; + else if (is_feature_with_center(*m_selected_features.second.feature)) + // hovering over a feature with center + colors = { hovering_color(), NEUTRAL_COLOR }; + else + colors = { hovering_color() }; + } + else { + switch (m_curr_feature->get_type()) + { + default: { assert(false); break; } + case Measure::SurfaceFeatureType::Point: + { + colors.emplace_back(hover_selection_color()); + break; + } + case Measure::SurfaceFeatureType::Edge: + case Measure::SurfaceFeatureType::Circle: + { + if (m_selected_features.first.is_center && m_curr_feature == m_selected_features.first.source) + colors = { SELECTED_1ST_COLOR, NEUTRAL_COLOR }; + else if (m_selected_features.second.is_center && m_curr_feature == m_selected_features.second.source) + colors = { SELECTED_2ND_COLOR, NEUTRAL_COLOR }; + else + colors = { hovering_color(), hovering_color() }; + break; + } + case Measure::SurfaceFeatureType::Plane: + { + colors.emplace_back(hovering_color()); + break; + } + } + } + + render_feature(*m_curr_feature, colors, inv_zoom, true, true); + } + + if (m_selected_features.first.feature.has_value() && (!m_curr_feature.has_value() || *m_curr_feature != *m_selected_features.first.feature)) { + // render 1st selected feature + + std::optional feature_to_render; + std::vector colors; + bool requires_raycaster_update = false; + if (m_hover_id == SEL_SPHERE_1_ID && (m_selected_features.first.is_center || is_feature_with_center(*m_selected_features.first.feature))) { + // hovering over a center + feature_to_render = m_selected_features.first.source; + colors = { NEUTRAL_COLOR, SELECTED_1ST_COLOR }; + requires_raycaster_update = true; + } + else if (is_feature_with_center(*m_selected_features.first.feature)) { + // hovering over a feature with center + feature_to_render = m_selected_features.first.feature; + colors = { SELECTED_1ST_COLOR, NEUTRAL_COLOR }; + requires_raycaster_update = true; + } + else { + feature_to_render = m_selected_features.first.feature; + colors = { SELECTED_1ST_COLOR }; + requires_raycaster_update = m_selected_features.first.feature->get_type() == Measure::SurfaceFeatureType::Point; + } + + render_feature(*feature_to_render, colors, inv_zoom, m_hover_id == SEL_SPHERE_1_ID, false); + + if (requires_raycaster_update) { + auto it = std::find_if(m_selected_sphere_raycasters.begin(), m_selected_sphere_raycasters.end(), + [](std::shared_ptr item) { return SceneRaycaster::decode_id(SceneRaycaster::EType::Gizmo, item->get_id()) == SEL_SPHERE_1_ID; }); + if (it != m_selected_sphere_raycasters.end()) + (*it)->set_transform(Geometry::translation_transform(get_feature_offset(*m_selected_features.first.feature)) * Geometry::scale_transform(inv_zoom)); + } + } + + if (m_selected_features.second.feature.has_value() && (!m_curr_feature.has_value() || *m_curr_feature != *m_selected_features.second.feature)) { + // render 2nd selected feature + + std::optional feature_to_render; + std::vector colors; + bool requires_raycaster_update = false; + if (m_hover_id == SEL_SPHERE_2_ID && (m_selected_features.second.is_center || is_feature_with_center(*m_selected_features.second.feature))) { + // hovering over a center + feature_to_render = m_selected_features.second.source; + colors = { NEUTRAL_COLOR, SELECTED_2ND_COLOR }; + requires_raycaster_update = true; + } + else if (is_feature_with_center(*m_selected_features.second.feature)) { + // hovering over a feature with center + feature_to_render = m_selected_features.second.feature; + colors = { SELECTED_2ND_COLOR, NEUTRAL_COLOR }; + requires_raycaster_update = true; + } + else { + feature_to_render = m_selected_features.second.feature; + colors = { SELECTED_2ND_COLOR }; + requires_raycaster_update = m_selected_features.second.feature->get_type() == Measure::SurfaceFeatureType::Point; + } + + render_feature(*feature_to_render, colors, inv_zoom, m_hover_id == SEL_SPHERE_2_ID, false); + + if (requires_raycaster_update) { + auto it = std::find_if(m_selected_sphere_raycasters.begin(), m_selected_sphere_raycasters.end(), + [](std::shared_ptr item) { return SceneRaycaster::decode_id(SceneRaycaster::EType::Gizmo, item->get_id()) == SEL_SPHERE_2_ID; }); + if (it != m_selected_sphere_raycasters.end()) + (*it)->set_transform(Geometry::translation_transform(get_feature_offset(*m_selected_features.second.feature)) * Geometry::scale_transform(inv_zoom)); + } + } + + if (is_hovering_on_feature && m_curr_point_on_feature_position.has_value()) { + if (m_hover_id != POINT_ID) { + // render point on feature while SHIFT is pressed + const Transform3d matrix = Geometry::translation_transform(*m_curr_point_on_feature_position) * Geometry::scale_transform(inv_zoom); + set_matrix_uniforms(matrix); + const ColorRGBA color = hover_selection_color(); + set_emission_uniform(color, true); + m_sphere.model.set_color(color); + m_sphere.model.render(); + } + } + + shader->stop_using(); + + if (old_cullface) + glsafe(::glEnable(GL_CULL_FACE)); + + render_dimensioning(); +} + +void GLGizmoMeasure::update_if_needed() +{ + auto update_plane_models_cache = [this](const indexed_triangle_set& its) { + m_plane_models_cache.clear(); + m_plane_models_cache.resize(m_measuring->get_num_of_planes(), GLModel()); + + auto& plane_models_cache = m_plane_models_cache; + const auto& measuring = m_measuring; + + //for (int idx = 0; idx < m_measuring->get_num_of_planes(); ++idx) { + tbb::parallel_for(tbb::blocked_range(0, m_measuring->get_num_of_planes()), + [&plane_models_cache, &measuring, &its](const tbb::blocked_range& range) { + for (size_t idx = range.begin(); idx != range.end(); ++idx) { + GLModel::Geometry init_data = init_plane_data(its, measuring->get_plane_triangle_indices(idx)); + plane_models_cache[idx].init_from(std::move(init_data)); + } + }); + }; + + auto do_update = [this, update_plane_models_cache](const std::vector& volumes_cache, const Selection& selection) { + TriangleMesh composite_mesh; + for (const auto& vol : volumes_cache) { +// if (selection.is_single_full_instance() && vol.volume->is_modifier()) +// continue; + + TriangleMesh volume_mesh = vol.volume->mesh(); + volume_mesh.transform(vol.world_trafo); + + if (vol.world_trafo.matrix().determinant() < 0.0) + volume_mesh.flip_triangles(); + + composite_mesh.merge(volume_mesh); + } + + m_measuring.reset(new Measure::Measuring(composite_mesh.its)); + update_plane_models_cache(m_measuring->get_its()); + m_raycaster.reset(new MeshRaycaster(std::make_shared(composite_mesh))); + m_volumes_cache = volumes_cache; + }; + + const Selection& selection = m_parent.get_selection(); + if (selection.is_empty()) + return; + + const Selection::IndicesList& idxs = selection.get_volume_idxs(); + std::vector volumes_cache; + volumes_cache.reserve(idxs.size()); + for (unsigned int idx : idxs) { + const GLVolume* v = selection.get_volume(idx); + const int volume_idx = v->volume_idx(); + if (volume_idx < 0) + continue; + + const ModelObject* obj = selection.get_model()->objects[v->object_idx()]; + const ModelInstance* inst = obj->instances[v->instance_idx()]; + const ModelVolume* vol = obj->volumes[volume_idx]; + const VolumeCacheItem item = { + obj, inst, vol, + Geometry::translation_transform(selection.get_first_volume()->get_sla_shift_z() * Vec3d::UnitZ()) * inst->get_matrix() * vol->get_matrix() + }; + volumes_cache.emplace_back(item); + } + + if (m_state != On || volumes_cache.empty()) + return; + + if (m_measuring == nullptr || m_volumes_cache != volumes_cache) + do_update(volumes_cache, selection); +} + +void GLGizmoMeasure::disable_scene_raycasters() +{ + for (auto r : m_scene_raycasters) { + r.raycaster->set_active(false); + } +} + +void GLGizmoMeasure::restore_scene_raycasters_state() +{ + for (auto r : m_scene_raycasters) { + r.raycaster->set_active(r.state); + } +} + +void GLGizmoMeasure::render_dimensioning() +{ + static SelectedFeatures last_selected_features; + + if (!m_selected_features.first.feature.has_value()) + return; + + if (!m_selected_features.second.feature.has_value() && m_selected_features.first.feature->get_type() != Measure::SurfaceFeatureType::Circle) + return; + + GLShaderProgram* shader = wxGetApp().get_shader("flat"); + if (shader == nullptr) + return; + + auto point_point = [this, &shader](const Vec3d& v1, const Vec3d& v2, float distance) { + if ((v2 - v1).squaredNorm() < 0.000001 || distance < 0.001f) + return; + + const Camera& camera = wxGetApp().plater()->get_camera(); + const Matrix4d projection_view_matrix = camera.get_projection_matrix().matrix() * camera.get_view_matrix().matrix(); + const std::array& viewport = camera.get_viewport(); + + // screen coordinates + const Vec2d v1ss = TransformHelper::world_to_ss(v1, projection_view_matrix, viewport); + const Vec2d v2ss = TransformHelper::world_to_ss(v2, projection_view_matrix, viewport); + + if (v1ss.isApprox(v2ss)) + return; + + const Vec2d v12ss = v2ss - v1ss; + const double v12ss_len = v12ss.norm(); + + const bool overlap = v12ss_len - 2.0 * TRIANGLE_HEIGHT < 0.0; + + const auto q12ss = Eigen::Quaternion::FromTwoVectors(Vec3d::UnitX(), Vec3d(v12ss.x(), v12ss.y(), 0.0)); + const auto q21ss = Eigen::Quaternion::FromTwoVectors(Vec3d::UnitX(), Vec3d(-v12ss.x(), -v12ss.y(), 0.0)); + + shader->set_uniform("projection_matrix", Transform3d::Identity()); + + const Vec3d v1ss_3 = { v1ss.x(), v1ss.y(), 0.0 }; + const Vec3d v2ss_3 = { v2ss.x(), v2ss.y(), 0.0 }; + + const Transform3d ss_to_ndc_matrix = TransformHelper::ndc_to_ss_matrix_inverse(viewport); + +#if ENABLE_GL_CORE_PROFILE + if (OpenGLManager::get_gl_info().is_core_profile()) { + shader->stop_using(); + + shader = wxGetApp().get_shader("dashed_thick_lines"); + if (shader == nullptr) + return; + + shader->start_using(); + shader->set_uniform("projection_matrix", Transform3d::Identity()); + const std::array& viewport = camera.get_viewport(); + shader->set_uniform("viewport_size", Vec2d(double(viewport[2]), double(viewport[3]))); + shader->set_uniform("width", 1.0f); + shader->set_uniform("gap_size", 0.0f); + } + else +#endif // ENABLE_GL_CORE_PROFILE + glsafe(::glLineWidth(2.0f)); + + // stem + shader->set_uniform("view_model_matrix", overlap ? + ss_to_ndc_matrix * Geometry::translation_transform(v1ss_3) * q12ss * Geometry::translation_transform(-2.0 * TRIANGLE_HEIGHT * Vec3d::UnitX()) * Geometry::scale_transform({ v12ss_len + 4.0 * TRIANGLE_HEIGHT, 1.0f, 1.0f }) : + ss_to_ndc_matrix * Geometry::translation_transform(v1ss_3) * q12ss * Geometry::scale_transform({ v12ss_len, 1.0f, 1.0f })); + m_dimensioning.line.set_color(ColorRGBA::WHITE()); + m_dimensioning.line.render(); + +#if ENABLE_GL_CORE_PROFILE + if (OpenGLManager::get_gl_info().is_core_profile()) { + shader->stop_using(); + + shader = wxGetApp().get_shader("flat"); + if (shader == nullptr) + return; + + shader->start_using(); + } + else +#endif // ENABLE_GL_CORE_PROFILE + glsafe(::glLineWidth(1.0f)); + + // arrow 1 + shader->set_uniform("view_model_matrix", overlap ? + ss_to_ndc_matrix * Geometry::translation_transform(v1ss_3) * q12ss : + ss_to_ndc_matrix * Geometry::translation_transform(v1ss_3) * q21ss); + m_dimensioning.triangle.render(); + + // arrow 2 + shader->set_uniform("view_model_matrix", overlap ? + ss_to_ndc_matrix * Geometry::translation_transform(v2ss_3) * q21ss : + ss_to_ndc_matrix * Geometry::translation_transform(v2ss_3) * q12ss); + m_dimensioning.triangle.render(); + + const bool use_inches = wxGetApp().app_config->get_bool("use_inches"); + const double curr_value = use_inches ? GizmoObjectManipulation::mm_to_in * distance : distance; + const std::string curr_value_str = format_double(curr_value); + const std::string units = use_inches ? _u8L("in") : _u8L("mm"); + const float value_str_width = 20.0f + ImGui::CalcTextSize(curr_value_str.c_str()).x; + static double edit_value = 0.0; + + const Vec2d label_position = 0.5 * (v1ss + v2ss); + m_imgui->set_next_window_pos(label_position.x(), viewport[3] - label_position.y(), ImGuiCond_Always, 0.0f, 1.0f); + m_imgui->set_next_window_bg_alpha(0.0f); + + if (!m_editing_distance) { + ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.0f); + ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f); + ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, { 1.0f, 1.0f }); + m_imgui->begin(std::string("distance"), ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoDecoration); + ImGui::BringWindowToDisplayFront(ImGui::GetCurrentWindow()); + ImGui::AlignTextToFramePadding(); + ImDrawList* draw_list = ImGui::GetWindowDrawList(); + const ImVec2 pos = ImGui::GetCursorScreenPos(); + const std::string txt = curr_value_str + " " + units; + ImVec2 txt_size = ImGui::CalcTextSize(txt.c_str()); + const ImGuiStyle& style = ImGui::GetStyle(); + draw_list->AddRectFilled({ pos.x - style.FramePadding.x, pos.y + style.FramePadding.y }, { pos.x + txt_size.x + 2.0f * style.FramePadding.x , pos.y + txt_size.y + 2.0f * style.FramePadding.y }, + ImGuiWrapper::to_ImU32(ColorRGBA(0.5f, 0.5f, 0.5f, 0.5f))); + ImGui::SetCursorScreenPos({ pos.x + style.FramePadding.x, pos.y }); + m_imgui->text(txt); + ImGui::SameLine(); + if (m_imgui->image_button(ImGui::SliderFloatEditBtnIcon, _L("Edit to scale"))) { + m_editing_distance = true; + edit_value = curr_value; + m_imgui->requires_extra_frame(); + } + m_imgui->end(); + ImGui::PopStyleVar(3); + } + + if (m_editing_distance && !ImGui::IsPopupOpen("distance_popup")) + ImGui::OpenPopup("distance_popup"); + + ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.0f); + ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f); + ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, { 1.0f, 1.0f }); + ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, { 4.0f, 0.0f }); + if (ImGui::BeginPopupModal("distance_popup", nullptr, ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoDecoration)) { + auto perform_scale = [this](double new_value, double old_value) { + if (new_value == old_value || new_value <= 0.0) + return; + + const double ratio = new_value / old_value; + wxGetApp().plater()->take_snapshot(_u8L("Scale")); + + struct TrafoData + { + double ratio; + Vec3d old_pivot; + Vec3d new_pivot; + Transform3d scale_matrix; + + TrafoData(double ratio, const Vec3d& old_pivot, const Vec3d& new_pivot) { + this->ratio = ratio; + this->scale_matrix = Geometry::scale_transform(ratio); + this->old_pivot = old_pivot; + this->new_pivot = new_pivot; + } + + Vec3d transform(const Vec3d& point) const { return this->scale_matrix * (point - this->old_pivot) + this->new_pivot; } + }; + + auto scale_feature = [](Measure::SurfaceFeature& feature, const TrafoData& trafo_data) { + switch (feature.get_type()) + { + case Measure::SurfaceFeatureType::Point: + { + feature = Measure::SurfaceFeature(trafo_data.transform(feature.get_point())); + break; + } + case Measure::SurfaceFeatureType::Edge: + { + const auto [from, to] = feature.get_edge(); + const std::optional extra = feature.get_extra_point(); + const std::optional new_extra = extra.has_value() ? trafo_data.transform(*extra) : extra; + feature = Measure::SurfaceFeature(Measure::SurfaceFeatureType::Edge, trafo_data.transform(from), trafo_data.transform(to), new_extra); + break; + } + case Measure::SurfaceFeatureType::Circle: + { + const auto [center, radius, normal] = feature.get_circle(); + feature = Measure::SurfaceFeature(Measure::SurfaceFeatureType::Circle, trafo_data.transform(center), normal, std::nullopt, trafo_data.ratio * radius); + break; + } + case Measure::SurfaceFeatureType::Plane: + { + const auto [idx, normal, origin] = feature.get_plane(); + feature = Measure::SurfaceFeature(Measure::SurfaceFeatureType::Plane, normal, trafo_data.transform(origin), std::nullopt, idx); + break; + } + default: { break; } + } + }; + + // apply scale + TransformationType type; + type.set_world(); + type.set_relative(); + type.set_joint(); + + // scale selection + Selection& selection = m_parent.get_selection(); + const Vec3d old_center = selection.get_bounding_box().center(); + selection.setup_cache(); + selection.scale(ratio * Vec3d::Ones(), type); + wxGetApp().plater()->canvas3D()->do_scale(""); // avoid storing another snapshot + wxGetApp().obj_manipul()->set_dirty(); + + // scale dimensioning + const Vec3d new_center = selection.get_bounding_box().center(); + const TrafoData trafo_data(ratio, old_center, new_center); + scale_feature(*m_selected_features.first.feature, trafo_data); + if (m_selected_features.second.feature.has_value()) + scale_feature(*m_selected_features.second.feature, trafo_data); + + // update measure on next call to data_changed() + m_pending_scale = true; + }; + auto action_exit = [this]() { + m_editing_distance = false; + m_is_editing_distance_first_frame = true; + ImGui::CloseCurrentPopup(); + }; + auto action_scale = [perform_scale, action_exit](double new_value, double old_value) { + perform_scale(new_value, old_value); + action_exit(); + }; + + m_imgui->disable_background_fadeout_animation(); + ImGui::PushItemWidth(value_str_width); + if (ImGui::InputDouble("##distance", &edit_value, 0.0f, 0.0f, "%.3f")) { + } + + // trick to auto-select text in the input widgets on 1st frame + if (m_is_editing_distance_first_frame) { + ImGui::SetKeyboardFocusHere(0); + m_is_editing_distance_first_frame = false; + m_imgui->set_requires_extra_frame(); + } + + // handle keys input + if (ImGui::IsKeyPressedMap(ImGuiKey_Enter) || ImGui::IsKeyPressedMap(ImGuiKey_KeyPadEnter)) + action_scale(edit_value, curr_value); + else if (ImGui::IsKeyPressedMap(ImGuiKey_Escape)) + action_exit(); + + ImGui::SameLine(); + if (m_imgui->button(_CTX(L_CONTEXT("Scale", "Verb"), "Verb"))) + action_scale(edit_value, curr_value); + ImGui::SameLine(); + if (m_imgui->button(_L("Cancel"))) + action_exit(); + ImGui::EndPopup(); + } + ImGui::PopStyleVar(4); + }; + + auto point_edge = [this, shader](const Measure::SurfaceFeature& f1, const Measure::SurfaceFeature& f2) { + assert(f1.get_type() == Measure::SurfaceFeatureType::Point && f2.get_type() == Measure::SurfaceFeatureType::Edge); + std::pair e = f2.get_edge(); + const Vec3d v_proj = m_measurement_result.distance_infinite->to; + const Vec3d e1e2 = e.second - e.first; + const Vec3d v_proje1 = v_proj - e.first; + const bool on_e1_side = v_proje1.dot(e1e2) < -EPSILON; + const bool on_e2_side = !on_e1_side && v_proje1.norm() > e1e2.norm(); + if (on_e1_side || on_e2_side) { + const Camera& camera = wxGetApp().plater()->get_camera(); + const Matrix4d projection_view_matrix = camera.get_projection_matrix().matrix() * camera.get_view_matrix().matrix(); + const std::array& viewport = camera.get_viewport(); + const Transform3d ss_to_ndc_matrix = TransformHelper::ndc_to_ss_matrix_inverse(viewport); + + const Vec2d v_projss = TransformHelper::world_to_ss(v_proj, projection_view_matrix, viewport); + auto render_extension = [this, &v_projss, &projection_view_matrix, &viewport, &ss_to_ndc_matrix, shader](const Vec3d& p) { + const Vec2d pss = TransformHelper::world_to_ss(p, projection_view_matrix, viewport); + if (!pss.isApprox(v_projss)) { + const Vec2d pv_projss = v_projss - pss; + const double pv_projss_len = pv_projss.norm(); + + const auto q = Eigen::Quaternion::FromTwoVectors(Vec3d::UnitX(), Vec3d(pv_projss.x(), pv_projss.y(), 0.0)); + + shader->set_uniform("projection_matrix", Transform3d::Identity()); + shader->set_uniform("view_model_matrix", ss_to_ndc_matrix * Geometry::translation_transform({ pss.x(), pss.y(), 0.0 }) * q * + Geometry::scale_transform({ pv_projss_len, 1.0f, 1.0f })); + m_dimensioning.line.set_color(ColorRGBA::LIGHT_GRAY()); + m_dimensioning.line.render(); + } + }; + + render_extension(on_e1_side ? e.first : e.second); + } + }; + + auto arc_edge_edge = [this, &shader](const Measure::SurfaceFeature& f1, const Measure::SurfaceFeature& f2, double radius = 0.0) { + assert(f1.get_type() == Measure::SurfaceFeatureType::Edge && f2.get_type() == Measure::SurfaceFeatureType::Edge); + if (!m_measurement_result.angle.has_value()) + return; + + const double angle = m_measurement_result.angle->angle; + const Vec3d center = m_measurement_result.angle->center; + const std::pair e1 = m_measurement_result.angle->e1; + const std::pair e2 = m_measurement_result.angle->e2; + const double calc_radius = m_measurement_result.angle->radius; + const bool coplanar = m_measurement_result.angle->coplanar; + + if (std::abs(angle) < EPSILON || std::abs(calc_radius) < EPSILON) + return; + + const double draw_radius = (radius > 0.0) ? radius : calc_radius; + + const Vec3d e1_unit = Measure::edge_direction(e1); + const Vec3d e2_unit = Measure::edge_direction(e2); + + const unsigned int resolution = std::max(2, 64 * angle / double(PI)); + const double step = angle / double(resolution); + const Vec3d normal = e1_unit.cross(e2_unit).normalized(); + + if (!m_dimensioning.arc.is_initialized()) { + GLModel::Geometry init_data; + init_data.format = { GLModel::Geometry::EPrimitiveType::LineStrip, GLModel::Geometry::EVertexLayout::P3 }; + init_data.color = ColorRGBA::WHITE(); + init_data.reserve_vertices(resolution + 1); + init_data.reserve_indices(resolution + 1); + + // vertices + indices + for (unsigned int i = 0; i <= resolution; ++i) { + const double a = step * double(i); + const Vec3d v = draw_radius * (Eigen::Quaternion(Eigen::AngleAxisd(a, normal)) * e1_unit); + init_data.add_vertex((Vec3f)v.cast()); + init_data.add_index(i); + } + + m_dimensioning.arc.init_from(std::move(init_data)); + } + + const Camera& camera = wxGetApp().plater()->get_camera(); +#if ENABLE_GL_CORE_PROFILE + if (OpenGLManager::get_gl_info().is_core_profile()) { + shader->stop_using(); + + shader = wxGetApp().get_shader("dashed_thick_lines"); + if (shader == nullptr) + return; + + shader->start_using(); + shader->set_uniform("projection_matrix", Transform3d::Identity()); + const std::array& viewport = camera.get_viewport(); + shader->set_uniform("viewport_size", Vec2d(double(viewport[2]), double(viewport[3]))); + shader->set_uniform("width", 1.0f); + shader->set_uniform("gap_size", 0.0f); + } + else +#endif // ENABLE_GL_CORE_PROFILE + glsafe(::glLineWidth(2.0f)); + + // arc + shader->set_uniform("projection_matrix", camera.get_projection_matrix()); + shader->set_uniform("view_model_matrix", camera.get_view_matrix() * Geometry::translation_transform(center)); + m_dimensioning.arc.render(); + +#if ENABLE_GL_CORE_PROFILE + if (OpenGLManager::get_gl_info().is_core_profile()) { + shader->stop_using(); + + shader = wxGetApp().get_shader("flat"); + if (shader == nullptr) + return; + + shader->start_using(); + } + else +#endif // ENABLE_GL_CORE_PROFILE + glsafe(::glLineWidth(1.0f)); + + // arrows + auto render_arrow = [this, shader, &camera, &normal, ¢er, &e1_unit, draw_radius, step, resolution](unsigned int endpoint_id) { + const double angle = (endpoint_id == 1) ? 0.0 : step * double(resolution); + const Vec3d position_model = Geometry::translation_transform(center) * (draw_radius * (Eigen::Quaternion(Eigen::AngleAxisd(angle, normal)) * e1_unit)); + const Vec3d direction_model = (endpoint_id == 1) ? -normal.cross(position_model - center).normalized() : normal.cross(position_model - center).normalized(); + const auto qz = Eigen::Quaternion::FromTwoVectors(Vec3d::UnitZ(), (endpoint_id == 1) ? normal : -normal); + const auto qx = Eigen::Quaternion::FromTwoVectors(qz * Vec3d::UnitX(), direction_model); + const Transform3d view_model_matrix = camera.get_view_matrix() * Geometry::translation_transform(position_model) * + qx * qz * Geometry::scale_transform(camera.get_inv_zoom()); + shader->set_uniform("view_model_matrix", view_model_matrix); + m_dimensioning.triangle.render(); + }; + + glsafe(::glDisable(GL_CULL_FACE)); + render_arrow(1); + render_arrow(2); + glsafe(::glEnable(GL_CULL_FACE)); + + // edge 1 extension + const Vec3d e11e12 = e1.second - e1.first; + const Vec3d e11center = center - e1.first; + const double e11center_len = e11center.norm(); + if (e11center_len > EPSILON && e11center.dot(e11e12) < 0.0) { + shader->set_uniform("view_model_matrix", camera.get_view_matrix() * Geometry::translation_transform(center) * + Eigen::Quaternion::FromTwoVectors(Vec3d::UnitX(), Measure::edge_direction(e1.first, e1.second)) * + Geometry::scale_transform({ e11center_len, 1.0f, 1.0f })); + m_dimensioning.line.set_color(ColorRGBA::LIGHT_GRAY()); + m_dimensioning.line.render(); + } + + // edge 2 extension + const Vec3d e21center = center - e2.first; + const double e21center_len = e21center.norm(); + if (e21center_len > EPSILON) { + shader->set_uniform("view_model_matrix", camera.get_view_matrix() * Geometry::translation_transform(center) * + Eigen::Quaternion::FromTwoVectors(Vec3d::UnitX(), Measure::edge_direction(e2.first, e2.second)) * + Geometry::scale_transform({ (coplanar && radius > 0.0) ? e21center_len : draw_radius, 1.0f, 1.0f })); + m_dimensioning.line.set_color(ColorRGBA::LIGHT_GRAY()); + m_dimensioning.line.render(); + } + + // label + // label world coordinates + const Vec3d label_position_world = Geometry::translation_transform(center) * (draw_radius * (Eigen::Quaternion(Eigen::AngleAxisd(step * 0.5 * double(resolution), normal)) * e1_unit)); + + // label screen coordinates + const std::array& viewport = camera.get_viewport(); + const Vec2d label_position_ss = TransformHelper::world_to_ss(label_position_world, + camera.get_projection_matrix().matrix() * camera.get_view_matrix().matrix(), viewport); + + m_imgui->set_next_window_pos(label_position_ss.x(), viewport[3] - label_position_ss.y(), ImGuiCond_Always, 0.0f, 1.0f); + m_imgui->set_next_window_bg_alpha(0.0f); + ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.0f); + m_imgui->begin(wxString("##angle"), ImGuiWindowFlags_NoMouseInputs | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoMove); + ImGui::BringWindowToDisplayFront(ImGui::GetCurrentWindow()); + ImGui::AlignTextToFramePadding(); + ImDrawList* draw_list = ImGui::GetWindowDrawList(); + const ImVec2 pos = ImGui::GetCursorScreenPos(); + const std::string txt = format_double(Geometry::rad2deg(angle)) + "°"; + ImVec2 txt_size = ImGui::CalcTextSize(txt.c_str()); + const ImGuiStyle& style = ImGui::GetStyle(); + draw_list->AddRectFilled({ pos.x - style.FramePadding.x, pos.y + style.FramePadding.y }, { pos.x + txt_size.x + 2.0f * style.FramePadding.x , pos.y + txt_size.y + 2.0f * style.FramePadding.y }, + ImGuiWrapper::to_ImU32(ColorRGBA(0.5f, 0.5f, 0.5f, 0.5f))); + ImGui::SetCursorScreenPos({ pos.x + style.FramePadding.x, pos.y }); + m_imgui->text(txt); + m_imgui->end(); + ImGui::PopStyleVar(); + }; + + auto arc_edge_plane = [this, arc_edge_edge](const Measure::SurfaceFeature& f1, const Measure::SurfaceFeature& f2) { + assert(f1.get_type() == Measure::SurfaceFeatureType::Edge && f2.get_type() == Measure::SurfaceFeatureType::Plane); + if (!m_measurement_result.angle.has_value()) + return; + + const std::pair e1 = m_measurement_result.angle->e1; + const std::pair e2 = m_measurement_result.angle->e2; + const double calc_radius = m_measurement_result.angle->radius; + + if (calc_radius == 0.0) + return; + + arc_edge_edge(Measure::SurfaceFeature(Measure::SurfaceFeatureType::Edge, e1.first, e1.second), + Measure::SurfaceFeature(Measure::SurfaceFeatureType::Edge, e2.first, e2.second), calc_radius); + }; + + auto arc_plane_plane = [this, arc_edge_edge](const Measure::SurfaceFeature& f1, const Measure::SurfaceFeature& f2) { + assert(f1.get_type() == Measure::SurfaceFeatureType::Plane && f2.get_type() == Measure::SurfaceFeatureType::Plane); + if (!m_measurement_result.angle.has_value()) + return; + + const std::pair e1 = m_measurement_result.angle->e1; + const std::pair e2 = m_measurement_result.angle->e2; + const double calc_radius = m_measurement_result.angle->radius; + + if (calc_radius == 0.0) + return; + + arc_edge_edge(Measure::SurfaceFeature(Measure::SurfaceFeatureType::Edge, e1.first, e1.second), + Measure::SurfaceFeature(Measure::SurfaceFeatureType::Edge, e2.first, e2.second), calc_radius); + }; + + shader->start_using(); + + if (!m_dimensioning.line.is_initialized()) { + GLModel::Geometry init_data; + init_data.format = { GLModel::Geometry::EPrimitiveType::Lines, GLModel::Geometry::EVertexLayout::P3 }; + init_data.color = ColorRGBA::WHITE(); + init_data.reserve_vertices(2); + init_data.reserve_indices(2); + + // vertices + init_data.add_vertex(Vec3f(0.0f, 0.0f, 0.0f)); + init_data.add_vertex(Vec3f(1.0f, 0.0f, 0.0f)); + + // indices + init_data.add_line(0, 1); + + m_dimensioning.line.init_from(std::move(init_data)); + } + + if (!m_dimensioning.triangle.is_initialized()) { + GLModel::Geometry init_data; + init_data.format = { GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3 }; + init_data.color = ColorRGBA::WHITE(); + init_data.reserve_vertices(3); + init_data.reserve_indices(3); + + // vertices + init_data.add_vertex(Vec3f(0.0f, 0.0f, 0.0f)); + init_data.add_vertex(Vec3f(-TRIANGLE_HEIGHT, 0.5f * TRIANGLE_BASE, 0.0f)); + init_data.add_vertex(Vec3f(-TRIANGLE_HEIGHT, -0.5f * TRIANGLE_BASE, 0.0f)); + + // indices + init_data.add_triangle(0, 1, 2); + + m_dimensioning.triangle.init_from(std::move(init_data)); + } + + if (last_selected_features != m_selected_features) + m_dimensioning.arc.reset(); + + glsafe(::glDisable(GL_DEPTH_TEST)); + + const bool has_distance = m_measurement_result.has_distance_data(); + + const Measure::SurfaceFeature* f1 = &(*m_selected_features.first.feature); + const Measure::SurfaceFeature* f2 = nullptr; + std::unique_ptr temp_feature; + if (m_selected_features.second.feature.has_value()) + f2 = &(*m_selected_features.second.feature); + else { + assert(m_selected_features.first.feature->get_type() == Measure::SurfaceFeatureType::Circle); + temp_feature = std::make_unique(std::get<0>(m_selected_features.first.feature->get_circle())); + f2 = temp_feature.get(); + } + + if (!m_selected_features.second.feature.has_value() && m_selected_features.first.feature->get_type() != Measure::SurfaceFeatureType::Circle) + return; + + Measure::SurfaceFeatureType ft1 = f1->get_type(); + Measure::SurfaceFeatureType ft2 = f2->get_type(); + + // Order features by type so following conditions are simple. + if (ft1 > ft2) { + std::swap(ft1, ft2); + std::swap(f1, f2); + } + + // If there is an angle to show, draw the arc: + if (ft1 == Measure::SurfaceFeatureType::Edge && ft2 == Measure::SurfaceFeatureType::Edge) + arc_edge_edge(*f1, *f2); + else if (ft1 == Measure::SurfaceFeatureType::Edge && ft2 == Measure::SurfaceFeatureType::Plane) + arc_edge_plane(*f1, *f2); + else if (ft1 == Measure::SurfaceFeatureType::Plane && ft2 == Measure::SurfaceFeatureType::Plane) + arc_plane_plane(*f1, *f2); + + if (has_distance){ + // Where needed, draw the extension of the edge to where the dist is measured: + if (ft1 == Measure::SurfaceFeatureType::Point && ft2 == Measure::SurfaceFeatureType::Edge) + point_edge(*f1, *f2); + + // Render the arrow between the points that the backend passed: + const Measure::DistAndPoints& dap = m_measurement_result.distance_infinite.has_value() + ? *m_measurement_result.distance_infinite + : *m_measurement_result.distance_strict; + point_point(dap.from, dap.to, dap.dist); + } + + glsafe(::glEnable(GL_DEPTH_TEST)); + + shader->stop_using(); +} + +static void add_row_to_table(std::function col_1 = nullptr, std::function col_2 = nullptr) +{ + assert(col_1 != nullptr && col_2 != nullptr); + ImGui::TableNextRow(); + ImGui::TableSetColumnIndex(0); + col_1(); + ImGui::TableSetColumnIndex(1); + col_2(); +} + +static void add_strings_row_to_table(ImGuiWrapper& imgui, const std::string& col_1, const ImVec4& col_1_color, const std::string& col_2, const ImVec4& col_2_color) +{ + add_row_to_table([&]() { imgui.text_colored(col_1_color, col_1); }, [&]() { imgui.text_colored(col_2_color, col_2); }); +}; + +#if ENABLE_MEASURE_GIZMO_DEBUG +void GLGizmoMeasure::render_debug_dialog() +{ + auto add_feature_data = [this](const SelectedFeatures::Item& item) { + const std::string text = (item.source == item.feature) ? surface_feature_type_as_string(item.feature->get_type()) : point_on_feature_type_as_string(item.source->get_type(), m_hover_id); + add_strings_row_to_table(*m_imgui, "Type", ImGuiWrapper::COL_ORANGE_LIGHT, text, ImGui::GetStyleColorVec4(ImGuiCol_Text)); + switch (item.feature->get_type()) + { + case Measure::SurfaceFeatureType::Point: + { + add_strings_row_to_table(*m_imgui, "m_pt1", ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(item.feature->get_point()), ImGui::GetStyleColorVec4(ImGuiCol_Text)); + break; + } + case Measure::SurfaceFeatureType::Edge: + { + auto [from, to] = item.feature->get_edge(); + add_strings_row_to_table(*m_imgui, "m_pt1", ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(from), ImGui::GetStyleColorVec4(ImGuiCol_Text)); + add_strings_row_to_table(*m_imgui, "m_pt2", ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(to), ImGui::GetStyleColorVec4(ImGuiCol_Text)); + break; + } + case Measure::SurfaceFeatureType::Plane: + { + auto [idx, normal, origin] = item.feature->get_plane(); + add_strings_row_to_table(*m_imgui, "m_pt1", ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(normal), ImGui::GetStyleColorVec4(ImGuiCol_Text)); + add_strings_row_to_table(*m_imgui, "m_pt2", ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(origin), ImGui::GetStyleColorVec4(ImGuiCol_Text)); + add_strings_row_to_table(*m_imgui, "m_value", ImGuiWrapper::COL_ORANGE_LIGHT, format_double(idx), ImGui::GetStyleColorVec4(ImGuiCol_Text)); + break; + } + case Measure::SurfaceFeatureType::Circle: + { + auto [center, radius, normal] = item.feature->get_circle(); + const Vec3d on_circle = center + radius * Measure::get_orthogonal(normal, true); + radius = (on_circle - center).norm(); + add_strings_row_to_table(*m_imgui, "m_pt1", ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(center), ImGui::GetStyleColorVec4(ImGuiCol_Text)); + add_strings_row_to_table(*m_imgui, "m_pt2", ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(normal), ImGui::GetStyleColorVec4(ImGuiCol_Text)); + add_strings_row_to_table(*m_imgui, "m_value", ImGuiWrapper::COL_ORANGE_LIGHT, format_double(radius), ImGui::GetStyleColorVec4(ImGuiCol_Text)); + break; + } + } + std::optional extra_point = item.feature->get_extra_point(); + if (extra_point.has_value()) + add_strings_row_to_table(*m_imgui, "m_pt3", ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(*extra_point), ImGui::GetStyleColorVec4(ImGuiCol_Text)); + }; + + m_imgui->begin("Measure tool debug", ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse); + if (ImGui::BeginTable("Mode", 2)) { + std::string txt; + switch (m_mode) + { + case EMode::FeatureSelection: { txt = "Feature selection"; break; } + case EMode::PointSelection: { txt = "Point selection"; break; } + default: { assert(false); break; } + } + add_strings_row_to_table(*m_imgui, "Mode", ImGuiWrapper::COL_ORANGE_LIGHT, txt, ImGui::GetStyleColorVec4(ImGuiCol_Text)); + ImGui::EndTable(); + } + + ImGui::Separator(); + if (ImGui::BeginTable("Hover", 2)) { + add_strings_row_to_table(*m_imgui, "Hover id", ImGuiWrapper::COL_ORANGE_LIGHT, std::to_string(m_hover_id), ImGui::GetStyleColorVec4(ImGuiCol_Text)); + const std::string txt = m_curr_feature.has_value() ? surface_feature_type_as_string(m_curr_feature->get_type()) : "None"; + add_strings_row_to_table(*m_imgui, "Current feature", ImGuiWrapper::COL_ORANGE_LIGHT, txt, ImGui::GetStyleColorVec4(ImGuiCol_Text)); + ImGui::EndTable(); + } + + ImGui::Separator(); + if (!m_selected_features.first.feature.has_value() && !m_selected_features.second.feature.has_value()) + m_imgui->text("Empty selection"); + else { + const ImGuiTableFlags flags = ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersH; + if (m_selected_features.first.feature.has_value()) { + m_imgui->text_colored(ImGuiWrapper::COL_ORANGE_LIGHT, "Selection 1"); + if (ImGui::BeginTable("Selection 1", 2, flags)) { + add_feature_data(m_selected_features.first); + ImGui::EndTable(); + } + } + if (m_selected_features.second.feature.has_value()) { + m_imgui->text_colored(ImGuiWrapper::COL_ORANGE_LIGHT, "Selection 2"); + if (ImGui::BeginTable("Selection 2", 2, flags)) { + add_feature_data(m_selected_features.second); + ImGui::EndTable(); + } + } + } + m_imgui->end(); +} +#endif // ENABLE_MEASURE_GIZMO_DEBUG + +void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit) +{ + static std::optional last_feature; + static EMode last_mode = EMode::FeatureSelection; + static SelectedFeatures last_selected_features; + + static float last_y = 0.0f; + static float last_h = 0.0f; + + if (m_editing_distance) + return; + + m_imgui->begin(get_name(), ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse); + + // adjust window position to avoid overlap the view toolbar + const float win_h = ImGui::GetWindowHeight(); + y = std::min(y, bottom_limit - win_h); + ImGui::SetWindowPos(ImVec2(x, y), ImGuiCond_Always); + if (last_h != win_h || last_y != y) { + // ask canvas for another frame to render the window in the correct position + m_imgui->set_requires_extra_frame(); + if (last_h != win_h) + last_h = win_h; + if (last_y != y) + last_y = y; + } + + if (ImGui::BeginTable("Commands", 2)) { + unsigned int row_count = 1; + add_row_to_table( + [this]() { + m_imgui->text_colored(ImGuiWrapper::COL_ORANGE_LIGHT, _u8L("Left mouse button")); + }, + [this]() { + std::string text; + ColorRGBA color; + if (m_selected_features.second.feature.has_value()) { + if (m_selected_features.first.feature == m_curr_feature && m_mode == EMode::FeatureSelection) { + // hovering over 1st selected feature + text = _u8L("Unselect feature"); + color = SELECTED_1ST_COLOR; + } + else if (m_hover_id == SEL_SPHERE_1_ID) { + if (m_selected_features.first.is_center) { + // hovering over center selected as 1st feature + text = _u8L("Unselect center"); + color = SELECTED_1ST_COLOR; + } + else if (is_feature_with_center(*m_selected_features.first.feature)) { + // hovering over center of 1st selected feature + text = _u8L("Select center"); + color = SELECTED_1ST_COLOR; + } + else { + // hovering over point selected as 1st feature + text = _u8L("Unselect point"); + color = SELECTED_1ST_COLOR; + } + } + else if (m_selected_features.first.is_center && m_selected_features.first.source == m_curr_feature) { + // hovering over feature whose center is selected as 1st feature + text = _u8L("Select feature"); + color = SELECTED_1ST_COLOR; + } + else if (m_selected_features.second.feature == m_curr_feature && m_mode == EMode::FeatureSelection) { + // hovering over 2nd selected feature + text = _u8L("Unselect feature"); + color = SELECTED_2ND_COLOR; + } + else if (m_hover_id == SEL_SPHERE_2_ID) { + if (m_selected_features.second.is_center) { + // hovering over center selected as 2nd feature + text = _u8L("Unselect feature"); + color = SELECTED_2ND_COLOR; + } + else if (is_feature_with_center(*m_selected_features.second.feature)) { + // hovering over center of 2nd selected feature + text = _u8L("Select center"); + color = SELECTED_2ND_COLOR; + } + else { + // hovering over point selected as 2nd feature + text = _u8L("Unselect point"); + color = SELECTED_2ND_COLOR; + } + } + else if (m_selected_features.second.is_center && m_selected_features.second.source == m_curr_feature) { + // hovering over feature whose center is selected as 2nd feature + text = _u8L("Select feature"); + color = SELECTED_2ND_COLOR; + } + else { + // 1st feature selected + text = (m_mode == EMode::PointSelection) ? _u8L("Select point") : _u8L("Select feature"); + color = SELECTED_2ND_COLOR; + } + } + else { + if (m_selected_features.first.feature.has_value()) { + if (m_selected_features.first.feature == m_curr_feature && m_mode == EMode::FeatureSelection) { + // hovering over 1st selected feature + text = _u8L("Unselect feature"); + color = SELECTED_1ST_COLOR; + } + else { + if (m_hover_id == SEL_SPHERE_1_ID) { + if (m_selected_features.first.is_center) { + // hovering over center selected as 1st feature + text = _u8L("Unselect feature"); + color = SELECTED_1ST_COLOR; + } + else if (is_feature_with_center(*m_selected_features.first.feature)) { + // hovering over center of 1st selected feature + text = _u8L("Select center"); + color = SELECTED_1ST_COLOR; + } + else { + // hovering over point selected as 1st feature + text = _u8L("Unselect point"); + color = SELECTED_1ST_COLOR; + } + } + else { + if (m_selected_features.first.is_center && m_selected_features.first.source == m_curr_feature) { + // hovering over feature whose center is selected as 1st feature + text = _u8L("Select feature"); + color = SELECTED_1ST_COLOR; + } + else { + // 1st feature selected + text = (m_mode == EMode::PointSelection) ? _u8L("Select point") : _u8L("Select feature"); + color = SELECTED_2ND_COLOR; + } + } + } + } + else { + // nothing is selected + text = (m_mode == EMode::PointSelection) ? _u8L("Select point") : _u8L("Select feature"); + color = SELECTED_1ST_COLOR; + } + } + + assert(!text.empty()); + + m_imgui->text_colored(ImGui::GetStyleColorVec4(ImGuiCol_Text), text); + ImGui::SameLine(); + const ImVec2 pos = ImGui::GetCursorScreenPos(); + const float rect_size = ImGui::GetTextLineHeight(); + ImGui::GetWindowDrawList()->AddRectFilled(ImVec2(pos.x + 1.0f, pos.y + 1.0f), ImVec2(pos.x + rect_size, pos.y + rect_size), ImGuiWrapper::to_ImU32(color)); + ImGui::Dummy(ImVec2(rect_size, rect_size)); + } + ); + + if (m_mode == EMode::FeatureSelection && m_hover_id != -1) { + add_strings_row_to_table(*m_imgui, "Shift", ImGuiWrapper::COL_ORANGE_LIGHT, _u8L("Enable point selection"), ImGui::GetStyleColorVec4(ImGuiCol_Text)); + ++row_count; + } + + if (m_selected_features.first.feature.has_value()) { + add_strings_row_to_table(*m_imgui, "Delete", ImGuiWrapper::COL_ORANGE_LIGHT, _u8L("Restart selection"), ImGui::GetStyleColorVec4(ImGuiCol_Text)); + ++row_count; + } + + if (m_selected_features.first.feature.has_value() || m_selected_features.second.feature.has_value()) { + add_row_to_table( + [this]() { + m_imgui->text_colored(ImGuiWrapper::COL_ORANGE_LIGHT, "Esc"); + }, + [this]() { + m_imgui->text_colored(ImGui::GetStyleColorVec4(ImGuiCol_Text), _u8L("Unselect")); + ImGui::SameLine(); + const ImVec2 pos = ImGui::GetCursorScreenPos(); + const float rect_size = ImGui::GetTextLineHeight(); + const ColorRGBA color = m_selected_features.second.feature.has_value() ? SELECTED_2ND_COLOR : SELECTED_1ST_COLOR; + ImGui::GetWindowDrawList()->AddRectFilled(ImVec2(pos.x + 1.0f, pos.y + 1.0f), ImVec2(pos.x + rect_size, pos.y + rect_size), ImGuiWrapper::to_ImU32(color)); + ImGui::Dummy(ImVec2(rect_size, rect_size)); + } + ); + + ++row_count; + } + + // add dummy rows to keep dialog size fixed + for (unsigned int i = row_count; i < 4; ++i) { + add_strings_row_to_table(*m_imgui, " ", ImGuiWrapper::COL_ORANGE_LIGHT, " ", ImGui::GetStyleColorVec4(ImGuiCol_Text)); + } + + ImGui::EndTable(); + } + + const bool use_inches = wxGetApp().app_config->get_bool("use_inches"); + const std::string units = use_inches ? " " + _u8L("in") : " " + _u8L("mm"); + + ImGui::Separator(); + const ImGuiTableFlags flags = ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersH; + if (ImGui::BeginTable("Selection", 2, flags)) { + auto format_item_text = [this, use_inches, &units](const SelectedFeatures::Item& item) { + if (!item.feature.has_value()) + return _u8L("None"); + + std::string text = (item.source == item.feature) ? surface_feature_type_as_string(item.feature->get_type()) : + item.is_center ? center_on_feature_type_as_string(item.source->get_type()) : point_on_feature_type_as_string(item.source->get_type(), m_hover_id); + if (item.feature.has_value() && item.feature->get_type() == Measure::SurfaceFeatureType::Circle) { + auto [center, radius, normal] = item.feature->get_circle(); + const Vec3d on_circle = center + radius * Measure::get_orthogonal(normal, true); + radius = (on_circle - center).norm(); + if (use_inches) + radius = GizmoObjectManipulation::mm_to_in * radius; + text += " (" + _u8L("Diameter") + ": " + format_double(2.0 * radius) + units + ")"; + } + else if (item.feature.has_value() && item.feature->get_type() == Measure::SurfaceFeatureType::Edge) { + auto [start, end] = item.feature->get_edge(); + double length = (end - start).norm(); + if (use_inches) + length = GizmoObjectManipulation::mm_to_in * length; + text += " (" + _u8L("Length") + ": " + format_double(length) + units + ")"; + } + return text; + }; + + add_strings_row_to_table(*m_imgui, _u8L("Selection") + " 1:", ImGuiWrapper::to_ImVec4(SELECTED_1ST_COLOR), format_item_text(m_selected_features.first), + ImGuiWrapper::to_ImVec4(SELECTED_1ST_COLOR)); + add_strings_row_to_table(*m_imgui, _u8L("Selection") + " 2:", ImGuiWrapper::to_ImVec4(SELECTED_2ND_COLOR), format_item_text(m_selected_features.second), + ImGuiWrapper::to_ImVec4(SELECTED_2ND_COLOR)); + ImGui::EndTable(); + } + + m_imgui->disabled_begin(!m_selected_features.first.feature.has_value()); + if (m_imgui->button(_L("Restart selection"))) { + m_selected_features.reset(); + m_selected_sphere_raycasters.clear(); + m_imgui->set_requires_extra_frame(); + } + m_imgui->disabled_end(); + + auto add_measure_row_to_table = [this](const std::string& col_1, const ImVec4& col_1_color, const std::string& col_2, const ImVec4& col_2_color) { + ImGui::TableNextRow(); + ImGui::TableSetColumnIndex(0); + m_imgui->text_colored(col_1_color, col_1); + ImGui::TableSetColumnIndex(1); + m_imgui->text_colored(col_2_color, col_2); + ImGui::TableSetColumnIndex(2); + if (m_imgui->image_button(ImGui::ClipboardBtnIcon, _L("Copy to clipboard"))) { + wxTheClipboard->Open(); + wxTheClipboard->SetData(new wxTextDataObject(col_1 + ": " + col_2)); + wxTheClipboard->Close(); + } + }; + + ImGui::Separator(); + m_imgui->text(_u8L("Measure")); + + const unsigned int max_measure_row_count = 2; + unsigned int measure_row_count = 0; + if (ImGui::BeginTable("Measure", 4)) { + if (m_selected_features.second.feature.has_value()) { + const Measure::MeasurementResult& measure = m_measurement_result; + if (measure.angle.has_value()) { + ImGui::PushID("ClipboardAngle"); + add_measure_row_to_table(_u8L("Angle"), ImGuiWrapper::COL_ORANGE_LIGHT, format_double(Geometry::rad2deg(measure.angle->angle)) + "°", + ImGui::GetStyleColorVec4(ImGuiCol_Text)); + ++measure_row_count; + ImGui::PopID(); + } + + const bool show_strict = measure.distance_strict.has_value() && + (!measure.distance_infinite.has_value() || std::abs(measure.distance_strict->dist - measure.distance_infinite->dist) > EPSILON); + + if (measure.distance_infinite.has_value()) { + double distance = measure.distance_infinite->dist; + if (use_inches) + distance = GizmoObjectManipulation::mm_to_in * distance; + ImGui::PushID("ClipboardDistanceInfinite"); + add_measure_row_to_table(show_strict ? _u8L("Perpendicular distance") : _u8L("Distance"), ImGuiWrapper::COL_ORANGE_LIGHT, format_double(distance) + units, + ImGui::GetStyleColorVec4(ImGuiCol_Text)); + ++measure_row_count; + ImGui::PopID(); + } + if (show_strict) { + double distance = measure.distance_strict->dist; + if (use_inches) + distance = GizmoObjectManipulation::mm_to_in * distance; + ImGui::PushID("ClipboardDistanceStrict"); + add_measure_row_to_table(_u8L("Direct distance"), ImGuiWrapper::COL_ORANGE_LIGHT, format_double(distance) + units, + ImGui::GetStyleColorVec4(ImGuiCol_Text)); + ++measure_row_count; + ImGui::PopID(); + } + if (measure.distance_xyz.has_value() && measure.distance_xyz->norm() > EPSILON) { + Vec3d distance = *measure.distance_xyz; + if (use_inches) + distance = GizmoObjectManipulation::mm_to_in * distance; + ImGui::PushID("ClipboardDistanceXYZ"); + add_measure_row_to_table(_u8L("Distance XYZ"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(distance), + ImGui::GetStyleColorVec4(ImGuiCol_Text)); + ++measure_row_count; + ImGui::PopID(); + } + } + + // add dummy rows to keep dialog size fixed + for (unsigned int i = measure_row_count; i < max_measure_row_count; ++i) { + add_strings_row_to_table(*m_imgui, " ", ImGuiWrapper::COL_ORANGE_LIGHT, " ", ImGui::GetStyleColorVec4(ImGuiCol_Text)); + } + ImGui::EndTable(); + } + + if (last_feature != m_curr_feature || last_mode != m_mode || last_selected_features != m_selected_features) { + // the dialog may have changed its size, ask for an extra frame to render it properly + last_feature = m_curr_feature; + last_mode = m_mode; + last_selected_features = m_selected_features; + m_imgui->set_requires_extra_frame(); + } + + m_imgui->end(); +} + +void GLGizmoMeasure::on_register_raycasters_for_picking() +{ + // the features are rendered on top of the scene, so the raytraced picker should take it into account + m_parent.set_raycaster_gizmos_on_top(true); +} + +void GLGizmoMeasure::on_unregister_raycasters_for_picking() +{ + m_parent.remove_raycasters_for_picking(SceneRaycaster::EType::Gizmo); + m_parent.set_raycaster_gizmos_on_top(false); + m_raycasters.clear(); + m_selected_sphere_raycasters.clear(); +} + +void GLGizmoMeasure::remove_selected_sphere_raycaster(int id) +{ + auto it = std::find_if(m_selected_sphere_raycasters.begin(), m_selected_sphere_raycasters.end(), + [id](std::shared_ptr item) { return SceneRaycaster::decode_id(SceneRaycaster::EType::Gizmo, item->get_id()) == id; }); + if (it != m_selected_sphere_raycasters.end()) + m_selected_sphere_raycasters.erase(it); + m_parent.remove_raycasters_for_picking(SceneRaycaster::EType::Gizmo, id); +} + +void GLGizmoMeasure::update_measurement_result() +{ + if (!m_selected_features.first.feature.has_value()) + m_measurement_result = Measure::MeasurementResult(); + else if (m_selected_features.second.feature.has_value()) + m_measurement_result = Measure::get_measurement(*m_selected_features.first.feature, *m_selected_features.second.feature, m_measuring.get()); + else if (!m_selected_features.second.feature.has_value() && m_selected_features.first.feature->get_type() == Measure::SurfaceFeatureType::Circle) + m_measurement_result = Measure::get_measurement(*m_selected_features.first.feature, Measure::SurfaceFeature(std::get<0>(m_selected_features.first.feature->get_circle())), m_measuring.get()); +} + +} // namespace GUI +} // namespace Slic3r diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp new file mode 100644 index 00000000000..4ab67b8d00c --- /dev/null +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp @@ -0,0 +1,190 @@ +///|/ Copyright (c) Prusa Research 2019 - 2023 Oleksandra Iushchenko @YuSanka, Lukáš Matěna @lukasmatena, Enrico Turri @enricoturri1966, Vojtěch Bubník @bubnikv, Filip Sykala @Jony01 +///|/ +///|/ PrusaSlicer is released under the terms of the AGPLv3 or higher +///|/ +#ifndef slic3r_GLGizmoMeasure_hpp_ +#define slic3r_GLGizmoMeasure_hpp_ + +#include "GLGizmoBase.hpp" +#include "slic3r/GUI/GLModel.hpp" +#include "slic3r/GUI/GUI_Utils.hpp" +#include "slic3r/GUI/MeshUtils.hpp" +#include "slic3r/GUI/I18N.hpp" +#include "libslic3r/Measure.hpp" +#include "libslic3r/Model.hpp" + +namespace Slic3r { + +enum class ModelVolumeType : int; + +namespace Measure { class Measuring; } + + +namespace GUI { + +enum class SLAGizmoEventType : unsigned char; + +class GLGizmoMeasure : public GLGizmoBase +{ + enum class EMode : unsigned char + { + FeatureSelection, + PointSelection + }; + + struct SelectedFeatures + { + struct Item + { + bool is_center{ false }; + std::optional source; + std::optional feature; + + bool operator == (const Item& other) const { + return this->is_center == other.is_center && this->source == other.source && this->feature == other.feature; + } + + bool operator != (const Item& other) const { + return !operator == (other); + } + + void reset() { + is_center = false; + source.reset(); + feature.reset(); + } + }; + + Item first; + Item second; + + void reset() { + first.reset(); + second.reset(); + } + + bool operator == (const SelectedFeatures & other) const { + if (this->first != other.first) return false; + return this->second == other.second; + } + + bool operator != (const SelectedFeatures & other) const { + return !operator == (other); + } + }; + + struct VolumeCacheItem + { + const ModelObject* object{ nullptr }; + const ModelInstance* instance{ nullptr }; + const ModelVolume* volume{ nullptr }; + Transform3d world_trafo; + + bool operator == (const VolumeCacheItem& other) const { + return this->object == other.object && this->instance == other.instance && this->volume == other.volume && + this->world_trafo.isApprox(other.world_trafo); + } + }; + + std::vector m_volumes_cache; + + EMode m_mode{ EMode::FeatureSelection }; + Measure::MeasurementResult m_measurement_result; + + std::unique_ptr m_measuring; // PIMPL + + PickingModel m_sphere; + PickingModel m_cylinder; + PickingModel m_circle; + PickingModel m_plane; + struct Dimensioning + { + GLModel line; + GLModel triangle; + GLModel arc; + }; + Dimensioning m_dimensioning; + + // Uses a standalone raycaster and not the shared one because of the + // difference in how the mesh is updated + std::unique_ptr m_raycaster; + + std::vector m_plane_models_cache; + std::map> m_raycasters; + // used to keep the raycasters for point/center spheres + std::vector> m_selected_sphere_raycasters; + std::optional m_curr_feature; + std::optional m_curr_point_on_feature_position; + struct SceneRaycasterState + { + std::shared_ptr raycaster{ nullptr }; + bool state{true}; + + }; + std::vector m_scene_raycasters; + + // These hold information to decide whether recalculation is necessary: + float m_last_inv_zoom{ 0.0f }; + std::optional m_last_circle; + int m_last_plane_idx{ -1 }; + + bool m_mouse_left_down{ false }; // for detection left_up of this gizmo + + Vec2d m_mouse_pos{ Vec2d::Zero() }; + + KeyAutoRepeatFilter m_shift_kar_filter; + + SelectedFeatures m_selected_features; + bool m_pending_scale{ false }; + bool m_editing_distance{ false }; + bool m_is_editing_distance_first_frame{ true }; + + void update_if_needed(); + + void disable_scene_raycasters(); + void restore_scene_raycasters_state(); + + void render_dimensioning(); + +#if ENABLE_MEASURE_GIZMO_DEBUG + void render_debug_dialog(); +#endif // ENABLE_MEASURE_GIZMO_DEBUG + +public: + GLGizmoMeasure(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id); + + /// + /// Apply rotation on select plane + /// + /// Keep information about mouse click + /// Return True when use the information otherwise False. + bool on_mouse(const wxMouseEvent &mouse_event) override; + + void data_changed(bool is_serializing) override; + + bool gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_position, bool shift_down, bool alt_down, bool control_down); + + bool wants_enter_leave_snapshots() const override { return true; } + std::string get_gizmo_entering_text() const override { return _u8L("Entering Measure gizmo"); } + std::string get_gizmo_leaving_text() const override { return _u8L("Leaving Measure gizmo"); } + std::string get_action_snapshot_name() const override { return _u8L("Measure gizmo editing"); } + +protected: + bool on_init() override; + std::string on_get_name() const override; + bool on_is_activable() const override; + void on_render() override; + void on_set_state() override; + + virtual void on_render_input_window(float x, float y, float bottom_limit) override; + virtual void on_register_raycasters_for_picking() override; + virtual void on_unregister_raycasters_for_picking() override; + + void remove_selected_sphere_raycaster(int id); + void update_measurement_result(); +}; + +} // namespace GUI +} // namespace Slic3r + +#endif // slic3r_GLGizmoMeasure_hpp_ diff --git a/src/slic3r/GUI/Gizmos/GLGizmosCommon.hpp b/src/slic3r/GUI/Gizmos/GLGizmosCommon.hpp index a0631671256..6f2138346eb 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosCommon.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosCommon.hpp @@ -30,8 +30,12 @@ enum class SLAGizmoEventType : unsigned char { Dragging, Delete, SelectAll, + CtrlDown, + CtrlUp, + ShiftDown, ShiftUp, AltUp, + Escape, ApplyChanges, DiscardChanges, AutomaticGeneration, diff --git a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp index 7b5735d8030..25169aca8bf 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp @@ -27,6 +27,7 @@ #include "slic3r/GUI/Gizmos/GLGizmoSeam.hpp" #include "slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.hpp" #include "slic3r/GUI/Gizmos/GLGizmoSimplify.hpp" +#include "slic3r/GUI/Gizmos/GLGizmoMeasure.hpp" #include "slic3r/GUI/Gizmos/GLGizmoText.hpp" #include "slic3r/GUI/Gizmos/GLGizmoMeshBoolean.hpp" @@ -195,6 +196,7 @@ bool GLGizmosManager::init() m_gizmos.emplace_back(new GLGizmoSeam(m_parent, m_is_dark ? "toolbar_seam_dark.svg" : "toolbar_seam.svg", EType::Seam)); m_gizmos.emplace_back(new GLGizmoText(m_parent, m_is_dark ? "toolbar_text_dark.svg" : "toolbar_text.svg", EType::Text)); m_gizmos.emplace_back(new GLGizmoMmuSegmentation(m_parent, m_is_dark ? "mmu_segmentation_dark.svg" : "mmu_segmentation.svg", EType::MmuSegmentation)); + m_gizmos.emplace_back(new GLGizmoMeasure(m_parent, "measure.svg", EType::Measure)); m_gizmos.emplace_back(new GLGizmoSimplify(m_parent, "reduce_triangles.svg", EType::Simplify)); //m_gizmos.emplace_back(new GLGizmoSlaSupports(m_parent, "sla_supports.svg", sprite_id++)); //m_gizmos.emplace_back(new GLGizmoFaceDetector(m_parent, "face recognition.svg", sprite_id++)); @@ -438,6 +440,8 @@ bool GLGizmosManager::gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_p return dynamic_cast(m_gizmos[MmuSegmentation].get())->gizmo_event(action, mouse_position, shift_down, alt_down, control_down); else if (m_current == Text) return dynamic_cast(m_gizmos[Text].get())->gizmo_event(action, mouse_position, shift_down, alt_down, control_down); + else if (m_current == Measure) + return dynamic_cast(m_gizmos[Measure].get())->gizmo_event(action, mouse_position, shift_down, alt_down, control_down); else if (m_current == Cut) return dynamic_cast(m_gizmos[Cut].get())->gizmo_event(action, mouse_position, shift_down, alt_down, control_down); else if (m_current == MeshBoolean) @@ -689,8 +693,10 @@ bool GLGizmosManager::on_char(wxKeyEvent& evt) // key ESC case WXK_ESCAPE: { - if (m_current != Undefined) - { + if (m_current != Undefined) { + if (m_current == Measure && gizmo_event(SLAGizmoEventType::Escape)) { + // do nothing + } else //if ((m_current != SlaSupports) || !gizmo_event(SLAGizmoEventType::DiscardChanges)) reset_all_states(); @@ -698,7 +704,14 @@ bool GLGizmosManager::on_char(wxKeyEvent& evt) } break; } - //skip some keys when gizmo + case WXK_BACK: + case WXK_DELETE: + { + if ((m_current == Cut || m_current == Measure) && gizmo_event(SLAGizmoEventType::Delete)) + processed = true; + + break; + } case 'A': case 'a': { @@ -827,6 +840,12 @@ bool GLGizmosManager::on_key(wxKeyEvent& evt) processed = true; } }*/ + if (m_current == Measure) { + if (keyCode == WXK_CONTROL) + gizmo_event(SLAGizmoEventType::CtrlUp, Vec2d::Zero(), evt.ShiftDown(), evt.AltDown(), evt.CmdDown()); + else if (keyCode == WXK_SHIFT) + gizmo_event(SLAGizmoEventType::ShiftUp, Vec2d::Zero(), evt.ShiftDown(), evt.AltDown(), evt.CmdDown()); + } // if (processed) // m_parent.set_cursor(GLCanvas3D::Standard); @@ -897,6 +916,12 @@ bool GLGizmosManager::on_key(wxKeyEvent& evt) wxGetApp().imgui()->set_requires_extra_frame(); } } + else if (m_current == Measure) { + if (keyCode == WXK_CONTROL) + gizmo_event(SLAGizmoEventType::CtrlDown, Vec2d::Zero(), evt.ShiftDown(), evt.AltDown(), evt.CmdDown()); + else if (keyCode == WXK_SHIFT) + gizmo_event(SLAGizmoEventType::ShiftDown, Vec2d::Zero(), evt.ShiftDown(), evt.AltDown(), evt.CmdDown()); + } } if (processed) diff --git a/src/slic3r/GUI/Gizmos/GLGizmosManager.hpp b/src/slic3r/GUI/Gizmos/GLGizmosManager.hpp index a2a9b2f3a9b..02169e08d4d 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosManager.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosManager.hpp @@ -88,6 +88,7 @@ class GLGizmosManager : public Slic3r::ObjectBase // BBS Text, MmuSegmentation, + Measure, Simplify, //SlaSupports, // BBS diff --git a/src/slic3r/GUI/ImGuiWrapper.cpp b/src/slic3r/GUI/ImGuiWrapper.cpp index 037ba161dd0..37135f5336a 100644 --- a/src/slic3r/GUI/ImGuiWrapper.cpp +++ b/src/slic3r/GUI/ImGuiWrapper.cpp @@ -1,3 +1,8 @@ +///|/ Copyright (c) Prusa Research 2018 - 2023 Oleksandra Iushchenko @YuSanka, Lukáš Matěna @lukasmatena, Enrico Turri @enricoturri1966, David Kocík @kocikdav, Vojtěch Bubník @bubnikv, Tomáš Mészáros @tamasmeszaros, Filip Sykala @Jony01, Lukáš Hejl @hejllukas, Vojtěch Král @vojtechkral +///|/ Copyright (c) 2019 Jason Tibbitts @jasontibbitts +///|/ +///|/ PrusaSlicer is released under the terms of the AGPLv3 or higher +///|/ #include "ImGuiWrapper.hpp" #include @@ -63,6 +68,7 @@ static const std::map font_icons = { #if ENABLE_ENHANCED_IMGUI_SLIDER_FLOAT {ImGui::SliderFloatEditBtnIcon, "edit_button" }, #endif // ENABLE_ENHANCED_IMGUI_SLIDER_FLOAT + {ImGui::ClipboardBtnIcon , "copy_menu" }, {ImGui::CircleButtonIcon , "circle_paint" }, {ImGui::TriangleButtonIcon , "triangle_paint" }, {ImGui::FillButtonIcon , "fill_paint" }, @@ -789,11 +795,6 @@ bool ImGuiWrapper::radio_button(const wxString &label, bool active) return ImGui::RadioButton(label_utf8.c_str(), active); } -bool ImGuiWrapper::image_button() -{ - return false; -} - bool ImGuiWrapper::input_double(const std::string &label, const double &value, const std::string &format) { return ImGui::InputDouble(label.c_str(), const_cast(&value), 0.0f, 0.0f, format.c_str(), ImGuiInputTextFlags_CharsDecimal); @@ -1035,6 +1036,71 @@ bool ImGuiWrapper::slider_float(const wxString& label, float* v, float v_min, fl } #endif // ENABLE_ENHANCED_IMGUI_SLIDER_FLOAT +static bool image_button_ex(ImGuiID id, ImTextureID texture_id, const ImVec2& size, const ImVec2& uv0, const ImVec2& uv1, const ImVec2& padding, const ImVec4& bg_col, const ImVec4& tint_col, ImGuiButtonFlags flags) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = ImGui::GetCurrentWindow(); + if (window->SkipItems) + return false; + + const ImRect bb(window->DC.CursorPos, window->DC.CursorPos + size + padding * 2); + ImGui::ItemSize(bb); + if (!ImGui::ItemAdd(bb, id)) + return false; + + bool hovered, held; + bool pressed = ImGui::ButtonBehavior(bb, id, &hovered, &held, flags); + + // Render + const ImU32 col = ImGui::GetColorU32((held && hovered) ? ImGuiCol_ButtonActive : hovered ? ImGuiCol_ButtonHovered : ImGuiCol_Button); + ImGui::RenderNavHighlight(bb, id); + ImGui::RenderFrame(bb.Min, bb.Max, col, true, ImClamp((float)ImMin(padding.x, padding.y), 0.0f, g.Style.FrameRounding)); + if (bg_col.w > 0.0f) + window->DrawList->AddRectFilled(bb.Min + padding, bb.Max - padding, ImGui::GetColorU32(bg_col)); + window->DrawList->AddImage(texture_id, bb.Min + padding, bb.Max - padding, uv0, uv1, ImGui::GetColorU32(tint_col)); + + return pressed; +} + +bool ImGuiWrapper::image_button(ImTextureID user_texture_id, const ImVec2& size, const ImVec2& uv0, const ImVec2& uv1, int frame_padding, const ImVec4& bg_col, const ImVec4& tint_col, ImGuiButtonFlags flags) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + if (window->SkipItems) + return false; + + // Default to using texture ID as ID. User can still push string/integer prefixes. + ImGui::PushID((void*)(intptr_t)user_texture_id); + const ImGuiID id = window->GetID("#image"); + ImGui::PopID(); + + const ImVec2 padding = (frame_padding >= 0) ? ImVec2((float)frame_padding, (float)frame_padding) : g.Style.FramePadding; + return image_button_ex(id, user_texture_id, size, uv0, uv1, padding, bg_col, tint_col, flags); +} + +bool ImGuiWrapper::image_button(const wchar_t icon, const wxString& tooltip) +{ + const ImGuiIO& io = ImGui::GetIO(); + const ImTextureID tex_id = io.Fonts->TexID; + assert(io.Fonts->TexWidth > 0 && io.Fonts->TexHeight > 0); + const float inv_tex_w = 1.0f / float(io.Fonts->TexWidth); + const float inv_tex_h = 1.0f / float(io.Fonts->TexHeight); + const ImFontAtlasCustomRect* const rect = GetTextureCustomRect(icon); + const ImVec2 size = { float(rect->Width), float(rect->Height) }; + const ImVec2 uv0 = ImVec2(float(rect->X) * inv_tex_w, float(rect->Y) * inv_tex_h); + const ImVec2 uv1 = ImVec2(float(rect->X + rect->Width) * inv_tex_w, float(rect->Y + rect->Height) * inv_tex_h); + ImGui::PushStyleColor(ImGuiCol_Button, { 0.25f, 0.25f, 0.25f, 0.0f }); + ImGui::PushStyleColor(ImGuiCol_ButtonHovered, { 0.4f, 0.4f, 0.4f, 1.0f }); + ImGui::PushStyleColor(ImGuiCol_ButtonActive, { 0.25f, 0.25f, 0.25f, 1.0f }); + const bool res = image_button(tex_id, size, uv0, uv1); + ImGui::PopStyleColor(3); + + if (!tooltip.empty() && ImGui::IsItemHovered()) + this->tooltip(tooltip, ImGui::GetFontSize() * 20.0f); + + return res; +} + bool ImGuiWrapper::combo(const wxString& label, const std::vector& options, int& selection) { // this is to force the label to the left of the widget: @@ -1780,6 +1846,17 @@ bool ImGuiWrapper::want_any_input() const return io.WantCaptureMouse || io.WantCaptureKeyboard || io.WantTextInput; } +ImFontAtlasCustomRect* ImGuiWrapper::GetTextureCustomRect(const wchar_t& tex_id) +{ + auto item = m_custom_glyph_rects_ids.find(tex_id); + return (item != m_custom_glyph_rects_ids.end()) ? ImGui::GetIO().Fonts->GetCustomRectByIndex(m_custom_glyph_rects_ids[tex_id]) : nullptr; +} + +void ImGuiWrapper::disable_background_fadeout_animation() +{ + GImGui->DimBgRatio = 1.0f; +} + ImU32 ImGuiWrapper::to_ImU32(const ColorRGBA& color) { return ImGui::GetColorU32({ color.r(), color.g(), color.b(), color.a() }); @@ -2151,12 +2228,18 @@ void ImGuiWrapper::init_font(bool compress) int rect_id = io.Fonts->CustomRects.Size; // id of the rectangle added next // add rectangles for the icons to the font atlas - for (auto& icon : font_icons) + for (auto& icon : font_icons) { + m_custom_glyph_rects_ids[icon.first] = io.Fonts->AddCustomRectFontGlyph(default_font, icon.first, icon_sz, icon_sz, 3.0 * font_scale + icon_sz); - for (auto& icon : font_icons_large) + } + for (auto& icon : font_icons_large) { + m_custom_glyph_rects_ids[icon.first] = io.Fonts->AddCustomRectFontGlyph(default_font, icon.first, icon_sz * 2, icon_sz * 2, 3.0 * font_scale + icon_sz * 2); - for (auto& icon : font_icons_extra_large) + } + for (auto& icon : font_icons_extra_large) { + m_custom_glyph_rects_ids[icon.first] = io.Fonts->AddCustomRectFontGlyph(default_font, icon.first, icon_sz * 4, icon_sz * 4, 3.0 * font_scale + icon_sz * 4); + } // Build texture atlas unsigned char* pixels; @@ -2164,55 +2247,37 @@ void ImGuiWrapper::init_font(bool compress) io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height); // Load as RGBA 32-bits (75% of the memory is wasted, but default font is so small) because it is more likely to be compatible with user's existing shaders. If your ImTextureId represent a higher-level concept than just a GL texture id, consider calling GetTexDataAsAlpha8() instead to save on GPU memory. BOOST_LOG_TRIVIAL(trace) << "Build default font texture done. width: " << width << ", height: " << height; - // Fill rectangles from the SVG-icons - for (auto icon : font_icons) { + auto load_icon_from_svg = [this, &io, pixels, width, &rect_id](const std::pair icon, int icon_sz) { if (const ImFontAtlas::CustomRect* rect = io.Fonts->GetCustomRectByIndex(rect_id)) { assert(rect->Width == icon_sz); assert(rect->Height == icon_sz); - unsigned outwidth, outheight; + unsigned outwidth, outheight; std::vector raw_data = load_svg(icon.second, icon_sz, icon_sz, &outwidth, &outheight); - const ImU32* pIn = (ImU32*)raw_data.data(); - for (unsigned y = 0; y < outheight; y++) { - ImU32* pOut = (ImU32*)pixels + (rect->Y + y) * width + (rect->X); - for (unsigned x = 0; x < outwidth; x++) - *pOut++ = *pIn++; + if (!raw_data.empty()) { + const ImU32* pIn = (ImU32*)raw_data.data(); + for (unsigned y = 0; y < outheight; y++) { + ImU32* pOut = (ImU32*)pixels + (rect->Y + y) * width + (rect->X); + for (unsigned x = 0; x < outwidth; x++) + *pOut++ = *pIn++; + } } } rect_id++; + }; + + // Fill rectangles from the SVG-icons + for (auto icon : font_icons) { + load_icon_from_svg(icon, icon_sz); } icon_sz *= 2; // default size of large icon is 32 px for (auto icon : font_icons_large) { - if (const ImFontAtlas::CustomRect* rect = io.Fonts->GetCustomRectByIndex(rect_id)) { - assert(rect->Width == icon_sz); - assert(rect->Height == icon_sz); - unsigned outwidth, outheight; - std::vector raw_data = load_svg(icon.second, icon_sz, icon_sz, &outwidth, &outheight); - const ImU32* pIn = (ImU32*)raw_data.data(); - for (unsigned y = 0; y < outheight; y++) { - ImU32* pOut = (ImU32*)pixels + (rect->Y + y) * width + (rect->X); - for (unsigned x = 0; x < outwidth; x++) - *pOut++ = *pIn++; - } - } - rect_id++; + load_icon_from_svg(icon, icon_sz); } icon_sz *= 2; // default size of extra large icon is 64 px for (auto icon : font_icons_extra_large) { - if (const ImFontAtlas::CustomRect* rect = io.Fonts->GetCustomRectByIndex(rect_id)) { - assert(rect->Width == icon_sz); - assert(rect->Height == icon_sz); - unsigned outwidth, outheight; - std::vector raw_data = load_svg(icon.second, icon_sz, icon_sz, &outwidth, &outheight); - const ImU32* pIn = (ImU32*)raw_data.data(); - for (unsigned y = 0; y < outheight; y++) { - ImU32* pOut = (ImU32*)pixels + (rect->Y + y) * width + (rect->X); - for (unsigned x = 0; x < outwidth; x++) - *pOut++ = *pIn++; - } - } - rect_id++; + load_icon_from_svg(icon, icon_sz); } // Upload texture to graphics system diff --git a/src/slic3r/GUI/ImGuiWrapper.hpp b/src/slic3r/GUI/ImGuiWrapper.hpp index 5f37c16eb7f..aefd933f051 100644 --- a/src/slic3r/GUI/ImGuiWrapper.hpp +++ b/src/slic3r/GUI/ImGuiWrapper.hpp @@ -1,3 +1,7 @@ +///|/ Copyright (c) Prusa Research 2018 - 2023 Oleksandra Iushchenko @YuSanka, Enrico Turri @enricoturri1966, Filip Sykala @Jony01, Lukáš Matěna @lukasmatena, Vojtěch Bubník @bubnikv, Lukáš Hejl @hejllukas, David Kocík @kocikdav, Vojtěch Král @vojtechkral +///|/ +///|/ PrusaSlicer is released under the terms of the AGPLv3 or higher +///|/ #ifndef slic3r_ImGuiWrapper_hpp_ #define slic3r_ImGuiWrapper_hpp_ @@ -61,6 +65,7 @@ class ImGuiWrapper #if ENABLE_ENHANCED_IMGUI_SLIDER_FLOAT bool m_requires_extra_frame{ false }; #endif // ENABLE_ENHANCED_IMGUI_SLIDER_FLOAT + std::map m_custom_glyph_rects_ids; std::string m_clipboard_text; public: @@ -117,7 +122,6 @@ class ImGuiWrapper bool bbl_button(const wxString &label); bool button(const wxString& label, float width, float height); bool radio_button(const wxString &label, bool active); - bool image_button(); bool input_double(const std::string &label, const double &value, const std::string &format = "%.3f"); bool input_double(const wxString &label, const double &value, const std::string &format = "%.3f"); bool input_vec3(const std::string &label, const Vec3d &value, float width, const std::string &format = "%.3f"); @@ -150,6 +154,9 @@ class ImGuiWrapper bool slider_float(const wxString& label, float* v, float v_min, float v_max, const char* format = "%.3f", float power = 1.0f, bool clamp = true); #endif // ENABLE_ENHANCED_IMGUI_SLIDER_FLOAT + bool image_button(ImTextureID user_texture_id, const ImVec2& size, const ImVec2& uv0 = ImVec2(0.0, 0.0), const ImVec2& uv1 = ImVec2(1.0, 1.0), int frame_padding = -1, const ImVec4& bg_col = ImVec4(0.0, 0.0, 0.0, 0.0), const ImVec4& tint_col = ImVec4(1.0, 1.0, 1.0, 1.0), ImGuiButtonFlags flags = 0); + bool image_button(const wchar_t icon, const wxString& tooltip = L""); + bool combo(const wxString& label, const std::vector& options, int& selection); // Use -1 to not mark any option as selected bool undo_redo_list(const ImVec2& size, const bool is_undo, bool (*items_getter)(const bool, int, const char**), int& hovered, int& selected, int& mouse_wheel); void search_list(const ImVec2& size, bool (*items_getter)(int, const char** label, const char** tooltip), char* search_str, @@ -184,11 +191,15 @@ class ImGuiWrapper void reset_requires_extra_frame() { m_requires_extra_frame = false; } #endif // ENABLE_ENHANCED_IMGUI_SLIDER_FLOAT + void disable_background_fadeout_animation(); + static ImU32 to_ImU32(const ColorRGBA& color); static ImVec4 to_ImVec4(const ColorRGBA& color); static ColorRGBA from_ImU32(const ImU32& color); static ColorRGBA from_ImVec4(const ImVec4& color); + ImFontAtlasCustomRect* GetTextureCustomRect(const wchar_t& tex_id); + static const ImVec4 COL_GREY_DARK; static const ImVec4 COL_GREY_LIGHT; static const ImVec4 COL_ORANGE_DARK; diff --git a/src/slic3r/GUI/SceneRaycaster.cpp b/src/slic3r/GUI/SceneRaycaster.cpp index 903c8dc17f7..96be46de298 100644 --- a/src/slic3r/GUI/SceneRaycaster.cpp +++ b/src/slic3r/GUI/SceneRaycaster.cpp @@ -1,8 +1,14 @@ +///|/ Copyright (c) Prusa Research 2022 - 2023 Oleksandra Iushchenko @YuSanka, Enrico Turri @enricoturri1966, Tomáš Mészáros @tamasmeszaros +///|/ +///|/ PrusaSlicer is released under the terms of the AGPLv3 or higher +///|/ #include "libslic3r/libslic3r.h" #include "SceneRaycaster.hpp" #include "Camera.hpp" #include "GUI_App.hpp" +#include "Selection.hpp" +#include "Plater.hpp" namespace Slic3r { namespace GUI { @@ -35,10 +41,11 @@ std::shared_ptr SceneRaycaster::add_raycaster(EType type, in const Transform3d& trafo, bool use_back_faces) { switch (type) { - case EType::Bed: { return m_bed.emplace_back(std::make_shared(encode_id(type, id), raycaster, trafo, use_back_faces)); } + case EType::Bed: { return m_bed.emplace_back(std::make_shared(encode_id(type, id), raycaster, trafo, use_back_faces)); } case EType::Volume: { return m_volumes.emplace_back(std::make_shared(encode_id(type, id), raycaster, trafo, use_back_faces)); } - case EType::Gizmo: { return m_gizmos.emplace_back(std::make_shared(encode_id(type, id), raycaster, trafo, use_back_faces)); } - default: { assert(false); return nullptr; } + case EType::Gizmo: { return m_gizmos.emplace_back(std::make_shared(encode_id(type, id), raycaster, trafo, use_back_faces)); } + case EType::FallbackGizmo: { return m_fallback_gizmos.emplace_back(std::make_shared(encode_id(type, id), raycaster, trafo, use_back_faces)); } + default: { assert(false); return nullptr; } }; } @@ -60,6 +67,7 @@ void SceneRaycaster::remove_raycasters(EType type) case EType::Bed: { m_bed.clear(); break; } case EType::Volume: { m_volumes.clear(); break; } case EType::Gizmo: { m_gizmos.clear(); break; } + case EType::FallbackGizmo: { m_fallback_gizmos.clear(); break; } default: { break; } }; } @@ -84,28 +92,72 @@ void SceneRaycaster::remove_raycaster(std::shared_ptr item) return; } } + for (auto it = m_fallback_gizmos.begin(); it != m_fallback_gizmos.end(); ++it) { + if (*it == item) { + m_fallback_gizmos.erase(it); + return; + } + } } -SceneRaycaster::HitResult SceneRaycaster::hit(const Vec2d& mouse_pos, const Camera& camera, const ClippingPlane* clipping_plane) +SceneRaycaster::HitResult SceneRaycaster::hit(const Vec2d& mouse_pos, const Camera& camera, const ClippingPlane* clipping_plane) const { + // helper class used to return currently selected volume as hit when overlapping with other volumes + // to allow the user to click and drag on a selected volume + class VolumeKeeper + { + std::optional m_selected_volume_id; + Vec3f m_closest_hit_pos{ std::numeric_limits::max(), std::numeric_limits::max(), std::numeric_limits::max() }; + bool m_selected_volume_already_found{ false }; + + public: + VolumeKeeper() { + const Selection& selection = wxGetApp().plater()->get_selection(); + if (selection.is_single_volume() || selection.is_single_modifier()) { + const GLVolume* volume = selection.get_first_volume(); + if (!volume->is_wipe_tower && !volume->is_sla_pad() && !volume->is_sla_support()) + m_selected_volume_id = *selection.get_volume_idxs().begin(); + } + } + + bool is_active() const { return m_selected_volume_id.has_value(); } + const Vec3f& get_closest_hit_pos() const { return m_closest_hit_pos; } + bool check_hit_result(const HitResult& hit) { + assert(is_active()); + + if (m_selected_volume_already_found && hit.type == SceneRaycaster::EType::Volume && hit.position.isApprox(m_closest_hit_pos)) + return false; + + if (hit.type == SceneRaycaster::EType::Volume) + m_selected_volume_already_found = *m_selected_volume_id == (unsigned int)decode_id(hit.type, hit.raycaster_id); + + m_closest_hit_pos = hit.position; + return true; + } + }; + + VolumeKeeper volume_keeper; + double closest_hit_squared_distance = std::numeric_limits::max(); - auto is_closest = [&closest_hit_squared_distance](const Camera& camera, const Vec3f& hit) { + auto is_closest = [&closest_hit_squared_distance, &volume_keeper](const Camera& camera, const Vec3f& hit) { const double hit_squared_distance = (camera.get_position() - hit.cast()).squaredNorm(); - const bool ret = hit_squared_distance < closest_hit_squared_distance; + bool ret = hit_squared_distance < closest_hit_squared_distance; + if (volume_keeper.is_active()) + ret |= hit.isApprox(volume_keeper.get_closest_hit_pos()); if (ret) closest_hit_squared_distance = hit_squared_distance; return ret; }; #if ENABLE_RAYCAST_PICKING_DEBUG - m_last_hit.reset(); + const_cast*>(&m_last_hit)->reset(); #endif // ENABLE_RAYCAST_PICKING_DEBUG HitResult ret; - auto test_raycasters = [this, is_closest, clipping_plane](EType type, const Vec2d& mouse_pos, const Camera& camera, HitResult& ret) { + auto test_raycasters = [this, is_closest, clipping_plane, &volume_keeper](EType type, const Vec2d& mouse_pos, const Camera& camera, HitResult& ret) { const ClippingPlane* clip_plane = (clipping_plane != nullptr && type == EType::Volume) ? clipping_plane : nullptr; - std::vector>* raycasters = get_raycasters(type); + const std::vector>* raycasters = get_raycasters(type); const Vec3f camera_forward = camera.get_dir_forward().cast(); HitResult current_hit = { type }; for (std::shared_ptr item : *raycasters) { @@ -117,9 +169,14 @@ SceneRaycaster::HitResult SceneRaycaster::hit(const Vec2d& mouse_pos, const Came if (item->get_raycaster()->closest_hit(mouse_pos, trafo, camera, current_hit.position, current_hit.normal, clip_plane)) { current_hit.position = (trafo * current_hit.position.cast()).cast(); current_hit.normal = (trafo.matrix().block(0, 0, 3, 3).inverse().transpose() * current_hit.normal.cast()).normalized().cast(); - if (item->use_back_faces() || current_hit.normal.dot(camera_forward) < 0.0f){ + if (item->use_back_faces() || current_hit.normal.dot(camera_forward) < 0.0f) { if (is_closest(camera, current_hit.position)) { - ret = current_hit; + if (volume_keeper.is_active()) { + if (volume_keeper.check_hit_result(current_hit)) + ret = current_hit; + } + else + ret = current_hit; } } } @@ -129,6 +186,9 @@ SceneRaycaster::HitResult SceneRaycaster::hit(const Vec2d& mouse_pos, const Came if (!m_gizmos.empty()) test_raycasters(EType::Gizmo, mouse_pos, camera, ret); + if (!m_fallback_gizmos.empty() && !ret.is_valid()) + test_raycasters(EType::FallbackGizmo, mouse_pos, camera, ret); + if (!m_gizmos_on_top || !ret.is_valid()) { if (camera.is_looking_downward() && !m_bed.empty()) test_raycasters(EType::Bed, mouse_pos, camera, ret); @@ -140,7 +200,7 @@ SceneRaycaster::HitResult SceneRaycaster::hit(const Vec2d& mouse_pos, const Came ret.raycaster_id = decode_id(ret.type, ret.raycaster_id); #if ENABLE_RAYCAST_PICKING_DEBUG - m_last_hit = ret; + *const_cast*>(&m_last_hit) = ret; #endif // ENABLE_RAYCAST_PICKING_DEBUG return ret; } @@ -171,6 +231,39 @@ void SceneRaycaster::render_hit(const Camera& camera) shader->stop_using(); } + +size_t SceneRaycaster::active_beds_count() const { + size_t count = 0; + for (const auto& b : m_bed) { + if (b->is_active()) + ++count; + } + return count; +} +size_t SceneRaycaster::active_volumes_count() const { + size_t count = 0; + for (const auto& v : m_volumes) { + if (v->is_active()) + ++count; + } + return count; +} +size_t SceneRaycaster::active_gizmos_count() const { + size_t count = 0; + for (const auto& g : m_gizmos) { + if (g->is_active()) + ++count; + } + return count; +} +size_t SceneRaycaster::active_fallback_gizmos_count() const { + size_t count = 0; + for (const auto& g : m_fallback_gizmos) { + if (g->is_active()) + ++count; + } + return count; +} #endif // ENABLE_RAYCAST_PICKING_DEBUG std::vector>* SceneRaycaster::get_raycasters(EType type) @@ -181,6 +274,22 @@ std::vector>* SceneRaycaster::get_raycasters case EType::Bed: { ret = &m_bed; break; } case EType::Volume: { ret = &m_volumes; break; } case EType::Gizmo: { ret = &m_gizmos; break; } + case EType::FallbackGizmo: { ret = &m_fallback_gizmos; break; } + default: { break; } + } + assert(ret != nullptr); + return ret; +} + +const std::vector>* SceneRaycaster::get_raycasters(EType type) const +{ + const std::vector>* ret = nullptr; + switch (type) + { + case EType::Bed: { ret = &m_bed; break; } + case EType::Volume: { ret = &m_volumes; break; } + case EType::Gizmo: { ret = &m_gizmos; break; } + case EType::FallbackGizmo: { ret = &m_fallback_gizmos; break; } default: { break; } } assert(ret != nullptr); @@ -194,6 +303,7 @@ int SceneRaycaster::base_id(EType type) case EType::Bed: { return int(EIdBase::Bed); } case EType::Volume: { return int(EIdBase::Volume); } case EType::Gizmo: { return int(EIdBase::Gizmo); } + case EType::FallbackGizmo: { return int(EIdBase::FallbackGizmo); } default: { break; } }; diff --git a/src/slic3r/GUI/SceneRaycaster.hpp b/src/slic3r/GUI/SceneRaycaster.hpp index e0063659c25..778ec0ab434 100644 --- a/src/slic3r/GUI/SceneRaycaster.hpp +++ b/src/slic3r/GUI/SceneRaycaster.hpp @@ -1,3 +1,7 @@ +///|/ Copyright (c) Prusa Research 2022 - 2023 Oleksandra Iushchenko @YuSanka, Enrico Turri @enricoturri1966, Tomáš Mészáros @tamasmeszaros +///|/ +///|/ PrusaSlicer is released under the terms of the AGPLv3 or higher +///|/ #ifndef slic3r_SceneRaycaster_hpp_ #define slic3r_SceneRaycaster_hpp_ @@ -42,14 +46,16 @@ class SceneRaycaster None, Bed, Volume, - Gizmo + Gizmo, + FallbackGizmo // Is used for gizmo grabbers which will be hit after all grabbers of Gizmo type }; enum class EIdBase { Bed = 0, Volume = 1000, - Gizmo = 1000000 + Gizmo = 1000000, + FallbackGizmo = 2000000 }; struct HitResult @@ -66,6 +72,7 @@ class SceneRaycaster std::vector> m_bed; std::vector> m_volumes; std::vector> m_gizmos; + std::vector> m_fallback_gizmos; // When set to true, if checking gizmos returns a valid hit, // the search is not performed on other types @@ -87,10 +94,11 @@ class SceneRaycaster void remove_raycaster(std::shared_ptr item); std::vector>* get_raycasters(EType type); + const std::vector>* get_raycasters(EType type) const; void set_gizmos_on_top(bool value) { m_gizmos_on_top = value; } - HitResult hit(const Vec2d& mouse_pos, const Camera& camera, const ClippingPlane* clipping_plane = nullptr); + HitResult hit(const Vec2d& mouse_pos, const Camera& camera, const ClippingPlane* clipping_plane = nullptr) const; #if ENABLE_RAYCAST_PICKING_DEBUG void render_hit(const Camera& camera); @@ -98,11 +106,17 @@ class SceneRaycaster size_t beds_count() const { return m_bed.size(); } size_t volumes_count() const { return m_volumes.size(); } size_t gizmos_count() const { return m_gizmos.size(); } + size_t fallback_gizmos_count() const { return m_fallback_gizmos.size(); } + size_t active_beds_count() const; + size_t active_volumes_count() const; + size_t active_gizmos_count() const; + size_t active_fallback_gizmos_count() const; #endif // ENABLE_RAYCAST_PICKING_DEBUG + static int decode_id(EType type, int id); + private: static int encode_id(EType type, int id); - static int decode_id(EType type, int id); static int base_id(EType type); }; diff --git a/src/slic3r/GUI/Selection.cpp b/src/slic3r/GUI/Selection.cpp index 36f2294cb51..05bb7cdcc2c 100644 --- a/src/slic3r/GUI/Selection.cpp +++ b/src/slic3r/GUI/Selection.cpp @@ -1,3 +1,7 @@ +///|/ Copyright (c) Prusa Research 2019 - 2023 Enrico Turri @enricoturri1966, Oleksandra Iushchenko @YuSanka, Vojtěch Bubník @bubnikv, Tomáš Mészáros @tamasmeszaros, Lukáš Matěna @lukasmatena, Filip Sykala @Jony01 +///|/ +///|/ PrusaSlicer is released under the terms of the AGPLv3 or higher +///|/ #include "libslic3r/libslic3r.h" #include "Selection.hpp" @@ -710,6 +714,17 @@ bool Selection::contains_any_volume(const std::vector& volume_idxs return false; } +bool Selection::contains_sinking_volumes(bool ignore_modifiers) const +{ + for (const GLVolume* v : *m_volumes) { + if (!ignore_modifiers || !v->is_modifier) { + if (v->is_sinking()) + return true; + } + } + return false; +} + bool Selection::matches(const std::vector& volume_idxs) const { unsigned int count = 0; diff --git a/src/slic3r/GUI/Selection.hpp b/src/slic3r/GUI/Selection.hpp index 1337bec3866..594c7996079 100644 --- a/src/slic3r/GUI/Selection.hpp +++ b/src/slic3r/GUI/Selection.hpp @@ -1,7 +1,12 @@ +///|/ Copyright (c) Prusa Research 2019 - 2023 Enrico Turri @enricoturri1966, Oleksandra Iushchenko @YuSanka, Filip Sykala @Jony01, Lukáš Matěna @lukasmatena, Vojtěch Bubník @bubnikv +///|/ +///|/ PrusaSlicer is released under the terms of the AGPLv3 or higher +///|/ #ifndef slic3r_GUI_Selection_hpp_ #define slic3r_GUI_Selection_hpp_ #include "libslic3r/Geometry.hpp" +#include "GUI_Geometry.hpp" #include "GLModel.hpp" #include @@ -26,58 +31,6 @@ using ModelObjectPtrs = std::vector; namespace GUI { -class TransformationType -{ -public: - enum Enum { - // Transforming in a world coordinate system - World = 0, - // Transforming in a local coordinate system - Local = 1, - // Absolute transformations, allowed in local coordinate system only. - Absolute = 0, - // Relative transformations, allowed in both local and world coordinate system. - Relative = 2, - // For group selection, the transformation is performed as if the group made a single solid body. - Joint = 0, - // For group selection, the transformation is performed on each object independently. - Independent = 4, - - World_Relative_Joint = World | Relative | Joint, - World_Relative_Independent = World | Relative | Independent, - Local_Absolute_Joint = Local | Absolute | Joint, - Local_Absolute_Independent = Local | Absolute | Independent, - Local_Relative_Joint = Local | Relative | Joint, - Local_Relative_Independent = Local | Relative | Independent, - }; - - TransformationType() : m_value(World) {} - TransformationType(Enum value) : m_value(value) {} - TransformationType& operator=(Enum value) { m_value = value; return *this; } - - Enum operator()() const { return m_value; } - bool has(Enum v) const { return ((unsigned int)m_value & (unsigned int)v) != 0; } - - void set_world() { this->remove(Local); } - void set_local() { this->add(Local); } - void set_absolute() { this->remove(Relative); } - void set_relative() { this->add(Relative); } - void set_joint() { this->remove(Independent); } - void set_independent() { this->add(Independent); } - - bool world() const { return !this->has(Local); } - bool local() const { return this->has(Local); } - bool absolute() const { return !this->has(Relative); } - bool relative() const { return this->has(Relative); } - bool joint() const { return !this->has(Independent); } - bool independent() const { return this->has(Independent); } - -private: - void add(Enum v) { m_value = Enum((unsigned int)m_value | (unsigned int)v); } - void remove(Enum v) { m_value = Enum((unsigned int)m_value & (~(unsigned int)v)); } - - Enum m_value; -}; class Selection { @@ -307,6 +260,8 @@ class Selection bool contains_all_volumes(const std::vector& volume_idxs) const; // returns true if the selection contains at least one of the given indices bool contains_any_volume(const std::vector& volume_idxs) const; + // returns true if the selection contains any sinking volume + bool contains_sinking_volumes(bool ignore_modifiers = true) const; // returns true if the selection contains all and only the given indices bool matches(const std::vector& volume_idxs) const; From c31e1f52293f11953d3978cd3a54a0b46c034919 Mon Sep 17 00:00:00 2001 From: Noisyfox Date: Tue, 31 Oct 2023 11:44:20 +0800 Subject: [PATCH 81/99] Measure: Fix measure window position --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 5b4d3bd9321..7ca5f9d75d9 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -1810,12 +1810,10 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit if (m_editing_distance) return; - m_imgui->begin(get_name(), ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse); - // adjust window position to avoid overlap the view toolbar const float win_h = ImGui::GetWindowHeight(); y = std::min(y, bottom_limit - win_h); - ImGui::SetWindowPos(ImVec2(x, y), ImGuiCond_Always); + GizmoImguiSetNextWIndowPos(x, y, ImGuiCond_Always, 0.0f, 0.0f); if (last_h != win_h || last_y != y) { // ask canvas for another frame to render the window in the correct position m_imgui->set_requires_extra_frame(); @@ -1825,6 +1823,8 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit last_y = y; } + GizmoImguiBegin(get_name(), ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse); + if (ImGui::BeginTable("Commands", 2)) { unsigned int row_count = 1; add_row_to_table( @@ -2114,7 +2114,7 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit m_imgui->set_requires_extra_frame(); } - m_imgui->end(); + GizmoImguiEnd(); } void GLGizmoMeasure::on_register_raycasters_for_picking() From d25780ae4a9b376fee5743c45b9bb99cb1477779 Mon Sep 17 00:00:00 2001 From: Noisyfox Date: Tue, 31 Oct 2023 16:23:13 +0800 Subject: [PATCH 82/99] Fix-position tooltip should also be clamped inside render area --- src/imgui/imgui.cpp | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/imgui/imgui.cpp b/src/imgui/imgui.cpp index fd32e4cf5fb..8f45263a39d 100644 --- a/src/imgui/imgui.cpp +++ b/src/imgui/imgui.cpp @@ -6046,8 +6046,18 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) window->Pos = FindBestWindowPosForPopup(window); else if ((flags & ImGuiWindowFlags_Popup) != 0 && !window_pos_set_by_api && window_just_appearing_after_hidden_for_resize) window->Pos = FindBestWindowPosForPopup(window); - else if ((flags & ImGuiWindowFlags_Tooltip) != 0 && !window_pos_set_by_api && !window_is_child_tooltip) - window->Pos = FindBestWindowPosForPopup(window); + // Orca: Allow fixed tooltip pos while still being clamped inside the render area + else if ((flags & ImGuiWindowFlags_Tooltip) != 0 && !window_is_child_tooltip) { + if (window_pos_set_by_api) { + // Hack: add ImGuiWindowFlags_Popup so it does not follow cursor + ImGuiWindowFlags old_flags = window->Flags; + window->Flags |= ImGuiWindowFlags_Popup; + window->Pos = FindBestWindowPosForPopup(window); + window->Flags = old_flags; + } else { + window->Pos = FindBestWindowPosForPopup(window); + } + } // Calculate the range of allowed position for that window (to be movable and visible past safe area padding) // When clamping to stay visible, we will enforce that window->Pos stays inside of visibility_rect. From 2c00408d086dbf2eb8884564ed7557f48380e3ae Mon Sep 17 00:00:00 2001 From: Noisyfox Date: Tue, 31 Oct 2023 16:27:44 +0800 Subject: [PATCH 83/99] Measure: Update measure gizmo tooltip --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 224 ++++++----------------- src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp | 8 + 2 files changed, 68 insertions(+), 164 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 7ca5f9d75d9..08ef1b205d2 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -526,6 +526,16 @@ bool GLGizmoMeasure::gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_po bool GLGizmoMeasure::on_init() { m_shortcut_key = WXK_CONTROL_U; + + m_desc["feature_selection_caption"] = _L("ShiftLeft mouse button"); + m_desc["feature_selection"] = _L("Select feature"); + m_desc["point_selection_caption"] = _L("Shift + Left mouse button"); + m_desc["point_selection"] = _L("Select point"); + m_desc["reset_caption"] = _L("Delete"); + m_desc["reset"] = _L("Restart selection"); + m_desc["unselect_caption"] = _L("Esc"); + m_desc["unselect"] = _L("Unselect"); + return true; } @@ -1822,177 +1832,22 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit if (last_y != y) last_y = y; } + + // Orca + ImGuiWrapper::push_toolbar_style(m_parent.get_scale()); - GizmoImguiBegin(get_name(), ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse); - - if (ImGui::BeginTable("Commands", 2)) { - unsigned int row_count = 1; - add_row_to_table( - [this]() { - m_imgui->text_colored(ImGuiWrapper::COL_ORANGE_LIGHT, _u8L("Left mouse button")); - }, - [this]() { - std::string text; - ColorRGBA color; - if (m_selected_features.second.feature.has_value()) { - if (m_selected_features.first.feature == m_curr_feature && m_mode == EMode::FeatureSelection) { - // hovering over 1st selected feature - text = _u8L("Unselect feature"); - color = SELECTED_1ST_COLOR; - } - else if (m_hover_id == SEL_SPHERE_1_ID) { - if (m_selected_features.first.is_center) { - // hovering over center selected as 1st feature - text = _u8L("Unselect center"); - color = SELECTED_1ST_COLOR; - } - else if (is_feature_with_center(*m_selected_features.first.feature)) { - // hovering over center of 1st selected feature - text = _u8L("Select center"); - color = SELECTED_1ST_COLOR; - } - else { - // hovering over point selected as 1st feature - text = _u8L("Unselect point"); - color = SELECTED_1ST_COLOR; - } - } - else if (m_selected_features.first.is_center && m_selected_features.first.source == m_curr_feature) { - // hovering over feature whose center is selected as 1st feature - text = _u8L("Select feature"); - color = SELECTED_1ST_COLOR; - } - else if (m_selected_features.second.feature == m_curr_feature && m_mode == EMode::FeatureSelection) { - // hovering over 2nd selected feature - text = _u8L("Unselect feature"); - color = SELECTED_2ND_COLOR; - } - else if (m_hover_id == SEL_SPHERE_2_ID) { - if (m_selected_features.second.is_center) { - // hovering over center selected as 2nd feature - text = _u8L("Unselect feature"); - color = SELECTED_2ND_COLOR; - } - else if (is_feature_with_center(*m_selected_features.second.feature)) { - // hovering over center of 2nd selected feature - text = _u8L("Select center"); - color = SELECTED_2ND_COLOR; - } - else { - // hovering over point selected as 2nd feature - text = _u8L("Unselect point"); - color = SELECTED_2ND_COLOR; - } - } - else if (m_selected_features.second.is_center && m_selected_features.second.source == m_curr_feature) { - // hovering over feature whose center is selected as 2nd feature - text = _u8L("Select feature"); - color = SELECTED_2ND_COLOR; - } - else { - // 1st feature selected - text = (m_mode == EMode::PointSelection) ? _u8L("Select point") : _u8L("Select feature"); - color = SELECTED_2ND_COLOR; - } - } - else { - if (m_selected_features.first.feature.has_value()) { - if (m_selected_features.first.feature == m_curr_feature && m_mode == EMode::FeatureSelection) { - // hovering over 1st selected feature - text = _u8L("Unselect feature"); - color = SELECTED_1ST_COLOR; - } - else { - if (m_hover_id == SEL_SPHERE_1_ID) { - if (m_selected_features.first.is_center) { - // hovering over center selected as 1st feature - text = _u8L("Unselect feature"); - color = SELECTED_1ST_COLOR; - } - else if (is_feature_with_center(*m_selected_features.first.feature)) { - // hovering over center of 1st selected feature - text = _u8L("Select center"); - color = SELECTED_1ST_COLOR; - } - else { - // hovering over point selected as 1st feature - text = _u8L("Unselect point"); - color = SELECTED_1ST_COLOR; - } - } - else { - if (m_selected_features.first.is_center && m_selected_features.first.source == m_curr_feature) { - // hovering over feature whose center is selected as 1st feature - text = _u8L("Select feature"); - color = SELECTED_1ST_COLOR; - } - else { - // 1st feature selected - text = (m_mode == EMode::PointSelection) ? _u8L("Select point") : _u8L("Select feature"); - color = SELECTED_2ND_COLOR; - } - } - } - } - else { - // nothing is selected - text = (m_mode == EMode::PointSelection) ? _u8L("Select point") : _u8L("Select feature"); - color = SELECTED_1ST_COLOR; - } - } - - assert(!text.empty()); - - m_imgui->text_colored(ImGui::GetStyleColorVec4(ImGuiCol_Text), text); - ImGui::SameLine(); - const ImVec2 pos = ImGui::GetCursorScreenPos(); - const float rect_size = ImGui::GetTextLineHeight(); - ImGui::GetWindowDrawList()->AddRectFilled(ImVec2(pos.x + 1.0f, pos.y + 1.0f), ImVec2(pos.x + rect_size, pos.y + rect_size), ImGuiWrapper::to_ImU32(color)); - ImGui::Dummy(ImVec2(rect_size, rect_size)); - } - ); - - if (m_mode == EMode::FeatureSelection && m_hover_id != -1) { - add_strings_row_to_table(*m_imgui, "Shift", ImGuiWrapper::COL_ORANGE_LIGHT, _u8L("Enable point selection"), ImGui::GetStyleColorVec4(ImGuiCol_Text)); - ++row_count; - } - - if (m_selected_features.first.feature.has_value()) { - add_strings_row_to_table(*m_imgui, "Delete", ImGuiWrapper::COL_ORANGE_LIGHT, _u8L("Restart selection"), ImGui::GetStyleColorVec4(ImGuiCol_Text)); - ++row_count; - } - - if (m_selected_features.first.feature.has_value() || m_selected_features.second.feature.has_value()) { - add_row_to_table( - [this]() { - m_imgui->text_colored(ImGuiWrapper::COL_ORANGE_LIGHT, "Esc"); - }, - [this]() { - m_imgui->text_colored(ImGui::GetStyleColorVec4(ImGuiCol_Text), _u8L("Unselect")); - ImGui::SameLine(); - const ImVec2 pos = ImGui::GetCursorScreenPos(); - const float rect_size = ImGui::GetTextLineHeight(); - const ColorRGBA color = m_selected_features.second.feature.has_value() ? SELECTED_2ND_COLOR : SELECTED_1ST_COLOR; - ImGui::GetWindowDrawList()->AddRectFilled(ImVec2(pos.x + 1.0f, pos.y + 1.0f), ImVec2(pos.x + rect_size, pos.y + rect_size), ImGuiWrapper::to_ImU32(color)); - ImGui::Dummy(ImVec2(rect_size, rect_size)); - } - ); - - ++row_count; - } + GizmoImguiBegin(get_name(), ImGuiWindowFlags_NoMove | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoTitleBar); - // add dummy rows to keep dialog size fixed - for (unsigned int i = row_count; i < 4; ++i) { - add_strings_row_to_table(*m_imgui, " ", ImGuiWrapper::COL_ORANGE_LIGHT, " ", ImGui::GetStyleColorVec4(ImGuiCol_Text)); - } - - ImGui::EndTable(); + float caption_max = 0.f; + float total_text_max = 0.f; + for (const auto &t : std::array{"feature_selection", "point_selection", "reset", "unselect"}) { + caption_max = std::max(caption_max, m_imgui->calc_text_size(m_desc[t + "_caption"]).x); + total_text_max = std::max(total_text_max, m_imgui->calc_text_size(m_desc[t]).x); } const bool use_inches = wxGetApp().app_config->get_bool("use_inches"); const std::string units = use_inches ? " " + _u8L("in") : " " + _u8L("mm"); - ImGui::Separator(); const ImGuiTableFlags flags = ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersH; if (ImGui::BeginTable("Selection", 2, flags)) { auto format_item_text = [this, use_inches, &units](const SelectedFeatures::Item& item) { @@ -2106,6 +1961,17 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit ImGui::EndTable(); } + ImGui::Separator(); + + ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(6.0f, 10.0f)); + float get_cur_y = ImGui::GetContentRegionMax().y + ImGui::GetFrameHeight() + y; + show_tooltip_information(caption_max, x, get_cur_y); + + float f_scale =m_parent.get_gizmos_manager().get_layout_scale(); + ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(6.0f, 4.0f * f_scale)); + + ImGui::PopStyleVar(2); + if (last_feature != m_curr_feature || last_mode != m_mode || last_selected_features != m_selected_features) { // the dialog may have changed its size, ask for an extra frame to render it properly last_feature = m_curr_feature; @@ -2115,6 +1981,9 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit } GizmoImguiEnd(); + + // Orca + ImGuiWrapper::pop_toolbar_style(); } void GLGizmoMeasure::on_register_raycasters_for_picking() @@ -2150,5 +2019,32 @@ void GLGizmoMeasure::update_measurement_result() m_measurement_result = Measure::get_measurement(*m_selected_features.first.feature, Measure::SurfaceFeature(std::get<0>(m_selected_features.first.feature->get_circle())), m_measuring.get()); } +void GLGizmoMeasure::show_tooltip_information(float caption_max, float x, float y) +{ + ImTextureID normal_id = m_parent.get_gizmos_manager().get_icon_texture_id(GLGizmosManager::MENU_ICON_NAME::IC_TOOLBAR_TOOLTIP); + ImTextureID hover_id = m_parent.get_gizmos_manager().get_icon_texture_id(GLGizmosManager::MENU_ICON_NAME::IC_TOOLBAR_TOOLTIP_HOVER); + + caption_max += m_imgui->calc_text_size(": ").x + 35.f; + + float font_size = ImGui::GetFontSize(); + ImVec2 button_size = ImVec2(font_size * 1.8, font_size * 1.3); + ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 0.0f); + ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, { 0, ImGui::GetStyle().FramePadding.y }); + ImGui::ImageButton3(normal_id, hover_id, button_size); + + if (ImGui::IsItemHovered()) { + ImGui::BeginTooltip2(ImVec2(x, y)); + auto draw_text_with_caption = [this, &caption_max](const wxString &caption, const wxString &text) { + m_imgui->text_colored(ImGuiWrapper::COL_ACTIVE, caption); + ImGui::SameLine(caption_max); + m_imgui->text_colored(ImGuiWrapper::COL_WINDOW_BG, text); + }; + + for (const auto &t : std::array{"feature_selection", "point_selection", "reset", "unselect"}) draw_text_with_caption(m_desc.at(t + "_caption") + ": ", m_desc.at(t)); + ImGui::EndTooltip(); + } + ImGui::PopStyleVar(2); +} + } // namespace GUI } // namespace Slic3r diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp index 4ab67b8d00c..0fc7577b43e 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp @@ -182,6 +182,14 @@ class GLGizmoMeasure : public GLGizmoBase void remove_selected_sphere_raycaster(int id); void update_measurement_result(); + + // Orca + void show_tooltip_information(float caption_max, float x, float y); + +private: + // This map holds all translated description texts, so they can be easily referenced during layout calculations + // etc. When language changes, GUI is recreated and this class constructed again, so the change takes effect. + std::map m_desc; }; } // namespace GUI From 4843cda535ed56b51a4002092be972a33caa218a Mon Sep 17 00:00:00 2001 From: Noisyfox Date: Tue, 31 Oct 2023 16:36:28 +0800 Subject: [PATCH 84/99] Measure: Use Orca color schema --- resources/images/copy_menu.svg | 20 ++-- resources/images/copy_menu_dark.svg | 37 ++++++++ .../{measure.svg => toolbar_measure.svg} | 34 +++---- resources/images/toolbar_measure_dark.svg | 93 +++++++++++++++++++ src/imgui/imconfig.h | 1 + src/libslic3r/Color.hpp | 1 + src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 56 ++++++----- src/slic3r/GUI/Gizmos/GLGizmosManager.cpp | 5 +- src/slic3r/GUI/ImGuiWrapper.cpp | 2 + src/slic3r/GUI/ImGuiWrapper.hpp | 1 + 10 files changed, 198 insertions(+), 52 deletions(-) create mode 100644 resources/images/copy_menu_dark.svg rename resources/images/{measure.svg => toolbar_measure.svg} (86%) create mode 100644 resources/images/toolbar_measure_dark.svg diff --git a/resources/images/copy_menu.svg b/resources/images/copy_menu.svg index 0d1af6a0a7c..23e0bfeb2aa 100644 --- a/resources/images/copy_menu.svg +++ b/resources/images/copy_menu.svg @@ -4,33 +4,33 @@ viewBox="0 0 128 128" enable-background="new 0 0 128 128" xml:space="preserve"> - - - - - - - - - - diff --git a/resources/images/copy_menu_dark.svg b/resources/images/copy_menu_dark.svg new file mode 100644 index 00000000000..eaee113a1b6 --- /dev/null +++ b/resources/images/copy_menu_dark.svg @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/resources/images/measure.svg b/resources/images/toolbar_measure.svg similarity index 86% rename from resources/images/measure.svg rename to resources/images/toolbar_measure.svg index 3ea137a1ed9..1606b5ee6f5 100644 --- a/resources/images/measure.svg +++ b/resources/images/toolbar_measure.svg @@ -43,50 +43,50 @@ inkscape:current-layer="Layer_1" /> diff --git a/resources/images/toolbar_measure_dark.svg b/resources/images/toolbar_measure_dark.svg new file mode 100644 index 00000000000..a273e753473 --- /dev/null +++ b/resources/images/toolbar_measure_dark.svg @@ -0,0 +1,93 @@ + + + + + + + + + + + + + + + + diff --git a/src/imgui/imconfig.h b/src/imgui/imconfig.h index be78d7cd40b..9380ea16498 100644 --- a/src/imgui/imconfig.h +++ b/src/imgui/imconfig.h @@ -197,6 +197,7 @@ namespace ImGui const wchar_t CloseBlockNotifButton = 0x0833; const wchar_t CloseBlockNotifHoverButton = 0x0834; const wchar_t BlockNotifErrorIcon = 0x0835; + const wchar_t ClipboardBtnDarkIcon = 0x0836; // void MyFunction(const char* name, const MyMatrix44& v); } diff --git a/src/libslic3r/Color.hpp b/src/libslic3r/Color.hpp index efde3fe4daf..ea17328bec1 100644 --- a/src/libslic3r/Color.hpp +++ b/src/libslic3r/Color.hpp @@ -127,6 +127,7 @@ class ColorRGBA 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 ORCA() { return {0.0f, 150.f / 255.0f, 136.0f / 255, 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 }; } diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 08ef1b205d2..580a98ec32c 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -1238,6 +1238,7 @@ void GLGizmoMeasure::render_dimensioning() const float value_str_width = 20.0f + ImGui::CalcTextSize(curr_value_str.c_str()).x; static double edit_value = 0.0; + ImGuiWrapper::push_common_window_style(m_parent.get_scale()); const Vec2d label_position = 0.5 * (v1ss + v2ss); m_imgui->set_next_window_pos(label_position.x(), viewport[3] - label_position.y(), ImGuiCond_Always, 0.0f, 1.0f); m_imgui->set_next_window_bg_alpha(0.0f); @@ -1255,7 +1256,7 @@ void GLGizmoMeasure::render_dimensioning() ImVec2 txt_size = ImGui::CalcTextSize(txt.c_str()); const ImGuiStyle& style = ImGui::GetStyle(); draw_list->AddRectFilled({ pos.x - style.FramePadding.x, pos.y + style.FramePadding.y }, { pos.x + txt_size.x + 2.0f * style.FramePadding.x , pos.y + txt_size.y + 2.0f * style.FramePadding.y }, - ImGuiWrapper::to_ImU32(ColorRGBA(0.5f, 0.5f, 0.5f, 0.5f))); + ImGuiWrapper::to_ImU32(ColorRGBA(1.0f, 1.0f, 1.0f, 0.5f))); ImGui::SetCursorScreenPos({ pos.x + style.FramePadding.x, pos.y }); m_imgui->text(txt); ImGui::SameLine(); @@ -1385,14 +1386,19 @@ void GLGizmoMeasure::render_dimensioning() action_exit(); ImGui::SameLine(); + ImGuiWrapper::push_confirm_button_style(); if (m_imgui->button(_CTX(L_CONTEXT("Scale", "Verb"), "Verb"))) action_scale(edit_value, curr_value); + ImGuiWrapper::pop_confirm_button_style(); ImGui::SameLine(); + ImGuiWrapper::push_cancel_button_style(); if (m_imgui->button(_L("Cancel"))) action_exit(); + ImGuiWrapper::pop_cancel_button_style(); ImGui::EndPopup(); } ImGui::PopStyleVar(4); + ImGuiWrapper::pop_common_window_style(); }; auto point_edge = [this, shader](const Measure::SurfaceFeature& f1, const Measure::SurfaceFeature& f2) { @@ -1561,6 +1567,7 @@ void GLGizmoMeasure::render_dimensioning() const Vec2d label_position_ss = TransformHelper::world_to_ss(label_position_world, camera.get_projection_matrix().matrix() * camera.get_view_matrix().matrix(), viewport); + ImGuiWrapper::push_common_window_style(m_parent.get_scale()); m_imgui->set_next_window_pos(label_position_ss.x(), viewport[3] - label_position_ss.y(), ImGuiCond_Always, 0.0f, 1.0f); m_imgui->set_next_window_bg_alpha(0.0f); ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.0f); @@ -1573,11 +1580,12 @@ void GLGizmoMeasure::render_dimensioning() ImVec2 txt_size = ImGui::CalcTextSize(txt.c_str()); const ImGuiStyle& style = ImGui::GetStyle(); draw_list->AddRectFilled({ pos.x - style.FramePadding.x, pos.y + style.FramePadding.y }, { pos.x + txt_size.x + 2.0f * style.FramePadding.x , pos.y + txt_size.y + 2.0f * style.FramePadding.y }, - ImGuiWrapper::to_ImU32(ColorRGBA(0.5f, 0.5f, 0.5f, 0.5f))); + ImGuiWrapper::to_ImU32(ColorRGBA(1.0f, 1.0f, 1.0f, 0.5f))); ImGui::SetCursorScreenPos({ pos.x + style.FramePadding.x, pos.y }); m_imgui->text(txt); m_imgui->end(); ImGui::PopStyleVar(); + ImGuiWrapper::pop_common_window_style(); }; auto arc_edge_plane = [this, arc_edge_edge](const Measure::SurfaceFeature& f1, const Measure::SurfaceFeature& f2) { @@ -1724,27 +1732,27 @@ void GLGizmoMeasure::render_debug_dialog() { auto add_feature_data = [this](const SelectedFeatures::Item& item) { const std::string text = (item.source == item.feature) ? surface_feature_type_as_string(item.feature->get_type()) : point_on_feature_type_as_string(item.source->get_type(), m_hover_id); - add_strings_row_to_table(*m_imgui, "Type", ImGuiWrapper::COL_ORANGE_LIGHT, text, ImGui::GetStyleColorVec4(ImGuiCol_Text)); + add_strings_row_to_table(*m_imgui, "Type", ImGuiWrapper::COL_ORCA, text, ImGui::GetStyleColorVec4(ImGuiCol_Text)); switch (item.feature->get_type()) { case Measure::SurfaceFeatureType::Point: { - add_strings_row_to_table(*m_imgui, "m_pt1", ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(item.feature->get_point()), ImGui::GetStyleColorVec4(ImGuiCol_Text)); + add_strings_row_to_table(*m_imgui, "m_pt1", ImGuiWrapper::COL_ORCA, format_vec3(item.feature->get_point()), ImGui::GetStyleColorVec4(ImGuiCol_Text)); break; } case Measure::SurfaceFeatureType::Edge: { auto [from, to] = item.feature->get_edge(); - add_strings_row_to_table(*m_imgui, "m_pt1", ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(from), ImGui::GetStyleColorVec4(ImGuiCol_Text)); - add_strings_row_to_table(*m_imgui, "m_pt2", ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(to), ImGui::GetStyleColorVec4(ImGuiCol_Text)); + add_strings_row_to_table(*m_imgui, "m_pt1", ImGuiWrapper::COL_ORCA, format_vec3(from), ImGui::GetStyleColorVec4(ImGuiCol_Text)); + add_strings_row_to_table(*m_imgui, "m_pt2", ImGuiWrapper::COL_ORCA, format_vec3(to), ImGui::GetStyleColorVec4(ImGuiCol_Text)); break; } case Measure::SurfaceFeatureType::Plane: { auto [idx, normal, origin] = item.feature->get_plane(); - add_strings_row_to_table(*m_imgui, "m_pt1", ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(normal), ImGui::GetStyleColorVec4(ImGuiCol_Text)); - add_strings_row_to_table(*m_imgui, "m_pt2", ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(origin), ImGui::GetStyleColorVec4(ImGuiCol_Text)); - add_strings_row_to_table(*m_imgui, "m_value", ImGuiWrapper::COL_ORANGE_LIGHT, format_double(idx), ImGui::GetStyleColorVec4(ImGuiCol_Text)); + add_strings_row_to_table(*m_imgui, "m_pt1", ImGuiWrapper::COL_ORCA, format_vec3(normal), ImGui::GetStyleColorVec4(ImGuiCol_Text)); + add_strings_row_to_table(*m_imgui, "m_pt2", ImGuiWrapper::COL_ORCA, format_vec3(origin), ImGui::GetStyleColorVec4(ImGuiCol_Text)); + add_strings_row_to_table(*m_imgui, "m_value", ImGuiWrapper::COL_ORCA, format_double(idx), ImGui::GetStyleColorVec4(ImGuiCol_Text)); break; } case Measure::SurfaceFeatureType::Circle: @@ -1752,15 +1760,15 @@ void GLGizmoMeasure::render_debug_dialog() auto [center, radius, normal] = item.feature->get_circle(); const Vec3d on_circle = center + radius * Measure::get_orthogonal(normal, true); radius = (on_circle - center).norm(); - add_strings_row_to_table(*m_imgui, "m_pt1", ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(center), ImGui::GetStyleColorVec4(ImGuiCol_Text)); - add_strings_row_to_table(*m_imgui, "m_pt2", ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(normal), ImGui::GetStyleColorVec4(ImGuiCol_Text)); - add_strings_row_to_table(*m_imgui, "m_value", ImGuiWrapper::COL_ORANGE_LIGHT, format_double(radius), ImGui::GetStyleColorVec4(ImGuiCol_Text)); + add_strings_row_to_table(*m_imgui, "m_pt1", ImGuiWrapper::COL_ORCA, format_vec3(center), ImGui::GetStyleColorVec4(ImGuiCol_Text)); + add_strings_row_to_table(*m_imgui, "m_pt2", ImGuiWrapper::COL_ORCA, format_vec3(normal), ImGui::GetStyleColorVec4(ImGuiCol_Text)); + add_strings_row_to_table(*m_imgui, "m_value", ImGuiWrapper::COL_ORCA, format_double(radius), ImGui::GetStyleColorVec4(ImGuiCol_Text)); break; } } std::optional extra_point = item.feature->get_extra_point(); if (extra_point.has_value()) - add_strings_row_to_table(*m_imgui, "m_pt3", ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(*extra_point), ImGui::GetStyleColorVec4(ImGuiCol_Text)); + add_strings_row_to_table(*m_imgui, "m_pt3", ImGuiWrapper::COL_ORCA, format_vec3(*extra_point), ImGui::GetStyleColorVec4(ImGuiCol_Text)); }; m_imgui->begin("Measure tool debug", ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse); @@ -1772,15 +1780,15 @@ void GLGizmoMeasure::render_debug_dialog() case EMode::PointSelection: { txt = "Point selection"; break; } default: { assert(false); break; } } - add_strings_row_to_table(*m_imgui, "Mode", ImGuiWrapper::COL_ORANGE_LIGHT, txt, ImGui::GetStyleColorVec4(ImGuiCol_Text)); + add_strings_row_to_table(*m_imgui, "Mode", ImGuiWrapper::COL_ORCA, txt, ImGui::GetStyleColorVec4(ImGuiCol_Text)); ImGui::EndTable(); } ImGui::Separator(); if (ImGui::BeginTable("Hover", 2)) { - add_strings_row_to_table(*m_imgui, "Hover id", ImGuiWrapper::COL_ORANGE_LIGHT, std::to_string(m_hover_id), ImGui::GetStyleColorVec4(ImGuiCol_Text)); + add_strings_row_to_table(*m_imgui, "Hover id", ImGuiWrapper::COL_ORCA, std::to_string(m_hover_id), ImGui::GetStyleColorVec4(ImGuiCol_Text)); const std::string txt = m_curr_feature.has_value() ? surface_feature_type_as_string(m_curr_feature->get_type()) : "None"; - add_strings_row_to_table(*m_imgui, "Current feature", ImGuiWrapper::COL_ORANGE_LIGHT, txt, ImGui::GetStyleColorVec4(ImGuiCol_Text)); + add_strings_row_to_table(*m_imgui, "Current feature", ImGuiWrapper::COL_ORCA, txt, ImGui::GetStyleColorVec4(ImGuiCol_Text)); ImGui::EndTable(); } @@ -1790,14 +1798,14 @@ void GLGizmoMeasure::render_debug_dialog() else { const ImGuiTableFlags flags = ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersH; if (m_selected_features.first.feature.has_value()) { - m_imgui->text_colored(ImGuiWrapper::COL_ORANGE_LIGHT, "Selection 1"); + m_imgui->text_colored(ImGuiWrapper::COL_ORCA, "Selection 1"); if (ImGui::BeginTable("Selection 1", 2, flags)) { add_feature_data(m_selected_features.first); ImGui::EndTable(); } } if (m_selected_features.second.feature.has_value()) { - m_imgui->text_colored(ImGuiWrapper::COL_ORANGE_LIGHT, "Selection 2"); + m_imgui->text_colored(ImGuiWrapper::COL_ORCA, "Selection 2"); if (ImGui::BeginTable("Selection 2", 2, flags)) { add_feature_data(m_selected_features.second); ImGui::EndTable(); @@ -1896,7 +1904,7 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit ImGui::TableSetColumnIndex(1); m_imgui->text_colored(col_2_color, col_2); ImGui::TableSetColumnIndex(2); - if (m_imgui->image_button(ImGui::ClipboardBtnIcon, _L("Copy to clipboard"))) { + if (m_imgui->image_button(m_is_dark_mode ? ImGui::ClipboardBtnDarkIcon : ImGui::ClipboardBtnIcon, _L("Copy to clipboard"))) { wxTheClipboard->Open(); wxTheClipboard->SetData(new wxTextDataObject(col_1 + ": " + col_2)); wxTheClipboard->Close(); @@ -1913,7 +1921,7 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit const Measure::MeasurementResult& measure = m_measurement_result; if (measure.angle.has_value()) { ImGui::PushID("ClipboardAngle"); - add_measure_row_to_table(_u8L("Angle"), ImGuiWrapper::COL_ORANGE_LIGHT, format_double(Geometry::rad2deg(measure.angle->angle)) + "°", + add_measure_row_to_table(_u8L("Angle"), ImGuiWrapper::COL_ORCA, format_double(Geometry::rad2deg(measure.angle->angle)) + "°", ImGui::GetStyleColorVec4(ImGuiCol_Text)); ++measure_row_count; ImGui::PopID(); @@ -1927,7 +1935,7 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit if (use_inches) distance = GizmoObjectManipulation::mm_to_in * distance; ImGui::PushID("ClipboardDistanceInfinite"); - add_measure_row_to_table(show_strict ? _u8L("Perpendicular distance") : _u8L("Distance"), ImGuiWrapper::COL_ORANGE_LIGHT, format_double(distance) + units, + add_measure_row_to_table(show_strict ? _u8L("Perpendicular distance") : _u8L("Distance"), ImGuiWrapper::COL_ORCA, format_double(distance) + units, ImGui::GetStyleColorVec4(ImGuiCol_Text)); ++measure_row_count; ImGui::PopID(); @@ -1937,7 +1945,7 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit if (use_inches) distance = GizmoObjectManipulation::mm_to_in * distance; ImGui::PushID("ClipboardDistanceStrict"); - add_measure_row_to_table(_u8L("Direct distance"), ImGuiWrapper::COL_ORANGE_LIGHT, format_double(distance) + units, + add_measure_row_to_table(_u8L("Direct distance"), ImGuiWrapper::COL_ORCA, format_double(distance) + units, ImGui::GetStyleColorVec4(ImGuiCol_Text)); ++measure_row_count; ImGui::PopID(); @@ -1947,7 +1955,7 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit if (use_inches) distance = GizmoObjectManipulation::mm_to_in * distance; ImGui::PushID("ClipboardDistanceXYZ"); - add_measure_row_to_table(_u8L("Distance XYZ"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(distance), + add_measure_row_to_table(_u8L("Distance XYZ"), ImGuiWrapper::COL_ORCA, format_vec3(distance), ImGui::GetStyleColorVec4(ImGuiCol_Text)); ++measure_row_count; ImGui::PopID(); @@ -1956,7 +1964,7 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit // add dummy rows to keep dialog size fixed for (unsigned int i = measure_row_count; i < max_measure_row_count; ++i) { - add_strings_row_to_table(*m_imgui, " ", ImGuiWrapper::COL_ORANGE_LIGHT, " ", ImGui::GetStyleColorVec4(ImGuiCol_Text)); + add_strings_row_to_table(*m_imgui, " ", ImGuiWrapper::COL_ORCA, " ", ImGui::GetStyleColorVec4(ImGuiCol_Text)); } ImGui::EndTable(); } diff --git a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp index 25169aca8bf..5e113372e68 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp @@ -160,6 +160,9 @@ void GLGizmosManager::switch_gizmos_icon_filename() case(EType::MeshBoolean): gizmo->set_icon_filename(m_is_dark ? "toolbar_meshboolean_dark.svg" : "toolbar_meshboolean.svg"); break; + case(EType::Measure): + gizmo->set_icon_filename(m_is_dark ? "toolbar_measure_dark.svg" : "toolbar_measure.svg"); + break; } } @@ -196,7 +199,7 @@ bool GLGizmosManager::init() m_gizmos.emplace_back(new GLGizmoSeam(m_parent, m_is_dark ? "toolbar_seam_dark.svg" : "toolbar_seam.svg", EType::Seam)); m_gizmos.emplace_back(new GLGizmoText(m_parent, m_is_dark ? "toolbar_text_dark.svg" : "toolbar_text.svg", EType::Text)); m_gizmos.emplace_back(new GLGizmoMmuSegmentation(m_parent, m_is_dark ? "mmu_segmentation_dark.svg" : "mmu_segmentation.svg", EType::MmuSegmentation)); - m_gizmos.emplace_back(new GLGizmoMeasure(m_parent, "measure.svg", EType::Measure)); + m_gizmos.emplace_back(new GLGizmoMeasure(m_parent, m_is_dark ? "toolbar_measure_dark.svg" : "toolbar_measure.svg", EType::Measure)); m_gizmos.emplace_back(new GLGizmoSimplify(m_parent, "reduce_triangles.svg", EType::Simplify)); //m_gizmos.emplace_back(new GLGizmoSlaSupports(m_parent, "sla_supports.svg", sprite_id++)); //m_gizmos.emplace_back(new GLGizmoFaceDetector(m_parent, "face recognition.svg", sprite_id++)); diff --git a/src/slic3r/GUI/ImGuiWrapper.cpp b/src/slic3r/GUI/ImGuiWrapper.cpp index 37135f5336a..47b9ea21bea 100644 --- a/src/slic3r/GUI/ImGuiWrapper.cpp +++ b/src/slic3r/GUI/ImGuiWrapper.cpp @@ -85,6 +85,7 @@ static const std::map font_icons = { {ImGui::PreferencesDarkButton , "notification_preferences_dark" }, {ImGui::PreferencesHoverDarkButton , "notification_preferences_hover_dark"}, + {ImGui::ClipboardBtnDarkIcon , "copy_menu_dark" }, {ImGui::CircleButtonDarkIcon , "circle_paint_dark" }, {ImGui::TriangleButtonDarkIcon , "triangle_paint_dark" }, {ImGui::FillButtonDarkIcon , "fill_paint_dark" }, @@ -154,6 +155,7 @@ const ImVec4 ImGuiWrapper::COL_SEPARATOR_DARK = { 0.24f, 0.24f, 0.27f, 1.0f } const ImVec4 ImGuiWrapper::COL_TITLE_BG = { 0.745f, 0.745f, 0.745f, 1.0f }; const ImVec4 ImGuiWrapper::COL_WINDOW_BG = { 1.000f, 1.000f, 1.000f, 1.0f }; const ImVec4 ImGuiWrapper::COL_WINDOW_BG_DARK = { 45 / 255.f, 45 / 255.f, 49 / 255.f, 1.f }; +const ImVec4 ImGuiWrapper::COL_ORCA = to_ImVec4(ColorRGBA::ORCA()); int ImGuiWrapper::TOOLBAR_WINDOW_FLAGS = ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoMove diff --git a/src/slic3r/GUI/ImGuiWrapper.hpp b/src/slic3r/GUI/ImGuiWrapper.hpp index aefd933f051..38c9bac8192 100644 --- a/src/slic3r/GUI/ImGuiWrapper.hpp +++ b/src/slic3r/GUI/ImGuiWrapper.hpp @@ -219,6 +219,7 @@ class ImGuiWrapper static const ImVec4 COL_WINDOW_BG_DARK; static const ImVec4 COL_SEPARATOR; static const ImVec4 COL_SEPARATOR_DARK; + static const ImVec4 COL_ORCA; //BBS static void on_change_color_mode(bool is_dark); From 1bfd9f63b6226edcaab5376bdeef0d6acafceb34 Mon Sep 17 00:00:00 2001 From: Noisyfox Date: Tue, 31 Oct 2023 20:00:12 +0800 Subject: [PATCH 85/99] Measure: Update measure dialog layout --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 580a98ec32c..edc650a66a2 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -1856,8 +1856,8 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit const bool use_inches = wxGetApp().app_config->get_bool("use_inches"); const std::string units = use_inches ? " " + _u8L("in") : " " + _u8L("mm"); - const ImGuiTableFlags flags = ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersH; - if (ImGui::BeginTable("Selection", 2, flags)) { + // Show selection + { auto format_item_text = [this, use_inches, &units](const SelectedFeatures::Item& item) { if (!item.feature.has_value()) return _u8L("None"); @@ -1882,11 +1882,21 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit return text; }; - add_strings_row_to_table(*m_imgui, _u8L("Selection") + " 1:", ImGuiWrapper::to_ImVec4(SELECTED_1ST_COLOR), format_item_text(m_selected_features.first), - ImGuiWrapper::to_ImVec4(SELECTED_1ST_COLOR)); - add_strings_row_to_table(*m_imgui, _u8L("Selection") + " 2:", ImGuiWrapper::to_ImVec4(SELECTED_2ND_COLOR), format_item_text(m_selected_features.second), - ImGuiWrapper::to_ImVec4(SELECTED_2ND_COLOR)); - ImGui::EndTable(); + const float selection_cap_length = ImGui::CalcTextSize((_u8L("Selection") + " 1").c_str()).x * 2; + + ImGui::AlignTextToFramePadding(); + ImGui::PushStyleColor(ImGuiCol_Text, ImGuiWrapper::to_ImVec4(SELECTED_1ST_COLOR)); + m_imgui->text(_u8L("Selection") + " 1"); + ImGui::SameLine(selection_cap_length); + m_imgui->text(format_item_text(m_selected_features.first)); + ImGui::PopStyleColor(); + + ImGui::AlignTextToFramePadding(); + ImGui::PushStyleColor(ImGuiCol_Text, ImGuiWrapper::to_ImVec4(SELECTED_2ND_COLOR)); + m_imgui->text(_u8L("Selection") + " 2"); + ImGui::SameLine(selection_cap_length); + m_imgui->text(format_item_text(m_selected_features.second)); + ImGui::PopStyleColor(); } m_imgui->disabled_begin(!m_selected_features.first.feature.has_value()); From ce2836a7f9e26274120477d40658755c48cd931f Mon Sep 17 00:00:00 2001 From: Noisyfox Date: Tue, 31 Oct 2023 20:04:07 +0800 Subject: [PATCH 86/99] Measure: Fix copy to clipboard encoding --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index edc650a66a2..0c8b42fe16d 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -1916,7 +1916,7 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit ImGui::TableSetColumnIndex(2); if (m_imgui->image_button(m_is_dark_mode ? ImGui::ClipboardBtnDarkIcon : ImGui::ClipboardBtnIcon, _L("Copy to clipboard"))) { wxTheClipboard->Open(); - wxTheClipboard->SetData(new wxTextDataObject(col_1 + ": " + col_2)); + wxTheClipboard->SetData(new wxTextDataObject(wxString((col_1 + ": " + col_2).c_str(), wxConvUTF8))); wxTheClipboard->Close(); } }; From 18406c31c05e84939601bac80f3800c7d020a479 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Tue, 31 Oct 2023 23:01:05 +0800 Subject: [PATCH 87/99] Cut: Initial porting of Cut Gizmo --- src/OrcaSlicer.cpp | 22 +- src/imgui/imconfig.h | 5 +- src/libslic3r/CMakeLists.txt | 2 + src/libslic3r/CutUtils.cpp | 663 ++++ src/libslic3r/CutUtils.hpp | 74 + src/libslic3r/Format/bbs_3mf.cpp | 189 +- src/libslic3r/Geometry.cpp | 27 + src/libslic3r/Geometry.hpp | 2 + src/libslic3r/Model.cpp | 534 +-- src/libslic3r/Model.hpp | 187 +- src/libslic3r/TriangleMesh.cpp | 277 +- src/libslic3r/TriangleMesh.hpp | 13 + src/libslic3r/TriangleMeshSlicer.cpp | 79 +- src/libslic3r/TriangleMeshSlicer.hpp | 14 +- src/libslic3r/Utils.hpp | 5 + src/libslic3r/utils.cpp | 76 + src/slic3r/CMakeLists.txt | 4 +- src/slic3r/GUI/3DScene.hpp | 14 + src/slic3r/GUI/GLCanvas3D.hpp | 4 + src/slic3r/GUI/GLSelectionRectangle.cpp | 35 +- src/slic3r/GUI/GLSelectionRectangle.hpp | 8 +- src/slic3r/GUI/GUI_ObjectList.cpp | 6 +- src/slic3r/GUI/GUI_ObjectList.hpp | 2 +- src/slic3r/GUI/Gizmos/GLGizmoBase.hpp | 3 + src/slic3r/GUI/Gizmos/GLGizmoCut.cpp | 3892 +++++++++++++++++++-- src/slic3r/GUI/Gizmos/GLGizmoCut.hpp | 407 ++- src/slic3r/GUI/Gizmos/GLGizmosManager.cpp | 23 +- src/slic3r/GUI/ImGuiWrapper.cpp | 60 +- src/slic3r/GUI/ImGuiWrapper.hpp | 19 +- src/slic3r/GUI/MsgDialog.cpp | 56 + src/slic3r/GUI/MsgDialog.hpp | 6 + src/slic3r/GUI/Plater.cpp | 155 +- src/slic3r/GUI/Plater.hpp | 28 +- src/slic3r/Utils/CalibUtils.cpp | 46 +- 34 files changed, 5607 insertions(+), 1330 deletions(-) create mode 100644 src/libslic3r/CutUtils.cpp create mode 100644 src/libslic3r/CutUtils.hpp diff --git a/src/OrcaSlicer.cpp b/src/OrcaSlicer.cpp index c8ba1cdd313..7271af2d973 100644 --- a/src/OrcaSlicer.cpp +++ b/src/OrcaSlicer.cpp @@ -1553,23 +1553,11 @@ int CLI::run(int argc, char **argv) o->cut(Z, m_config.opt_float("cut"), &out); } #else - ModelObject* object = model.objects.front(); - const BoundingBoxf3& box = object->bounding_box(); - const float Margin = 20.0; - const float max_x = box.size()(0) / 2.0 + Margin; - const float min_x = -max_x; - const float max_y = box.size()(1) / 2.0 + Margin; - const float min_y = -max_y; - - std::array plane_points; - plane_points[0] = { min_x, min_y, 0 }; - plane_points[1] = { max_x, min_y, 0 }; - plane_points[2] = { max_x, max_y, 0 }; - plane_points[3] = { min_x, max_y, 0 }; - for (Vec3d& point : plane_points) { - point += box.center(); - } - model.objects.front()->cut(0, plane_points, ModelObjectCutAttribute::KeepUpper | ModelObjectCutAttribute::KeepLower); + Cut cut(model.objects.front(), 0, Geometry::translation_transform(m_config.opt_float("cut") * Vec3d::UnitZ()), + ModelObjectCutAttribute::KeepLower | ModelObjectCutAttribute::KeepUpper | ModelObjectCutAttribute::PlaceOnCutUpper); + auto cut_objects = cut.perform_with_plane(); + for (ModelObject* obj : cut_objects) + model.add_object(*obj); #endif model.delete_object(size_t(0)); } diff --git a/src/imgui/imconfig.h b/src/imgui/imconfig.h index 9380ea16498..e9cedd8f30e 100644 --- a/src/imgui/imconfig.h +++ b/src/imgui/imconfig.h @@ -153,7 +153,9 @@ namespace ImGui // const wchar_t CustomSupportsMarker = 0x1D; // const wchar_t CustomSeamMarker = 0x1E; // const wchar_t MmuSegmentationMarker = 0x1F; - + const wchar_t PlugMarker = 0x1E; + const wchar_t DowelMarker = 0x1F; + const wchar_t SnapMarker = 0x20; // Do not forget use following letters only in wstring //BBS use 08xx to avoid unicode character which may be used const wchar_t DocumentationButton = 0x0800; @@ -198,6 +200,7 @@ namespace ImGui const wchar_t CloseBlockNotifHoverButton = 0x0834; const wchar_t BlockNotifErrorIcon = 0x0835; const wchar_t ClipboardBtnDarkIcon = 0x0836; + const wchar_t InfoMarkerSmall = 0x0837; // void MyFunction(const char* name, const MyMatrix44& v); } diff --git a/src/libslic3r/CMakeLists.txt b/src/libslic3r/CMakeLists.txt index c5d6463a39f..01347071786 100644 --- a/src/libslic3r/CMakeLists.txt +++ b/src/libslic3r/CMakeLists.txt @@ -202,6 +202,8 @@ set(lisbslic3r_sources BlacklistedLibraryCheck.hpp LocalesUtils.cpp LocalesUtils.hpp + CutUtils.cpp + CutUtils.hpp Model.cpp Model.hpp ModelArrange.hpp diff --git a/src/libslic3r/CutUtils.cpp b/src/libslic3r/CutUtils.cpp new file mode 100644 index 00000000000..8dd8fd7901f --- /dev/null +++ b/src/libslic3r/CutUtils.cpp @@ -0,0 +1,663 @@ +///|/ Copyright (c) Prusa Research 2023 Oleksandra Iushchenko @YuSanka +///|/ +///|/ PrusaSlicer is released under the terms of the AGPLv3 or higher +///|/ + +#include "CutUtils.hpp" +#include "Geometry.hpp" +#include "libslic3r.h" +#include "Model.hpp" +#include "TriangleMeshSlicer.hpp" +#include "TriangleSelector.hpp" +#include "ObjectID.hpp" + +#include + +namespace Slic3r { + +using namespace Geometry; + +static void apply_tolerance(ModelVolume* vol) +{ + ModelVolume::CutInfo& cut_info = vol->cut_info; + + assert(cut_info.is_connector); + if (!cut_info.is_processed) + return; + + Vec3d sf = vol->get_scaling_factor(); + + // make a "hole" wider + sf[X] += double(cut_info.radius_tolerance); + sf[Y] += double(cut_info.radius_tolerance); + + // make a "hole" dipper + sf[Z] += double(cut_info.height_tolerance); + + vol->set_scaling_factor(sf); + + // correct offset in respect to the new depth + Vec3d rot_norm = rotation_transform(vol->get_rotation()) * Vec3d::UnitZ(); + if (rot_norm.norm() != 0.0) + rot_norm.normalize(); + + double z_offset = 0.5 * static_cast(cut_info.height_tolerance); + if (cut_info.connector_type == CutConnectorType::Plug || + cut_info.connector_type == CutConnectorType::Snap) + z_offset -= 0.05; // add small Z offset to better preview + + vol->set_offset(vol->get_offset() + rot_norm * z_offset); +} + +static void add_cut_volume(TriangleMesh& mesh, ModelObject* object, const ModelVolume* src_volume, const Transform3d& cut_matrix, const std::string& suffix = {}, ModelVolumeType type = ModelVolumeType::MODEL_PART) +{ + if (mesh.empty()) + return; + + mesh.transform(cut_matrix); + ModelVolume* vol = object->add_volume(mesh); + vol->set_type(type); + + vol->name = src_volume->name + suffix; + // Don't copy the config's ID. + vol->config.assign_config(src_volume->config); + assert(vol->config.id().valid()); + assert(vol->config.id() != src_volume->config.id()); + vol->set_material(src_volume->material_id(), *src_volume->material()); + vol->cut_info = src_volume->cut_info; +} + +static void process_volume_cut( ModelVolume* volume, const Transform3d& instance_matrix, const Transform3d& cut_matrix, + ModelObjectCutAttributes attributes, TriangleMesh& upper_mesh, TriangleMesh& lower_mesh) +{ + const auto volume_matrix = volume->get_matrix(); + + const Transformation cut_transformation = Transformation(cut_matrix); + const Transform3d invert_cut_matrix = cut_transformation.get_rotation_matrix().inverse() * translation_transform(-1 * cut_transformation.get_offset()); + + // Transform the mesh by the combined transformation matrix. + // Flip the triangles in case the composite transformation is left handed. + TriangleMesh mesh(volume->mesh()); + mesh.transform(invert_cut_matrix * instance_matrix * volume_matrix, true); + + indexed_triangle_set upper_its, lower_its; + cut_mesh(mesh.its, 0.0f, &upper_its, &lower_its); + if (attributes.has(ModelObjectCutAttribute::KeepUpper)) + upper_mesh = TriangleMesh(upper_its); + if (attributes.has(ModelObjectCutAttribute::KeepLower)) + lower_mesh = TriangleMesh(lower_its); +} + +static void process_connector_cut( ModelVolume* volume, const Transform3d& instance_matrix, const Transform3d& cut_matrix, + ModelObjectCutAttributes attributes, ModelObject* upper, ModelObject* lower, + std::vector& dowels) +{ + assert(volume->cut_info.is_connector); + volume->cut_info.set_processed(); + + const auto volume_matrix = volume->get_matrix(); + + // ! Don't apply instance transformation for the conntectors. + // This transformation is already there + if (volume->cut_info.connector_type != CutConnectorType::Dowel) { + if (attributes.has(ModelObjectCutAttribute::KeepUpper)) { + ModelVolume* vol = nullptr; + if (volume->cut_info.connector_type == CutConnectorType::Snap) { + TriangleMesh mesh = TriangleMesh(its_make_cylinder(1.0, 1.0, PI / 180.)); + + vol = upper->add_volume(std::move(mesh)); + vol->set_transformation(volume->get_transformation()); + vol->set_type(ModelVolumeType::NEGATIVE_VOLUME); + + vol->cut_info = volume->cut_info; + vol->name = volume->name; + } + else + vol = upper->add_volume(*volume); + + vol->set_transformation(volume_matrix); + apply_tolerance(vol); + } + if (attributes.has(ModelObjectCutAttribute::KeepLower)) { + ModelVolume* vol = lower->add_volume(*volume); + vol->set_transformation(volume_matrix); + // for lower part change type of connector from NEGATIVE_VOLUME to MODEL_PART if this connector is a plug + vol->set_type(ModelVolumeType::MODEL_PART); + } + } + else { + if (attributes.has(ModelObjectCutAttribute::CreateDowels)) { + ModelObject* dowel{ nullptr }; + // Clone the object to duplicate instances, materials etc. + volume->get_object()->clone_for_cut(&dowel); + + // add one more solid part same as connector if this connector is a dowel + ModelVolume* vol = dowel->add_volume(*volume); + vol->set_type(ModelVolumeType::MODEL_PART); + + // But discard rotation and Z-offset for this volume + vol->set_rotation(Vec3d::Zero()); + vol->set_offset(Z, 0.0); + + dowels.push_back(dowel); + } + + // Cut the dowel + apply_tolerance(volume); + + // Perform cut + TriangleMesh upper_mesh, lower_mesh; + process_volume_cut(volume, Transform3d::Identity(), cut_matrix, attributes, upper_mesh, lower_mesh); + + // add small Z offset to better preview + upper_mesh.translate((-0.05 * Vec3d::UnitZ()).cast()); + lower_mesh.translate((0.05 * Vec3d::UnitZ()).cast()); + + // Add cut parts to the related objects + add_cut_volume(upper_mesh, upper, volume, cut_matrix, "_A", volume->type()); + add_cut_volume(lower_mesh, lower, volume, cut_matrix, "_B", volume->type()); + } +} + +static void process_modifier_cut(ModelVolume* volume, const Transform3d& instance_matrix, const Transform3d& inverse_cut_matrix, + ModelObjectCutAttributes attributes, ModelObject* upper, ModelObject* lower) +{ + const auto volume_matrix = instance_matrix * volume->get_matrix(); + + // Modifiers are not cut, but we still need to add the instance transformation + // to the modifier volume transformation to preserve their shape properly. + volume->set_transformation(Transformation(volume_matrix)); + + if (attributes.has(ModelObjectCutAttribute::KeepAsParts)) { + upper->add_volume(*volume); + return; + } + + // Some logic for the negative volumes/connectors. Add only needed modifiers + auto bb = volume->mesh().transformed_bounding_box(inverse_cut_matrix * volume_matrix); + bool is_crossed_by_cut = bb.min[Z] <= 0 && bb.max[Z] >= 0; + if (attributes.has(ModelObjectCutAttribute::KeepUpper) && (bb.min[Z] >= 0 || is_crossed_by_cut)) + upper->add_volume(*volume); + if (attributes.has(ModelObjectCutAttribute::KeepLower) && (bb.max[Z] <= 0 || is_crossed_by_cut)) + lower->add_volume(*volume); +} + +static void process_solid_part_cut(ModelVolume* volume, const Transform3d& instance_matrix, const Transform3d& cut_matrix, + ModelObjectCutAttributes attributes, ModelObject* upper, ModelObject* lower) +{ + // Perform cut + TriangleMesh upper_mesh, lower_mesh; + process_volume_cut(volume, instance_matrix, cut_matrix, attributes, upper_mesh, lower_mesh); + + // Add required cut parts to the objects + + if (attributes.has(ModelObjectCutAttribute::KeepAsParts)) { + add_cut_volume(upper_mesh, upper, volume, cut_matrix, "_A"); + if (!lower_mesh.empty()) { + add_cut_volume(lower_mesh, upper, volume, cut_matrix, "_B"); + upper->volumes.back()->cut_info.is_from_upper = false; + } + return; + } + + if (attributes.has(ModelObjectCutAttribute::KeepUpper)) + add_cut_volume(upper_mesh, upper, volume, cut_matrix); + + if (attributes.has(ModelObjectCutAttribute::KeepLower) && !lower_mesh.empty()) + add_cut_volume(lower_mesh, lower, volume, cut_matrix); +} + +static void reset_instance_transformation(ModelObject* object, size_t src_instance_idx, + const Transform3d& cut_matrix = Transform3d::Identity(), + bool place_on_cut = false, bool flip = false) +{ + // Reset instance transformation except offset and Z-rotation + + for (size_t i = 0; i < object->instances.size(); ++i) { + auto& obj_instance = object->instances[i]; + const double rot_z = obj_instance->get_rotation().z(); + + Transformation inst_trafo = Transformation(obj_instance->get_transformation().get_matrix(false, false, true)); + // add respect to mirroring + if (obj_instance->is_left_handed()) + inst_trafo = inst_trafo * Transformation(scale_transform(Vec3d(-1, 1, 1))); + + obj_instance->set_transformation(inst_trafo); + + Vec3d rotation = Vec3d::Zero(); + if (!flip && !place_on_cut) { + if ( i != src_instance_idx) + rotation[Z] = rot_z; + } + else { + Transform3d rotation_matrix = Transform3d::Identity(); + if (flip) + rotation_matrix = rotation_transform(PI * Vec3d::UnitX()); + + if (place_on_cut) + rotation_matrix = rotation_matrix * Transformation(cut_matrix).get_rotation_matrix().inverse(); + + if (i != src_instance_idx) + rotation_matrix = rotation_transform(rot_z * Vec3d::UnitZ()) * rotation_matrix; + + rotation = Transformation(rotation_matrix).get_rotation(); + } + + obj_instance->set_rotation(rotation); + } +} + + +Cut::Cut(const ModelObject* object, int instance, const Transform3d& cut_matrix, + ModelObjectCutAttributes attributes/*= ModelObjectCutAttribute::KeepUpper | ModelObjectCutAttribute::KeepLower | ModelObjectCutAttribute::KeepAsParts*/) + : m_instance(instance), m_cut_matrix(cut_matrix), m_attributes(attributes) +{ + m_model = Model(); + if (object) + m_model.add_object(*object); +} + +void Cut::post_process(ModelObject* object, ModelObjectPtrs& cut_object_ptrs, bool keep, bool place_on_cut, bool flip) +{ + if (!object) return; + + if (keep && !object->volumes.empty()) { + reset_instance_transformation(object, m_instance, m_cut_matrix, place_on_cut, flip); + cut_object_ptrs.push_back(object); + } + else + m_model.objects.push_back(object); // will be deleted in m_model.clear_objects(); +} + +void Cut::post_process(ModelObject* upper, ModelObject* lower, ModelObjectPtrs& cut_object_ptrs) +{ + post_process(upper, cut_object_ptrs, + m_attributes.has(ModelObjectCutAttribute::KeepUpper), + m_attributes.has(ModelObjectCutAttribute::PlaceOnCutUpper), + m_attributes.has(ModelObjectCutAttribute::FlipUpper)); + + post_process(lower, cut_object_ptrs, + m_attributes.has(ModelObjectCutAttribute::KeepLower), + m_attributes.has(ModelObjectCutAttribute::PlaceOnCutLower), + m_attributes.has(ModelObjectCutAttribute::PlaceOnCutLower) || m_attributes.has(ModelObjectCutAttribute::FlipLower)); +} + + +void Cut::finalize(const ModelObjectPtrs& objects) +{ + //clear model from temporarry objects + m_model.clear_objects(); + + // add to model result objects + m_model.objects = objects; +} + + +const ModelObjectPtrs& Cut::perform_with_plane() +{ + if (!m_attributes.has(ModelObjectCutAttribute::KeepUpper) && !m_attributes.has(ModelObjectCutAttribute::KeepLower)) { + m_model.clear_objects(); + return m_model.objects; + } + + ModelObject* mo = m_model.objects.front(); + + BOOST_LOG_TRIVIAL(trace) << "ModelObject::cut - start"; + + // Clone the object to duplicate instances, materials etc. + ModelObject* upper{ nullptr }; + if (m_attributes.has(ModelObjectCutAttribute::KeepUpper)) + mo->clone_for_cut(&upper); + + ModelObject* lower{ nullptr }; + if (m_attributes.has(ModelObjectCutAttribute::KeepLower) && !m_attributes.has(ModelObjectCutAttribute::KeepAsParts)) + mo->clone_for_cut(&lower); + + std::vector dowels; + + // Because transformations are going to be applied to meshes directly, + // we reset transformation of all instances and volumes, + // except for translation and Z-rotation on instances, which are preserved + // in the transformation matrix and not applied to the mesh transform. + + const auto instance_matrix = mo->instances[m_instance]->get_transformation().get_matrix(true); + const Transformation cut_transformation = Transformation(m_cut_matrix); + const Transform3d inverse_cut_matrix = cut_transformation.get_rotation_matrix().inverse() * translation_transform(-1. * cut_transformation.get_offset()); + + for (ModelVolume* volume : mo->volumes) { + volume->reset_extra_facets(); + + if (!volume->is_model_part()) { + if (volume->cut_info.is_processed) + process_modifier_cut(volume, instance_matrix, inverse_cut_matrix, m_attributes, upper, lower); + else + process_connector_cut(volume, instance_matrix, m_cut_matrix, m_attributes, upper, lower, dowels); + } + else if (!volume->mesh().empty()) + process_solid_part_cut(volume, instance_matrix, m_cut_matrix, m_attributes, upper, lower); + } + + // Post-process cut parts + + if (m_attributes.has(ModelObjectCutAttribute::KeepAsParts) && upper->volumes.empty()) { + m_model = Model(); + m_model.objects.push_back(upper); + return m_model.objects; + } + + ModelObjectPtrs cut_object_ptrs; + + if (m_attributes.has(ModelObjectCutAttribute::KeepAsParts) && !upper->volumes.empty()) { + reset_instance_transformation(upper, m_instance, m_cut_matrix); + cut_object_ptrs.push_back(upper); + } + else { + // Delete all modifiers which are not intersecting with solid parts bounding box + auto delete_extra_modifiers = [this](ModelObject* mo) { + if (!mo) return; + const BoundingBoxf3 obj_bb = mo->instance_bounding_box(m_instance); + const Transform3d inst_matrix = mo->instances[m_instance]->get_transformation().get_matrix(); + + for (int i = int(mo->volumes.size()) - 1; i >= 0; --i) + if (const ModelVolume* vol = mo->volumes[i]; + !vol->is_model_part() && !vol->is_cut_connector()) { + auto bb = vol->mesh().transformed_bounding_box(inst_matrix * vol->get_matrix()); + if (!obj_bb.intersects(bb)) + mo->delete_volume(i); + } + }; + + post_process(upper, lower, cut_object_ptrs); + delete_extra_modifiers(upper); + delete_extra_modifiers(lower); + + if (m_attributes.has(ModelObjectCutAttribute::CreateDowels) && !dowels.empty()) { + for (auto dowel : dowels) { + reset_instance_transformation(dowel, m_instance); + dowel->name += "-Dowel-" + dowel->volumes[0]->name; + cut_object_ptrs.push_back(dowel); + } + } + } + + BOOST_LOG_TRIVIAL(trace) << "ModelObject::cut - end"; + + finalize(cut_object_ptrs); + + return m_model.objects; +} + +static void distribute_modifiers_from_object(ModelObject* from_obj, const int instance_idx, ModelObject* to_obj1, ModelObject* to_obj2) +{ + auto obj1_bb = to_obj1 ? to_obj1->instance_bounding_box(instance_idx) : BoundingBoxf3(); + auto obj2_bb = to_obj2 ? to_obj2->instance_bounding_box(instance_idx) : BoundingBoxf3(); + const Transform3d inst_matrix = from_obj->instances[instance_idx]->get_transformation().get_matrix(); + + for (ModelVolume* vol : from_obj->volumes) + if (!vol->is_model_part()) { + auto bb = vol->mesh().transformed_bounding_box(inst_matrix * vol->get_matrix()); + // Don't add modifiers which are not intersecting with solid parts + if (obj1_bb.intersects(bb)) + to_obj1->add_volume(*vol); + if (obj2_bb.intersects(bb)) + to_obj2->add_volume(*vol); + } +} + +static void merge_solid_parts_inside_object(ModelObjectPtrs& objects) +{ + for (ModelObject* mo : objects) { + TriangleMesh mesh; + // Merge all SolidPart but not Connectors + for (const ModelVolume* mv : mo->volumes) { + if (mv->is_model_part() && !mv->is_cut_connector()) { + TriangleMesh m = mv->mesh(); + m.transform(mv->get_matrix()); + mesh.merge(m); + } + } + if (!mesh.empty()) { + ModelVolume* new_volume = mo->add_volume(mesh); + new_volume->name = mo->name; + // Delete all merged SolidPart but not Connectors + for (int i = int(mo->volumes.size()) - 2; i >= 0; --i) { + const ModelVolume* mv = mo->volumes[i]; + if (mv->is_model_part() && !mv->is_cut_connector()) + mo->delete_volume(i); + } + } + } +} + + +const ModelObjectPtrs& Cut::perform_by_contour(std::vector parts, int dowels_count) +{ + ModelObject* cut_mo = m_model.objects.front(); + + // Clone the object to duplicate instances, materials etc. + ModelObject* upper{ nullptr }; + if (m_attributes.has(ModelObjectCutAttribute::KeepUpper)) cut_mo->clone_for_cut(&upper); + ModelObject* lower{ nullptr }; + if (m_attributes.has(ModelObjectCutAttribute::KeepLower)) cut_mo->clone_for_cut(&lower); + + const size_t cut_parts_cnt = parts.size(); + bool has_modifiers = false; + + // Distribute SolidParts to the Upper/Lower object + for (size_t id = 0; id < cut_parts_cnt; ++id) { + if (parts[id].is_modifier) + has_modifiers = true; // modifiers will be added later to the related parts + else if (ModelObject* obj = (parts[id].selected ? upper : lower)) + obj->add_volume(*(cut_mo->volumes[id])); + } + + if (has_modifiers) { + // Distribute Modifiers to the Upper/Lower object + distribute_modifiers_from_object(cut_mo, m_instance, upper, lower); + } + + ModelObjectPtrs cut_object_ptrs; + + ModelVolumePtrs& volumes = cut_mo->volumes; + if (volumes.size() == cut_parts_cnt) { + // Means that object is cut without connectors + + // Just add Upper and Lower objects to cut_object_ptrs + post_process(upper, lower, cut_object_ptrs); + + // Now merge all model parts together: + merge_solid_parts_inside_object(cut_object_ptrs); + + // replace initial objects in model with cut object + finalize(cut_object_ptrs); + } + else if (volumes.size() > cut_parts_cnt) { + // Means that object is cut with connectors + + // All volumes are distributed to Upper / Lower object, + // So we don’t need them anymore + for (size_t id = 0; id < cut_parts_cnt; id++) + delete* (volumes.begin() + id); + volumes.erase(volumes.begin(), volumes.begin() + cut_parts_cnt); + + // Perform cut just to get connectors + Cut cut(cut_mo, m_instance, m_cut_matrix, m_attributes); + const ModelObjectPtrs& cut_connectors_obj = cut.perform_with_plane(); + assert(dowels_count > 0 ? cut_connectors_obj.size() >= 3 : cut_connectors_obj.size() == 2); + + // Connectors from upper object + for (const ModelVolume* volume : cut_connectors_obj[0]->volumes) + upper->add_volume(*volume, volume->type()); + + // Connectors from lower object + for (const ModelVolume* volume : cut_connectors_obj[1]->volumes) + lower->add_volume(*volume, volume->type()); + + // Add Upper and Lower objects to cut_object_ptrs + post_process(upper, lower, cut_object_ptrs); + + // Now merge all model parts together: + merge_solid_parts_inside_object(cut_object_ptrs); + + // replace initial objects in model with cut object + finalize(cut_object_ptrs); + + // Add Dowel-connectors as separate objects to model + if (cut_connectors_obj.size() >= 3) + for (size_t id = 2; id < cut_connectors_obj.size(); id++) + m_model.add_object(*cut_connectors_obj[id]); + } + + return m_model.objects; +} + + +const ModelObjectPtrs& Cut::perform_with_groove(const Groove& groove, const Transform3d& rotation_m, bool keep_as_parts/* = false*/) +{ + ModelObject* cut_mo = m_model.objects.front(); + + // Clone the object to duplicate instances, materials etc. + ModelObject* upper{ nullptr }; + cut_mo->clone_for_cut(&upper); + ModelObject* lower{ nullptr }; + cut_mo->clone_for_cut(&lower); + + const double groove_half_depth = 0.5 * double(groove.depth); + + Model tmp_model_for_cut = Model(); + + Model tmp_model = Model(); + tmp_model.add_object(*cut_mo); + ModelObject* tmp_object = tmp_model.objects.front(); + + auto add_volumes_from_cut = [](ModelObject* object, const ModelObjectCutAttribute attribute, const Model& tmp_model_for_cut) { + const auto& volumes = tmp_model_for_cut.objects.front()->volumes; + for (const ModelVolume* volume : volumes) + if (volume->is_model_part()) { + if ((attribute == ModelObjectCutAttribute::KeepUpper && volume->is_from_upper()) || + (attribute != ModelObjectCutAttribute::KeepUpper && !volume->is_from_upper())) { + ModelVolume* new_vol = object->add_volume(*volume); + new_vol->reset_from_upper(); + } + } + }; + + auto cut = [this, add_volumes_from_cut] + (ModelObject* object, const Transform3d& cut_matrix, const ModelObjectCutAttribute add_volumes_attribute, Model& tmp_model_for_cut) { + Cut cut(object, m_instance, cut_matrix); + + tmp_model_for_cut = Model(); + tmp_model_for_cut.add_object(*cut.perform_with_plane().front()); + assert(!tmp_model_for_cut.objects.empty()); + + object->clear_volumes(); + add_volumes_from_cut(object, add_volumes_attribute, tmp_model_for_cut); + reset_instance_transformation(object, m_instance); + }; + + // cut by upper plane + + const Transform3d cut_matrix_upper = translation_transform(rotation_m * (groove_half_depth * Vec3d::UnitZ())) * m_cut_matrix; + { + cut(tmp_object, cut_matrix_upper, ModelObjectCutAttribute::KeepLower, tmp_model_for_cut); + add_volumes_from_cut(upper, ModelObjectCutAttribute::KeepUpper, tmp_model_for_cut); + } + + // cut by lower plane + + const Transform3d cut_matrix_lower = translation_transform(rotation_m * (-groove_half_depth * Vec3d::UnitZ())) * m_cut_matrix; + { + cut(tmp_object, cut_matrix_lower, ModelObjectCutAttribute::KeepUpper, tmp_model_for_cut); + add_volumes_from_cut(lower, ModelObjectCutAttribute::KeepLower, tmp_model_for_cut); + } + + // cut middle part with 2 angles and add parts to related upper/lower objects + + const double h_side_shift = 0.5 * double(groove.width + groove.depth / tan(groove.flaps_angle)); + + // cut by angle1 plane + { + const Transform3d cut_matrix_angle1 = translation_transform(rotation_m * (-h_side_shift * Vec3d::UnitX())) * m_cut_matrix * rotation_transform(Vec3d(0, -groove.flaps_angle, -groove.angle)); + + cut(tmp_object, cut_matrix_angle1, ModelObjectCutAttribute::KeepLower, tmp_model_for_cut); + add_volumes_from_cut(lower, ModelObjectCutAttribute::KeepUpper, tmp_model_for_cut); + } + + // cut by angle2 plane + { + const Transform3d cut_matrix_angle2 = translation_transform(rotation_m * (h_side_shift * Vec3d::UnitX())) * m_cut_matrix * rotation_transform(Vec3d(0, groove.flaps_angle, groove.angle)); + + cut(tmp_object, cut_matrix_angle2, ModelObjectCutAttribute::KeepLower, tmp_model_for_cut); + add_volumes_from_cut(lower, ModelObjectCutAttribute::KeepUpper, tmp_model_for_cut); + } + + // apply tolerance to the middle part + { + const double h_groove_shift_tolerance = groove_half_depth - (double)groove.depth_tolerance; + + const Transform3d cut_matrix_lower_tolerance = translation_transform(rotation_m * (-h_groove_shift_tolerance * Vec3d::UnitZ())) * m_cut_matrix; + cut(tmp_object, cut_matrix_lower_tolerance, ModelObjectCutAttribute::KeepUpper, tmp_model_for_cut); + + const double h_side_shift_tolerance = h_side_shift - 0.5 * double(groove.width_tolerance); + + const Transform3d cut_matrix_angle1_tolerance = translation_transform(rotation_m * (-h_side_shift_tolerance * Vec3d::UnitX())) * m_cut_matrix * rotation_transform(Vec3d(0, -groove.flaps_angle, -groove.angle)); + cut(tmp_object, cut_matrix_angle1_tolerance, ModelObjectCutAttribute::KeepLower, tmp_model_for_cut); + + const Transform3d cut_matrix_angle2_tolerance = translation_transform(rotation_m * (h_side_shift_tolerance * Vec3d::UnitX())) * m_cut_matrix * rotation_transform(Vec3d(0, groove.flaps_angle, groove.angle)); + cut(tmp_object, cut_matrix_angle2_tolerance, ModelObjectCutAttribute::KeepUpper, tmp_model_for_cut); + } + + // this part can be added to the upper object now + add_volumes_from_cut(upper, ModelObjectCutAttribute::KeepLower, tmp_model_for_cut); + + ModelObjectPtrs cut_object_ptrs; + + if (keep_as_parts) { + // add volumes from lower object to the upper, but mark them as a lower + const auto& volumes = lower->volumes; + for (const ModelVolume* volume : volumes) { + ModelVolume* new_vol = upper->add_volume(*volume); + new_vol->cut_info.is_from_upper = false; + } + + // add modifiers + for (const ModelVolume* volume : cut_mo->volumes) + if (!volume->is_model_part()) + upper->add_volume(*volume); + + cut_object_ptrs.push_back(upper); + + // add lower object to the cut_object_ptrs just to correct delete it from the Model destructor and avoid memory leaks + cut_object_ptrs.push_back(lower); + } + else { + // add modifiers if object has any + for (const ModelVolume* volume : cut_mo->volumes) + if (!volume->is_model_part()) { + distribute_modifiers_from_object(cut_mo, m_instance, upper, lower); + break; + } + + assert(!upper->volumes.empty() && !lower->volumes.empty()); + + // Add Upper and Lower parts to cut_object_ptrs + + post_process(upper, lower, cut_object_ptrs); + + // Now merge all model parts together: + merge_solid_parts_inside_object(cut_object_ptrs); + } + + finalize(cut_object_ptrs); + + return m_model.objects; +} + +ModelObjectPtrs Cut::cut_horizontal(const ModelObject *object, size_t instance_idx, double z, ModelObjectCutAttributes attributes) +{ + Cut cut(object, instance_idx, Geometry::translation_transform(z * Vec3d::UnitZ()), attributes); + return cut.perform_with_plane(); +} + +} // namespace Slic3r + diff --git a/src/libslic3r/CutUtils.hpp b/src/libslic3r/CutUtils.hpp new file mode 100644 index 00000000000..d2bf88db549 --- /dev/null +++ b/src/libslic3r/CutUtils.hpp @@ -0,0 +1,74 @@ +///|/ Copyright (c) Prusa Research 2023 Oleksandra Iushchenko @YuSanka +///|/ +///|/ PrusaSlicer is released under the terms of the AGPLv3 or higher +///|/ +#ifndef slic3r_CutUtils_hpp_ +#define slic3r_CutUtils_hpp_ + +#include "enum_bitmask.hpp" +#include "Point.hpp" +#include "Model.hpp" + +#include + +namespace Slic3r { + +using ModelObjectPtrs = std::vector; + +enum class ModelObjectCutAttribute : int { KeepUpper, KeepLower, KeepAsParts, FlipUpper, FlipLower, PlaceOnCutUpper, PlaceOnCutLower, CreateDowels, InvalidateCutInfo }; +using ModelObjectCutAttributes = enum_bitmask; +ENABLE_ENUM_BITMASK_OPERATORS(ModelObjectCutAttribute); + + +class Cut { + + Model m_model; + int m_instance; + const Transform3d m_cut_matrix; + ModelObjectCutAttributes m_attributes; + + void post_process(ModelObject* object, ModelObjectPtrs& objects, bool keep, bool place_on_cut, bool flip); + void post_process(ModelObject* upper_object, ModelObject* lower_object, ModelObjectPtrs& objects); + void finalize(const ModelObjectPtrs& objects); + +public: + + Cut(const ModelObject* object, int instance, const Transform3d& cut_matrix, + ModelObjectCutAttributes attributes = ModelObjectCutAttribute::KeepUpper | + ModelObjectCutAttribute::KeepLower | + ModelObjectCutAttribute::KeepAsParts ); + ~Cut() { m_model.clear_objects(); } + + struct Groove + { + float depth{ 0.f }; + float width{ 0.f }; + float flaps_angle{ 0.f }; + float angle{ 0.f }; + float depth_init{ 0.f }; + float width_init{ 0.f }; + float flaps_angle_init{ 0.f }; + float angle_init{ 0.f }; + float depth_tolerance{ 0.1f }; + float width_tolerance{ 0.1f }; + }; + + struct Part + { + bool selected; + bool is_modifier; + }; + + const ModelObjectPtrs& perform_with_plane(); + const ModelObjectPtrs& perform_by_contour(std::vector parts, int dowels_count); + const ModelObjectPtrs& perform_with_groove(const Groove& groove, const Transform3d& rotation_m, bool keep_as_parts = false); + + static ModelObjectPtrs cut_horizontal(const ModelObject *object, size_t instance_idx, double z, ModelObjectCutAttributes attributes); + +}; // namespace Cut + + + +} // namespace Slic3r + +#endif /* slic3r_CutUtils_hpp_ */ diff --git a/src/libslic3r/Format/bbs_3mf.cpp b/src/libslic3r/Format/bbs_3mf.cpp index f6936efaaa1..c616d0f1b4d 100644 --- a/src/libslic3r/Format/bbs_3mf.cpp +++ b/src/libslic3r/Format/bbs_3mf.cpp @@ -1,3 +1,8 @@ +///|/ Copyright (c) Prusa Research 2018 - 2023 Oleksandra Iushchenko @YuSanka, David Kocík @kocikdav, Enrico Turri @enricoturri1966, Lukáš Matěna @lukasmatena, Lukáš Hejl @hejllukas, Filip Sykala @Jony01, Vojtěch Bubník @bubnikv, Tomáš Mészáros @tamasmeszaros +///|/ Copyright (c) 2020 Henner Zeller +///|/ +///|/ PrusaSlicer is released under the terms of the AGPLv3 or higher +///|/ #include "../libslic3r.h" #include "../Exception.hpp" #include "../Model.hpp" @@ -741,8 +746,6 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) { int volume_id; int type; - float radius; - float height; float r_tolerance; float h_tolerance; }; @@ -758,10 +761,10 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) //typedef std::map IdToAliasesMap; typedef std::vector InstancesList; typedef std::map IdToMetadataMap; - typedef std::map IdToCutObjectInfoMap; //typedef std::map IdToGeometryMap; typedef std::map> IdToLayerHeightsProfileMap; typedef std::map IdToLayerConfigRangesMap; + typedef std::map IdToCutObjectInfoMap; /*typedef std::map> IdToSlaSupportPointsMap; typedef std::map> IdToSlaDrainHolesMap;*/ @@ -951,7 +954,7 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) //IdToGeometryMap m_orig_geometries; // backup & restore CurrentConfig m_curr_config; IdToMetadataMap m_objects_metadata; - IdToCutObjectInfoMap m_cut_object_infos; + IdToCutObjectInfoMap m_cut_object_infos; IdToLayerHeightsProfileMap m_layer_heights_profiles; IdToLayerConfigRangesMap m_layer_config_ranges; /*IdToSlaSupportPointsMap m_sla_support_points; @@ -1013,7 +1016,7 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) bool _extract_xml_from_archive(mz_zip_archive& archive, std::string const & path, XML_StartElementHandler start_handler, XML_EndElementHandler end_handler); bool _extract_xml_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat, XML_StartElementHandler start_handler, XML_EndElementHandler end_handler); bool _extract_model_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat); - void _extract_cut_information_from_archive(mz_zip_archive &archive, const mz_zip_archive_file_stat &stat, ConfigSubstitutionContext &config_substitutions); + void _extract_cut_information_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat, ConfigSubstitutionContext& config_substitutions); void _extract_layer_heights_profile_config_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat); void _extract_layer_config_ranges_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat, ConfigSubstitutionContext& config_substitutions); void _extract_sla_support_points_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat); @@ -1955,11 +1958,14 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) IdToCutObjectInfoMap::iterator cut_object_info = m_cut_object_infos.find(object.second + 1); if (cut_object_info != m_cut_object_infos.end()) { model_object->cut_id = cut_object_info->second.id; - + int vol_cnt = int(model_object->volumes.size()); for (auto connector : cut_object_info->second.connectors) { - assert(0 <= connector.volume_id && connector.volume_id <= int(model_object->volumes.size())); - model_object->volumes[connector.volume_id]->cut_info = - ModelVolume::CutInfo(CutConnectorType(connector.type), connector.radius, connector.height, connector.r_tolerance, connector.h_tolerance, true); + if (connector.volume_id < 0 || connector.volume_id >= vol_cnt) { + add_error("Invalid connector is found"); + continue; + } + model_object->volumes[connector.volume_id]->cut_info = + ModelVolume::CutInfo(CutConnectorType(connector.type), connector.r_tolerance, connector.h_tolerance, true); } } } @@ -2324,7 +2330,7 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) void _BBS_3MF_Importer::_extract_cut_information_from_archive(mz_zip_archive &archive, const mz_zip_archive_file_stat &stat, ConfigSubstitutionContext &config_substitutions) { if (stat.m_uncomp_size > 0) { - std::string buffer((size_t) stat.m_uncomp_size, 0); + std::string buffer((size_t)stat.m_uncomp_size, 0); mz_bool res = mz_zip_reader_extract_file_to_mem(&archive, stat.m_filename, (void *) buffer.data(), (size_t) stat.m_uncomp_size, 0); if (res == 0) { add_error("Error while reading cut information data to buffer"); @@ -2332,12 +2338,12 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) } std::istringstream iss(buffer); // wrap returned xml to istringstream - pt::ptree objects_tree; + pt::ptree objects_tree; pt::read_xml(iss, objects_tree); - for (const auto &object : objects_tree.get_child("objects")) { + for (const auto& object : objects_tree.get_child("objects")) { pt::ptree object_tree = object.second; - int obj_idx = object_tree.get(".id", -1); + int obj_idx = object_tree.get(".id", -1); if (obj_idx <= 0) { add_error("Found invalid object id"); continue; @@ -2349,30 +2355,33 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) continue; } - CutObjectBase cut_id; - std::vector connectors; + CutObjectBase cut_id; + std::vector connectors; - for (const auto &obj_cut_info : object_tree) { + for (const auto& obj_cut_info : object_tree) { if (obj_cut_info.first == "cut_id") { pt::ptree cut_id_tree = obj_cut_info.second; - cut_id = CutObjectBase(ObjectID(cut_id_tree.get(".id")), cut_id_tree.get(".check_sum"), - cut_id_tree.get(".connectors_cnt")); + cut_id = CutObjectBase(ObjectID( cut_id_tree.get(".id")), + cut_id_tree.get(".check_sum"), + cut_id_tree.get(".connectors_cnt")); } if (obj_cut_info.first == "connectors") { pt::ptree cut_connectors_tree = obj_cut_info.second; - for (const auto &cut_connector : cut_connectors_tree) { - if (cut_connector.first != "connector") continue; - pt::ptree connector_tree = cut_connector.second; - CutObjectInfo::Connector connector = {connector_tree.get(".volume_id"), connector_tree.get(".type"), - connector_tree.get(".radius", 0.f), connector_tree.get(".height", 0.f), - connector_tree.get(".r_tolerance"), connector_tree.get(".h_tolerance")}; + for (const auto& cut_connector : cut_connectors_tree) { + if (cut_connector.first != "connector") + continue; + pt::ptree connector_tree = cut_connector.second; + CutObjectInfo::Connector connector = {connector_tree.get(".volume_id"), + connector_tree.get(".type"), + connector_tree.get(".r_tolerance"), + connector_tree.get(".h_tolerance")}; connectors.emplace_back(connector); } } } - CutObjectInfo cut_info{cut_id, connectors}; - m_cut_object_infos.insert({obj_idx, cut_info}); + CutObjectInfo cut_info {cut_id, connectors}; + m_cut_object_infos.insert({ obj_idx, cut_info }); } } } @@ -5260,6 +5269,7 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) //BBS: change volume to seperate objects bool _add_mesh_to_object_stream(std::function const &flush, ObjectData const &object_data) const; bool _add_build_to_model_stream(std::stringstream& stream, const BuildItemsList& build_items) const; + bool _add_cut_information_file_to_archive(mz_zip_archive& archive, Model& model); bool _add_layer_height_profile_file_to_archive(mz_zip_archive& archive, Model& model); bool _add_layer_config_ranges_file_to_archive(mz_zip_archive& archive, Model& model); bool _add_sla_support_points_file_to_archive(mz_zip_archive& archive, Model& model); @@ -5270,7 +5280,6 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) //BBS: add project embedded preset files bool _add_project_embedded_presets_to_archive(mz_zip_archive& archive, Model& model, std::vector project_presets); bool _add_model_config_file_to_archive(mz_zip_archive& archive, const Model& model, PlateDataPtrs& plate_data_list, const ObjectToObjectDataMap &objects_data, int export_plate_idx = -1, bool save_gcode = true, bool use_loaded_id = false); - bool _add_cut_information_file_to_archive(mz_zip_archive &archive, Model &model); bool _add_slice_info_config_file_to_archive(mz_zip_archive &archive, const Model &model, PlateDataPtrs &plate_data_list, const ObjectToObjectDataMap &objects_data, const DynamicPrintConfig& config); bool _add_gcode_file_to_archive(mz_zip_archive& archive, const Model& model, PlateDataPtrs& plate_data_list, Export3mfProgressFn proFn = nullptr); bool _add_custom_gcode_per_print_z_file_to_archive(mz_zip_archive& archive, Model& model, const DynamicPrintConfig* config); @@ -6704,6 +6713,69 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) return true; } + bool _BBS_3MF_Exporter::_add_cut_information_file_to_archive(mz_zip_archive &archive, Model &model) + { + std::string out = ""; + pt::ptree tree; + + unsigned int object_cnt = 0; + for (const ModelObject* object : model.objects) { + object_cnt++; + if (!object->is_cut()) + continue; + pt::ptree& obj_tree = tree.add("objects.object", ""); + + obj_tree.put(".id", object_cnt); + + // Store info for cut_id + pt::ptree& cut_id_tree = obj_tree.add("cut_id", ""); + + // store cut_id atributes + cut_id_tree.put(".id", object->cut_id.id().id); + cut_id_tree.put(".check_sum", object->cut_id.check_sum()); + cut_id_tree.put(".connectors_cnt", object->cut_id.connectors_cnt()); + + int volume_idx = -1; + for (const ModelVolume* volume : object->volumes) { + ++volume_idx; + if (volume->is_cut_connector()) { + pt::ptree& connectors_tree = obj_tree.add("connectors.connector", ""); + connectors_tree.put(".volume_id", volume_idx); + connectors_tree.put(".type", int(volume->cut_info.connector_type)); + connectors_tree.put(".r_tolerance", volume->cut_info.radius_tolerance); + connectors_tree.put(".h_tolerance", volume->cut_info.height_tolerance); + } + } + } + + if (!tree.empty()) { + std::ostringstream oss; + pt::write_xml(oss, tree); + out = oss.str(); + + // Post processing("beautification") of the output string for a better preview + boost::replace_all(out, ">\n \n ", ">\n "); + boost::replace_all(out, ">\n ", ">\n "); + boost::replace_all(out, ">\n ", ">\n "); + boost::replace_all(out, ">", ">\n "); + // OR just + boost::replace_all(out, "><", ">\n<"); + } + + if (!out.empty()) { + if (!mz_zip_writer_add_mem(&archive, CUT_INFORMATION_FILE.c_str(), (const void*)out.data(), out.length(), MZ_DEFAULT_COMPRESSION)) { + add_error("Unable to add cut information file to archive"); + return false; + } + } + + return true; + } + bool _BBS_3MF_Exporter::_add_layer_height_profile_file_to_archive(mz_zip_archive& archive, Model& model) { assert(is_decimal_separator_point()); @@ -7266,69 +7338,6 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) return true; } - bool _BBS_3MF_Exporter::_add_cut_information_file_to_archive(mz_zip_archive &archive, Model &model) - { - std::string out = ""; - pt::ptree tree; - - unsigned int object_cnt = 0; - for (const ModelObject *object : model.objects) { - object_cnt++; - pt::ptree &obj_tree = tree.add("objects.object", ""); - - obj_tree.put(".id", object_cnt); - - // Store info for cut_id - pt::ptree &cut_id_tree = obj_tree.add("cut_id", ""); - - // store cut_id atributes - cut_id_tree.put(".id", object->cut_id.id().id); - cut_id_tree.put(".check_sum", object->cut_id.check_sum()); - cut_id_tree.put(".connectors_cnt", object->cut_id.connectors_cnt()); - - int volume_idx = -1; - for (const ModelVolume *volume : object->volumes) { - ++volume_idx; - if (volume->is_cut_connector()) { - pt::ptree &connectors_tree = obj_tree.add("connectors.connector", ""); - connectors_tree.put(".volume_id", volume_idx); - connectors_tree.put(".type", int(volume->cut_info.connector_type)); - connectors_tree.put(".radius", volume->cut_info.radius); - connectors_tree.put(".height", volume->cut_info.height); - connectors_tree.put(".r_tolerance", volume->cut_info.radius_tolerance); - connectors_tree.put(".h_tolerance", volume->cut_info.height_tolerance); - } - } - } - - if (!tree.empty()) { - std::ostringstream oss; - pt::write_xml(oss, tree); - out = oss.str(); - - // Post processing("beautification") of the output string for a better preview - boost::replace_all(out, ">\n \n ", ">\n "); - boost::replace_all(out, ">\n ", ">\n "); - boost::replace_all(out, ">\n ", ">\n "); - boost::replace_all(out, ">", ">\n "); - // OR just - boost::replace_all(out, "><", ">\n<"); - } - - if (!out.empty()) { - if (!mz_zip_writer_add_mem(&archive, CUT_INFORMATION_FILE.c_str(), (const void *) out.data(), out.length(), MZ_DEFAULT_COMPRESSION)) { - add_error("Unable to add cut information file to archive"); - return false; - } - } - - return true; - } - bool _BBS_3MF_Exporter::_add_slice_info_config_file_to_archive(mz_zip_archive& archive, const Model& model, PlateDataPtrs& plate_data_list, const ObjectToObjectDataMap &objects_data, const DynamicPrintConfig& config) { std::stringstream stream; diff --git a/src/libslic3r/Geometry.cpp b/src/libslic3r/Geometry.cpp index ecee432bbad..e57b774f34e 100644 --- a/src/libslic3r/Geometry.cpp +++ b/src/libslic3r/Geometry.cpp @@ -1,3 +1,17 @@ +///|/ Copyright (c) Prusa Research 2016 - 2023 Vojtěch Bubník @bubnikv, Enrico Turri @enricoturri1966, Lukáš Matěna @lukasmatena, Filip Sykala @Jony01, Tomáš Mészáros @tamasmeszaros +///|/ Copyright (c) Slic3r 2013 - 2016 Alessandro Ranellucci @alranel +///|/ +///|/ ported from lib/Slic3r/Geometry.pm: +///|/ Copyright (c) Prusa Research 2017 - 2022 Vojtěch Bubník @bubnikv +///|/ Copyright (c) Slic3r 2011 - 2015 Alessandro Ranellucci @alranel +///|/ Copyright (c) 2013 Jose Luis Perez Diez +///|/ Copyright (c) 2013 Anders Sundman +///|/ Copyright (c) 2013 Jesse Vincent +///|/ Copyright (c) 2012 Mike Sheldrake @mesheldrake +///|/ Copyright (c) 2012 Mark Hindess +///|/ +///|/ PrusaSlicer is released under the terms of the AGPLv3 or higher +///|/ #include "libslic3r.h" #include "Exception.hpp" #include "Geometry.hpp" @@ -432,6 +446,14 @@ Vec3d extract_euler_angles(const Transform3d& transform) return extract_euler_angles(m); } +static Transform3d extract_rotation_matrix(const Transform3d& trafo) +{ + Matrix3d rotation; + Matrix3d scale; + trafo.computeRotationScaling(&rotation, &scale); + return Transform3d(rotation); +} + void rotation_from_two_vectors(Vec3d from, Vec3d to, Vec3d& rotation_axis, double& phi, Matrix3d* rotation_matrix) { double epsilon = 1e-5; @@ -504,6 +526,11 @@ void Transformation::set_offset(Axis axis, double offset) } } +Transform3d Transformation::get_rotation_matrix() const +{ + return extract_rotation_matrix(m_matrix); +} + void Transformation::set_rotation(const Vec3d& rotation) { set_rotation(X, rotation.x()); diff --git a/src/libslic3r/Geometry.hpp b/src/libslic3r/Geometry.hpp index 0a3dcad7d51..4f6511ff6fd 100644 --- a/src/libslic3r/Geometry.hpp +++ b/src/libslic3r/Geometry.hpp @@ -440,6 +440,8 @@ class Transformation const Vec3d& get_rotation() const { return m_rotation; } double get_rotation(Axis axis) const { return m_rotation(axis); } + Transform3d get_rotation_matrix() const; + void set_rotation(const Vec3d& rotation); void set_rotation(Axis axis, double rotation); diff --git a/src/libslic3r/Model.cpp b/src/libslic3r/Model.cpp index 90879d49c21..2d0ff44ca35 100644 --- a/src/libslic3r/Model.cpp +++ b/src/libslic3r/Model.cpp @@ -1,3 +1,16 @@ +///|/ Copyright (c) Prusa Research 2016 - 2023 Tomáš Mészáros @tamasmeszaros, Oleksandra Iushchenko @YuSanka, David Kocík @kocikdav, Enrico Turri @enricoturri1966, Lukáš Matěna @lukasmatena, Vojtěch Bubník @bubnikv, Lukáš Hejl @hejllukas, Filip Sykala @Jony01, Vojtěch Král @vojtechkral +///|/ Copyright (c) 2021 Boleslaw Ciesielski +///|/ Copyright (c) 2019 John Drake @foxox +///|/ Copyright (c) 2019 Sijmen Schoon +///|/ Copyright (c) Slic3r 2014 - 2016 Alessandro Ranellucci @alranel +///|/ Copyright (c) 2015 Maksim Derbasov @ntfshard +///|/ +///|/ ported from lib/Slic3r/Model.pm: +///|/ Copyright (c) Prusa Research 2016 - 2022 Vojtěch Bubník @bubnikv, Enrico Turri @enricoturri1966 +///|/ Copyright (c) Slic3r 2012 - 2016 Alessandro Ranellucci @alranel +///|/ +///|/ PrusaSlicer is released under the terms of the AGPLv3 or higher +///|/ #include "Model.hpp" #include "libslic3r.h" #include "BuildVolume.hpp" @@ -1693,68 +1706,6 @@ bool ModelObject::has_connectors() const return false; } -indexed_triangle_set ModelObject::get_connector_mesh(CutConnectorAttributes connector_attributes) -{ - indexed_triangle_set connector_mesh; - - int sectorCount {1}; - switch (CutConnectorShape(connector_attributes.shape)) { - case CutConnectorShape::Triangle: - sectorCount = 3; - break; - case CutConnectorShape::Square: - sectorCount = 4; - break; - case CutConnectorShape::Circle: - sectorCount = 360; - break; - case CutConnectorShape::Hexagon: - sectorCount = 6; - break; - default: - break; - } - - if (connector_attributes.style == CutConnectorStyle::Prizm) - connector_mesh = its_make_cylinder(1.0, 1.0, (2 * PI / sectorCount)); - else if (connector_attributes.type == CutConnectorType::Plug) - connector_mesh = its_make_cone(1.0, 1.0, (2 * PI / sectorCount)); - else - connector_mesh = its_make_frustum_dowel(1.0, 1.0, sectorCount); - - return connector_mesh; -} - -void ModelObject::apply_cut_connectors(const std::string &name) -{ - if (cut_connectors.empty()) - return; - - using namespace Geometry; - - size_t connector_id = cut_id.connectors_cnt(); - for (const CutConnector &connector : cut_connectors) { - TriangleMesh mesh = TriangleMesh(get_connector_mesh(connector.attribs)); - // Mesh will be centered when loading. - ModelVolume *new_volume = add_volume(std::move(mesh), ModelVolumeType::NEGATIVE_VOLUME); - - Transform3d translate_transform = Transform3d::Identity(); - translate_transform.translate(connector.pos); - Transform3d scale_transform = Transform3d::Identity(); - scale_transform.scale(Vec3f(connector.radius, connector.radius, connector.height).cast()); - - // Transform the new modifier to be aligned inside the instance - new_volume->set_transformation(translate_transform * connector.rotation_m * scale_transform); - - new_volume->cut_info = {connector.attribs.type, connector.radius, connector.height, connector.radius_tolerance, connector.height_tolerance}; - new_volume->name = name + "-" + std::to_string(++connector_id); - } - cut_id.increase_connectors_cnt(cut_connectors.size()); - - // delete all connectors - cut_connectors.clear(); -} - void ModelObject::invalidate_cut() { this->cut_id.invalidate(); @@ -1770,43 +1721,10 @@ void ModelObject::delete_connectors() } } -void ModelObject::synchronize_model_after_cut() -{ - for (ModelObject *obj : m_model->objects) { - if (obj == this || obj->cut_id.is_equal(this->cut_id)) continue; - if (obj->is_cut() && obj->cut_id.has_same_id(this->cut_id)) - obj->cut_id.copy(this->cut_id); - } -} - -void ModelObject::apply_cut_attributes(ModelObjectCutAttributes attributes) -{ - // we don't save cut information, if result will not contains all parts of initial object - if (!attributes.has(ModelObjectCutAttribute::KeepUpper) || - !attributes.has(ModelObjectCutAttribute::KeepLower) || - attributes.has(ModelObjectCutAttribute::InvalidateCutInfo)) - return; - - if (cut_id.id().invalid()) - cut_id.init(); - - { - int cut_obj_cnt = -1; - if (attributes.has(ModelObjectCutAttribute::KeepUpper)) - cut_obj_cnt++; - if (attributes.has(ModelObjectCutAttribute::KeepLower)) - cut_obj_cnt++; - if (attributes.has(ModelObjectCutAttribute::CreateDowels)) - cut_obj_cnt++; - if (cut_obj_cnt > 0) - cut_id.increase_check_sum(size_t(cut_obj_cnt)); - } -} - void ModelObject::clone_for_cut(ModelObject **obj) { (*obj) = ModelObject::new_clone(*this); - (*obj)->set_model(nullptr); + (*obj)->set_model(this->get_model()); (*obj)->sla_support_points.clear(); (*obj)->sla_drain_holes.clear(); (*obj)->sla_points_status = sla::PointsStatus::NoPoints; @@ -1814,189 +1732,11 @@ void ModelObject::clone_for_cut(ModelObject **obj) (*obj)->input_file.clear(); } -Transform3d ModelObject::calculate_cut_plane_inverse_matrix(const std::array& plane_points) -{ - Vec3d mid_point = {0.0, 0.0, 0.0}; - for (auto pt : plane_points) - mid_point += pt; - mid_point /= (double) plane_points.size(); - - Vec3d movement = -mid_point; - - Vec3d v01 = plane_points[1] - plane_points[0]; - Vec3d v12 = plane_points[2] - plane_points[1]; - - Vec3d plane_normal = v01.cross(v12); - plane_normal.normalize(); - - Vec3d axis = {0.0, 0.0, 0.0}; - double phi = 0.0; - Matrix3d matrix; - matrix.setIdentity(); - Geometry::rotation_from_two_vectors(plane_normal, {0.0, 0.0, 1.0}, axis, phi, &matrix); - Vec3d angles = Geometry::extract_euler_angles(matrix); - - movement = matrix * movement; - Transform3d transfo; - transfo.setIdentity(); - transfo.translate(movement); - transfo.rotate(Eigen::AngleAxisd(angles(2), Vec3d::UnitZ()) * Eigen::AngleAxisd(angles(1), Vec3d::UnitY()) * Eigen::AngleAxisd(angles(0), Vec3d::UnitX())); - return transfo; -} - -void ModelObject::process_connector_cut( - ModelVolume *volume, - const Transform3d & instance_matrix, - const Transform3d& cut_matrix, - ModelObjectCutAttributes attributes, - ModelObject *upper, ModelObject *lower, - std::vector &dowels, - Vec3d &local_dowels_displace) -{ - assert(volume->cut_info.is_connector); - volume->cut_info.set_processed(); - - const auto volume_matrix = volume->get_matrix(); - - // ! Don't apply instance transformation for the conntectors. - // This transformation is already there - if (volume->cut_info.connector_type != CutConnectorType::Dowel) { - if (attributes.has(ModelObjectCutAttribute::KeepUpper)) { - ModelVolume *vol = upper->add_volume(*volume); - vol->set_transformation(volume_matrix); - vol->apply_tolerance(); - } - if (attributes.has(ModelObjectCutAttribute::KeepLower)) { - ModelVolume *vol = lower->add_volume(*volume); - vol->set_transformation(volume_matrix); - // for lower part change type of connector from NEGATIVE_VOLUME to MODEL_PART if this connector is a plug - vol->set_type(ModelVolumeType::MODEL_PART); - } - } - else { - if (attributes.has(ModelObjectCutAttribute::CreateDowels)) { - ModelObject *dowel{nullptr}; - // Clone the object to duplicate instances, materials etc. - clone_for_cut(&dowel); - - // add one more solid part same as connector if this connector is a dowel - ModelVolume *vol = dowel->add_volume(*volume); - vol->set_type(ModelVolumeType::MODEL_PART); - - // But discard rotation and Z-offset for this volume - vol->set_rotation(Vec3d::Zero()); - vol->set_offset(Z, 0.0); - - // Compute the displacement (in instance coordinates) to be applied to place the dowels - local_dowels_displace = lower->full_raw_mesh_bounding_box().size().cwiseProduct(Vec3d(1.0, 1.0, 0.0)); - - dowels.push_back(dowel); - } - - // Cut the dowel - volume->apply_tolerance(); - - // Perform cut - TriangleMesh upper_mesh, lower_mesh; - process_volume_cut(volume, Transform3d::Identity(), cut_matrix, attributes, upper_mesh, lower_mesh); - - // add small Z offset to better preview - upper_mesh.translate((-0.05 * Vec3d::UnitZ()).cast()); - lower_mesh.translate((0.05 * Vec3d::UnitZ()).cast()); - - // Add cut parts to the related objects - add_cut_volume(upper_mesh, upper, volume, cut_matrix, "_A", volume->type()); - add_cut_volume(lower_mesh, lower, volume, cut_matrix, "_B", volume->type()); - } -} - -void ModelObject::process_modifier_cut( - ModelVolume *volume, - const Transform3d &instance_matrix, - const Transform3d &inverse_cut_matrix, - ModelObjectCutAttributes attributes, - ModelObject *upper, - ModelObject *lower) -{ - const auto volume_matrix = instance_matrix * volume->get_matrix(); - - // Modifiers are not cut, but we still need to add the instance transformation - // to the modifier volume transformation to preserve their shape properly. - volume->set_transformation(Geometry::Transformation(volume_matrix)); - - if (attributes.has(ModelObjectCutAttribute::CutToParts)) { - upper->add_volume(*volume); - return; - } - - // Some logic for the negative volumes/connectors. Add only needed modifiers - auto bb = volume->mesh().transformed_bounding_box(inverse_cut_matrix * volume_matrix); - bool is_crossed_by_cut = bb.min[Z] <= 0 && bb.max[Z] >= 0; - if (attributes.has(ModelObjectCutAttribute::KeepUpper) && (bb.min[Z] >= 0 || is_crossed_by_cut)) - upper->add_volume(*volume); - if (attributes.has(ModelObjectCutAttribute::KeepLower) && (bb.max[Z] <= 0 || is_crossed_by_cut)) - lower->add_volume(*volume); -} - -void ModelObject::process_volume_cut(ModelVolume * volume, - const Transform3d & instance_matrix, - const Transform3d & cut_matrix, - ModelObjectCutAttributes attributes, - TriangleMesh & upper_mesh, - TriangleMesh & lower_mesh) +void ModelVolume::reset_extra_facets() { - const auto volume_matrix = volume->get_matrix(); - - using namespace Geometry; - - const Geometry::Transformation cut_transformation = Geometry::Transformation(cut_matrix); - const Transform3d invert_cut_matrix = cut_transformation.get_matrix(true, false, true, true).inverse() - * translation_transform(-1 * cut_transformation.get_offset()); - - // Transform the mesh by the combined transformation matrix. - // Flip the triangles in case the composite transformation is left handed. - TriangleMesh mesh(volume->mesh()); - mesh.transform(invert_cut_matrix * instance_matrix * volume_matrix, true); - - indexed_triangle_set upper_its, lower_its; - cut_mesh(mesh.its, 0.0f, &upper_its, &lower_its); - if (attributes.has(ModelObjectCutAttribute::KeepUpper)) - upper_mesh = TriangleMesh(upper_its); - if (attributes.has(ModelObjectCutAttribute::KeepLower)) - lower_mesh = TriangleMesh(lower_its); -} - -void ModelObject::process_solid_part_cut(ModelVolume * volume, - const Transform3d & instance_matrix, - const Transform3d & cut_matrix, - const std::array &plane_points, - ModelObjectCutAttributes attributes, - ModelObject * upper, - ModelObject * lower, - Vec3d & local_displace) -{ - // Perform cut - TriangleMesh upper_mesh, lower_mesh; - process_volume_cut(volume, instance_matrix, cut_matrix, attributes, upper_mesh, lower_mesh); - - // Add required cut parts to the objects - if (attributes.has(ModelObjectCutAttribute::CutToParts)) { - add_cut_volume(upper_mesh, upper, volume, cut_matrix, "_A"); - add_cut_volume(lower_mesh, upper, volume, cut_matrix, "_B"); - return; - } - - if (attributes.has(ModelObjectCutAttribute::KeepUpper)) - add_cut_volume(upper_mesh, upper, volume, cut_matrix); - - if (attributes.has(ModelObjectCutAttribute::KeepLower) && !lower_mesh.empty()) { - add_cut_volume(lower_mesh, lower, volume, cut_matrix); - - // Compute the displacement (in instance coordinates) to be applied to place the upper parts - // The upper part displacement is set to half of the lower part bounding box - // this is done in hope at least a part of the upper part will always be visible and draggable - local_displace = lower->full_raw_mesh_bounding_box().size().cwiseProduct(Vec3d(-0.5, -0.5, 0.0)); - } + this->supported_facets.reset(); + this->seam_facets.reset(); + this->mmu_segmentation_facets.reset(); } static void invalidate_translations(ModelObject* object, const ModelInstance* src_instance) @@ -2073,215 +1813,6 @@ static void reset_instance_transformation(ModelObject* object, size_t src_instan } } -// BBS: replace z with plane_points -ModelObjectPtrs ModelObject::cut(size_t instance, std::array plane_points, ModelObjectCutAttributes attributes) -{ - if (! attributes.has(ModelObjectCutAttribute::KeepUpper) && ! attributes.has(ModelObjectCutAttribute::KeepLower)) - return {}; - - BOOST_LOG_TRIVIAL(trace) << "ModelObject::cut - start"; - - // apply cut attributes for object - apply_cut_attributes(attributes); - - ModelObject* upper{ nullptr }; - if (attributes.has(ModelObjectCutAttribute::KeepUpper)) - clone_for_cut(&upper); - - ModelObject* lower{ nullptr }; - if (attributes.has(ModelObjectCutAttribute::KeepLower) && !attributes.has(ModelObjectCutAttribute::CutToParts)) - clone_for_cut(&lower); - - // Because transformations are going to be applied to meshes directly, - // we reset transformation of all instances and volumes, - // except for translation and Z-rotation on instances, which are preserved - // in the transformation matrix and not applied to the mesh transform. - - // const auto instance_matrix = instances[instance]->get_matrix(true); - const auto instance_matrix = Geometry::assemble_transform( - Vec3d::Zero(), // don't apply offset - instances[instance]->get_rotation().cwiseProduct(Vec3d(1.0, 1.0, 1.0)), // BBS: do apply Z-rotation - instances[instance]->get_scaling_factor(), - instances[instance]->get_mirror() - ); - - // BBS - //z -= instances[instance]->get_offset().z(); - for (Vec3d& point : plane_points) { - point -= instances[instance]->get_offset(); - } - Transform3d inverse_cut_matrix = calculate_cut_plane_inverse_matrix(plane_points); - Transform3d cut_matrix = inverse_cut_matrix.inverse(); - - std::vector dowels; - // Displacement (in instance coordinates) to be applied to place the upper parts - Vec3d local_displace = Vec3d::Zero(); - Vec3d local_dowels_displace = Vec3d::Zero(); - - for (ModelVolume *volume : volumes) { - const auto volume_matrix = volume->get_matrix(); - - volume->supported_facets.reset(); - volume->seam_facets.reset(); - volume->mmu_segmentation_facets.reset(); - - if (! volume->is_model_part()) { - if (volume->cut_info.is_processed) { - // Modifiers are not cut, but we still need to add the instance transformation - // to the modifier volume transformation to preserve their shape properly. - //Transform3d inverse_cut_matrix = calculate_cut_plane_inverse_matrix(plane_points); - process_modifier_cut(volume, instance_matrix, inverse_cut_matrix, attributes, upper, lower); - } - else { - process_connector_cut(volume, instance_matrix, cut_matrix, attributes, upper, lower, dowels, local_dowels_displace); - } - } - else if (! volume->mesh().empty()) { - process_solid_part_cut(volume, instance_matrix, cut_matrix, plane_points, attributes, upper, lower, local_displace); - } - } - - ModelObjectPtrs res; - - if (attributes.has(ModelObjectCutAttribute::CutToParts) && !upper->volumes.empty()) { - reset_instance_transformation(upper, instance, cut_matrix); - res.push_back(upper); - } - else { - if (attributes.has(ModelObjectCutAttribute::KeepUpper) && upper->volumes.size() > 0) { - reset_instance_transformation(upper, instance, cut_matrix, attributes.has(ModelObjectCutAttribute::PlaceOnCutUpper), - attributes.has(ModelObjectCutAttribute::FlipUpper), local_displace); - - res.push_back(upper); - } - if (attributes.has(ModelObjectCutAttribute::KeepLower) && lower->volumes.size() > 0) { - reset_instance_transformation(lower, instance, cut_matrix, attributes.has(ModelObjectCutAttribute::PlaceOnCutLower), - attributes.has(ModelObjectCutAttribute::PlaceOnCutLower) ? true : attributes.has(ModelObjectCutAttribute::FlipLower)); - - res.push_back(lower); - } - - if (attributes.has(ModelObjectCutAttribute::CreateDowels) && !dowels.empty()) { - for (auto dowel : dowels) { - reset_instance_transformation(dowel, instance, Transform3d::Identity(), false, false, local_dowels_displace); - - local_dowels_displace += dowel->full_raw_mesh_bounding_box().size().cwiseProduct(Vec3d(-1.5, -1.5, 0.0)); - dowel->name += "-Dowel-" + dowel->volumes[0]->name; - res.push_back(dowel); - } - } - } - - BOOST_LOG_TRIVIAL(trace) << "ModelObject::cut - end"; - - synchronize_model_after_cut(); - - return res; -} - -// BBS -ModelObjectPtrs ModelObject::segment(size_t instance, unsigned int max_extruders, double smoothing_alpha, int segment_number) -{ - BOOST_LOG_TRIVIAL(trace) << "ModelObject::segment - start"; - - // Clone the object to duplicate instances, materials etc. - ModelObject* upper = ModelObject::new_clone(*this); - - upper->set_model(nullptr); - upper->sla_support_points.clear(); - upper->sla_drain_holes.clear(); - upper->sla_points_status = sla::PointsStatus::NoPoints; - upper->clear_volumes(); - upper->input_file.clear(); - - // Because transformations are going to be applied to meshes directly, - // we reset transformation of all instances and volumes, - // except for translation and Z-rotation on instances, which are preserved - // in the transformation matrix and not applied to the mesh transform. - - // const auto instance_matrix = instances[instance]->get_matrix(true); - const auto instance_matrix = Geometry::assemble_transform( - Vec3d::Zero(), // don't apply offset - instances[instance]->get_rotation(), // BBS: keep Z-rotation - instances[instance]->get_scaling_factor(), - instances[instance]->get_mirror() - ); - - for (ModelVolume* volume : volumes) { - const auto volume_matrix = volume->get_matrix(); - - volume->supported_facets.reset(); - volume->seam_facets.reset(); - - if (!volume->is_model_part()) { - // Modifiers are not cut, but we still need to add the instance transformation - // to the modifier volume transformation to preserve their shape properly. - volume->set_transformation(Geometry::Transformation(instance_matrix * volume_matrix)); - upper->add_volume(*volume); - } - else if (!volume->mesh().empty()) { - // Transform the mesh by the combined transformation matrix. - // Flip the triangles in case the composite transformation is left handed. - TriangleMesh mesh(volume->mesh()); - mesh.transform(instance_matrix * volume_matrix, true); - volume->reset_mesh(); - - auto mesh_segments = MeshBoolean::cgal::segment(mesh, smoothing_alpha, segment_number); - - - // Reset volume transformation except for offset - const Vec3d offset = volume->get_offset(); - volume->set_transformation(Geometry::Transformation()); - volume->set_offset(offset); - - unsigned int extruder_counter = 0; - for (int idx=0;idx 0) { - ModelVolume* vol = upper->add_volume(mesh_segment); - vol->name = volume->name.substr(0, volume->name.find_last_of('.')) + "_" + std::to_string(idx); - // Don't copy the config's ID. - vol->config.assign_config(volume->config); -#if 0 - assert(vol->config.id().valid()); - assert(vol->config.id() != volume->config.id()); - vol->set_material(volume->material_id(), *volume->material()); -#else - vol->config.set("extruder", auto_extruder_id(max_extruders, extruder_counter)); -#endif - } - } - } - } - - ModelObjectPtrs res; - - if (upper->volumes.size() > 0) { - upper->invalidate_bounding_box(); - - // Reset instance transformation except offset and Z-rotation - for (size_t i = 0; i < instances.size(); i++) { - auto& instance = upper->instances[i]; - const Vec3d offset = instance->get_offset(); - // BBS - //const double rot_z = instance->get_rotation()(2); - - instance->set_transformation(Geometry::Transformation()); - instance->set_offset(offset); - // BBS - //instance->set_rotation(Vec3d(0.0, 0.0, rot_z)); - } - - res.push_back(upper); - } - - BOOST_LOG_TRIVIAL(trace) << "ModelObject::segment - end"; - - return res; -} - void ModelObject::split(ModelObjectPtrs* new_objects) { std::vector all_meshes; @@ -2801,35 +2332,6 @@ bool ModelVolume::is_splittable() const return m_is_splittable == 1; } -void ModelVolume::apply_tolerance() -{ - assert(cut_info.is_connector); - if (!cut_info.is_processed) - return; - - Vec3d sf = get_scaling_factor(); - // make a "hole" wider - double size_scale = 1.f; - if (abs(cut_info.radius - 0) < EPSILON) // For compatibility with old files - size_scale = 1.f + double(cut_info.radius_tolerance); - else - size_scale = (double(cut_info.radius) + double(cut_info.radius_tolerance)) / double(cut_info.radius); - - sf[X] *= size_scale; - sf[Y] *= size_scale; - - // make a "hole" dipper - double height_scale = 1.f; - if (abs(cut_info.height - 0) < EPSILON) // For compatibility with old files - height_scale = 1.f + double(cut_info.height_tolerance); - else - height_scale = (double(cut_info.height) + double(cut_info.height_tolerance)) / double(cut_info.height); - - sf[Z] *= height_scale; - - set_scaling_factor(sf); -} - // BBS std::vector ModelVolume::get_extruders() const { diff --git a/src/libslic3r/Model.hpp b/src/libslic3r/Model.hpp index 33e7ff6a905..0705012c765 100644 --- a/src/libslic3r/Model.hpp +++ b/src/libslic3r/Model.hpp @@ -246,79 +246,92 @@ class LayerHeightProfile final : public ObjectWithTimestamp { }; enum class CutConnectorType : int { - Plug, - Dowel, - Undef + Plug + , Dowel + , Snap + , Undef }; enum class CutConnectorStyle : int { - Prizm, - Frustum, - Undef + Prism + , Frustum + , Undef //,Claw }; enum class CutConnectorShape : int { - Triangle, - Square, - Hexagon, - Circle, - Undef + Triangle + , Square + , Hexagon + , Circle + , Undef //,D-shape }; struct CutConnectorAttributes { - CutConnectorType type{CutConnectorType::Plug}; - CutConnectorStyle style{CutConnectorStyle::Prizm}; - CutConnectorShape shape{CutConnectorShape::Circle}; + CutConnectorType type{ CutConnectorType::Plug }; + CutConnectorStyle style{ CutConnectorStyle::Prism }; + CutConnectorShape shape{ CutConnectorShape::Circle }; CutConnectorAttributes() {} - CutConnectorAttributes(CutConnectorType t, CutConnectorStyle st, CutConnectorShape sh) : type(t), style(st), shape(sh) {} + CutConnectorAttributes(CutConnectorType t, CutConnectorStyle st, CutConnectorShape sh) + : type(t), style(st), shape(sh) + {} - CutConnectorAttributes(const CutConnectorAttributes &rhs) : CutConnectorAttributes(rhs.type, rhs.style, rhs.shape) {} + CutConnectorAttributes(const CutConnectorAttributes& rhs) : + CutConnectorAttributes(rhs.type, rhs.style, rhs.shape) {} - bool operator==(const CutConnectorAttributes &other) const; + bool operator==(const CutConnectorAttributes& other) const; - bool operator!=(const CutConnectorAttributes &other) const { return !(other == (*this)); } + bool operator!=(const CutConnectorAttributes& other) const { return !(other == (*this)); } - bool operator<(const CutConnectorAttributes &other) const - { - return this->type < other.type || (this->type == other.type && this->style < other.style) || - (this->type == other.type && this->style == other.style && this->shape < other.shape); + bool operator<(const CutConnectorAttributes& other) const { + return this->type < other.type || + (this->type == other.type && this->style < other.style) || + (this->type == other.type && this->style == other.style && this->shape < other.shape); } - template inline void serialize(Archive &ar) { ar(type, style, shape); } + template inline void serialize(Archive& ar) { + ar(type, style, shape); + } }; struct CutConnector { - Vec3d pos; - Transform3d rotation_m; - float radius; - float height; - float radius_tolerance; // [0.f : 1.f] - float height_tolerance; // [0.f : 1.f] + Vec3d pos; + Transform3d rotation_m; + float radius; + float height; + float radius_tolerance;// [0.f : 1.f] + float height_tolerance;// [0.f : 1.f] + float z_angle {0.f}; CutConnectorAttributes attribs; - CutConnector() : pos(Vec3d::Zero()), rotation_m(Transform3d::Identity()), radius(5.f), height(10.f), radius_tolerance(0.f), height_tolerance(0.1f) {} + CutConnector() + : pos(Vec3d::Zero()), rotation_m(Transform3d::Identity()), radius(5.f), height(10.f), radius_tolerance(0.f), height_tolerance(0.1f), z_angle(0.f) + {} - CutConnector(Vec3d p, Transform3d rot, float r, float h, float rt, float ht, CutConnectorAttributes attributes) - : pos(p), rotation_m(rot), radius(r), height(h), radius_tolerance(rt), height_tolerance(ht), attribs(attributes) + CutConnector(Vec3d p, Transform3d rot, float r, float h, float rt, float ht, float za, CutConnectorAttributes attributes) + : pos(p), rotation_m(rot), radius(r), height(h), radius_tolerance(rt), height_tolerance(ht), z_angle(za), attribs(attributes) {} - CutConnector(const CutConnector &rhs) : CutConnector(rhs.pos, rhs.rotation_m, rhs.radius, rhs.height, rhs.radius_tolerance, rhs.height_tolerance, rhs.attribs) {} + CutConnector(const CutConnector& rhs) : + CutConnector(rhs.pos, rhs.rotation_m, rhs.radius, rhs.height, rhs.radius_tolerance, rhs.height_tolerance, rhs.z_angle, rhs.attribs) {} - bool operator==(const CutConnector &other) const; + bool operator==(const CutConnector& other) const; - bool operator!=(const CutConnector &other) const { return !(other == (*this)); } + bool operator!=(const CutConnector& other) const { return !(other == (*this)); } - template inline void serialize(Archive &ar) { ar(pos, rotation_m, radius, height, radius_tolerance, height_tolerance, attribs); } + template inline void serialize(Archive& ar) { + ar(pos, rotation_m, radius, height, radius_tolerance, height_tolerance, z_angle, attribs); + } }; using CutConnectors = std::vector; + // Declared outside of ModelVolume, so it could be forward declared. enum class ModelVolumeType : int { INVALID = -1, @@ -326,13 +339,9 @@ enum class ModelVolumeType : int { NEGATIVE_VOLUME, PARAMETER_MODIFIER, SUPPORT_BLOCKER, - SUPPORT_ENFORCER + SUPPORT_ENFORCER, }; -enum class ModelObjectCutAttribute : int { KeepUpper, KeepLower, FlipUpper, FlipLower, PlaceOnCutUpper, PlaceOnCutLower, CreateDowels, CutToParts, InvalidateCutInfo }; -using ModelObjectCutAttributes = enum_bitmask; -ENABLE_ENUM_BITMASK_OPERATORS(ModelObjectCutAttribute); - // A printable object, possibly having multiple print volumes (each with its own set of parameters and materials), // and possibly having multiple modifier volumes, each modifier volume with its set of parameters and materials. // Each ModelObject may be instantiated mutliple times, each instance having different placement on the print bed, @@ -371,6 +380,10 @@ class ModelObject final : public ObjectBase // Holes to be drilled into the object so resin can flow out sla::DrainHoles sla_drain_holes; + // Connectors to be added into the object before cut and are used to create a solid/negative volumes during a cut perform + CutConnectors cut_connectors; + CutObjectBase cut_id; + /* This vector accumulates the total translation applied to the object by the center_around_origin() method. Callers might want to apply the same translation to new volumes before adding them to this object in order to preserve alignment @@ -380,10 +393,6 @@ class ModelObject final : public ObjectBase // BBS: save for compare with new load volumes std::vector volume_ids; - // Connectors to be added into the object before cut and are used to create a solid/negative volumes during a cut perform - CutConnectors cut_connectors; - CutObjectBase cut_id; - Model* get_model() { return m_model; } const Model* get_model() const { return m_model; } // BBS: production extension @@ -480,52 +489,13 @@ class ModelObject final : public ObjectBase size_t materials_count() const; size_t facets_count() const; size_t parts_count() const; - - bool is_cut() const { return cut_id.id().valid(); } - bool has_connectors() const; - static indexed_triangle_set get_connector_mesh(CutConnectorAttributes connector_attributes); - void apply_cut_connectors(const std::string &name); // invalidate cut state for this object and its connectors/volumes void invalidate_cut(); // delete volumes which are marked as connector for this object void delete_connectors(); - void synchronize_model_after_cut(); - void apply_cut_attributes(ModelObjectCutAttributes attributes); void clone_for_cut(ModelObject **obj); - Transform3d calculate_cut_plane_inverse_matrix(const std::array &plane_points); - void process_connector_cut(ModelVolume *volume, - const Transform3d & instance_matrix, - const Transform3d& cut_matrix, - ModelObjectCutAttributes attributes, - ModelObject *upper, ModelObject *lower, - std::vector &dowels, - Vec3d &local_dowels_displace); - void process_modifier_cut(ModelVolume * volume, - const Transform3d & instance_matrix, - const Transform3d & inverse_cut_matrix, - ModelObjectCutAttributes attributes, - ModelObject * upper, - ModelObject * lower); - void process_volume_cut(ModelVolume * volume, - const Transform3d & instance_matrix, - const Transform3d & cut_matrix, - ModelObjectCutAttributes attributes, - TriangleMesh & upper_mesh, - TriangleMesh & lower_mesh); - void process_solid_part_cut(ModelVolume * volume, - const Transform3d & instance_matrix, - const Transform3d & cut_matrix, - const std::array &plane_points, - ModelObjectCutAttributes attributes, - ModelObject * upper, - ModelObject * lower, - Vec3d & local_displace); - - // BBS: replace z with plane_points - ModelObjectPtrs cut(size_t instance, std::array plane_points, ModelObjectCutAttributes attributes); - // BBS - ModelObjectPtrs segment(size_t instance, unsigned int max_extruders, double smoothing_alpha = 0.5, int segment_number = 5); - void split(ModelObjectPtrs* new_objects); + + void split(ModelObjectPtrs*new_objects); void merge(); // BBS: Boolean opts - Musang King @@ -553,6 +523,8 @@ class ModelObject final : public ObjectBase // Get count of errors in the mesh( or all object's meshes, if volume index isn't defined) int get_repaired_errors_count(const int vol_idx = -1) const; + bool is_cut() const { return cut_id.id().valid(); } + bool has_connectors() const; private: friend class Model; // This constructor assigns new ID to this ModelObject and its config. @@ -853,33 +825,41 @@ class ModelVolume final : public ObjectBase }; Source source; - // struct used by cut command + // struct used by cut command // It contains information about connetors struct CutInfo { - bool is_connector{false}; - bool is_processed{true}; - CutConnectorType connector_type{CutConnectorType::Plug}; - float radius{0.f}; - float height{0.f}; - float radius_tolerance{0.f}; // [0.f : 1.f] - float height_tolerance{0.f}; // [0.f : 1.f] + bool is_from_upper{ true }; + bool is_connector{ false }; + bool is_processed{ true }; + CutConnectorType connector_type{ CutConnectorType::Plug }; + float radius_tolerance{ 0.f };// [0.f : 1.f] + float height_tolerance{ 0.f };// [0.f : 1.f] CutInfo() = default; - CutInfo(CutConnectorType type, float radius_, float height_, float rad_tolerance, float h_tolerance, bool processed = false) - : is_connector(true), is_processed(processed), connector_type(type) - , radius(radius_), height(height_), radius_tolerance(rad_tolerance), height_tolerance(h_tolerance) + CutInfo(CutConnectorType type, float rad_tolerance, float h_tolerance, bool processed = false) : + is_connector(true), + is_processed(processed), + connector_type(type), + radius_tolerance(rad_tolerance), + height_tolerance(h_tolerance) {} void set_processed() { is_processed = true; } - void invalidate() { is_connector = false; } + void invalidate() { is_connector = false; } + void reset_from_upper() { is_from_upper = true; } - template inline void serialize(Archive &ar) { ar(is_connector, is_processed, connector_type, radius_tolerance, height_tolerance); } + template inline void serialize(Archive& ar) { + ar(is_connector, is_processed, connector_type, radius_tolerance, height_tolerance); + } }; - CutInfo cut_info; + CutInfo cut_info; - bool is_cut_connector() const { return cut_info.is_processed && cut_info.is_connector; } - void invalidate_cut_info() { cut_info.invalidate(); } + bool is_from_upper() const { return cut_info.is_from_upper; } + void reset_from_upper() { cut_info.reset_from_upper(); } + + bool is_cut_connector() const { return cut_info.is_processed && cut_info.is_connector; } + void invalidate_cut_info() { cut_info.invalidate(); } // The triangular model. const TriangleMesh& mesh() const { return *m_mesh.get(); } @@ -922,6 +902,7 @@ class ModelVolume final : public ObjectBase bool is_support_blocker() const { return m_type == ModelVolumeType::SUPPORT_BLOCKER; } bool is_support_modifier() const { return m_type == ModelVolumeType::SUPPORT_BLOCKER || m_type == ModelVolumeType::SUPPORT_ENFORCER; } t_model_material_id material_id() const { return m_material_id; } + void reset_extra_facets(); void set_material_id(t_model_material_id material_id); ModelMaterial* material() const; void set_material(t_model_material_id material_id, const ModelMaterial &material); @@ -931,8 +912,6 @@ class ModelVolume final : public ObjectBase bool is_splittable() const; - void apply_tolerance(); - // BBS std::vector get_extruders() const; void update_extruder_count(size_t extruder_count); diff --git a/src/libslic3r/TriangleMesh.cpp b/src/libslic3r/TriangleMesh.cpp index b5d0d108834..92557dfdb5e 100644 --- a/src/libslic3r/TriangleMesh.cpp +++ b/src/libslic3r/TriangleMesh.cpp @@ -1,3 +1,18 @@ +///|/ Copyright (c) Prusa Research 2016 - 2023 Oleksandra Iushchenko @YuSanka, Enrico Turri @enricoturri1966, Lukáš Matěna @lukasmatena, Vojtěch Bubník @bubnikv, Tomáš Mészáros @tamasmeszaros, Filip Sykala @Jony01, Lukáš Hejl @hejllukas, Vojtěch Král @vojtechkral +///|/ Copyright (c) 2019 Jason Tibbitts @jasontibbitts +///|/ Copyright (c) 2019 Sijmen Schoon +///|/ Copyright (c) 2016 Joseph Lenox @lordofhyphens +///|/ Copyright (c) Slic3r 2013 - 2016 Alessandro Ranellucci @alranel +///|/ Copyright (c) 2015 Maksim Derbasov @ntfshard +///|/ Copyright (c) 2014 Miro Hrončok @hroncok +///|/ Copyright (c) 2014 Petr Ledvina @ledvinap +///|/ +///|/ ported from lib/Slic3r/TriangleMesh.pm: +///|/ Copyright (c) Slic3r 2011 - 2014 Alessandro Ranellucci @alranel +///|/ Copyright (c) 2012 - 2013 Mark Hindess +///|/ +///|/ PrusaSlicer is released under the terms of the AGPLv3 or higher +///|/ #include "Exception.hpp" #include "TriangleMesh.hpp" #include "TriangleMeshSlicer.hpp" @@ -958,6 +973,51 @@ indexed_triangle_set its_make_cylinder(double r, double h, double fa) return mesh; } +indexed_triangle_set its_make_frustum(double r, double h, double fa) +{ + indexed_triangle_set mesh; + size_t n_steps = (size_t)ceil(2. * PI / fa); + double angle_step = 2. * PI / n_steps; + + auto &vertices = mesh.vertices; + auto &facets = mesh.indices; + vertices.reserve(2 * n_steps + 2); + facets.reserve(4 * n_steps); + + // 2 special vertices, top and bottom center, rest are relative to this + vertices.emplace_back(Vec3f(0.f, 0.f, 0.f)); + vertices.emplace_back(Vec3f(0.f, 0.f, float(h))); + + // for each line along the polygon approximating the top/bottom of the + // circle, generate four points and four facets (2 for the wall, 2 for the + // top and bottom. + // Special case: Last line shares 2 vertices with the first line. + Vec2f vec_top = Eigen::Rotation2Df(0.f) * Eigen::Vector2f(0, 0.5f*r); + Vec2f vec_botton = Eigen::Rotation2Df(0.f) * Eigen::Vector2f(0, r); + + vertices.emplace_back(Vec3f(vec_botton(0), vec_botton(1), 0.f)); + vertices.emplace_back(Vec3f(vec_top(0), vec_top(1), float(h))); + for (size_t i = 1; i < n_steps; ++i) { + vec_top = Eigen::Rotation2Df(angle_step * i) * Eigen::Vector2f(0, 0.5f*float(r)); + vec_botton = Eigen::Rotation2Df(angle_step * i) * Eigen::Vector2f(0, float(r)); + vertices.emplace_back(Vec3f(vec_botton(0), vec_botton(1), 0.f)); + vertices.emplace_back(Vec3f(vec_top(0), vec_top(1), float(h))); + int id = (int)vertices.size() - 1; + facets.emplace_back( 0, id - 1, id - 3); // top + facets.emplace_back(id, 1, id - 2); // bottom + facets.emplace_back(id, id - 2, id - 3); // upper-right of side + facets.emplace_back(id, id - 3, id - 1); // bottom-left of side + } + // Connect the last set of vertices with the first. + int id = (int)vertices.size() - 1; + facets.emplace_back( 0, 2, id - 1); + facets.emplace_back( 3, 1, id); + facets.emplace_back(id, 2, 3); + facets.emplace_back(id, id - 1, 2); + + return mesh; +} + indexed_triangle_set its_make_cone(double r, double h, double fa) { indexed_triangle_set mesh; @@ -984,42 +1044,64 @@ indexed_triangle_set its_make_cone(double r, double h, double fa) return mesh; } -// Generates mesh for a frustum dowel centered about the origin, using the count of sectors -// Note: This function uses code for sphere generation, but for stackCount = 2; -indexed_triangle_set its_make_frustum_dowel(double radius, double h, int sectorCount) +indexed_triangle_set its_make_pyramid(float base, float height) { - int stackCount = 2; - float sectorStep = float(2. * M_PI / sectorCount); - float stackStep = float(M_PI / stackCount); + float a = base / 2.f; + return { + { + {0, 1, 2}, + {0, 2, 3}, + {0, 1, 4}, + {1, 2, 4}, + {2, 3, 4}, + {3, 0, 4} + }, + { + {-a, -a, 0}, {a, -a, 0}, {a, a, 0}, + {-a, a, 0}, {0.f, 0.f, height} + } + }; +} + +// Generates mesh for a sphere centered about the origin, using the generated angle +// to determine the granularity. +// Default angle is 1 degree. +//FIXME better to discretize an Icosahedron recursively http://www.songho.ca/opengl/gl_sphere.html +indexed_triangle_set its_make_sphere(double radius, double fa) +{ + int sectorCount = int(ceil(2. * M_PI / fa)); + int stackCount = int(ceil(M_PI / fa)); + float sectorStep = float(2. * M_PI / sectorCount); + float stackStep = float(M_PI / stackCount); indexed_triangle_set mesh; auto& vertices = mesh.vertices; vertices.reserve((stackCount - 1) * sectorCount + 2); - for (int i = 0; i <= stackCount; ++i) { + for (int i = 0; i <= stackCount; ++ i) { // from pi/2 to -pi/2 double stackAngle = 0.5 * M_PI - stackStep * i; double xy = radius * cos(stackAngle); - double z = radius * sin(stackAngle); + double z = radius * sin(stackAngle); if (i == 0 || i == stackCount) - vertices.emplace_back(Vec3f(float(xy), 0.f, float(h * sin(stackAngle)))); + vertices.emplace_back(Vec3f(float(xy), 0.f, float(z))); else - for (int j = 0; j < sectorCount; ++j) { + for (int j = 0; j < sectorCount; ++ j) { // from 0 to 2pi - double sectorAngle = sectorStep * j + 0.25 * M_PI; + double sectorAngle = sectorStep * j; vertices.emplace_back(Vec3d(xy * std::cos(sectorAngle), xy * std::sin(sectorAngle), z).cast()); } } auto& facets = mesh.indices; facets.reserve(2 * (stackCount - 1) * sectorCount); - for (int i = 0; i < stackCount; ++i) { + for (int i = 0; i < stackCount; ++ i) { // Beginning of current stack. int k1 = (i == 0) ? 0 : (1 + (i - 1) * sectorCount); int k1_first = k1; // Beginning of next stack. int k2 = (i == 0) ? 1 : (k1 + sectorCount); int k2_first = k2; - for (int j = 0; j < sectorCount; ++j) { + for (int j = 0; j < sectorCount; ++ j) { // 2 triangles per sector excluding first and last stacks int k1_next = k1; int k2_next = k2; @@ -1039,64 +1121,42 @@ indexed_triangle_set its_make_frustum_dowel(double radius, double h, int sectorC return mesh; } -indexed_triangle_set its_make_pyramid(float base, float height) -{ - float a = base / 2.f; - return { - { - {0, 1, 2}, - {0, 2, 3}, - {0, 1, 4}, - {1, 2, 4}, - {2, 3, 4}, - {3, 0, 4} - }, - { - {-a, -a, 0}, {a, -a, 0}, {a, a, 0}, - {-a, a, 0}, {0.f, 0.f, height} - } - }; -} - -// Generates mesh for a sphere centered about the origin, using the generated angle -// to determine the granularity. -// Default angle is 1 degree. -//FIXME better to discretize an Icosahedron recursively http://www.songho.ca/opengl/gl_sphere.html -indexed_triangle_set its_make_sphere(double radius, double fa) +// Generates mesh for a frustum dowel centered about the origin, using the count of sectors +// Note: This function uses code for sphere generation, but for stackCount = 2; +indexed_triangle_set its_make_frustum_dowel(double radius, double h, int sectorCount) { - int sectorCount = int(ceil(2. * M_PI / fa)); - int stackCount = int(ceil(M_PI / fa)); - float sectorStep = float(2. * M_PI / sectorCount); - float stackStep = float(M_PI / stackCount); + int stackCount = 2; + float sectorStep = float(2. * M_PI / sectorCount); + float stackStep = float(M_PI / stackCount); indexed_triangle_set mesh; auto& vertices = mesh.vertices; vertices.reserve((stackCount - 1) * sectorCount + 2); - for (int i = 0; i <= stackCount; ++ i) { + for (int i = 0; i <= stackCount; ++i) { // from pi/2 to -pi/2 double stackAngle = 0.5 * M_PI - stackStep * i; double xy = radius * cos(stackAngle); - double z = radius * sin(stackAngle); + double z = radius * sin(stackAngle); if (i == 0 || i == stackCount) - vertices.emplace_back(Vec3f(float(xy), 0.f, float(z))); + vertices.emplace_back(Vec3f(float(xy), 0.f, float(h * sin(stackAngle)))); else - for (int j = 0; j < sectorCount; ++ j) { + for (int j = 0; j < sectorCount; ++j) { // from 0 to 2pi - double sectorAngle = sectorStep * j; + double sectorAngle = sectorStep * j + 0.25 * M_PI; vertices.emplace_back(Vec3d(xy * std::cos(sectorAngle), xy * std::sin(sectorAngle), z).cast()); } } auto& facets = mesh.indices; facets.reserve(2 * (stackCount - 1) * sectorCount); - for (int i = 0; i < stackCount; ++ i) { + for (int i = 0; i < stackCount; ++i) { // Beginning of current stack. int k1 = (i == 0) ? 0 : (1 + (i - 1) * sectorCount); int k1_first = k1; // Beginning of next stack. int k2 = (i == 0) ? 1 : (k1 + sectorCount); int k2_first = k2; - for (int j = 0; j < sectorCount; ++ j) { + for (int j = 0; j < sectorCount; ++j) { // 2 triangles per sector excluding first and last stacks int k1_next = k1; int k2_next = k2; @@ -1116,6 +1176,127 @@ indexed_triangle_set its_make_sphere(double radius, double fa) return mesh; } +indexed_triangle_set its_make_snap(double r, double h, float space_proportion, float bulge_proportion) +{ + const float radius = (float)r; + const float height = (float)h; + const size_t sectors_cnt = 10; //(float)fa; + const float halfPI = 0.5f * (float)PI; + + const float space_len = space_proportion * radius; + + const float b_len = radius; + const float m_len = (1 + bulge_proportion) * radius; + const float t_len = 0.5f * radius; + + const float b_height = 0.f; + const float m_height = 0.5f * height; + const float t_height = height; + + const float b_angle = acos(space_len/b_len); + const float t_angle = acos(space_len/t_len); + + const float b_angle_step = b_angle / (float)sectors_cnt; + const float t_angle_step = t_angle / (float)sectors_cnt; + + const Vec2f b_vec = Eigen::Vector2f(0, b_len); + const Vec2f t_vec = Eigen::Vector2f(0, t_len); + + + auto add_side_vertices = [b_vec, t_vec, b_height, m_height, t_height](std::vector& vertices, float b_angle, float t_angle, const Vec2f& m_vec) { + Vec2f b_pt = Eigen::Rotation2Df(b_angle) * b_vec; + Vec2f m_pt = Eigen::Rotation2Df(b_angle) * m_vec; + Vec2f t_pt = Eigen::Rotation2Df(t_angle) * t_vec; + + vertices.emplace_back(Vec3f(b_pt(0), b_pt(1), b_height)); + vertices.emplace_back(Vec3f(m_pt(0), m_pt(1), m_height)); + vertices.emplace_back(Vec3f(t_pt(0), t_pt(1), t_height)); + }; + + auto add_side_facets = [](std::vector& facets, int vertices_cnt, int frst_id, int scnd_id) { + int id = vertices_cnt - 1; + + facets.emplace_back(frst_id, id - 2, id - 5); + + facets.emplace_back(id - 2, id - 1, id - 5); + facets.emplace_back(id - 1, id - 4, id - 5); + facets.emplace_back(id - 4, id - 1, id); + facets.emplace_back(id, id - 3, id - 4); + + facets.emplace_back(id, scnd_id, id - 3); + }; + + const float f = (b_len - m_len) / m_len; // Flattening + + auto get_m_len = [b_len, f](float angle) { + const float rad_sqr = b_len * b_len; + const float sin_sqr = sin(angle) * sin(angle); + const float f_sqr = (1-f)*(1-f); + return sqrtf(rad_sqr / (1 + (1 / f_sqr - 1) * sin_sqr)); + }; + + auto add_sub_mesh = [add_side_vertices, add_side_facets, get_m_len, + b_height, t_height, b_angle, t_angle, b_angle_step, t_angle_step] + (indexed_triangle_set& mesh, float center_x, float angle_rotation, int frst_vertex_id) { + auto& vertices = mesh.vertices; + auto& facets = mesh.indices; + + // 2 special vertices, top and bottom center, rest are relative to this + vertices.emplace_back(Vec3f(center_x, 0.f, b_height)); + vertices.emplace_back(Vec3f(center_x, 0.f, t_height)); + + float b_angle_start = angle_rotation - b_angle; + float t_angle_start = angle_rotation - t_angle; + const float b_angle_stop = angle_rotation + b_angle; + + const int frst_id = frst_vertex_id; + const int scnd_id = frst_id + 1; + + // add first side vertices and internal facets + { + const Vec2f m_vec = Eigen::Vector2f(0, get_m_len(b_angle_start)); + add_side_vertices(vertices, b_angle_start, t_angle_start, m_vec); + + int id = (int)vertices.size() - 1; + + facets.emplace_back(frst_id, id - 2, id - 1); + facets.emplace_back(frst_id, id - 1, id); + facets.emplace_back(frst_id, id, scnd_id); + } + + // add d side vertices and facets + while (!is_approx(b_angle_start, b_angle_stop)) { + b_angle_start += b_angle_step; + t_angle_start += t_angle_step; + + const Vec2f m_vec = Eigen::Vector2f(0, get_m_len(b_angle_start)); + add_side_vertices(vertices, b_angle_start, t_angle_start, m_vec); + + add_side_facets(facets, (int)vertices.size(), frst_id, scnd_id); + } + + // add last internal facets to close the mesh + { + int id = (int)vertices.size() - 1; + + facets.emplace_back(frst_id, scnd_id, id); + facets.emplace_back(frst_id, id, id - 1); + facets.emplace_back(frst_id, id - 1, id - 2); + } + }; + + + indexed_triangle_set mesh; + + mesh.vertices.reserve(2 * (3 * (2 * sectors_cnt + 1) + 2)); + mesh.indices.reserve(2 * (6 * 2 * sectors_cnt + 6)); + + add_sub_mesh(mesh, -space_len, halfPI , 0); + add_sub_mesh(mesh, space_len, 3 * halfPI, (int)mesh.vertices.size()); + + return mesh; +} + indexed_triangle_set its_convex_hull(const std::vector &pts) { std::vector dst_vertices; diff --git a/src/libslic3r/TriangleMesh.hpp b/src/libslic3r/TriangleMesh.hpp index 9afaddd4ebd..12002cc5357 100644 --- a/src/libslic3r/TriangleMesh.hpp +++ b/src/libslic3r/TriangleMesh.hpp @@ -1,3 +1,14 @@ +///|/ Copyright (c) Prusa Research 2017 - 2023 Oleksandra Iushchenko @YuSanka, Lukáš Matěna @lukasmatena, Vojtěch Bubník @bubnikv, Tomáš Mészáros @tamasmeszaros, Enrico Turri @enricoturri1966, Filip Sykala @Jony01 +///|/ Copyright (c) 2019 Sijmen Schoon +///|/ Copyright (c) 2016 Joseph Lenox @lordofhyphens +///|/ Copyright (c) Slic3r 2013 - 2016 Alessandro Ranellucci @alranel +///|/ +///|/ ported from lib/Slic3r/TriangleMesh.pm: +///|/ Copyright (c) Slic3r 2011 - 2014 Alessandro Ranellucci @alranel +///|/ Copyright (c) 2012 - 2013 Mark Hindess +///|/ +///|/ PrusaSlicer is released under the terms of the AGPLv3 or higher +///|/ #ifndef slic3r_TriangleMesh_hpp_ #define slic3r_TriangleMesh_hpp_ @@ -337,9 +348,11 @@ indexed_triangle_set its_make_cube(double x, double y, double z); indexed_triangle_set its_make_prism(float width, float length, float height); indexed_triangle_set its_make_cylinder(double r, double h, double fa=(2*PI/360)); indexed_triangle_set its_make_cone(double r, double h, double fa=(2*PI/360)); +indexed_triangle_set its_make_frustum(double r, double h, double fa=(2*PI/360)); indexed_triangle_set its_make_frustum_dowel(double r, double h, int sectorCount); indexed_triangle_set its_make_pyramid(float base, float height); indexed_triangle_set its_make_sphere(double radius, double fa); +indexed_triangle_set its_make_snap(double r, double h, float space_proportion = 0.25f, float bulge_proportion = 0.125f); indexed_triangle_set its_convex_hull(const std::vector &pts); inline indexed_triangle_set its_convex_hull(const indexed_triangle_set &its) { return its_convex_hull(its.vertices); } diff --git a/src/libslic3r/TriangleMeshSlicer.cpp b/src/libslic3r/TriangleMeshSlicer.cpp index 3fd0da6604e..204b267c22f 100644 --- a/src/libslic3r/TriangleMeshSlicer.cpp +++ b/src/libslic3r/TriangleMeshSlicer.cpp @@ -1,3 +1,7 @@ +///|/ Copyright (c) Prusa Research 2021 - 2023 Vojtěch Bubník @bubnikv, Lukáš Matěna @lukasmatena, Pavel Mikuš @Godrak, Lukáš Hejl @hejllukas +///|/ +///|/ PrusaSlicer is released under the terms of the AGPLv3 or higher +///|/ #include "ClipperUtils.hpp" #include "Geometry.hpp" #include "Tesselate.hpp" @@ -2300,79 +2304,4 @@ void cut_mesh(const indexed_triangle_set& mesh, float z, indexed_triangle_set* u } } -// BBS: implement plane cut with cgal -static Vec3d calc_plane_normal(const std::array& plane_points) -{ - Vec3d v01 = plane_points[1] - plane_points[0]; - Vec3d v12 = plane_points[2] - plane_points[1]; - - Vec3d plane_normal = v01.cross(v12); - plane_normal.normalize(); - return plane_normal; -} - -void cut_mesh -( - const indexed_triangle_set& mesh, // model object coordinate - std::array plane_points, // model object coordinate - indexed_triangle_set* upper, - indexed_triangle_set* lower, - bool triangulate_caps -) -{ - assert(upper || lower); - if (upper == nullptr && lower == nullptr) - return; - - BOOST_LOG_TRIVIAL(trace) << "cut_mesh - slicing object"; - - Vec3d plane_normal = calc_plane_normal(plane_points); - if (std::abs(plane_normal(0)) < EPSILON && std::abs(plane_normal(1)) < EPSILON) { - cut_mesh(mesh, plane_points[0](2), upper, lower); - return; - } - - // BBS - if (std::abs(plane_normal(2)) < EPSILON) { - // keep the side on the normal direction - } - else if (plane_normal(2) < 0.0) { - std::reverse(plane_points.begin(), plane_points.end()); - } - plane_normal = calc_plane_normal(plane_points); - - Vec3d mid_point = { 0.0, 0.0, 0.0 }; - for (auto pt : plane_points) - mid_point += pt; - mid_point /= (double)plane_points.size(); - Vec3d movement = -mid_point; - - Vec3d axis = { 0.0, 0.0, 0.0 }; - double phi = 0.0; - Matrix3d matrix; - matrix.setIdentity(); - Geometry::rotation_from_two_vectors(plane_normal, { 0.0, 0.0, 1.0 }, axis, phi, &matrix); - Vec3d angles = Geometry::extract_euler_angles(matrix); - - movement = matrix * movement; - Transform3d transfo; - transfo.setIdentity(); - transfo.translate(movement); - transfo.rotate(Eigen::AngleAxisd(angles(2), Vec3d::UnitZ()) * Eigen::AngleAxisd(angles(1), Vec3d::UnitY()) * Eigen::AngleAxisd(angles(0), Vec3d::UnitX())); - - indexed_triangle_set mesh_temp = mesh; - its_transform(mesh_temp, transfo); - cut_mesh(mesh_temp, 0., upper, lower); - - Transform3d transfo_inv = transfo.inverse(); - if (upper) { - its_transform(*upper, transfo_inv); - } - - if (lower) { - its_transform(*lower, transfo_inv); - } -} - - } // namespace Slic3r diff --git a/src/libslic3r/TriangleMeshSlicer.hpp b/src/libslic3r/TriangleMeshSlicer.hpp index 1a8b6436294..a7ad62acd9a 100644 --- a/src/libslic3r/TriangleMeshSlicer.hpp +++ b/src/libslic3r/TriangleMeshSlicer.hpp @@ -1,3 +1,7 @@ +///|/ Copyright (c) Prusa Research 2021 - 2022 Vojtěch Bubník @bubnikv +///|/ +///|/ PrusaSlicer is released under the terms of the AGPLv3 or higher +///|/ #ifndef slic3r_TriangleMeshSlicer_hpp_ #define slic3r_TriangleMeshSlicer_hpp_ @@ -130,14 +134,6 @@ void cut_mesh( indexed_triangle_set *lower, bool triangulate_caps = true); -// BBS -void cut_mesh( - const indexed_triangle_set &mesh, - std::array plane_points, - indexed_triangle_set *upper, - indexed_triangle_set *lower, - bool triangulate_caps = true); - -} +} // namespace Slic3r #endif // slic3r_TriangleMeshSlicer_hpp_ diff --git a/src/libslic3r/Utils.hpp b/src/libslic3r/Utils.hpp index 08f10b28876..ce12a334863 100644 --- a/src/libslic3r/Utils.hpp +++ b/src/libslic3r/Utils.hpp @@ -160,6 +160,11 @@ void flush_logs(); // This type is only needed for Perl bindings to relay to Perl that the string is raw, not UTF-8 encoded. typedef std::string local_encoded_string; +// Returns next utf8 sequence length. =number of bytes in string, that creates together one utf-8 character. +// Starting at pos. ASCII characters returns 1. Works also if pos is in the middle of the sequence. +extern size_t get_utf8_sequence_length(const std::string& text, size_t pos = 0); +extern size_t get_utf8_sequence_length(const char *seq, size_t size); + // Convert an UTF-8 encoded string into local coding. // On Windows, the UTF-8 string is converted to a local 8-bit code page. // On OSX and Linux, this function does no conversion and returns a copy of the source string. diff --git a/src/libslic3r/utils.cpp b/src/libslic3r/utils.cpp index f5915175c71..e31656cda9a 100644 --- a/src/libslic3r/utils.cpp +++ b/src/libslic3r/utils.cpp @@ -1,3 +1,9 @@ +///|/ Copyright (c) Prusa Research 2016 - 2023 Pavel Mikuš @Godrak, Oleksandra Iushchenko @YuSanka, Vojtěch Bubník @bubnikv, Lukáš Matěna @lukasmatena, Filip Sykala @Jony01, David Kocík @kocikdav, Roman Beránek @zavorka, Enrico Turri @enricoturri1966, Tomáš Mészáros @tamasmeszaros, Vojtěch Král @vojtechkral +///|/ Copyright (c) 2021 Justin Schuh @jschuh +///|/ Copyright (c) Slic3r 2013 - 2015 Alessandro Ranellucci @alranel +///|/ +///|/ PrusaSlicer is released under the terms of the AGPLv3 or higher +///|/ #include "Utils.hpp" #include "I18N.hpp" @@ -1030,6 +1036,76 @@ bool is_shapes_dir(const std::string& dir) namespace Slic3r { +size_t get_utf8_sequence_length(const std::string& text, size_t pos) +{ + assert(pos < text.size()); + return get_utf8_sequence_length(text.c_str() + pos, text.size() - pos); +} + +size_t get_utf8_sequence_length(const char *seq, size_t size) +{ + size_t length = 0; + unsigned char c = seq[0]; + if (c < 0x80) { // 0x00-0x7F + // is ASCII letter + length++; + } + // Bytes 0x80 to 0xBD are trailer bytes in a multibyte sequence. + // pos is in the middle of a utf-8 sequence. Add the utf-8 trailer bytes. + else if (c < 0xC0) { // 0x80-0xBF + length++; + while (length < size) { + c = seq[length]; + if (c < 0x80 || c >= 0xC0) { + break; // prevent overrun + } + length++; // add a utf-8 trailer byte + } + } + // Bytes 0xC0 to 0xFD are header bytes in a multibyte sequence. + // The number of one bits above the topmost zero bit indicates the number of bytes (including this one) in the whole sequence. + else if (c < 0xE0) { // 0xC0-0xDF + // add a utf-8 sequence (2 bytes) + if (2 > size) { + return size; // prevent overrun + } + length += 2; + } + else if (c < 0xF0) { // 0xE0-0xEF + // add a utf-8 sequence (3 bytes) + if (3 > size) { + return size; // prevent overrun + } + length += 3; + } + else if (c < 0xF8) { // 0xF0-0xF7 + // add a utf-8 sequence (4 bytes) + if (4 > size) { + return size; // prevent overrun + } + length += 4; + } + else if (c < 0xFC) { // 0xF8-0xFB + // add a utf-8 sequence (5 bytes) + if (5 > size) { + return size; // prevent overrun + } + length += 5; + } + else if (c < 0xFE) { // 0xFC-0xFD + // add a utf-8 sequence (6 bytes) + if (6 > size) { + return size; // prevent overrun + } + length += 6; + } + else { // 0xFE-0xFF + // not a utf-8 sequence + length++; + } + return length; +} + // Encode an UTF-8 string to the local code page. std::string encode_path(const char *src) { diff --git a/src/slic3r/CMakeLists.txt b/src/slic3r/CMakeLists.txt index e1404b09a5f..173b0ce0127 100644 --- a/src/slic3r/CMakeLists.txt +++ b/src/slic3r/CMakeLists.txt @@ -132,8 +132,8 @@ set(SLIC3R_GUI_SOURCES GUI/Gizmos/GLGizmoFdmSupports.hpp GUI/Gizmos/GLGizmoFlatten.cpp GUI/Gizmos/GLGizmoFlatten.hpp - GUI/Gizmos/GLGizmoAdvancedCut.cpp - GUI/Gizmos/GLGizmoAdvancedCut.hpp + GUI/Gizmos/GLGizmoCut.cpp + GUI/Gizmos/GLGizmoCut.hpp #GUI/Gizmos/GLGizmoHollow.cpp #GUI/Gizmos/GLGizmoHollow.hpp GUI/Gizmos/GLGizmoPainterBase.cpp diff --git a/src/slic3r/GUI/3DScene.hpp b/src/slic3r/GUI/3DScene.hpp index 0d52ba48821..ce10a463f2f 100644 --- a/src/slic3r/GUI/3DScene.hpp +++ b/src/slic3r/GUI/3DScene.hpp @@ -411,6 +411,12 @@ class GLVolumeCollection // plane coeffs for clipping in shaders std::array m_clipping_plane; + // plane coeffs for render volumes with different colors in shaders + // used by cut gizmo + std::array m_color_clip_plane; + bool m_use_color_clip_plane{ false }; + std::array m_color_clip_plane_colors{ ColorRGBA::RED(), ColorRGBA::BLUE() }; + struct Slope { // toggle for slope rendering @@ -482,6 +488,14 @@ class GLVolumeCollection const std::array& get_z_range() const { return m_z_range; } const std::array& get_clipping_plane() const { return m_clipping_plane; } + void set_use_color_clip_plane(bool use) { m_use_color_clip_plane = use; } + void set_color_clip_plane(const Vec3d& cp_normal, double offset) { + for (int i = 0; i < 3; ++i) + m_color_clip_plane[i] = -cp_normal[i]; + m_color_clip_plane[3] = offset; + } + void set_color_clip_plane_colors(const std::array& colors) { m_color_clip_plane_colors = colors; } + bool is_slope_GlobalActive() const { return m_slope.isGlobalActive; } bool is_slope_active() const { return m_slope.active; } void set_slope_active(bool active) { m_slope.active = active; } diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp index afcd5bdcb8b..523b0d5f6e1 100644 --- a/src/slic3r/GUI/GLCanvas3D.hpp +++ b/src/slic3r/GUI/GLCanvas3D.hpp @@ -807,6 +807,10 @@ class GLCanvas3D bool get_use_clipping_planes() const { return m_use_clipping_planes; } const std::array &get_clipping_planes() const { return m_clipping_planes; }; + void set_use_color_clip_plane(bool use) { m_volumes.set_use_color_clip_plane(use); } + void set_color_clip_plane(const Vec3d& cp_normal, double offset) { m_volumes.set_color_clip_plane(cp_normal, offset); } + void set_color_clip_plane_colors(const std::array& colors) { m_volumes.set_color_clip_plane_colors(colors); } + void refresh_camera_scene_box(); BoundingBoxf3 volumes_bounding_box(bool current_plate_only = false) const; diff --git a/src/slic3r/GUI/GLSelectionRectangle.cpp b/src/slic3r/GUI/GLSelectionRectangle.cpp index ecced3c5644..68f9d096eb2 100644 --- a/src/slic3r/GUI/GLSelectionRectangle.cpp +++ b/src/slic3r/GUI/GLSelectionRectangle.cpp @@ -1,5 +1,10 @@ +///|/ Copyright (c) Prusa Research 2019 - 2022 Enrico Turri @enricoturri1966, Filip Sykala @Jony01, Lukáš Matěna @lukasmatena, Vojtěch Bubník @bubnikv +///|/ +///|/ PrusaSlicer is released under the terms of the AGPLv3 or higher +///|/ #include "GLSelectionRectangle.hpp" #include "Camera.hpp" +#include "CameraUtils.hpp" #include "3DScene.hpp" #include "GLCanvas3D.hpp" #include "GUI_App.hpp" @@ -29,35 +34,19 @@ namespace GUI { m_end_corner = mouse_position; } - std::vector GLSelectionRectangle::stop_dragging(const GLCanvas3D& canvas, const std::vector& points) + std::vector GLSelectionRectangle::contains(const std::vector& points) const { std::vector out; - if (!is_dragging()) - return out; - - m_state = Off; - - const Camera& camera = wxGetApp().plater()->get_camera(); - Matrix4d modelview = camera.get_view_matrix().matrix(); - Matrix4d projection= camera.get_projection_matrix().matrix(); - Vec4i viewport(camera.get_viewport().data()); - - // Convert our std::vector to Eigen dynamic matrix. - Eigen::Matrix pts(points.size(), 3); - for (size_t i=0; i(i, 0) = points[i]; - - // Get the projections. - Eigen::Matrix projections; - igl::project(pts, modelview, projection, viewport, projections); - // bounding box created from the rectangle corners - will take care of order of the corners - BoundingBox rectangle(Points{ Point(m_start_corner.cast()), Point(m_end_corner.cast()) }); + const BoundingBox rectangle(Points{ Point(m_start_corner.cast()), Point(m_end_corner.cast()) }); // Iterate over all points and determine whether they're in the rectangle. - for (int i = 0; iget_camera(); + Points points_2d = CameraUtils::project(camera, points); + unsigned int size = static_cast(points.size()); + for (unsigned int i = 0; i< size; ++i) + if (rectangle.contains(points_2d[i])) out.push_back(i); return out; diff --git a/src/slic3r/GUI/GLSelectionRectangle.hpp b/src/slic3r/GUI/GLSelectionRectangle.hpp index 5ec56a60a0e..8d87e18e46c 100644 --- a/src/slic3r/GUI/GLSelectionRectangle.hpp +++ b/src/slic3r/GUI/GLSelectionRectangle.hpp @@ -1,3 +1,7 @@ +///|/ Copyright (c) Prusa Research 2019 - 2022 Enrico Turri @enricoturri1966, Lukáš Matěna @lukasmatena +///|/ +///|/ PrusaSlicer is released under the terms of the AGPLv3 or higher +///|/ #ifndef slic3r_GLSelectionRectangle_hpp_ #define slic3r_GLSelectionRectangle_hpp_ @@ -25,8 +29,8 @@ class GLSelectionRectangle { void dragging(const Vec2d& mouse_position); // Given a vector of points in world coordinates, the function returns indices of those - // that are in the rectangle. It then disables the rectangle. - std::vector stop_dragging(const GLCanvas3D& canvas, const std::vector& points); + // that are in the rectangle. + std::vector contains(const std::vector& points) const; // Disables the rectangle. void stop_dragging(); diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp index ad885ebb4ee..4d632d17eb0 100644 --- a/src/slic3r/GUI/GUI_ObjectList.cpp +++ b/src/slic3r/GUI/GUI_ObjectList.cpp @@ -2811,7 +2811,7 @@ void ObjectList::merge(bool to_multipart_object) } } -void ObjectList::merge_volumes() +/*void ObjectList::merge_volumes() { std::vector obj_idxs, vol_idxs; get_selection_indexes(obj_idxs, vol_idxs); @@ -2839,11 +2839,11 @@ void ObjectList::merge_volumes() else { for (int vol_idx : vol_idxs) selection.add_volume(last_obj_idx, vol_idx, 0, false); - }*/ + }#1# #else wxGetApp().plater()->merge(obj_idxs[0], vol_idxs); #endif -} +}*/ void ObjectList::layers_editing() { diff --git a/src/slic3r/GUI/GUI_ObjectList.hpp b/src/slic3r/GUI/GUI_ObjectList.hpp index f4a6f0320a5..8bd1e8fbdf7 100644 --- a/src/slic3r/GUI/GUI_ObjectList.hpp +++ b/src/slic3r/GUI/GUI_ObjectList.hpp @@ -297,7 +297,7 @@ class ObjectList : public wxDataViewCtrl void del_info_item(const int obj_idx, InfoItemType type); void split(); void merge(bool to_multipart_object); - void merge_volumes(); // BBS: merge parts to single part + // void merge_volumes(); // BBS: merge parts to single part void layers_editing(); void boolean(); // BBS: Boolean Operation of parts diff --git a/src/slic3r/GUI/Gizmos/GLGizmoBase.hpp b/src/slic3r/GUI/Gizmos/GLGizmoBase.hpp index bcd4f2096f0..d60e5048560 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoBase.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoBase.hpp @@ -222,6 +222,9 @@ class GLGizmoBase void register_raycasters_for_picking() { register_grabbers_for_picking(); on_register_raycasters_for_picking(); } void unregister_raycasters_for_picking() { unregister_grabbers_for_picking(); on_unregister_raycasters_for_picking(); } + virtual bool is_in_editing_mode() const { return false; } + virtual bool is_selection_rectangle_dragging() const { return false; } + protected: float last_input_window_width = 0; virtual bool on_init() = 0; diff --git a/src/slic3r/GUI/Gizmos/GLGizmoCut.cpp b/src/slic3r/GUI/Gizmos/GLGizmoCut.cpp index 0e5d1c73087..7f6e9fc1a81 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoCut.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoCut.cpp @@ -1,344 +1,3776 @@ -// Include GLGizmoBase.hpp before I18N.hpp as it includes some libigl code, which overrides our localization "L" macro. +///|/ Copyright (c) Prusa Research 2019 - 2023 Oleksandra Iushchenko @YuSanka, Vojtěch Bubník @bubnikv, Lukáš Matěna @lukasmatena, Enrico Turri @enricoturri1966, Filip Sykala @Jony01, Vojtěch Král @vojtechkral +///|/ +///|/ PrusaSlicer is released under the terms of the AGPLv3 or higher +///|/ #include "GLGizmoCut.hpp" #include "slic3r/GUI/GLCanvas3D.hpp" #include -#include -#include -#include -#include - #include #include "slic3r/GUI/GUI_App.hpp" #include "slic3r/GUI/Plater.hpp" -#include "slic3r/GUI/GUI_ObjectManipulation.hpp" +#include "slic3r/GUI/Gizmos/GizmoObjectManipulation.hpp" +#include "slic3r/GUI/format.hpp" +#include "slic3r/Utils/UndoRedo.hpp" #include "libslic3r/AppConfig.hpp" -#include "libslic3r/Model.hpp" #include "libslic3r/TriangleMeshSlicer.hpp" +#include "imgui/imgui_internal.h" +#include "slic3r/GUI/Field.hpp" +#include "slic3r/GUI/MsgDialog.hpp" + namespace Slic3r { namespace GUI { -const double GLGizmoCut::Offset = 10.0; -const double GLGizmoCut::Margin = 20.0; -static const ColorRGBA GRABBER_COLOR = ColorRGBA::ORANGE(); -static const ColorRGBA PLANE_COLOR = { 0.8f, 0.8f, 0.8f, 0.5f }; +static const ColorRGBA GRABBER_COLOR = ColorRGBA::YELLOW(); +static const ColorRGBA UPPER_PART_COLOR = ColorRGBA::CYAN(); +static const ColorRGBA LOWER_PART_COLOR = ColorRGBA::MAGENTA(); +static const ColorRGBA MODIFIER_COLOR = ColorRGBA(0.75f, 0.75f, 0.75f, 0.5f); + +// connector colors +static const ColorRGBA PLAG_COLOR = ColorRGBA::YELLOW(); +static const ColorRGBA DOWEL_COLOR = ColorRGBA::DARK_YELLOW(); +static const ColorRGBA HOVERED_PLAG_COLOR = ColorRGBA::CYAN(); +static const ColorRGBA HOVERED_DOWEL_COLOR = ColorRGBA(0.0f, 0.5f, 0.5f, 1.0f); +static const ColorRGBA SELECTED_PLAG_COLOR = ColorRGBA::GRAY(); +static const ColorRGBA SELECTED_DOWEL_COLOR = ColorRGBA::DARK_GRAY(); +static const ColorRGBA CONNECTOR_DEF_COLOR = ColorRGBA(1.0f, 1.0f, 1.0f, 0.5f); +static const ColorRGBA CONNECTOR_ERR_COLOR = ColorRGBA(1.0f, 0.3f, 0.3f, 0.5f); +static const ColorRGBA HOVERED_ERR_COLOR = ColorRGBA(1.0f, 0.3f, 0.3f, 1.0f); + +static const ColorRGBA CUT_PLANE_DEF_COLOR = ColorRGBA(0.9f, 0.9f, 0.9f, 0.5f); +static const ColorRGBA CUT_PLANE_ERR_COLOR = ColorRGBA(1.0f, 0.8f, 0.8f, 0.5f); + +const unsigned int AngleResolution = 64; +const unsigned int ScaleStepsCount = 72; +const float ScaleStepRad = 2.0f * float(PI) / ScaleStepsCount; +const unsigned int ScaleLongEvery = 2; +const float ScaleLongTooth = 0.1f; // in percent of radius +const unsigned int SnapRegionsCount = 8; + +const float UndefFloat = -999.f; +const std::string UndefLabel = " "; + +using namespace Geometry; + +// Generates mesh for a line +static GLModel::Geometry its_make_line(Vec3f beg_pos, Vec3f end_pos) +{ + GLModel::Geometry init_data; + init_data.format = { GLModel::Geometry::EPrimitiveType::Lines, GLModel::Geometry::EVertexLayout::P3 }; + init_data.reserve_vertices(2); + init_data.reserve_indices(2); + + // vertices + init_data.add_vertex(beg_pos); + init_data.add_vertex(end_pos); + + // indices + init_data.add_line(0, 1); + return init_data; +} + +//! -- #ysFIXME those functions bodies are ported from GizmoRotation +// Generates mesh for a circle +static void init_from_circle(GLModel& model, double radius) +{ + GLModel::Geometry init_data; + init_data.format = { GLModel::Geometry::EPrimitiveType::LineLoop, GLModel::Geometry::EVertexLayout::P3 }; + init_data.reserve_vertices(ScaleStepsCount); + init_data.reserve_indices(ScaleStepsCount); + + // vertices + indices + for (unsigned int i = 0; i < ScaleStepsCount; ++i) { + const float angle = float(i * ScaleStepRad); + init_data.add_vertex(Vec3f(::cos(angle) * float(radius), ::sin(angle) * float(radius), 0.0f)); + init_data.add_index(i); + } -GLGizmoCut::GLGizmoCut(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id) - : GLGizmoBase(parent, icon_filename, sprite_id) -{} + model.init_from(std::move(init_data)); + model.set_color(ColorRGBA::WHITE()); +} -std::string GLGizmoCut::get_tooltip() const +// Generates mesh for a scale +static void init_from_scale(GLModel& model, double radius) { - double cut_z = m_cut_z; - if (wxGetApp().app_config->get("use_inches") == "1") - cut_z *= ObjectManipulation::mm_to_in; + const float out_radius_long = float(radius) * (1.0f + ScaleLongTooth); + const float out_radius_short = float(radius) * (1.0f + 0.5f * ScaleLongTooth); + + GLModel::Geometry init_data; + init_data.format = { GLModel::Geometry::EPrimitiveType::Lines, GLModel::Geometry::EVertexLayout::P3 }; + init_data.reserve_vertices(2 * ScaleStepsCount); + init_data.reserve_indices(2 * ScaleStepsCount); + + // vertices + indices + for (unsigned int i = 0; i < ScaleStepsCount; ++i) { + const float angle = float(i * ScaleStepRad); + const float cosa = ::cos(angle); + const float sina = ::sin(angle); + const float in_x = cosa * float(radius); + const float in_y = sina * float(radius); + const float out_x = (i % ScaleLongEvery == 0) ? cosa * out_radius_long : cosa * out_radius_short; + const float out_y = (i % ScaleLongEvery == 0) ? sina * out_radius_long : sina * out_radius_short; + + // vertices + init_data.add_vertex(Vec3f(in_x, in_y, 0.0f)); + init_data.add_vertex(Vec3f(out_x, out_y, 0.0f)); + + // indices + init_data.add_line(i * 2, i * 2 + 1); + } - return (m_hover_id == 0 || m_grabbers[0].dragging) ? "Z: " + format(cut_z, 2) : ""; + model.init_from(std::move(init_data)); + model.set_color(ColorRGBA::WHITE()); } -bool GLGizmoCut::on_init() +// Generates mesh for a snap_radii +static void init_from_snap_radii(GLModel& model, double radius) { - m_grabbers.emplace_back(); - m_shortcut_key = WXK_CONTROL_C; - return true; + const float step = 2.0f * float(PI) / float(SnapRegionsCount); + const float in_radius = float(radius) / 3.0f; + const float out_radius = 2.0f * in_radius; + + GLModel::Geometry init_data; + init_data.format = { GLModel::Geometry::EPrimitiveType::Lines, GLModel::Geometry::EVertexLayout::P3 }; + init_data.reserve_vertices(2 * ScaleStepsCount); + init_data.reserve_indices(2 * ScaleStepsCount); + + // vertices + indices + for (unsigned int i = 0; i < ScaleStepsCount; ++i) { + const float angle = float(i) * step; + const float cosa = ::cos(angle); + const float sina = ::sin(angle); + const float in_x = cosa * in_radius; + const float in_y = sina * in_radius; + const float out_x = cosa * out_radius; + const float out_y = sina * out_radius; + + // vertices + init_data.add_vertex(Vec3f(in_x, in_y, 0.0f)); + init_data.add_vertex(Vec3f(out_x, out_y, 0.0f)); + + // indices + init_data.add_line(i * 2, i * 2 + 1); + } + + model.init_from(std::move(init_data)); + model.set_color(ColorRGBA::WHITE()); } -std::string GLGizmoCut::on_get_name() const +// Generates mesh for a angle_arc +static void init_from_angle_arc(GLModel& model, double angle, double radius) { - return _u8L("Cut"); + model.reset(); + + const float step_angle = float(angle) / float(AngleResolution); + const float ex_radius = float(radius); + + GLModel::Geometry init_data; + init_data.format = { GLModel::Geometry::EPrimitiveType::LineStrip, GLModel::Geometry::EVertexLayout::P3 }; + init_data.reserve_vertices(1 + AngleResolution); + init_data.reserve_indices(1 + AngleResolution); + + // vertices + indices + for (unsigned int i = 0; i <= AngleResolution; ++i) { + const float angle = float(i) * step_angle; + init_data.add_vertex(Vec3f(::cos(angle) * ex_radius, ::sin(angle) * ex_radius, 0.0f)); + init_data.add_index(i); + } + + model.init_from(std::move(init_data)); } -void GLGizmoCut::on_set_state() +//! -- + +GLGizmoCut3D::GLGizmoCut3D(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id) + : GLGizmoBase(parent, icon_filename, sprite_id) + , m_connectors_group_id (GrabberID::Count) + , m_connector_type (CutConnectorType::Plug) + , m_connector_style (int(CutConnectorStyle::Prism)) + , m_connector_shape_id (int(CutConnectorShape::Circle)) { - // Reset m_cut_z on gizmo activation - if (get_state() == On) - m_cut_z = bounding_box().center().z(); + m_modes = { _u8L("Planar"), _u8L("Dovetail")//, _u8L("Grid") +// , _u8L("Radial"), _u8L("Modular") + }; + + m_connector_modes = { _u8L("Auto"), _u8L("Manual") }; + + std::map connetor_types = { + {ImGui::PlugMarker , _u8L("Plug") }, + {ImGui::DowelMarker, _u8L("Dowel") }, + //TRN Connectors type next to "Plug" and "Dowel" + {ImGui::SnapMarker, _u8L("Snap") }, + }; + for (auto connector : connetor_types) { + std::string type_label = " " + connector.second + " "; + type_label += connector.first; + m_connector_types.push_back(type_label); + } + + m_connector_styles = { _u8L("Prism"), _u8L("Frustum") +// , _u8L("Claw") + }; + + m_connector_shapes = { _u8L("Triangle"), _u8L("Square"), _u8L("Hexagon"), _u8L("Circle") +// , _u8L("D-shape") + }; + + m_axis_names = { "X", "Y", "Z" }; + + m_part_orientation_names = { + {"none", _L("Keep orientation")}, + {"on_cut", _L("Place on cut")}, + {"flip", _L("Flip upside down")}, + }; + + m_labels_map = { + {"Connectors" , _u8L("Connectors")}, + {"Type" , _u8L("Type")}, + {"Style" , _u8L("Style")}, + {"Shape" , _u8L("Shape")}, + {"Depth" , _u8L("Depth")}, + {"Size" , _u8L("Size")}, + {"Rotation" , _u8L("Rotation")}, + {"Groove" , _u8L("Groove")}, + {"Width" , _u8L("Width")}, + {"Flap Angle" , _u8L("Flap Angle")}, + {"Groove Angle" , _u8L("Groove Angle")}, + }; + +// update_connector_shape(); } -bool GLGizmoCut::on_is_activable() const +std::string GLGizmoCut3D::get_tooltip() const { - const Selection& selection = m_parent.get_selection(); - return selection.is_single_full_instance() && !selection.is_wipe_tower(); + std::string tooltip; + if (m_hover_id == Z || (m_dragging && m_hover_id == CutPlane)) { + double koef = m_imperial_units ? GizmoObjectManipulation::mm_to_in : 1.0; + std::string unit_str = " " + (m_imperial_units ? _u8L("in") : _u8L("mm")); + const BoundingBoxf3& tbb = m_transformed_bounding_box; + + const std::string name = m_keep_as_parts ? _u8L("Part") : _u8L("Object"); + if (tbb.max.z() >= 0.0) { + double top = (tbb.min.z() <= 0.0 ? tbb.max.z() : tbb.size().z()) * koef; + tooltip += format(static_cast(top), 2) + " " + unit_str + " (" + name + " A)"; + if (tbb.min.z() <= 0.0) + tooltip += "\n"; + } + if (tbb.min.z() <= 0.0) { + double bottom = (tbb.max.z() <= 0.0 ? tbb.size().z() : (tbb.min.z() * (-1))) * koef; + tooltip += format(static_cast(bottom), 2) + " " + unit_str + " (" + name + " B)"; + } + return tooltip; + } + + if (!m_dragging && m_hover_id == CutPlane) { + if (CutMode(m_mode) == CutMode::cutTongueAndGroove) + return _u8L("Click to flip the cut plane\n" + "Drag to move the cut plane"); + return _u8L("Click to flip the cut plane\n" + "Drag to move the cut plane\n" + "Right-click a part to assign it to the other side"); + } + + if (tooltip.empty() && (m_hover_id == X || m_hover_id == Y || m_hover_id == CutPlaneZRotation)) { + std::string axis = m_hover_id == X ? "X" : m_hover_id == Y ? "Y" : "Z"; + return axis + ": " + format(float(rad2deg(m_angle)), 1) + _u8L("°"); + } + + return tooltip; } -void GLGizmoCut::on_start_dragging() +bool GLGizmoCut3D::on_mouse(const wxMouseEvent &mouse_event) { - if (m_hover_id == -1) - return; + Vec2i mouse_coord(mouse_event.GetX(), mouse_event.GetY()); + Vec2d mouse_pos = mouse_coord.cast(); + + if (mouse_event.ShiftDown() && mouse_event.LeftDown()) + return gizmo_event(SLAGizmoEventType::LeftDown, mouse_pos, mouse_event.ShiftDown(), mouse_event.AltDown(), mouse_event.CmdDown()); + if (mouse_event.CmdDown() && mouse_event.LeftDown()) + return false; + if (cut_line_processing()) { + if (mouse_event.ShiftDown()) { + if (mouse_event.Moving()|| mouse_event.Dragging()) + return gizmo_event(SLAGizmoEventType::Moving, mouse_pos, mouse_event.ShiftDown(), mouse_event.AltDown(), mouse_event.CmdDown()); + if (mouse_event.LeftUp()) + return gizmo_event(SLAGizmoEventType::LeftUp, mouse_pos, mouse_event.ShiftDown(), mouse_event.AltDown(), mouse_event.CmdDown()); + } + discard_cut_line_processing(); + } + else if (mouse_event.Moving()) + return false; + + if (m_hover_id >= CutPlane && mouse_event.LeftDown() && !m_connectors_editing) { + // before processing of a use_grabbers(), detect start move position as a projection of mouse position to the cut plane + Vec3d pos; + Vec3d pos_world; + if (unproject_on_cut_plane(mouse_pos, pos, pos_world, false)) + m_cut_plane_start_move_pos = pos_world; + } - const BoundingBoxf3 box = bounding_box(); - m_max_z = box.max.z(); - m_start_z = m_cut_z; - m_drag_pos = m_grabbers[m_hover_id].center; - m_drag_center = box.center(); - m_drag_center.z() = m_cut_z; + if (use_grabbers(mouse_event)) { + if (m_hover_id >= m_connectors_group_id) { + if (mouse_event.LeftDown() && !mouse_event.CmdDown() && !mouse_event.AltDown()) + unselect_all_connectors(); + if (mouse_event.LeftUp() && !mouse_event.ShiftDown()) + gizmo_event(SLAGizmoEventType::LeftUp, mouse_pos, mouse_event.ShiftDown(), mouse_event.AltDown(), mouse_event.CmdDown()); + } + else if (m_hover_id == CutPlane) { + if (mouse_event.LeftDown()) { + m_was_cut_plane_dragged = m_was_contour_selected = false; + + // disable / enable current contour + Vec3d pos; + Vec3d pos_world; + m_was_contour_selected = unproject_on_cut_plane(mouse_pos.cast(), pos, pos_world); + if (m_was_contour_selected) { + // Following would inform the clipper about the mouse click, so it can + // toggle the respective contour as disabled. + //m_c->object_clipper()->pass_mouse_click(pos_world); + //process_contours(); + return true; + } + + } + else if (mouse_event.LeftUp() && !m_was_cut_plane_dragged && !m_was_contour_selected) + flip_cut_plane(); + } + + if (m_hover_id >= CutPlane && mouse_event.Dragging() && !m_connectors_editing) { + // if we continue to dragging a cut plane, than update a start move position as a projection of mouse position to the cut plane after processing of a use_grabbers() + Vec3d pos; + Vec3d pos_world; + if (unproject_on_cut_plane(mouse_pos, pos, pos_world, false)) + m_cut_plane_start_move_pos = pos_world; + } + + toggle_model_objects_visibility(); + return true; + } + + static bool pending_right_up = false; + if (mouse_event.LeftDown()) { + bool grabber_contains_mouse = (get_hover_id() != -1); + const bool shift_down = mouse_event.ShiftDown(); + if ((!shift_down || grabber_contains_mouse) && + gizmo_event(SLAGizmoEventType::LeftDown, mouse_pos, mouse_event.ShiftDown(), mouse_event.AltDown(), false)) + return true; + } + else if (mouse_event.Dragging()) { + bool control_down = mouse_event.CmdDown(); + if (m_parent.get_move_volume_id() != -1) { + // don't allow dragging objects with the Sla gizmo on + return true; + } + if (!control_down && + gizmo_event(SLAGizmoEventType::Dragging, mouse_pos, mouse_event.ShiftDown(), mouse_event.AltDown(), false)) { + // the gizmo got the event and took some action, no need to do + // anything more here + m_parent.set_as_dirty(); + return true; + } + if (control_down && (mouse_event.LeftIsDown() || mouse_event.RightIsDown())) { + // CTRL has been pressed while already dragging -> stop current action + if (mouse_event.LeftIsDown()) + gizmo_event(SLAGizmoEventType::LeftUp, mouse_pos, mouse_event.ShiftDown(), mouse_event.AltDown(), true); + else if (mouse_event.RightIsDown()) + pending_right_up = false; + } + } + else if (mouse_event.LeftUp() && !m_parent.is_mouse_dragging()) { + // in case SLA/FDM gizmo is selected, we just pass the LeftUp event + // and stop processing - neither object moving or selecting is + // suppressed in that case + gizmo_event(SLAGizmoEventType::LeftUp, mouse_pos, mouse_event.ShiftDown(), mouse_event.AltDown(), mouse_event.CmdDown()); + return true; + } + else if (mouse_event.RightDown()) { + if (! m_connectors_editing && mouse_event.GetModifiers() == wxMOD_NONE && + CutMode(m_mode) == CutMode::cutPlanar) { + // Check the internal part raycasters. + if (! m_part_selection.valid()) + process_contours(); + m_part_selection.toggle_selection(mouse_pos); + check_and_update_connectors_state(); // after a contour is deactivated, its connectors are inside the object + return true; + } + + if (m_parent.get_selection().get_object_idx() != -1 && + gizmo_event(SLAGizmoEventType::RightDown, mouse_pos, false, false, false)) { + // we need to set the following right up as processed to avoid showing + // the context menu if the user release the mouse over the object + pending_right_up = true; + // event was taken care of by the SlaSupports gizmo + return true; + } + } + else if (pending_right_up && mouse_event.RightUp()) { + pending_right_up = false; + return true; + } + return false; } -void GLGizmoCut::on_update(const UpdateData& data) +void GLGizmoCut3D::shift_cut(double delta) { - if (m_hover_id != -1) - set_cut_z(m_start_z + calc_projection(data.mouse_ray)); + Plater::TakeSnapshot snapshot(wxGetApp().plater(), _u8L("Move cut plane"), UndoRedo::SnapshotType::GizmoAction); + set_center(m_plane_center + m_cut_normal * delta, true); + m_ar_plane_center = m_plane_center; } -void GLGizmoCut::on_render() +void GLGizmoCut3D::rotate_vec3d_around_plane_center(Vec3d&vec) { - const BoundingBoxf3 box = bounding_box(); - Vec3d plane_center = box.center(); - plane_center.z() = m_cut_z; - m_max_z = box.max.z(); - set_cut_z(m_cut_z); + vec = Transformation(translation_transform(m_plane_center) * m_rotation_m * translation_transform(-m_plane_center)).get_matrix() * vec; +} + +void GLGizmoCut3D::put_connectors_on_cut_plane(const Vec3d& cp_normal, double cp_offset) +{ + ModelObject* mo = m_c->selection_info()->model_object(); + if (CutConnectors& connectors = mo->cut_connectors; !connectors.empty()) { + const float sla_shift = m_c->selection_info()->get_sla_shift(); + const Vec3d& instance_offset = mo->instances[m_c->selection_info()->get_active_instance()]->get_offset(); + + for (auto& connector : connectors) { + // convert connetor pos to the world coordinates + Vec3d pos = connector.pos + instance_offset; + pos[Z] += sla_shift; + // scalar distance from point to plane along the normal + double distance = -cp_normal.dot(pos) + cp_offset; + // move connector + connector.pos += distance * cp_normal; + } + } +} - update_contours(); +// returns true if the camera (forward) is pointing in the negative direction of the cut normal +bool GLGizmoCut3D::is_looking_forward() const +{ + const Camera& camera = wxGetApp().plater()->get_camera(); + const double dot = camera.get_dir_forward().dot(m_cut_normal); + return dot < 0.05; +} - const float min_x = box.min.x() - Margin; - const float max_x = box.max.x() + Margin; - const float min_y = box.min.y() - Margin; - const float max_y = box.max.y() + Margin; - glsafe(::glEnable(GL_DEPTH_TEST)); - glsafe(::glDisable(GL_CULL_FACE)); - glsafe(::glEnable(GL_BLEND)); - glsafe(::glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)); +void GLGizmoCut3D::update_clipper() +{ + // update cut_normal + Vec3d normal = m_rotation_m * Vec3d::UnitZ(); + normal.normalize(); + m_cut_normal = normal; + + // calculate normal and offset for clipping plane + Vec3d beg = m_bb_center; + beg[Z] -= m_radius; + rotate_vec3d_around_plane_center(beg); + + m_clp_normal = normal; + double offset = normal.dot(m_plane_center); + double dist = normal.dot(beg); + + m_parent.set_color_clip_plane(normal, offset); + + if (!is_looking_forward()) { + // recalculate normal and offset for clipping plane, if camera is looking downward to cut plane + normal = m_rotation_m * (-1. * Vec3d::UnitZ()); + normal.normalize(); + + beg = m_bb_center; + beg[Z] += m_radius; + rotate_vec3d_around_plane_center(beg); + + m_clp_normal = normal; + offset = normal.dot(m_plane_center); + dist = normal.dot(beg); + } - // Draw the cutting plane - ::glBegin(GL_QUADS); - ::glColor4fv(PLANE_COLOR.data()); - ::glVertex3f(min_x, min_y, plane_center.z()); - ::glVertex3f(max_x, min_y, plane_center.z()); - ::glVertex3f(max_x, max_y, plane_center.z()); - ::glVertex3f(min_x, max_y, plane_center.z()); - glsafe(::glEnd()); + m_c->object_clipper()->set_range_and_pos(normal, offset, dist); - glsafe(::glEnable(GL_CULL_FACE)); - glsafe(::glDisable(GL_BLEND)); + put_connectors_on_cut_plane(normal, offset); + + if (m_raycasters.empty()) + on_register_raycasters_for_picking(); + else + update_raycasters_for_picking_transform(); +} + +void GLGizmoCut3D::set_center(const Vec3d& center, bool update_tbb /*=false*/) +{ + set_center_pos(center, update_tbb); + check_and_update_connectors_state(); + update_clipper(); +} - // TODO: draw cut part contour? +void GLGizmoCut3D::switch_to_mode(size_t new_mode) +{ + m_mode = new_mode; + update_raycasters_for_picking(); - // Draw the grabber and the connecting line - m_grabbers[0].center = plane_center; - m_grabbers[0].center.z() = plane_center.z() + Offset; + apply_color_clip_plane_colors(); + if (auto oc = m_c->object_clipper()) { + m_contour_width = CutMode(m_mode) == CutMode::cutTongueAndGroove ? 0.f : 0.4f; + oc->set_behavior(m_connectors_editing, m_connectors_editing, double(m_contour_width)); + } - glsafe(::glClear(GL_DEPTH_BUFFER_BIT)); + update_plane_model(); + reset_cut_by_contours(); +} - glsafe(::glLineWidth(m_hover_id != -1 ? 2.0f : 1.5f)); - glsafe(::glColor3f(1.0, 1.0, 0.0)); - ::glBegin(GL_LINES); - ::glVertex3dv(plane_center.data()); - ::glVertex3dv(m_grabbers[0].center.data()); - glsafe(::glEnd()); +bool GLGizmoCut3D::render_cut_mode_combo() +{ + ImGui::AlignTextToFramePadding(); + int selection_idx = int(m_mode); + const bool is_changed = m_imgui->combo(_u8L("Mode"), m_modes, selection_idx, 0, m_label_width, m_control_width); - GLShaderProgram* shader = wxGetApp().get_shader("gouraud_light"); - if (shader == nullptr) - return; - shader->start_using(); - shader->set_uniform("emission_factor", 0.1f); + if (is_changed) { + Plater::TakeSnapshot snapshot(wxGetApp().plater(), _u8L("Change cut mode"), UndoRedo::SnapshotType::GizmoAction); + switch_to_mode(size_t(selection_idx)); + check_and_update_connectors_state(); + } - m_grabbers[0].color = GRABBER_COLOR; - m_grabbers[0].render(m_hover_id == 0, (float)((box.size().x() + box.size().y() + box.size().z()) / 3.0)); + return is_changed; +} - shader->stop_using(); +bool GLGizmoCut3D::render_combo(const std::string& label, const std::vector& lines, int& selection_idx) +{ + ImGui::AlignTextToFramePadding(); + const bool is_changed = m_imgui->combo(label, lines, selection_idx, 0, m_label_width, m_control_width); + + //if (is_changed) + // update_connector_shape(); - glsafe(::glPushMatrix()); - glsafe(::glTranslated(m_cut_contours.shift.x(), m_cut_contours.shift.y(), m_cut_contours.shift.z())); - glsafe(::glLineWidth(2.0f)); - m_cut_contours.contours.render(); - glsafe(::glPopMatrix()); + return is_changed; } -void GLGizmoCut::on_render_for_picking() +bool GLGizmoCut3D::render_double_input(const std::string& label, double& value_in) { - glsafe(::glDisable(GL_DEPTH_TEST)); - render_grabbers_for_picking(m_parent.get_selection().get_bounding_box()); + ImGui::AlignTextToFramePadding(); + m_imgui->text(label); + ImGui::SameLine(m_label_width); + ImGui::PushItemWidth(m_control_width); + + double value = value_in; + if (m_imperial_units) + value *= GizmoObjectManipulation::mm_to_in; + double old_val = value; + ImGui::InputDouble(("##" + label).c_str(), &value, 0.0f, 0.0f, "%.2f", ImGuiInputTextFlags_CharsDecimal); + + ImGui::SameLine(); + m_imgui->text(m_imperial_units ? _L("in") : _L("mm")); + + value_in = value * (m_imperial_units ? GizmoObjectManipulation::in_to_mm : 1.0); + return !is_approx(old_val, value); } -void GLGizmoCut::on_render_input_window(float x, float y, float bottom_limit) +bool GLGizmoCut3D::render_slider_double_input(const std::string& label, float& value_in, float& tolerance_in, float min_val/* = -0.1f*/, float max_tolerance/* = -0.1f*/) { - //static float last_y = 0.0f; - //static float last_h = 0.0f; + static constexpr const float UndefMinVal = -0.1f; + const float f_mm_to_in = static_cast(GizmoObjectManipulation::mm_to_in); + + auto render_slider = [this, f_mm_to_in] + (const std::string& label, float& val, float def_val, float max_val, const wxString& tooltip) { + float min_val = val < 0.f ? UndefMinVal : def_val; + float value = val; + if (m_imperial_units) { + min_val *= f_mm_to_in; + value *= f_mm_to_in; + } + const float old_val = value; + const std::string format = val < 0.f ? UndefLabel : (m_imperial_units ? "%.4f " + _u8L("in") : "%.2f " + _u8L("mm")); - //BBS: GUI refactor: move gizmo to the right -#if BBS_TOOLBAR_ON_TOP - m_imgui->set_next_window_pos(x, y, ImGuiCond_Always, 0.5f, 0.0f); -#else - m_imgui->set_next_window_pos(x, y, ImGuiCond_Always, 1.0f, 0.0f); -#endif + m_imgui->slider_float(label.c_str(), &value, min_val, max_val, format.c_str(), 1.f, true, tooltip); + val = value * (m_imperial_units ? static_cast(GizmoObjectManipulation::in_to_mm) : 1.f); - //BBS - ImGuiWrapper::push_toolbar_style(); + m_is_slider_editing_done |= m_imgui->get_last_slider_status().deactivated_after_edit; - m_imgui->begin(_L("Cut"), ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse); + return !is_approx(old_val, value); + }; - const bool imperial_units = wxGetApp().app_config->get("use_inches") == "1"; + const BoundingBoxf3 bbox = m_bounding_box; + const float mean_size = float((bbox.size().x() + bbox.size().y() + bbox.size().z()) / 9.0) * (m_imperial_units ? f_mm_to_in : 1.f); + const float min_v = min_val > 0.f ? /*std::min(max_val, mean_size)*/min_val : 1.f; - // adjust window position to avoid overlap the view toolbar - /*const float win_h = ImGui::GetWindowHeight(); - y = std::min(y, bottom_limit - win_h); - ImGui::SetWindowPos(ImVec2(x, y), ImGuiCond_Always); - if (last_h != win_h || last_y != y) { - // ask canvas for another frame to render the window in the correct position -#if ENABLE_ENHANCED_IMGUI_SLIDER_FLOAT - m_imgui->set_requires_extra_frame(); -#else - m_parent.request_extra_frame(); -#endif // ENABLE_ENHANCED_IMGUI_SLIDER_FLOAT - if (last_h != win_h) - last_h = win_h; - if (last_y != y) - last_y = y; - }*/ + m_imgui->text(label); - ImGui::AlignTextToFramePadding(); - m_imgui->text("Z"); + ImGui::SameLine(m_label_width); + ImGui::PushItemWidth(m_control_width * 0.7f); + +// const bool is_value_changed = render_slider("##" + label, value_in, 1.f, mean_size, _L("Value")); + const bool is_value_changed = render_slider("##" + label, value_in, min_v, mean_size, _L("Value")); + ImGui::SameLine(); - ImGui::PushItemWidth(m_imgui->get_style_scaling() * 150.0f); + ImGui::PushItemWidth(m_control_width * 0.45f); - double cut_z = m_cut_z; - if (imperial_units) - cut_z *= ObjectManipulation::mm_to_in; - ImGui::InputDouble("", &cut_z, 0.0f, 0.0f, "%.2f", ImGuiInputTextFlags_CharsDecimal); +// const bool is_tolerance_changed = render_slider("##tolerance_" + label, tolerance_in, 0.f, 0.5f * mean_size, _L("Tolerance")); + const float max_tolerance_v = max_tolerance > 0.f ? std::min(max_tolerance, 0.5f * mean_size) : 0.5f * mean_size; + const bool is_tolerance_changed = render_slider("##tolerance_" + label, tolerance_in, 0.f, max_tolerance_v, _L("Tolerance")); + + return is_value_changed || is_tolerance_changed; +} +void GLGizmoCut3D::render_move_center_input(int axis) +{ + m_imgui->text(m_axis_names[axis]+":"); ImGui::SameLine(); - m_imgui->text(imperial_units ? _L("in") : _L("mm")); + ImGui::PushItemWidth(0.3f*m_control_width); - m_cut_z = cut_z * (imperial_units ? ObjectManipulation::in_to_mm : 1.0); + Vec3d move = m_plane_center; + double in_val, value = in_val = move[axis]; + if (m_imperial_units) + value *= GizmoObjectManipulation::mm_to_in; + ImGui::InputDouble(("##move_" + m_axis_names[axis]).c_str(), &value, 0.0, 0.0, "%.2f", ImGuiInputTextFlags_CharsDecimal); + ImGui::SameLine(); - ImGui::Separator(); + double val = value * (m_imperial_units ? GizmoObjectManipulation::in_to_mm : 1.0); - m_imgui->checkbox(_L("Keep upper part"), m_keep_upper); - m_imgui->checkbox(_L("Keep lower part"), m_keep_lower); - m_imgui->checkbox(_L("Cut to parts"), m_cut_to_parts); // BBS - m_imgui->checkbox(_L("Rotate lower part upwards"), m_rotate_lower); + if (in_val != val) { + move[axis] = val; + Plater::TakeSnapshot snapshot(wxGetApp().plater(), _u8L("Move cut plane"), UndoRedo::SnapshotType::GizmoAction); + set_center(move, true); + m_ar_plane_center = m_plane_center; - // BBS - ImGui::Separator(); - m_imgui->checkbox(_L("Auto Segment"), m_do_segment); - m_imgui->disabled_begin(!m_do_segment); - ImGui::InputDouble("smoothing_alpha", &m_segment_smoothing_alpha, 0.0f, 0.0f, "%.2f"); - m_segment_smoothing_alpha = std::max(0.1, std::min(100.0, m_segment_smoothing_alpha)); - ImGui::InputInt("segment number", &m_segment_number); - m_segment_number = std::max(1, m_segment_number); - m_imgui->disabled_end(); + reset_cut_by_contours(); + } +} - ImGui::Separator(); +bool GLGizmoCut3D::render_connect_type_radio_button(CutConnectorType type) +{ + ImGui::SameLine(type == CutConnectorType::Plug ? m_label_width : 0); + ImGui::PushItemWidth(m_control_width); + if (ImGui::RadioButton(m_connector_types[size_t(type)].c_str(), m_connector_type == type)) { + m_connector_type = type; +// update_connector_shape(); + return true; + } + return false; +} - m_imgui->disabled_begin((!m_keep_upper && !m_keep_lower && !m_do_segment) || m_cut_z <= 0.0 || m_max_z <= m_cut_z); - const bool cut_clicked = m_imgui->button(_L("Perform cut")); - m_imgui->disabled_end(); +void GLGizmoCut3D::render_connect_mode_radio_button(CutConnectorMode mode) +{ + ImGui::SameLine(mode == CutConnectorMode::Auto ? m_label_width : 2 * m_label_width); + ImGui::PushItemWidth(m_control_width); + if (ImGui::RadioButton(m_connector_modes[int(mode)].c_str(), m_connector_mode == mode)) + m_connector_mode = mode; +} - m_imgui->end(); +bool GLGizmoCut3D::render_reset_button(const std::string& label_id, const std::string& tooltip) const +{ + const ImGuiStyle& style = ImGui::GetStyle(); + + ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, { 1, style.ItemSpacing.y }); + + ImGui::PushStyleColor(ImGuiCol_Button, { 0.25f, 0.25f, 0.25f, 0.0f }); + ImGui::PushStyleColor(ImGuiCol_ButtonHovered, { 0.4f, 0.4f, 0.4f, 1.0f }); + ImGui::PushStyleColor(ImGuiCol_ButtonActive, { 0.4f, 0.4f, 0.4f, 1.0f }); + + std::string btn_label; + btn_label += ImGui::RevertBtn; + const bool revert = ImGui::Button((btn_label +"##" + label_id).c_str()); + + ImGui::PopStyleColor(3); - //BBS - ImGuiWrapper::pop_toolbar_style(); + if (ImGui::IsItemHovered()) + m_imgui->tooltip(tooltip.c_str(), ImGui::GetFontSize() * 20.0f); - // BBS: m_do_segment - if (cut_clicked && (m_keep_upper || m_keep_lower || m_do_segment)) - perform_cut(m_parent.get_selection()); + ImGui::PopStyleVar(); + + return revert; } -void GLGizmoCut::set_cut_z(double cut_z) +static double get_grabber_mean_size(const BoundingBoxf3& bb) { - // Clamp the plane to the object's bounding box - m_cut_z = std::clamp(cut_z, 0.0, m_max_z); + return (bb.size().x() + bb.size().y() + bb.size().z()) / 30.; } -void GLGizmoCut::perform_cut(const Selection& selection) +indexed_triangle_set GLGizmoCut3D::its_make_groove_plane() { - const int instance_idx = selection.get_instance_idx(); - const int object_idx = selection.get_object_idx(); + // values for calculation - wxCHECK_RET(instance_idx >= 0 && object_idx >= 0, "GLGizmoCut: Invalid object selection"); + const float side_width = is_approx(m_groove.flaps_angle, 0.f) ? m_groove.depth : (m_groove.depth / sin(m_groove.flaps_angle)); + const float flaps_width = 2.f * side_width * cos(m_groove.flaps_angle); - // m_cut_z is the distance from the bed. Subtract possible SLA elevation. - const GLVolume* first_glvolume = selection.get_volume(*selection.get_volume_idxs().begin()); - const double object_cut_z = m_cut_z - first_glvolume->get_sla_shift_z(); + const float groove_half_width_upper = 0.5f * (m_groove.width); + const float groove_half_width_lower = 0.5f * (m_groove.width + flaps_width); + + const float cut_plane_radius = 1.5f * float(m_radius); + const float cut_plane_length = 1.5f * cut_plane_radius; + + const float groove_half_depth = 0.5f * m_groove.depth; + + const float x = 0.5f * cut_plane_radius; + const float y = 0.5f * cut_plane_length; + float z_upper = groove_half_depth; + float z_lower = -groove_half_depth; - // BBS: do segment - if (m_do_segment) + const float proj = y * tan(m_groove.angle); + + float ext_upper_x = groove_half_width_upper + proj; // upper_x extension + float ext_lower_x = groove_half_width_lower + proj; // lower_x extension + + float nar_upper_x = groove_half_width_upper - proj; // upper_x narrowing + float nar_lower_x = groove_half_width_lower - proj; // lower_x narrowing + + const float cut_plane_thiknes = 0.02f;// 0.02f * (float)get_grabber_mean_size(m_bounding_box); // cut_plane_thiknes + + // Vertices of the groove used to detection if groove is valid + // They are written as: + // {left_ext_lower, left_nar_lower, left_ext_upper, left_nar_upper, + // right_ext_lower, right_nar_lower, right_ext_upper, right_nar_upper } { - wxGetApp().plater()->segment(object_idx, instance_idx, m_segment_smoothing_alpha, m_segment_number); + m_groove_vertices.clear(); + m_groove_vertices.reserve(8); + + m_groove_vertices.emplace_back(Vec3f(-ext_lower_x, -y, z_lower).cast()); + m_groove_vertices.emplace_back(Vec3f(-nar_lower_x, y, z_lower).cast()); + m_groove_vertices.emplace_back(Vec3f(-ext_upper_x, -y, z_upper).cast()); + m_groove_vertices.emplace_back(Vec3f(-nar_upper_x, y, z_upper).cast()); + m_groove_vertices.emplace_back(Vec3f( ext_lower_x, -y, z_lower).cast()); + m_groove_vertices.emplace_back(Vec3f( nar_lower_x, y, z_lower).cast()); + m_groove_vertices.emplace_back(Vec3f( ext_upper_x, -y, z_upper).cast()); + m_groove_vertices.emplace_back(Vec3f( nar_upper_x, y, z_upper).cast()); } - else if (0.0 < object_cut_z && object_cut_z < m_max_z) { - //wxGetApp().plater()->cut(object_idx, instance_idx, object_cut_z, m_keep_upper, m_keep_lower, m_rotate_lower, m_cut_to_parts); + + // Different cases of groove plane: + + // groove is open + + if (groove_half_width_upper > proj && groove_half_width_lower > proj) { + indexed_triangle_set mesh; + + auto get_vertices = [x, y](float z_upper, float z_lower, float nar_upper_x, float nar_lower_x, float ext_upper_x, float ext_lower_x) { + return std::vector({ + // upper left part vertices + {-x, -y, z_upper}, {-x, y, z_upper}, {-nar_upper_x, y, z_upper}, {-ext_upper_x, -y, z_upper}, + // lower part vertices + {-ext_lower_x, -y, z_lower}, {-nar_lower_x, y, z_lower}, {nar_lower_x, y, z_lower}, {ext_lower_x, -y, z_lower}, + // upper right part vertices + {ext_upper_x, -y, z_upper}, {nar_upper_x, y, z_upper}, {x, y, z_upper}, {x, -y, z_upper} + }); + }; + + mesh.vertices = get_vertices(z_upper, z_lower, nar_upper_x, nar_lower_x, ext_upper_x, ext_lower_x); + mesh.vertices.reserve(2 * mesh.vertices.size()); + + z_upper -= cut_plane_thiknes; + z_lower -= cut_plane_thiknes; + + const float under_x_shift = cut_plane_thiknes / tan(0.5f * m_groove.flaps_angle); + + nar_upper_x += under_x_shift; + nar_lower_x += under_x_shift; + ext_upper_x += under_x_shift; + ext_lower_x += under_x_shift; + + std::vector vertices = get_vertices(z_upper, z_lower, nar_upper_x, nar_lower_x, ext_upper_x, ext_lower_x); + mesh.vertices.insert(mesh.vertices.end(), vertices.begin(), vertices.end()); + + mesh.indices = { + // above view + {5,4,7}, {5,7,6}, // lower part + {3,4,5}, {3,5,2}, // left side + {9,6,8}, {8,6,7}, // right side + {1,0,2}, {2,0,3}, // upper left part + {9,8,10}, {10,8,11}, // upper right part + // under view + {20,21,22}, {20,22,23}, // upper right part + {12,13,14}, {12,14,15}, // upper left part + {18,21,20}, {18,20,19}, // right side + {16,15,14}, {16,14,17}, // left side + {16,17,18}, {16,18,19}, // lower part + // left edge + {1,13,0}, {0,13,12}, + // front edge + {0,12,3}, {3,12,15}, {3,15,4}, {4,15,16}, {4,16,7}, {7,16,19}, {7,19,20}, {7,20,8}, {8,20,11}, {11,20,23}, + // right edge + {11,23,10}, {10,23,22}, + // back edge + {1,13,2}, {2,13,14}, {2,14,17}, {2,17,5}, {5,17,6}, {6,17,18}, {6,18,9}, {9,18,21}, {9,21,10}, {10,21,22} + }; + return mesh; } - else { - // the object is SLA-elevated and the plane is under it. + + float cross_pt_upper_y = groove_half_width_upper / tan(m_groove.angle); + + // groove is closed + + if (groove_half_width_upper < proj && groove_half_width_lower < proj) { + float cross_pt_lower_y = groove_half_width_lower / tan(m_groove.angle); + + indexed_triangle_set mesh; + + auto get_vertices = [x, y](float z_upper, float z_lower, float cross_pt_upper_y, float cross_pt_lower_y, float ext_upper_x, float ext_lower_x) { + return std::vector({ + // upper part vertices + {-x, -y, z_upper}, {-x, y, z_upper}, {x, y, z_upper}, {x, -y, z_upper}, + {ext_upper_x, -y, z_upper}, {0.f, cross_pt_upper_y, z_upper}, {-ext_upper_x, -y, z_upper}, + // lower part vertices + {-ext_lower_x, -y, z_lower}, {0.f, cross_pt_lower_y, z_lower}, {ext_lower_x, -y, z_lower} + }); + }; + + mesh.vertices = get_vertices(z_upper, z_lower, cross_pt_upper_y, cross_pt_lower_y, ext_upper_x, ext_lower_x); + mesh.vertices.reserve(2 * mesh.vertices.size()); + + z_upper -= cut_plane_thiknes; + z_lower -= cut_plane_thiknes; + + const float under_x_shift = cut_plane_thiknes / tan(0.5f * m_groove.flaps_angle); + + cross_pt_upper_y += cut_plane_thiknes; + cross_pt_lower_y += cut_plane_thiknes; + ext_upper_x += under_x_shift; + ext_lower_x += under_x_shift; + + std::vector vertices = get_vertices(z_upper, z_lower, cross_pt_upper_y, cross_pt_lower_y, ext_upper_x, ext_lower_x); + mesh.vertices.insert(mesh.vertices.end(), vertices.begin(), vertices.end()); + + mesh.indices = { + // above view + {8,7,9}, // lower part + {5,8,6}, {6,8,7}, // left side + {4,9,8}, {4,8,5}, // right side + {1,0,6}, {1,6,5},{1,5,2}, {2,5,4}, {2,4,3}, // upper part + // under view + {10,11,16}, {16,11,15}, {15,11,12}, {15,12,14}, {14,12,13}, // upper part + {18,15,14}, {14,18,19}, // right side + {17,16,15}, {17,15,18}, // left side + {17,18,19}, // lower part + // left edge + {1,11,0}, {0,11,10}, + // front edge + {0,10,6}, {6,10,16}, {6,17,16}, {6,7,17}, {7,17,19}, {7,19,9}, {4,14,19}, {4,19,9}, {4,14,13}, {4,13,3}, + // right edge + {3,13,12}, {3,12,2}, + // back edge + {2,12,11}, {2,11,1} + }; + + return mesh; } + + // groove is closed from the roof + + indexed_triangle_set mesh; + mesh.vertices = { + // upper part vertices + {-x, -y, z_upper}, {-x, y, z_upper}, {x, y, z_upper}, {x, -y, z_upper}, + {ext_upper_x, -y, z_upper}, {0.f, cross_pt_upper_y, z_upper}, {-ext_upper_x, -y, z_upper}, + // lower part vertices + {-ext_lower_x, -y, z_lower}, {-nar_lower_x, y, z_lower}, {nar_lower_x, y, z_lower}, {ext_lower_x, -y, z_lower} + }; + + mesh.vertices.reserve(2 * mesh.vertices.size() + 1); + + z_upper -= cut_plane_thiknes; + z_lower -= cut_plane_thiknes; + + const float under_x_shift = cut_plane_thiknes / tan(0.5f * m_groove.flaps_angle); + + nar_lower_x += under_x_shift; + ext_upper_x += under_x_shift; + ext_lower_x += under_x_shift; + + std::vector vertices = { + // upper part vertices + {-x, -y, z_upper}, {-x, y, z_upper}, {x, y, z_upper}, {x, -y, z_upper}, + {ext_upper_x, -y, z_upper}, {under_x_shift, cross_pt_upper_y, z_upper}, {-under_x_shift, cross_pt_upper_y, z_upper}, {-ext_upper_x, -y, z_upper}, + // lower part vertices + {-ext_lower_x, -y, z_lower}, {-nar_lower_x, y, z_lower}, {nar_lower_x, y, z_lower}, {ext_lower_x, -y, z_lower} + }; + mesh.vertices.insert(mesh.vertices.end(), vertices.begin(), vertices.end()); + + mesh.indices = { + // above view + {8,7,10}, {8,10,9}, // lower part + {5,8,7}, {5,7,6}, // left side + {4,10,9}, {4,9,5}, // right side + {1,0,6}, {1,6,5},{1,5,2}, {2,5,4}, {2,4,3}, // upper part + // under view + {11,12,18}, {18,12,17}, {17,12,16}, {16,12,13}, {16,13,15}, {15,13,14}, // upper part + {21,16,15}, {21,15,22}, // right side + {19,18,17}, {19,17,20}, // left side + {19,20,21}, {19,21,22}, // lower part + // left edge + {1,12,11}, {1,11,0}, + // front edge + {0,11,18}, {0,18,6}, {7,19,18}, {7,18,6}, {7,19,22}, {7,22,10}, {10,22,15}, {10,15,4}, {4,15,14}, {4,14,3}, + // right edge + {3,14,13}, {3,14,2}, + // back edge + {2,13,12}, {2,12,1}, {5,16,21}, {5,21,9}, {9,21,20}, {9,20,8}, {5,17,20}, {5,20,8} + }; + + return mesh; } -double GLGizmoCut::calc_projection(const Linef3& mouse_ray) const +void GLGizmoCut3D::render_cut_plane() { - double projection = 0.0; + if (cut_line_processing()) + return; - const Vec3d starting_vec = m_drag_pos - m_drag_center; - const double len_starting_vec = starting_vec.norm(); - if (len_starting_vec != 0.0) { - const Vec3d mouse_dir = mouse_ray.unit_vector(); - // finds the intersection of the mouse ray with the plane parallel to the camera viewport and passing throught the starting position - // use ray-plane intersection see i.e. https://en.wikipedia.org/wiki/Line%E2%80%93plane_intersection algebric form - // in our case plane normal and ray direction are the same (orthogonal view) - // when moving to perspective camera the negative z unit axis of the camera needs to be transformed in world space and used as plane normal - const Vec3d inters = mouse_ray.a + (m_drag_pos - mouse_ray.a).dot(mouse_dir) / mouse_dir.squaredNorm() * mouse_dir; - // vector from the starting position to the found intersection - const Vec3d inters_vec = inters - m_drag_pos; + GLShaderProgram* shader = wxGetApp().get_shader("flat"); + if (shader == nullptr) + return; - // finds projection of the vector along the staring direction - projection = inters_vec.dot(starting_vec.normalized()); + glsafe(::glEnable(GL_DEPTH_TEST)); + glsafe(::glDisable(GL_CULL_FACE)); + glsafe(::glEnable(GL_BLEND)); + glsafe(::glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)); + + shader->start_using(); + + const Camera& camera = wxGetApp().plater()->get_camera(); + + shader->set_uniform("projection_matrix", camera.get_projection_matrix()); + + ColorRGBA cp_clr = can_perform_cut() && has_valid_groove() ? CUT_PLANE_DEF_COLOR : CUT_PLANE_ERR_COLOR; + if (m_mode == size_t(CutMode::cutTongueAndGroove)) + cp_clr.a(cp_clr.a() - 0.1f); + m_plane.model.set_color(cp_clr); + + const Transform3d view_model_matrix = camera.get_view_matrix() * translation_transform(m_plane_center) * m_rotation_m; + shader->set_uniform("view_model_matrix", view_model_matrix); + m_plane.model.render(); + + glsafe(::glEnable(GL_CULL_FACE)); + glsafe(::glDisable(GL_BLEND)); + + shader->stop_using(); +} + +static double get_half_size(double size) +{ + return std::max(size * 0.35, 0.05); +} + +static double get_dragging_half_size(double size) +{ + return get_half_size(size) * 1.25; +} + +void GLGizmoCut3D::render_model(GLModel& model, const ColorRGBA& color, Transform3d view_model_matrix) +{ + GLShaderProgram* shader = wxGetApp().get_shader("gouraud_light"); + if (shader) { + shader->start_using(); + + shader->set_uniform("view_model_matrix", view_model_matrix); + shader->set_uniform("emission_factor", 0.2f); + shader->set_uniform("projection_matrix", wxGetApp().plater()->get_camera().get_projection_matrix()); + + model.set_color(color); + model.render(); + + shader->stop_using(); } - return projection; } -BoundingBoxf3 GLGizmoCut::bounding_box() const +void GLGizmoCut3D::render_line(GLModel& line_model, const ColorRGBA& color, Transform3d view_model_matrix, float width) { - BoundingBoxf3 ret; - const Selection& selection = m_parent.get_selection(); - const Selection::IndicesList& idxs = selection.get_volume_idxs(); - for (unsigned int i : idxs) { - const GLVolume* volume = selection.get_volume(i); - if (!volume->is_modifier) - ret.merge(volume->transformed_convex_hull_bounding_box()); + GLShaderProgram* shader = wxGetApp().get_shader("flat"); + if (shader) { + shader->start_using(); + + shader->set_uniform("view_model_matrix", view_model_matrix); + shader->set_uniform("projection_matrix", wxGetApp().plater()->get_camera().get_projection_matrix()); + shader->set_uniform("width", width); + + line_model.set_color(color); + line_model.render(); + + shader->stop_using(); } - return ret; } -void GLGizmoCut::update_contours() +void GLGizmoCut3D::render_rotation_snapping(GrabberID axis, const ColorRGBA& color) { - const Selection& selection = m_parent.get_selection(); - const GLVolume* first_glvolume = selection.get_volume(*selection.get_volume_idxs().begin()); - const BoundingBoxf3& box = first_glvolume->transformed_convex_hull_bounding_box(); + GLShaderProgram* line_shader = wxGetApp().get_shader("flat"); + if (!line_shader) + return; - const ModelObject* model_object = wxGetApp().model().objects[selection.get_object_idx()]; - const int instance_idx = selection.get_instance_idx(); + const Camera& camera = wxGetApp().plater()->get_camera(); + Transform3d view_model_matrix = camera.get_view_matrix() * translation_transform(m_plane_center) * m_start_dragging_m; + + if (axis == X) + view_model_matrix = view_model_matrix * rotation_transform(0.5 * PI * Vec3d::UnitY()) * rotation_transform(-PI * Vec3d::UnitZ()); + else if (axis == Y) + view_model_matrix = view_model_matrix * rotation_transform(-0.5 * PI * Vec3d::UnitZ()) * rotation_transform(-0.5 * PI * Vec3d::UnitY()); + else + view_model_matrix = view_model_matrix * rotation_transform(-0.5 * PI * Vec3d::UnitZ()); + + line_shader->start_using(); + line_shader->set_uniform("projection_matrix", camera.get_projection_matrix()); + line_shader->set_uniform("view_model_matrix", view_model_matrix); + line_shader->set_uniform("width", 0.25f); + + m_circle.render(); + m_scale.render(); + m_snap_radii.render(); + m_reference_radius.render(); + if (m_dragging) { + line_shader->set_uniform("width", 1.5f); + m_angle_arc.set_color(color); + m_angle_arc.render(); + } + + line_shader->stop_using(); +} + +void GLGizmoCut3D::render_grabber_connection(const ColorRGBA& color, Transform3d view_matrix, double line_len_koef/* = 1.0*/) +{ + const Transform3d line_view_matrix = view_matrix * scale_transform(Vec3d(1.0, 1.0, line_len_koef * m_grabber_connection_len)); + + render_line(m_grabber_connection, color, line_view_matrix, 0.2f); +}; + +void GLGizmoCut3D::render_cut_plane_grabbers() +{ + glsafe(::glClear(GL_DEPTH_BUFFER_BIT)); + + ColorRGBA color = ColorRGBA::GRAY(); + + const Transform3d view_matrix = wxGetApp().plater()->get_camera().get_view_matrix() * translation_transform(m_plane_center) * m_rotation_m; + + const double mean_size = get_grabber_mean_size(m_bounding_box); + double size; + + const bool no_xy_dragging = m_dragging && m_hover_id == CutPlane; + + if (!no_xy_dragging && m_hover_id != CutPlaneZRotation && m_hover_id != CutPlaneXMove && m_hover_id != CutPlaneYMove) { + render_grabber_connection(GRABBER_COLOR, view_matrix); + + // render sphere grabber + size = m_dragging ? get_dragging_half_size(mean_size) : get_half_size(mean_size); + color = m_hover_id == Y ? complementary(ColorRGBA::GREEN()) : + m_hover_id == X ? complementary(ColorRGBA::RED()) : + m_hover_id == Z ? GRABBER_COLOR : ColorRGBA::GRAY(); + render_model(m_sphere.model, color, view_matrix * translation_transform(m_grabber_connection_len * Vec3d::UnitZ()) * scale_transform(size)); + } + + const bool no_xy_grabber_hovered = !m_dragging && (m_hover_id < 0 || m_hover_id == CutPlane); + + // render X grabber + + if (no_xy_grabber_hovered || m_hover_id == X) + { + size = m_dragging && m_hover_id == X ? get_dragging_half_size(mean_size) : get_half_size(mean_size); + const Vec3d cone_scale = Vec3d(0.75 * size, 0.75 * size, 1.8 * size); + color = m_hover_id == X ? complementary(ColorRGBA::RED()) : ColorRGBA::RED(); + + if (m_hover_id == X) { + render_grabber_connection(color, view_matrix); + render_rotation_snapping(X, color); + } - if (0.0 < m_cut_z && m_cut_z < m_max_z) { - if (m_cut_contours.cut_z != m_cut_z || m_cut_contours.object_id != model_object->id() || m_cut_contours.instance_idx != instance_idx) { - m_cut_contours.cut_z = m_cut_z; - - if (m_cut_contours.object_id != model_object->id()) - m_cut_contours.mesh = model_object->raw_mesh(); - - m_cut_contours.position = box.center(); - m_cut_contours.shift = Vec3d::Zero(); - m_cut_contours.object_id = model_object->id(); - m_cut_contours.instance_idx = instance_idx; - m_cut_contours.contours.reset(); - - MeshSlicingParams slicing_params; - slicing_params.trafo = first_glvolume->get_instance_transformation().get_matrix(); - const Polygons polys = slice_mesh(m_cut_contours.mesh.its, m_cut_z, slicing_params); - if (!polys.empty()) { - m_cut_contours.contours.init_from(polys, static_cast(m_cut_z)); - m_cut_contours.contours.set_color(-1, { 1.0f, 1.0f, 1.0f, 1.0f }); + Vec3d offset = Vec3d(0.0, 1.25 * size, m_grabber_connection_len); + render_model(m_cone.model, color, view_matrix * translation_transform(offset) * rotation_transform(-0.5 * PI * Vec3d::UnitX()) * scale_transform(cone_scale)); + offset = Vec3d(0.0, -1.25 * size, m_grabber_connection_len); + render_model(m_cone.model, color, view_matrix * translation_transform(offset) * rotation_transform(0.5 * PI * Vec3d::UnitX()) * scale_transform(cone_scale)); + } + + // render Y grabber + + if (no_xy_grabber_hovered || m_hover_id == Y) + { + size = m_dragging && m_hover_id == Y ? get_dragging_half_size(mean_size) : get_half_size(mean_size); + const Vec3d cone_scale = Vec3d(0.75 * size, 0.75 * size, 1.8 * size); + color = m_hover_id == Y ? complementary(ColorRGBA::GREEN()) : ColorRGBA::GREEN(); + + if (m_hover_id == Y) { + render_grabber_connection(color, view_matrix); + render_rotation_snapping(Y, color); + } + + Vec3d offset = Vec3d(1.25 * size, 0.0, m_grabber_connection_len); + render_model(m_cone.model, color, view_matrix * translation_transform(offset) * rotation_transform(0.5 * PI * Vec3d::UnitY()) * scale_transform(cone_scale)); + offset = Vec3d(-1.25 * size, 0.0, m_grabber_connection_len); + render_model(m_cone.model, color, view_matrix * translation_transform(offset) * rotation_transform(-0.5 * PI * Vec3d::UnitY()) * scale_transform(cone_scale)); + } + + if (CutMode(m_mode) == CutMode::cutTongueAndGroove) { + + // render CutPlaneZRotation grabber + + if (no_xy_grabber_hovered || m_hover_id == CutPlaneZRotation) + { + size = 0.75 * (m_dragging ? get_dragging_half_size(mean_size) : get_half_size(mean_size)); + color = ColorRGBA::BLUE(); + const ColorRGBA cp_color = m_hover_id == CutPlaneZRotation ? color : m_plane.model.get_color(); + + const double grabber_shift = -1.75 * m_grabber_connection_len; + + render_model(m_sphere.model, cp_color, view_matrix * translation_transform(grabber_shift * Vec3d::UnitY()) * scale_transform(size)); + + if (m_hover_id == CutPlaneZRotation) { + const Vec3d cone_scale = Vec3d(0.75 * size, 0.75 * size, 1.8 * size); + + render_rotation_snapping(CutPlaneZRotation, color); + render_grabber_connection(GRABBER_COLOR, view_matrix * rotation_transform(0.5 * PI * Vec3d::UnitX()), 1.75); + + Vec3d offset = Vec3d(1.25 * size, grabber_shift, 0.0); + render_model(m_cone.model, color, view_matrix * translation_transform(offset) * rotation_transform(0.5 * PI * Vec3d::UnitY()) * scale_transform(cone_scale)); + offset = Vec3d(-1.25 * size, grabber_shift, 0.0); + render_model(m_cone.model, color, view_matrix * translation_transform(offset) * rotation_transform(-0.5 * PI * Vec3d::UnitY()) * scale_transform(cone_scale)); } } - else if (box.center() != m_cut_contours.position) { - m_cut_contours.shift = box.center() - m_cut_contours.position; + + const double xy_connection_len = 0.75 * m_grabber_connection_len; + + // render CutPlaneXMove grabber + + if (no_xy_grabber_hovered || m_hover_id == CutPlaneXMove) + { + size = (m_dragging ? get_dragging_half_size(mean_size) : get_half_size(mean_size)); + color = m_hover_id == CutPlaneXMove ? ColorRGBA::RED() : m_plane.model.get_color(); + + render_grabber_connection(GRABBER_COLOR, view_matrix * rotation_transform(0.5 * PI * Vec3d::UnitY()), 0.75); + + Vec3d offset = xy_connection_len * Vec3d::UnitX() - 0.5 * size * Vec3d::Ones(); + render_model(m_cube.model, color, view_matrix * translation_transform(offset) * scale_transform(size)); + + const Vec3d cone_scale = Vec3d(0.5 * size, 0.5 * size, 1.8 * size); + + offset = (size + xy_connection_len) * Vec3d::UnitX(); + render_model(m_cone.model, color, view_matrix * translation_transform(offset) * rotation_transform(0.5 * PI * Vec3d::UnitY()) * scale_transform(cone_scale)); + } + + // render CutPlaneYMove grabber + + if (m_groove.angle > 0.0f && (no_xy_grabber_hovered || m_hover_id == CutPlaneYMove)) + { + size = (m_dragging ? get_dragging_half_size(mean_size) : get_half_size(mean_size)); + color = m_hover_id == CutPlaneYMove ? ColorRGBA::GREEN() : m_plane.model.get_color(); + + render_grabber_connection(GRABBER_COLOR, view_matrix * rotation_transform(-0.5 * PI * Vec3d::UnitX()), 0.75); + + Vec3d offset = xy_connection_len * Vec3d::UnitY() - 0.5 * size * Vec3d::Ones(); + render_model(m_cube.model, color, view_matrix * translation_transform(offset) * scale_transform(size)); + + const Vec3d cone_scale = Vec3d(0.5 * size, 0.5 * size, 1.8 * size); + + offset = (size + xy_connection_len) * Vec3d::UnitY(); + render_model(m_cone.model, color, view_matrix * translation_transform(offset) * rotation_transform(-0.5 * PI * Vec3d::UnitX()) * scale_transform(cone_scale)); } } - else - m_cut_contours.contours.reset(); } +void GLGizmoCut3D::render_cut_line() +{ + if (!cut_line_processing() || m_line_end.isApprox(Vec3d::Zero())) + return; + + glsafe(::glEnable(GL_DEPTH_TEST)); + glsafe(::glClear(GL_DEPTH_BUFFER_BIT)); + + m_cut_line.reset(); + m_cut_line.init_from(its_make_line((Vec3f)m_line_beg.cast(), (Vec3f)m_line_end.cast())); + + render_line(m_cut_line, GRABBER_COLOR, wxGetApp().plater()->get_camera().get_view_matrix(), 0.25f); +} + +bool GLGizmoCut3D::on_init() +{ + m_grabbers.emplace_back(); + m_shortcut_key = WXK_CONTROL_C; + + // initiate info shortcuts + const wxString ctrl = GUI::shortkey_ctrl_prefix(); + const wxString alt = GUI::shortkey_alt_prefix(); + const wxString shift = "Shift+"; + + m_shortcuts.push_back(std::make_pair(_L("Left click"), _L("Add connector"))); + m_shortcuts.push_back(std::make_pair(_L("Right click"), _L("Remove connector"))); + m_shortcuts.push_back(std::make_pair(_L("Drag"), _L("Move connector"))); + m_shortcuts.push_back(std::make_pair(shift + _L("Left click"), _L("Add connector to selection"))); + m_shortcuts.push_back(std::make_pair(alt + _L("Left click"), _L("Remove connector from selection"))); + m_shortcuts.push_back(std::make_pair(ctrl + "A", _L("Select all connectors"))); + + return true; +} + +void GLGizmoCut3D::on_load(cereal::BinaryInputArchive& ar) +{ + size_t mode; + float groove_depth; + float groove_width; + float groove_flaps_angle; + float groove_angle; + float groove_depth_tolerance; + float groove_width_tolerance; + + ar( m_keep_upper, m_keep_lower, m_rotate_lower, m_rotate_upper, m_hide_cut_plane, mode, m_connectors_editing, + m_ar_plane_center, m_rotation_m, + groove_depth, groove_width, groove_flaps_angle, groove_angle, groove_depth_tolerance, groove_width_tolerance); + + m_start_dragging_m = m_rotation_m; + + m_transformed_bounding_box = transformed_bounding_box(m_ar_plane_center, m_rotation_m); + set_center_pos(m_ar_plane_center); + + if (m_mode != mode) + switch_to_mode(mode); + else if (CutMode(m_mode) == CutMode::cutTongueAndGroove) { + if (!is_approx(m_groove.depth , groove_depth) || + !is_approx(m_groove.width , groove_width) || + !is_approx(m_groove.flaps_angle , groove_flaps_angle) || + !is_approx(m_groove.angle , groove_angle) || + !is_approx(m_groove.depth_tolerance, groove_depth_tolerance) || + !is_approx(m_groove.width_tolerance, groove_width_tolerance) ) + { + m_groove.depth = groove_depth; + m_groove.width = groove_width; + m_groove.flaps_angle = groove_flaps_angle; + m_groove.angle = groove_angle; + m_groove.depth_tolerance= groove_depth_tolerance; + m_groove.width_tolerance= groove_width_tolerance; + update_plane_model(); + } + reset_cut_by_contours(); + } + + m_parent.request_extra_frame(); +} + +void GLGizmoCut3D::on_save(cereal::BinaryOutputArchive& ar) const +{ + ar( m_keep_upper, m_keep_lower, m_rotate_lower, m_rotate_upper, m_hide_cut_plane, m_mode, m_connectors_editing, + m_ar_plane_center, m_start_dragging_m, + m_groove.depth, m_groove.width, m_groove.flaps_angle, m_groove.angle, m_groove.depth_tolerance, m_groove.width_tolerance); +} + +std::string GLGizmoCut3D::on_get_name() const +{ + return _u8L("Cut"); +} + +void GLGizmoCut3D::apply_color_clip_plane_colors() +{ + if (CutMode(m_mode) == CutMode::cutTongueAndGroove) + m_parent.set_color_clip_plane_colors({ CUT_PLANE_DEF_COLOR , CUT_PLANE_DEF_COLOR }); + else + m_parent.set_color_clip_plane_colors({ UPPER_PART_COLOR , LOWER_PART_COLOR }); +} + +void GLGizmoCut3D::on_set_state() +{ + if (m_state == On) { + m_parent.set_use_color_clip_plane(true); + + update_bb(); + m_connectors_editing = !m_selected.empty(); + m_transformed_bounding_box = transformed_bounding_box(m_plane_center, m_rotation_m); + + // initiate archived values + m_ar_plane_center = m_plane_center; + m_start_dragging_m = m_rotation_m; + reset_cut_by_contours(); + + m_parent.request_extra_frame(); + } + else { + if (auto oc = m_c->object_clipper()) { + oc->set_behavior(true, true, 0.); + oc->release(); + } + m_selected.clear(); + m_parent.set_use_color_clip_plane(false); + //m_c->selection_info()->set_use_shift(false); + + // Make sure that the part selection data are released when the gizmo is closed. + // The CallAfter is needed because in perform_cut, the gizmo is closed BEFORE + // the cut is performed (because of undo/redo snapshots), so the data would + // be deleted prematurely. + if (m_part_selection.valid()) + wxGetApp().CallAfter([this]() { m_part_selection = PartSelection(); }); + } +} + +void GLGizmoCut3D::on_register_raycasters_for_picking() +{ + // assert(m_raycasters.empty()); + if (!m_raycasters.empty()) + on_unregister_raycasters_for_picking(); + // the gizmo grabbers are rendered on top of the scene, so the raytraced picker should take it into account + m_parent.set_raycaster_gizmos_on_top(true); + + init_picking_models(); + + if (m_connectors_editing) { + if (CommonGizmosDataObjects::SelectionInfo* si = m_c->selection_info()) { + const CutConnectors& connectors = si->model_object()->cut_connectors; + for (int i = 0; i < int(connectors.size()); ++i) + m_raycasters.emplace_back(m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, i + m_connectors_group_id, *(m_shapes[connectors[i].attribs]).mesh_raycaster, Transform3d::Identity())); + } + } + else if (!cut_line_processing()) { + m_raycasters.emplace_back(m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, X, *m_cone.mesh_raycaster, Transform3d::Identity())); + m_raycasters.emplace_back(m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, X, *m_cone.mesh_raycaster, Transform3d::Identity())); + + m_raycasters.emplace_back(m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, Y, *m_cone.mesh_raycaster, Transform3d::Identity())); + m_raycasters.emplace_back(m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, Y, *m_cone.mesh_raycaster, Transform3d::Identity())); + + m_raycasters.emplace_back(m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, Z, *m_sphere.mesh_raycaster, Transform3d::Identity())); + + m_raycasters.emplace_back(m_parent.add_raycaster_for_picking(SceneRaycaster::EType::FallbackGizmo, CutPlane, *m_plane.mesh_raycaster, Transform3d::Identity())); + + if (CutMode(m_mode) == CutMode::cutTongueAndGroove) { + m_raycasters.emplace_back(m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, CutPlaneZRotation, *m_sphere.mesh_raycaster, Transform3d::Identity())); + m_raycasters.emplace_back(m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, CutPlaneZRotation, *m_cone.mesh_raycaster, Transform3d::Identity())); + m_raycasters.emplace_back(m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, CutPlaneZRotation, *m_cone.mesh_raycaster, Transform3d::Identity())); + + m_raycasters.emplace_back(m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, CutPlaneXMove, *m_cube.mesh_raycaster, Transform3d::Identity())); + m_raycasters.emplace_back(m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, CutPlaneXMove, *m_cone.mesh_raycaster, Transform3d::Identity())); + + m_raycasters.emplace_back(m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, CutPlaneYMove, *m_cube.mesh_raycaster, Transform3d::Identity())); + m_raycasters.emplace_back(m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, CutPlaneYMove, *m_cone.mesh_raycaster, Transform3d::Identity())); + } + } + + update_raycasters_for_picking_transform(); +} + +void GLGizmoCut3D::on_unregister_raycasters_for_picking() +{ + m_parent.remove_raycasters_for_picking(SceneRaycaster::EType::Gizmo); + m_parent.remove_raycasters_for_picking(SceneRaycaster::EType::FallbackGizmo); + m_raycasters.clear(); + // the gizmo grabbers are rendered on top of the scene, so the raytraced picker should take it into account + m_parent.set_raycaster_gizmos_on_top(false); +} + +void GLGizmoCut3D::update_raycasters_for_picking() +{ + on_unregister_raycasters_for_picking(); + on_register_raycasters_for_picking(); +} + +void GLGizmoCut3D::set_volumes_picking_state(bool state) +{ + std::vector>* raycasters = m_parent.get_raycasters_for_picking(SceneRaycaster::EType::Volume); + if (raycasters != nullptr) { + const Selection& selection = m_parent.get_selection(); + const Selection::IndicesList ids = selection.get_volume_idxs(); + for (unsigned int id : ids) { + const GLVolume* v = selection.get_volume(id); + auto it = std::find_if(raycasters->begin(), raycasters->end(), [v](std::shared_ptr item) { return item->get_raycaster() == v->mesh_raycaster.get(); }); + if (it != raycasters->end()) + (*it)->set_active(state); + } + } +} + +void GLGizmoCut3D::update_raycasters_for_picking_transform() +{ + if (m_connectors_editing) { + CommonGizmosDataObjects::SelectionInfo* si = m_c->selection_info(); + if (!si) + return; + const ModelObject* mo = si->model_object(); + const CutConnectors& connectors = mo->cut_connectors; + if (connectors.empty()) + return; + auto inst_id = m_c->selection_info()->get_active_instance(); + if (inst_id < 0) + return; + + const Vec3d& instance_offset = mo->instances[inst_id]->get_offset(); + const double sla_shift = double(m_c->selection_info()->get_sla_shift()); + + const bool looking_forward = is_looking_forward(); + + for (size_t i = 0; i < connectors.size(); ++i) { + const CutConnector& connector = connectors[i]; + + float height = connector.height; + // recalculate connector position to world position + Vec3d pos = connector.pos + instance_offset; + if (connector.attribs.type == CutConnectorType::Dowel && + connector.attribs.style == CutConnectorStyle::Prism) { + height = 0.05f; + if (!looking_forward) + pos += 0.05 * m_clp_normal; + } + pos[Z] += sla_shift; + + const Transform3d scale_trafo = scale_transform(Vec3f(connector.radius, connector.radius, height).cast()); + m_raycasters[i]->set_transform(translation_transform(pos) * m_rotation_m * scale_trafo); + } + } + else if (!cut_line_processing()){ + const Transform3d trafo = translation_transform(m_plane_center) * m_rotation_m; + + const BoundingBoxf3 box = m_bounding_box; + + const double size = get_half_size(get_grabber_mean_size(box)); + Vec3d scale = Vec3d(0.75 * size, 0.75 * size, 1.8 * size); + + int id = 0; + + Vec3d offset = Vec3d(0.0, 1.25 * size, m_grabber_connection_len); + m_raycasters[id++]->set_transform(trafo * translation_transform(offset) * rotation_transform(-0.5 * PI * Vec3d::UnitX()) * scale_transform(scale)); + offset = Vec3d(0.0, -1.25 * size, m_grabber_connection_len); + m_raycasters[id++]->set_transform(trafo * translation_transform(offset) * rotation_transform(0.5 * PI * Vec3d::UnitX()) * scale_transform(scale)); + + offset = Vec3d(1.25 * size, 0.0, m_grabber_connection_len); + m_raycasters[id++]->set_transform(trafo * translation_transform(offset) * rotation_transform(0.5 * PI * Vec3d::UnitY()) * scale_transform(scale)); + offset = Vec3d(-1.25 * size, 0.0, m_grabber_connection_len); + m_raycasters[id++]->set_transform(trafo * translation_transform(offset) * rotation_transform(-0.5 * PI * Vec3d::UnitY()) * scale_transform(scale)); + + m_raycasters[id++]->set_transform(trafo * translation_transform(m_grabber_connection_len * Vec3d::UnitZ()) * scale_transform(size)); + + m_raycasters[id++]->set_transform(trafo); + + if (CutMode(m_mode) == CutMode::cutTongueAndGroove) { + + double grabber_y_shift = -1.75 * m_grabber_connection_len; + + m_raycasters[id++]->set_transform(trafo * translation_transform(grabber_y_shift * Vec3d::UnitY()) * scale_transform(size)); + + offset = Vec3d(1.25 * size, grabber_y_shift, 0.0); + m_raycasters[id++]->set_transform(trafo * translation_transform(offset) * rotation_transform(0.5 * PI * Vec3d::UnitY()) * scale_transform(scale)); + offset = Vec3d(-1.25 * size, grabber_y_shift, 0.0); + m_raycasters[id++]->set_transform(trafo * translation_transform(offset) * rotation_transform(-0.5 * PI * Vec3d::UnitY()) * scale_transform(scale)); + + const double xy_connection_len = 0.75 * m_grabber_connection_len; + const Vec3d cone_scale = Vec3d(0.5 * size, 0.5 * size, 1.8 * size); + + offset = xy_connection_len * Vec3d::UnitX() - 0.5 * size * Vec3d::Ones(); + m_raycasters[id++]->set_transform(trafo * translation_transform(offset) * scale_transform(size)); + offset = (size + xy_connection_len) * Vec3d::UnitX(); + m_raycasters[id++]->set_transform(trafo * translation_transform(offset) * rotation_transform(0.5 * PI * Vec3d::UnitY()) * scale_transform(cone_scale)); + + if (m_groove.angle > 0.0f) { + offset = xy_connection_len * Vec3d::UnitY() - 0.5 * size * Vec3d::Ones(); + m_raycasters[id++]->set_transform(trafo * translation_transform(offset) * scale_transform(size)); + offset = (size + xy_connection_len) * Vec3d::UnitY(); + m_raycasters[id++]->set_transform(trafo * translation_transform(offset) * rotation_transform(-0.5 * PI * Vec3d::UnitX()) * scale_transform(cone_scale)); + } + else { + // discard transformation for CutPlaneYMove grabbers + m_raycasters[id++]->set_transform(Transform3d::Identity()); + m_raycasters[id++]->set_transform(Transform3d::Identity()); + } + } + } +} + +void GLGizmoCut3D::update_plane_model() +{ + m_plane.reset(); + on_unregister_raycasters_for_picking(); + + init_picking_models(); +} + +void GLGizmoCut3D::on_set_hover_id() +{ +} + +bool GLGizmoCut3D::on_is_activable() const +{ + const Selection& selection = m_parent.get_selection(); + const int object_idx = selection.get_object_idx(); + if (object_idx < 0 || selection.is_wipe_tower()) + return false; + + if (const ModelObject* mo = wxGetApp().plater()->model().objects[object_idx]; + mo->is_cut() && mo->volumes.size() == 1) { + const ModelVolume* volume = mo->volumes[0]; + if (volume->is_cut_connector() && volume->cut_info.connector_type == CutConnectorType::Dowel) + return false; + } + + // This is assumed in GLCanvas3D::do_rotate, do not change this + // without updating that function too. + return selection.is_single_full_instance() && !m_parent.is_layers_editing_enabled(); +} + +bool GLGizmoCut3D::on_is_selectable() const +{ + return wxGetApp().get_mode() != comSimple; +} + +Vec3d GLGizmoCut3D::mouse_position_in_local_plane(GrabberID axis, const Linef3& mouse_ray) const +{ + double half_pi = 0.5 * PI; + + Transform3d m = Transform3d::Identity(); + + switch (axis) + { + case X: + { + m.rotate(Eigen::AngleAxisd(half_pi, Vec3d::UnitZ())); + m.rotate(Eigen::AngleAxisd(-half_pi, Vec3d::UnitY())); + break; + } + case Y: + { + m.rotate(Eigen::AngleAxisd(half_pi, Vec3d::UnitY())); + m.rotate(Eigen::AngleAxisd(half_pi, Vec3d::UnitZ())); + break; + } + case Z: + default: + { + // no rotation applied + break; + } + } + + m = m * m_start_dragging_m.inverse(); + m.translate(-m_plane_center); + + return transform(mouse_ray, m).intersect_plane(0.0); +} + +void GLGizmoCut3D::dragging_grabber_move(const GLGizmoBase::UpdateData &data) +{ + Vec3d starting_drag_position; + if (m_hover_id == Z) + starting_drag_position = translation_transform(m_plane_center) * m_rotation_m * (m_grabber_connection_len * Vec3d::UnitZ()); + else + starting_drag_position = m_cut_plane_start_move_pos; + + double projection = 0.0; + + Vec3d starting_vec = m_rotation_m * (m_hover_id == CutPlaneXMove ? Vec3d::UnitX() : m_hover_id == CutPlaneYMove ? Vec3d::UnitY() : Vec3d::UnitZ()); + if (starting_vec.norm() != 0.0) { + const Vec3d mouse_dir = data.mouse_ray.unit_vector(); + // finds the intersection of the mouse ray with the plane parallel to the camera viewport and passing through the starting position + // use ray-plane intersection see i.e. https://en.wikipedia.org/wiki/Line%E2%80%93plane_intersection algebraic form + // in our case plane normal and ray direction are the same (orthogonal view) + // when moving to perspective camera the negative z unit axis of the camera needs to be transformed in world space and used as plane normal + const Vec3d inters = data.mouse_ray.a + (starting_drag_position - data.mouse_ray.a).dot(mouse_dir) * mouse_dir; + // vector from the starting position to the found intersection + const Vec3d inters_vec = inters - starting_drag_position; + + starting_vec.normalize(); + // finds projection of the vector along the staring direction + projection = inters_vec.dot(starting_vec); + } + if (wxGetKeyState(WXK_SHIFT)) + projection = m_snap_step * std::round(projection / m_snap_step); + + const Vec3d shift = starting_vec * projection; + if (shift != Vec3d::Zero()) + reset_cut_by_contours(); + + // move cut plane center + set_center(m_plane_center + shift, true); + + m_was_cut_plane_dragged = true; +} + +void GLGizmoCut3D::dragging_grabber_rotation(const GLGizmoBase::UpdateData &data) +{ + const Vec2d mouse_pos = to_2d(mouse_position_in_local_plane((GrabberID)m_hover_id, data.mouse_ray)); + + const Vec2d orig_dir = Vec2d::UnitX(); + const Vec2d new_dir = mouse_pos.normalized(); + + const double two_pi = 2.0 * PI; + + double theta = ::acos(std::clamp(new_dir.dot(orig_dir), -1.0, 1.0)); + if (cross2(orig_dir, new_dir) < 0.0) + theta = two_pi - theta; + + const double len = mouse_pos.norm(); + // snap to coarse snap region + if (m_snap_coarse_in_radius <= len && len <= m_snap_coarse_out_radius) { + const double step = two_pi / double(SnapRegionsCount); + theta = step * std::round(theta / step); + } + // snap to fine snap region (scale) + else if (m_snap_fine_in_radius <= len && len <= m_snap_fine_out_radius) { + const double step = two_pi / double(ScaleStepsCount); + theta = step * std::round(theta / step); + } + + if (is_approx(theta, two_pi)) + theta = 0.0; + if (m_hover_id != Y) + theta += 0.5 * PI; + + if (!is_approx(theta, 0.0)) + reset_cut_by_contours(); + + Vec3d rotation = Vec3d::Zero(); + rotation[m_hover_id == CutPlaneZRotation ? Z : m_hover_id] = theta; + + const Transform3d rotation_tmp = m_start_dragging_m * rotation_transform(rotation); + const bool update_tbb = !m_rotation_m.rotation().isApprox(rotation_tmp.rotation()); + m_rotation_m = rotation_tmp; + if (update_tbb) + m_transformed_bounding_box = transformed_bounding_box(m_plane_center, m_rotation_m); + + m_angle = theta; + while (m_angle > two_pi) + m_angle -= two_pi; + if (m_angle < 0.0) + m_angle += two_pi; + + update_clipper(); +} + +void GLGizmoCut3D::dragging_connector(const GLGizmoBase::UpdateData &data) +{ + CutConnectors& connectors = m_c->selection_info()->model_object()->cut_connectors; + Vec3d pos; + Vec3d pos_world; + + if (unproject_on_cut_plane(data.mouse_pos.cast(), pos, pos_world)) { + connectors[m_hover_id - m_connectors_group_id].pos = pos; + update_raycasters_for_picking_transform(); + } +} + +void GLGizmoCut3D::on_dragging(const UpdateData& data) +{ + if (m_hover_id < 0) + return; + if (m_hover_id == Z || m_hover_id == CutPlane || m_hover_id == CutPlaneXMove || m_hover_id == CutPlaneYMove) + dragging_grabber_move(data); + else if (m_hover_id == X || m_hover_id == Y || m_hover_id == CutPlaneZRotation) + dragging_grabber_rotation(data); + else if (m_hover_id >= m_connectors_group_id && m_connector_mode == CutConnectorMode::Manual) + dragging_connector(data); + check_and_update_connectors_state(); + + if (CutMode(m_mode) == CutMode::cutTongueAndGroove) + reset_cut_by_contours(); +} + +void GLGizmoCut3D::on_start_dragging() +{ + m_angle = 0.0; + if (m_hover_id >= m_connectors_group_id && m_connector_mode == CutConnectorMode::Manual) + Plater::TakeSnapshot snapshot(wxGetApp().plater(), _u8L("Move connector"), UndoRedo::SnapshotType::GizmoAction); + + if (m_hover_id == X || m_hover_id == Y || m_hover_id == CutPlaneZRotation) + m_start_dragging_m = m_rotation_m; +} + +void GLGizmoCut3D::on_stop_dragging() +{ + if (m_hover_id == X || m_hover_id == Y || m_hover_id == CutPlaneZRotation) { + m_angle_arc.reset(); + m_angle = 0.0; + Plater::TakeSnapshot snapshot(wxGetApp().plater(), _u8L("Rotate cut plane"), UndoRedo::SnapshotType::GizmoAction); + m_start_dragging_m = m_rotation_m; + } + else if (m_hover_id == Z || m_hover_id == CutPlane || m_hover_id == CutPlaneXMove|| m_hover_id == CutPlaneYMove) { + if (m_was_cut_plane_dragged) + Plater::TakeSnapshot snapshot(wxGetApp().plater(), _u8L("Move cut plane"), UndoRedo::SnapshotType::GizmoAction); + m_ar_plane_center = m_plane_center; + } + + if (CutMode(m_mode) == CutMode::cutTongueAndGroove) + reset_cut_by_contours(); + //check_and_update_connectors_state(); +} + +void GLGizmoCut3D::set_center_pos(const Vec3d& center_pos, bool update_tbb /*=false*/) +{ + BoundingBoxf3 tbb = m_transformed_bounding_box; + if (update_tbb) { + Vec3d normal = m_rotation_m.inverse() * Vec3d(m_plane_center - center_pos); + tbb.translate(normal.z() * Vec3d::UnitZ()); + } + + bool can_set_center_pos = false; + { + double limit_val = /*CutMode(m_mode) == CutMode::cutTongueAndGroove ? 0.5 * double(m_groove.depth) : */0.5; + if (tbb.max.z() > -limit_val && tbb.min.z() < limit_val) + can_set_center_pos = true; + else { + const double old_dist = (m_bb_center - m_plane_center).norm(); + const double new_dist = (m_bb_center - center_pos).norm(); + // check if forcing is reasonable + if (new_dist < old_dist) + can_set_center_pos = true; + } + } + + if (can_set_center_pos) { + m_transformed_bounding_box = tbb; + m_plane_center = center_pos; + m_center_offset = m_plane_center - m_bb_center; + } +} + +BoundingBoxf3 GLGizmoCut3D::bounding_box() const +{ + BoundingBoxf3 ret; + const Selection& selection = m_parent.get_selection(); + const Selection::IndicesList& idxs = selection.get_volume_idxs(); + for (unsigned int i : idxs) { + const GLVolume* volume = selection.get_volume(i); + // respect just to the solid parts for FFF and ignore pad and supports for SLA + if (!volume->is_modifier && !volume->is_sla_pad() && !volume->is_sla_support()) + ret.merge(volume->transformed_convex_hull_bounding_box()); + } + return ret; +} + +BoundingBoxf3 GLGizmoCut3D::transformed_bounding_box(const Vec3d& plane_center, const Transform3d& rotation_m/* = Transform3d::Identity()*/) const +{ + const Selection& selection = m_parent.get_selection(); + + const auto first_volume = selection.get_first_volume(); + Vec3d instance_offset = first_volume->get_instance_offset(); + instance_offset[Z] += first_volume->get_sla_shift_z(); + + const auto cut_matrix = Transform3d::Identity() * rotation_m.inverse() * translation_transform(instance_offset - plane_center); + + const Selection::IndicesList& idxs = selection.get_volume_idxs(); + BoundingBoxf3 ret; + for (unsigned int i : idxs) { + const GLVolume* volume = selection.get_volume(i); + // respect just to the solid parts for FFF and ignore pad and supports for SLA + if (!volume->is_modifier && !volume->is_sla_pad() && !volume->is_sla_support()) { + + const auto instance_matrix = volume->get_instance_transformation().get_matrix(true); + auto volume_trafo = instance_matrix * volume->get_volume_transformation().get_matrix(); + ret.merge(volume->transformed_convex_hull_bounding_box(cut_matrix * volume_trafo)); + } + } + return ret; +} + +void GLGizmoCut3D::update_bb() +{ + const BoundingBoxf3 box = bounding_box(); + if (!box.defined) + return; + if (!m_max_pos.isApprox(box.max) || !m_min_pos.isApprox(box.min)) { + + m_bounding_box = box; + + // check, if mode is set to Planar, when object has a connectors + if (const int object_idx = m_parent.get_selection().get_object_idx(); + object_idx >= 0 && !wxGetApp().plater()->model().objects[object_idx]->cut_connectors.empty()) + m_mode = size_t(CutMode::cutPlanar); + + invalidate_cut_plane(); + reset_cut_by_contours(); + apply_color_clip_plane_colors(); + + m_max_pos = box.max; + m_min_pos = box.min; + m_bb_center = box.center(); + m_transformed_bounding_box = transformed_bounding_box(m_bb_center); + if (box.contains(m_center_offset)) + set_center_pos(m_bb_center + m_center_offset); + else + set_center_pos(m_bb_center); + + m_contour_width = CutMode(m_mode) == CutMode::cutTongueAndGroove ? 0.f : 0.4f; + + m_radius = box.radius(); + m_grabber_connection_len = 0.5 * m_radius;// std::min(0.75 * m_radius, 35.0); + m_grabber_radius = m_grabber_connection_len * 0.85; + + m_snap_coarse_in_radius = m_grabber_radius / 3.0; + m_snap_coarse_out_radius = m_snap_coarse_in_radius * 2.; + m_snap_fine_in_radius = m_grabber_connection_len * 0.85; + m_snap_fine_out_radius = m_grabber_connection_len * 1.15; + + // input params for cut with tongue and groove + m_groove.depth = m_groove.depth_init = std::max(1.f , 0.5f * float(get_grabber_mean_size(m_bounding_box))); + m_groove.width = m_groove.width_init = 4.0f * m_groove.depth; + m_groove.flaps_angle = m_groove.flaps_angle_init = float(PI) / 3.f; + m_groove.angle = m_groove.angle_init = 0.f; + m_plane.reset(); + m_cone.reset(); + m_sphere.reset(); + m_cube.reset(); + m_grabber_connection.reset(); + m_circle.reset(); + m_scale.reset(); + m_snap_radii.reset(); + m_reference_radius.reset(); + + on_unregister_raycasters_for_picking(); + + clear_selection(); + if (CommonGizmosDataObjects::SelectionInfo* selection = m_c->selection_info(); + selection && selection->model_object()) + m_selected.resize(selection->model_object()->cut_connectors.size(), false); + } +} + +void GLGizmoCut3D::init_picking_models() +{ + if (!m_cone.model.is_initialized()) { + indexed_triangle_set its = its_make_cone(1.0, 1.0, PI / 12.0); + m_cone.model.init_from(its); + m_cone.mesh_raycaster = std::make_unique(std::make_shared(std::move(its))); + } + if (!m_sphere.model.is_initialized()) { + indexed_triangle_set its = its_make_sphere(1.0, PI / 12.0); + m_sphere.model.init_from(its); + m_sphere.mesh_raycaster = std::make_unique(std::make_shared(std::move(its))); + } + if (!m_cube.model.is_initialized()) { + indexed_triangle_set its = its_make_cube(1., 1., 1.); + m_cube.model.init_from(its); + m_cube.mesh_raycaster = std::make_unique(std::make_shared(std::move(its))); + } + + if (!m_plane.model.is_initialized() && !m_hide_cut_plane && !m_connectors_editing) { + const double cp_width = 0.02 * get_grabber_mean_size(m_bounding_box); + indexed_triangle_set its = m_mode == size_t(CutMode::cutTongueAndGroove) ? its_make_groove_plane() : + its_make_frustum_dowel((double)m_cut_plane_radius_koef * m_radius, cp_width, m_cut_plane_as_circle ? 180 : 4); + + m_plane.model.init_from(its); + m_plane.mesh_raycaster = std::make_unique(std::make_shared(std::move(its))); + } + + if (m_shapes.empty()) + init_connector_shapes(); +} + +void GLGizmoCut3D::init_rendering_items() +{ + if (!m_grabber_connection.is_initialized()) + m_grabber_connection.init_from(its_make_line(Vec3f::Zero(), Vec3f::UnitZ())); + if (!m_circle.is_initialized()) + init_from_circle(m_circle, m_grabber_radius); + if (!m_scale.is_initialized()) + init_from_scale(m_scale, m_grabber_radius); + if (!m_snap_radii.is_initialized()) + init_from_snap_radii(m_snap_radii, m_grabber_radius); + if (!m_reference_radius.is_initialized()) { + m_reference_radius.init_from(its_make_line(Vec3f::Zero(), m_grabber_connection_len * Vec3f::UnitX())); + m_reference_radius.set_color(ColorRGBA::WHITE()); + } + if (!m_angle_arc.is_initialized() || m_angle != 0.0) + init_from_angle_arc(m_angle_arc, m_angle, m_grabber_connection_len); +} + +void GLGizmoCut3D::render_clipper_cut() +{ + if (! m_connectors_editing) + ::glDisable(GL_DEPTH_TEST); + + GLboolean cull_face = GL_FALSE; + ::glGetBooleanv(GL_CULL_FACE, &cull_face); + ::glDisable(GL_CULL_FACE); + m_c->object_clipper()->render_cut(m_part_selection.get_ignored_contours_ptr()); + if (cull_face) + ::glEnable(GL_CULL_FACE); + + if (! m_connectors_editing) + ::glEnable(GL_DEPTH_TEST); +} + +void GLGizmoCut3D::PartSelection::add_object(const ModelObject* object) +{ + m_model = Model(); + m_model.add_object(*object); + + const double sla_shift_z = wxGetApp().plater()->canvas3D()->get_selection().get_first_volume()->get_sla_shift_z(); + if (!is_approx(sla_shift_z, 0.)) { + Vec3d inst_offset = model_object()->instances[m_instance_idx]->get_offset(); + inst_offset[Z] += sla_shift_z; + model_object()->instances[m_instance_idx]->set_offset(inst_offset); + } +} + + +GLGizmoCut3D::PartSelection::PartSelection(const ModelObject* mo, const Transform3d& cut_matrix, int instance_idx_in, const Vec3d& center, const Vec3d& normal, const CommonGizmosDataObjects::ObjectClipper& oc) + : m_instance_idx(instance_idx_in) +{ + Cut cut(mo, instance_idx_in, cut_matrix); + add_object(cut.perform_with_plane().front()); + + const ModelVolumePtrs& volumes = model_object()->volumes; + + // split to parts + for (int id = int(volumes.size())-1; id >= 0; id--) + if (volumes[id]->is_splittable()) + volumes[id]->split(1); + + m_parts.clear(); + for (const ModelVolume* volume : volumes) { + assert(volume != nullptr); + m_parts.emplace_back(Part{GLModel(), MeshRaycaster(volume->mesh()), true, !volume->is_model_part()}); + m_parts.back().glmodel.set_color({ 0.f, 0.f, 1.f, 1.f }); + m_parts.back().glmodel.init_from(volume->mesh()); + + // Now check whether this part is below or above the plane. + Transform3d tr = (model_object()->instances[m_instance_idx]->get_matrix() * volume->get_matrix()).inverse(); + Vec3f pos = (tr * center).cast(); + Vec3f norm = (tr.linear().inverse().transpose() * normal).cast(); + for (const Vec3f& v : volume->mesh().its.vertices) { + double p = (v - pos).dot(norm); + if (std::abs(p) > EPSILON) { + m_parts.back().selected = p > 0.; + break; + } + } + } + + // Now go through the contours and create a map from contours to parts. + m_contour_points.clear(); + m_contour_to_parts.clear(); + m_debug_pts = std::vector>(m_parts.size(), std::vector()); + if (std::vector pts = oc.point_per_contour();! pts.empty()) { + + m_contour_to_parts.resize(pts.size()); + + for (size_t pt_idx=0; pt_idxinstances[m_instance_idx]->get_offset()) * translation_transform(model_object()->volumes[part_id]->get_offset())).inverse(); + for (double d : {-1., 1.}) { + const Vec3d dir_mesh = d * tr.linear().inverse().transpose() * normal; + const Vec3d src = tr * (m_contour_points[pt_idx] + d*0.01 * normal); + AABBMesh::hit_result hit = aabb.query_ray_hit(src, dir_mesh); + + m_debug_pts[part_id].emplace_back(src); + + if (hit.is_inside()) { + // This part belongs to this point. + if (d == 1.) + m_contour_to_parts[pt_idx].first.emplace_back(part_id); + else + m_contour_to_parts[pt_idx].second.emplace_back(part_id); + } + } + } + } + + } + + + m_valid = true; +} + +// In CutMode::cutTongueAndGroove we use PartSelection just for rendering +GLGizmoCut3D::PartSelection::PartSelection(const ModelObject* object, int instance_idx_in) + : m_instance_idx (instance_idx_in) +{ + add_object(object); + + m_parts.clear(); + + for (const ModelVolume* volume : object->volumes) { + assert(volume != nullptr); + m_parts.emplace_back(Part{ GLModel(), MeshRaycaster(volume->mesh()), true, !volume->is_model_part() }); + m_parts.back().glmodel.init_from(volume->mesh()); + + // Now check whether this part is below or above the plane. + m_parts.back().selected = volume->is_from_upper(); + } + + m_valid = true; +} + +void GLGizmoCut3D::PartSelection::render(const Vec3d* normal, GLModel& sphere_model) +{ + if (! valid()) + return; + + const Camera& camera = wxGetApp().plater()->get_camera(); + + if (GLShaderProgram* shader = wxGetApp().get_shader("gouraud_light")) { + shader->start_using(); + shader->set_uniform("projection_matrix", camera.get_projection_matrix()); + shader->set_uniform("emission_factor", 0.f); + + // FIXME: Cache the transforms. + + const Vec3d inst_offset = model_object()->instances[m_instance_idx]->get_offset(); + const Transform3d view_inst_matrix= camera.get_view_matrix() * translation_transform(inst_offset); + + const bool is_looking_forward = normal && camera.get_dir_forward().dot(*normal) < 0.05; + + for (size_t id=0; idset_uniform("view_model_matrix", view_inst_matrix * model_object()->volumes[id]->get_matrix()); + if (m_parts[id].is_modifier) { + glsafe(::glEnable(GL_BLEND)); + glsafe(::glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)); + } + m_parts[id].glmodel.set_color(m_parts[id].is_modifier ? MODIFIER_COLOR : (m_parts[id].selected ? UPPER_PART_COLOR : LOWER_PART_COLOR)); + m_parts[id].glmodel.render(); + if (m_parts[id].is_modifier) + glsafe(::glDisable(GL_BLEND)); + } + + shader->stop_using(); + } + + + + // { // Debugging render: + + // static int idx = -1; + // ImGui::Begin("DEBUG"); + // for (int i=0; i= m_parts.size()) + // idx = -1; + // ImGui::End(); + + // ::glDisable(GL_DEPTH_TEST); + // if (valid()) { + // for (size_t i=0; i GLGizmoCut3D::PartSelection::get_cut_parts() +{ + std::vector parts; + + for (const auto& part : m_parts) + parts.push_back({part.selected, part.is_modifier}); + + return parts; +} + + +void GLGizmoCut3D::PartSelection::toggle_selection(const Vec2d& mouse_pos) +{ + // FIXME: Cache the transforms. + const Camera& camera = wxGetApp().plater()->get_camera(); + const Vec3d& camera_pos = camera.get_position(); + + Vec3f pos; + Vec3f normal; + + std::vector> hits_id_and_sqdist; + + for (size_t id=0; idvolumes[id]->get_offset(); + Transform3d tr = translation_transform(model_object()->instances[m_instance_idx]->get_offset()) * translation_transform(model_object()->volumes[id]->get_offset()); + if (m_parts[id].raycaster.unproject_on_mesh(mouse_pos, tr, camera, pos, normal)) { + hits_id_and_sqdist.emplace_back(id, (camera_pos - tr*(pos.cast())).squaredNorm()); + } + } + if (! hits_id_and_sqdist.empty()) { + size_t id = std::min_element(hits_id_and_sqdist.begin(), hits_id_and_sqdist.end(), + [](const std::pair& a, const std::pair& b) { return a.second < b.second; })->first; + m_parts[id].selected = ! m_parts[id].selected; + + // And now recalculate the contours which should be ignored. + m_ignored_contours.clear(); + size_t cont_id = 0; + for (const auto& [parts_above, parts_below] : m_contour_to_parts) { + for (size_t upper : parts_above) { + bool upper_sel = m_parts[upper].selected; + if (std::find_if(parts_below.begin(), parts_below.end(), [this, &upper_sel](const size_t& i) { return m_parts[i].selected == upper_sel; }) != parts_below.end()) { + m_ignored_contours.emplace_back(cont_id); + break; + } + } + ++cont_id; + } + } +} + +void GLGizmoCut3D::PartSelection::turn_over_selection() +{ + for (Part& part : m_parts) + part.selected = !part.selected; +} + +void GLGizmoCut3D::on_render() +{ + if (m_state == On) { + // This gizmo is showing the object elevated. Tell the common + // SelectionInfo object to lie about the actual shift. + //m_c->selection_info()->set_use_shift(true); + } + + // check objects visibility + toggle_model_objects_visibility(); + + update_clipper(); + + init_picking_models(); + + init_rendering_items(); + + render_connectors(); + + if (!m_connectors_editing) + m_part_selection.render(nullptr, m_sphere.model); + else + m_part_selection.render(&m_cut_normal, m_sphere.model); + + render_clipper_cut(); + + if (!m_hide_cut_plane && !m_connectors_editing) { + render_cut_plane(); + render_cut_plane_grabbers(); + } + + render_cut_line(); + + m_selection_rectangle.render(m_parent); +} + +void GLGizmoCut3D::render_debug_input_window(float x) +{ + return; + m_imgui->begin(wxString("DEBUG")); + + m_imgui->end(); +/* + static bool hide_clipped = false; + static bool fill_cut = false; + static float contour_width = 0.4f; + + m_imgui->checkbox(_L("Hide cut plane and grabbers"), m_hide_cut_plane); + if (m_imgui->checkbox("hide_clipped", hide_clipped) && !hide_clipped) + m_clp_normal = m_c->object_clipper()->get_clipping_plane()->get_normal(); + m_imgui->checkbox("fill_cut", fill_cut); + m_imgui->slider_float("contour_width", &contour_width, 0.f, 3.f); + if (auto oc = m_c->object_clipper()) + oc->set_behavior(hide_clipped || m_connectors_editing, fill_cut || m_connectors_editing, double(contour_width)); +*/ + ImGui::PushItemWidth(0.5f * m_label_width); + if (auto oc = m_c->object_clipper(); oc && m_imgui->slider_float("contour_width", &m_contour_width, 0.f, 3.f)) + oc->set_behavior(m_connectors_editing, m_connectors_editing, double(m_contour_width)); + + ImGui::Separator(); + + if (m_imgui->checkbox(("Render cut plane as disc"), m_cut_plane_as_circle)) + m_plane.reset(); + + ImGui::PushItemWidth(0.5f * m_label_width); + if (m_imgui->slider_float("cut_plane_radius_koef", &m_cut_plane_radius_koef, 1.f, 2.f)) + m_plane.reset(); + + m_imgui->end(); +} + +void GLGizmoCut3D::adjust_window_position(float x, float y, float bottom_limit) +{ + static float last_y = 0.0f; + static float last_h = 0.0f; + + const float win_h = ImGui::GetWindowHeight(); + y = std::min(y, bottom_limit - win_h); + + ImGui::SetWindowPos(ImVec2(x, y), ImGuiCond_Always); + + if (!is_approx(last_h, win_h) || !is_approx(last_y, y)) { + // ask canvas for another frame to render the window in the correct position + m_imgui->set_requires_extra_frame(); + if (!is_approx(last_h, win_h)) + last_h = win_h; + if (!is_approx(last_y, y)) + last_y = y; + } +} + +void GLGizmoCut3D::unselect_all_connectors() +{ + std::fill(m_selected.begin(), m_selected.end(), false); + m_selected_count = 0; + validate_connector_settings(); +} + +void GLGizmoCut3D::select_all_connectors() +{ + std::fill(m_selected.begin(), m_selected.end(), true); + m_selected_count = int(m_selected.size()); +} + +void GLGizmoCut3D::render_shortcuts() +{ + if (m_imgui->button("? " + (m_show_shortcuts ? wxString(ImGui::CollapseBtn) : wxString(ImGui::ExpandBtn)))) + m_show_shortcuts = !m_show_shortcuts; + + if (m_shortcut_label_width < 0.f) { + for (const auto& shortcut : m_shortcuts) { + const float width = m_imgui->calc_text_size(shortcut.first).x; + if (m_shortcut_label_width < width) + m_shortcut_label_width = width; + } + m_shortcut_label_width += +m_imgui->scaled(1.f); + } + + if (m_show_shortcuts) + for (const auto&shortcut : m_shortcuts ){ + m_imgui->text_colored(ImGuiWrapper::COL_ORANGE_LIGHT, shortcut.first); + ImGui::SameLine(m_shortcut_label_width); + m_imgui->text(shortcut.second); + } +} + +void GLGizmoCut3D::apply_selected_connectors(std::function apply_fn) +{ + for (size_t idx = 0; idx < m_selected.size(); idx++) + if (m_selected[idx]) + apply_fn(idx); + check_and_update_connectors_state(); + update_raycasters_for_picking_transform(); +} + +void GLGizmoCut3D::render_connectors_input_window(CutConnectors &connectors) +{ + // add shortcuts panel + render_shortcuts(); + + // Connectors section + + ImGui::Separator(); + + // WIP : Auto : Need to implement + // m_imgui->text(_L("Mode")); + // render_connect_mode_radio_button(CutConnectorMode::Auto); + // render_connect_mode_radio_button(CutConnectorMode::Manual); + + ImGui::AlignTextToFramePadding(); + m_imgui->text_colored(ImGuiWrapper::COL_ORANGE_LIGHT, m_labels_map["Connectors"]); + + m_imgui->disabled_begin(connectors.empty()); + ImGui::SameLine(m_label_width); + const std::string act_name = _u8L("Remove connectors"); + if (render_reset_button("connectors", act_name)) { + Plater::TakeSnapshot snapshot(wxGetApp().plater(), act_name, UndoRedo::SnapshotType::GizmoAction); + reset_connectors(); + } + m_imgui->disabled_end(); + + render_flip_plane_button(m_connectors_editing && connectors.empty()); + + m_imgui->text(m_labels_map["Type"]); + bool type_changed = render_connect_type_radio_button(CutConnectorType::Plug); + type_changed |= render_connect_type_radio_button(CutConnectorType::Dowel); + type_changed |= render_connect_type_radio_button(CutConnectorType::Snap); + if (type_changed) + apply_selected_connectors([this, &connectors] (size_t idx) { connectors[idx].attribs.type = CutConnectorType(m_connector_type); }); + + m_imgui->disabled_begin(m_connector_type != CutConnectorType::Plug); + if (type_changed && m_connector_type == CutConnectorType::Dowel) { + m_connector_style = int(CutConnectorStyle::Prism); + apply_selected_connectors([this, &connectors](size_t idx) { connectors[idx].attribs.style = CutConnectorStyle(m_connector_style); }); + } + if (render_combo(m_labels_map["Style"], m_connector_styles, m_connector_style)) + apply_selected_connectors([this, &connectors](size_t idx) { connectors[idx].attribs.style = CutConnectorStyle(m_connector_style); }); + m_imgui->disabled_end(); + + m_imgui->disabled_begin(m_connector_type == CutConnectorType::Snap); + if (type_changed && m_connector_type == CutConnectorType::Snap) { + m_connector_shape_id = int(CutConnectorShape::Circle); + apply_selected_connectors([this, &connectors](size_t idx) { connectors[idx].attribs.shape = CutConnectorShape(m_connector_shape_id); }); + } + if (render_combo(m_labels_map["Shape"], m_connector_shapes, m_connector_shape_id)) + apply_selected_connectors([this, &connectors](size_t idx) { connectors[idx].attribs.shape = CutConnectorShape(m_connector_shape_id); }); + m_imgui->disabled_end(); + + const float depth_min_value = m_connector_type == CutConnectorType::Snap ? m_connector_size : -0.1f; + if (render_slider_double_input(m_labels_map["Depth"], m_connector_depth_ratio, m_connector_depth_ratio_tolerance, depth_min_value)) + apply_selected_connectors([this, &connectors](size_t idx) { + if (m_connector_depth_ratio > 0) + connectors[idx].height = m_connector_depth_ratio; + if (m_connector_depth_ratio_tolerance >= 0) + connectors[idx].height_tolerance = m_connector_depth_ratio_tolerance; + }); + + if (render_slider_double_input(m_labels_map["Size"], m_connector_size, m_connector_size_tolerance)) + apply_selected_connectors([this, &connectors](size_t idx) { + if (m_connector_size > 0) + connectors[idx].radius = 0.5f * m_connector_size; + if (m_connector_size_tolerance >= 0) + connectors[idx].radius_tolerance = 0.5f * m_connector_size_tolerance; + }); + + if (render_angle_input(m_labels_map["Rotation"], m_connector_angle, 0.f, 0.f, 180.f)) + apply_selected_connectors([this, &connectors](size_t idx) { + connectors[idx].z_angle = m_connector_angle; + }); + + if (m_connector_type == CutConnectorType::Snap) { + render_snap_specific_input(_u8L("Bulge"), _L("Bulge proportion related to radius"), m_snap_bulge_proportion, 0.15f, 5.f, 100.f * m_snap_space_proportion); + render_snap_specific_input(_u8L("Space"), _L("Space proportion related to radius"), m_snap_space_proportion, 0.3f, 10.f, 50.f); + } + + ImGui::Separator(); + + if (m_imgui->button(_L("Confirm connectors"))) { + unselect_all_connectors(); + set_connectors_editing(false); + } + + ImGui::SameLine(m_label_width + 1.15f * m_control_width); + + if (m_imgui->button(_L("Cancel"))) { + reset_connectors(); + set_connectors_editing(false); + } +} + +void GLGizmoCut3D::render_build_size() +{ + double koef = m_imperial_units ? GizmoObjectManipulation::mm_to_in : 1.0; + wxString unit_str = " " + (m_imperial_units ? _L("in") : _L("mm")); + + Vec3d tbb_sz = m_transformed_bounding_box.size(); + wxString size = "X: " + double_to_string(tbb_sz.x() * koef, 2) + unit_str + + ", Y: " + double_to_string(tbb_sz.y() * koef, 2) + unit_str + + ", Z: " + double_to_string(tbb_sz.z() * koef, 2) + unit_str; + + ImGui::AlignTextToFramePadding(); + m_imgui->text(_L("Build Volume")); + ImGui::SameLine(); + m_imgui->text_colored(ImGuiWrapper::COL_ORANGE_LIGHT, size); +} + +void GLGizmoCut3D::reset_cut_plane() +{ + m_angle_arc.reset(); + m_transformed_bounding_box = transformed_bounding_box(m_bb_center); + set_center(m_bb_center); + m_start_dragging_m = m_rotation_m = Transform3d::Identity(); + m_ar_plane_center = m_plane_center; + + reset_cut_by_contours(); + m_parent.request_extra_frame(); +} + +void GLGizmoCut3D::invalidate_cut_plane() +{ + m_rotation_m = Transform3d::Identity(); + m_plane_center = Vec3d::Zero(); + m_min_pos = Vec3d::Zero(); + m_max_pos = Vec3d::Zero(); + m_bb_center = Vec3d::Zero(); + m_center_offset = Vec3d::Zero(); +} + +void GLGizmoCut3D::set_connectors_editing(bool connectors_editing) +{ + if (m_connectors_editing == connectors_editing) + return; + + m_connectors_editing = connectors_editing; + update_raycasters_for_picking(); + + m_c->object_clipper()->set_behavior(m_connectors_editing, m_connectors_editing, double(m_contour_width)); + + m_parent.request_extra_frame(); +} + +void GLGizmoCut3D::flip_cut_plane() +{ + m_rotation_m = m_rotation_m * rotation_transform(PI * Vec3d::UnitX()); + m_transformed_bounding_box = transformed_bounding_box(m_plane_center, m_rotation_m); + + Plater::TakeSnapshot snapshot(wxGetApp().plater(), _u8L("Flip cut plane"), UndoRedo::SnapshotType::GizmoAction); + m_start_dragging_m = m_rotation_m; + + update_clipper(); + m_part_selection.turn_over_selection(); + + if (CutMode(m_mode) == CutMode::cutTongueAndGroove) + reset_cut_by_contours(); +} + +void GLGizmoCut3D::reset_cut_by_contours() +{ + m_part_selection = PartSelection(); + + if (CutMode(m_mode) == CutMode::cutTongueAndGroove) { + if (m_dragging || m_groove_editing || !has_valid_groove()) + return; + process_contours(); + } + else + toggle_model_objects_visibility(); +} + +void GLGizmoCut3D::process_contours() +{ + const Selection& selection = m_parent.get_selection(); + const ModelObjectPtrs& model_objects = selection.get_model()->objects; + + const int instance_idx = selection.get_instance_idx(); + if (instance_idx < 0) + return; + const int object_idx = selection.get_object_idx(); + + wxBusyCursor wait; + + if (CutMode(m_mode) == CutMode::cutTongueAndGroove) { + if (has_valid_groove()) { + Cut cut(model_objects[object_idx], instance_idx, get_cut_matrix(selection)); + const ModelObjectPtrs& new_objects = cut.perform_with_groove(m_groove, m_rotation_m, true); + if (!new_objects.empty()) + m_part_selection = PartSelection(new_objects.front(), instance_idx); + } + } + else { + reset_cut_by_contours(); + m_part_selection = PartSelection(model_objects[object_idx], get_cut_matrix(selection), instance_idx, m_plane_center, m_cut_normal, *m_c->object_clipper()); + } + + toggle_model_objects_visibility(); +} + +void GLGizmoCut3D::render_flip_plane_button(bool disable_pred /*=false*/) +{ + ImGui::SameLine(); + + if (m_hover_id == CutPlane) + ImGui::PushStyleColor(ImGuiCol_Button, ImGui::GetColorU32(ImGuiCol_ButtonHovered)); + + m_imgui->disabled_begin(disable_pred); + if (m_imgui->button(_L("Flip cut plane"))) + flip_cut_plane(); + m_imgui->disabled_end(); + + if (m_hover_id == CutPlane) + ImGui::PopStyleColor(); +} + +void GLGizmoCut3D::add_vertical_scaled_interval(float interval) +{ + ImGui::GetCurrentWindow()->DC.CursorPos.y += m_imgui->scaled(interval); +} + +void GLGizmoCut3D::add_horizontal_scaled_interval(float interval) +{ + ImGui::GetCurrentWindow()->DC.CursorPos.x += m_imgui->scaled(interval); +} + +void GLGizmoCut3D::add_horizontal_shift(float shift) +{ + ImGui::GetCurrentWindow()->DC.CursorPos.x += shift; +} + +void GLGizmoCut3D::render_color_marker(float size, const ImU32& color) +{ + ImGui::SameLine(); + const float radius = 0.5f * size; + ImVec2 pos = ImGui::GetCurrentWindow()->DC.CursorPos; + pos.x += size; + pos.y += 1.25f * radius; + ImGui::GetCurrentWindow()->DrawList->AddNgonFilled(pos, radius, color, 6); + m_imgui->text(" "); +} + +void GLGizmoCut3D::render_groove_float_input(const std::string& label, float& in_val, const float& init_val, float& in_tolerance) +{ + bool is_changed{false}; + + float val = in_val; + float tolerance = in_tolerance; + if (render_slider_double_input(label, val, tolerance, -0.1f, std::min(0.3f*in_val, 1.5f))) { + if (m_imgui->get_last_slider_status().can_take_snapshot) { + Plater::TakeSnapshot snapshot(wxGetApp().plater(), GUI::format("%1%: %2%", _u8L("Groove change"), label), UndoRedo::SnapshotType::GizmoAction); + m_imgui->get_last_slider_status().invalidate_snapshot(); + m_groove_editing = true; + } + in_val = val; + in_tolerance = tolerance; + is_changed = true; + } + + ImGui::SameLine(); + + m_imgui->disabled_begin(is_approx(in_val, init_val) && is_approx(in_tolerance, 0.1f)); + const std::string act_name = _u8L("Reset"); + if (render_reset_button(("##groove_" + label + act_name).c_str(), act_name)) { + Plater::TakeSnapshot snapshot(wxGetApp().plater(), GUI::format("%1%: %2%", act_name, label), UndoRedo::SnapshotType::GizmoAction); + in_val = init_val; + in_tolerance = 0.1f; + is_changed = true; + } + m_imgui->disabled_end(); + + if (is_changed) { + update_plane_model(); + reset_cut_by_contours(); + } + + if (m_is_slider_editing_done) { + m_groove_editing = false; + reset_cut_by_contours(); + } +} + +bool GLGizmoCut3D::render_angle_input(const std::string& label, float& in_val, const float& init_val, float min_val, float max_val) +{ + bool is_changed{ false }; + + m_imgui->text(label); + + ImGui::SameLine(m_label_width); + ImGui::PushItemWidth(m_control_width * 0.7f); + + float val = rad2deg(in_val); + const float old_val = val; + + const std::string format = "%.0f " + _u8L("°"); + m_imgui->slider_float(("##angle_" + label).c_str(), &val, min_val, max_val, format.c_str(), 1.f, true, from_u8(label)); + + m_is_slider_editing_done |= m_imgui->get_last_slider_status().deactivated_after_edit; + if (!is_approx(old_val, val)) { + if (m_imgui->get_last_slider_status().can_take_snapshot) { + // TRN: This is an entry in the Undo/Redo stack. The whole line will be 'Edited: (name of whatever was edited)'. + Plater::TakeSnapshot snapshot(wxGetApp().plater(), GUI::format("%1%: %2%", _L("Edited"), label), UndoRedo::SnapshotType::GizmoAction); + m_imgui->get_last_slider_status().invalidate_snapshot(); + if (m_mode == size_t(CutMode::cutTongueAndGroove)) + m_groove_editing = true; + } + in_val = deg2rad(val); + is_changed = true; + } + + ImGui::SameLine(); + + m_imgui->disabled_begin(is_approx(in_val, init_val)); + const std::string act_name = _u8L("Reset"); + if (render_reset_button(("##angle_" + label + act_name).c_str(), act_name)) { + Plater::TakeSnapshot snapshot(wxGetApp().plater(), GUI::format("%1%: %2%", act_name, label), UndoRedo::SnapshotType::GizmoAction); + in_val = init_val; + is_changed = true; + } + m_imgui->disabled_end(); + + return is_changed; +} + +void GLGizmoCut3D::render_groove_angle_input(const std::string& label, float& in_val, const float& init_val, float min_val, float max_val) +{ + if (render_angle_input(label, in_val, init_val, min_val, max_val)) { + update_plane_model(); + reset_cut_by_contours(); + } + + if (m_is_slider_editing_done) { + m_groove_editing = false; + reset_cut_by_contours(); + } +} + +void GLGizmoCut3D::render_snap_specific_input(const std::string& label, const wxString& tooltip, float& in_val, const float& init_val, const float min_val, const float max_val) +{ + m_imgui->text(label); + + ImGui::SameLine(m_label_width); + ImGui::PushItemWidth(m_control_width * 0.7f); + + bool is_changed = false; + const std::string format = "%.0f %%"; + + float val = in_val * 100.f; + if (m_imgui->slider_float(("##snap_" + label).c_str(), &val, min_val, max_val, format.c_str(), 1.f, true, tooltip)) { + in_val = val * 0.01f; + is_changed = true; + } + + ImGui::SameLine(); + + m_imgui->disabled_begin(is_approx(in_val, init_val)); + const std::string act_name = _u8L("Reset"); + if (render_reset_button(("##snap_" + label + act_name).c_str(), act_name)) { + in_val = init_val; + is_changed = true; + } + m_imgui->disabled_end(); + + if (is_changed) { + update_connector_shape(); + update_raycasters_for_picking(); + } +} + +void GLGizmoCut3D::render_cut_plane_input_window(CutConnectors &connectors) +{ +// if (m_mode == size_t(CutMode::cutPlanar)) { + CutMode mode = CutMode(m_mode); + if (mode == CutMode::cutPlanar || mode == CutMode::cutTongueAndGroove) { + ImGui::AlignTextToFramePadding(); + m_imgui->text(wxString(ImGui::InfoMarkerSmall)); + ImGui::SameLine(); + m_imgui->text_colored(ImGuiWrapper::COL_ORANGE_LIGHT, + get_wraped_wxString(_L("Hold SHIFT key to draw a cut line"), 40)); + ImGui::Separator(); + + const bool has_connectors = !connectors.empty(); + + m_imgui->disabled_begin(has_connectors); + if (render_cut_mode_combo()) + mode = CutMode(m_mode); + m_imgui->disabled_end(); + + render_build_size(); + + ImGui::AlignTextToFramePadding(); + m_imgui->text(_L("Cut position") + ": "); + ImGui::SameLine(); + render_move_center_input(Z); + ImGui::SameLine(); + + const bool is_cut_plane_init = m_rotation_m.isApprox(Transform3d::Identity()) && m_bb_center.isApprox(m_plane_center); + m_imgui->disabled_begin(is_cut_plane_init); + std::string act_name = _u8L("Reset cutting plane"); + if (render_reset_button("cut_plane", into_u8(act_name))) { + Plater::TakeSnapshot snapshot(wxGetApp().plater(), act_name, UndoRedo::SnapshotType::GizmoAction); + reset_cut_plane(); + } + m_imgui->disabled_end(); + +// render_flip_plane_button(); + + if (mode == CutMode::cutPlanar) { + add_vertical_scaled_interval(0.75f); + + m_imgui->disabled_begin(!m_keep_upper || !m_keep_lower || m_keep_as_parts || (m_part_selection.valid() && m_part_selection.is_one_object())); + if (m_imgui->button(has_connectors ? _L("Edit connectors") : _L("Add connectors"))) + set_connectors_editing(true); + m_imgui->disabled_end(); + + ImGui::SameLine(1.5f * m_control_width); + + m_imgui->disabled_begin(is_cut_plane_init && !has_connectors); + act_name = _u8L("Reset cut"); + if (m_imgui->button(act_name, _u8L("Reset cutting plane and remove connectors"))) { + Plater::TakeSnapshot snapshot(wxGetApp().plater(), act_name, UndoRedo::SnapshotType::GizmoAction); + reset_cut_plane(); + reset_connectors(); + } + m_imgui->disabled_end(); + } + else if (mode == CutMode::cutTongueAndGroove) { + m_is_slider_editing_done = false; + ImGui::Separator(); + m_imgui->text_colored(ImGuiWrapper::COL_ORANGE_LIGHT, m_labels_map["Groove"] + ": "); + render_groove_float_input(m_labels_map["Depth"], m_groove.depth, m_groove.depth_init, m_groove.depth_tolerance); + render_groove_float_input(m_labels_map["Width"], m_groove.width, m_groove.width_init, m_groove.width_tolerance); + render_groove_angle_input(m_labels_map["Flap Angle"], m_groove.flaps_angle, m_groove.flaps_angle_init, 30.f, 120.f); + render_groove_angle_input(m_labels_map["Groove Angle"], m_groove.angle, m_groove.angle_init, 0.f, 15.f); + } + + ImGui::Separator(); + + // render "After Cut" section + + ImVec2 label_size; + for (const auto& item : m_part_orientation_names) { + const ImVec2 text_size = m_imgui->calc_text_size(item.second); + if (label_size.x < text_size.x) + label_size.x = text_size.x; + if (label_size.y < text_size.y) + label_size.y = text_size.y; + } + const float h_shift = label_size.x + m_imgui->scaled(3.f); + const float marker_size = label_size.y; + + auto render_part_name = [this, marker_size, has_connectors](const wxString& name, bool& keep_part, const ImU32& color) { + bool keep = true; + add_horizontal_shift(m_imgui->scaled(1.2f)); + m_imgui->checkbox((m_keep_as_parts ? _L("Part") : _L("Object")) + " " + name, has_connectors ? keep : keep_part); + render_color_marker(marker_size, color); + }; + + auto render_part_actions = [this, h_shift] (const wxString& suffix, const bool& keep_part, bool& place_on_cut_part, bool& rotate_part) + { + float shift = m_imgui->scaled(1.2f); + if (suffix == "##lower") + shift += h_shift; + m_imgui->disabled_begin(!keep_part || m_keep_as_parts); + add_horizontal_shift(shift); + if (m_imgui->radio_button(m_part_orientation_names.at("none") + suffix, !place_on_cut_part && !rotate_part)) { + rotate_part = false; + place_on_cut_part = false; + } + + add_horizontal_shift(shift); + if (m_imgui->radio_button(m_part_orientation_names.at("on_cut") + suffix, place_on_cut_part)) { + place_on_cut_part = !place_on_cut_part; + rotate_part = false; + } + + add_horizontal_shift(shift); + if (m_imgui->radio_button(m_part_orientation_names.at("flip") + suffix, rotate_part)) { + rotate_part = !rotate_part; + place_on_cut_part = false; + } + m_imgui->disabled_end(); + }; + + m_imgui->text(_L("Cut result") + ": "); + add_vertical_scaled_interval(0.5f); + + m_imgui->disabled_begin(has_connectors || m_keep_as_parts); + render_part_name("A", m_keep_upper, m_imgui->to_ImU32(UPPER_PART_COLOR)); + ImGui::SameLine(h_shift + ImGui::GetCurrentWindow()->WindowPadding.x); + render_part_name("B", m_keep_lower, m_imgui->to_ImU32(LOWER_PART_COLOR)); + m_imgui->disabled_end(); + + add_vertical_scaled_interval(0.5f); + + const ImVec2 pos = ImGui::GetCurrentWindow()->DC.CursorPos; + render_part_actions("##upper", m_keep_upper, m_place_on_cut_upper, m_rotate_upper); + + ImGui::GetCurrentWindow()->DC.CursorPos = pos; + render_part_actions("##lower", m_keep_lower, m_place_on_cut_lower, m_rotate_lower); + + add_vertical_scaled_interval(0.75f); + + m_imgui->disabled_begin(has_connectors || m_part_selection.valid() || mode == CutMode::cutTongueAndGroove); + m_imgui->text(_L("Cut into") + ":"); + + if (m_part_selection.valid()) + m_keep_as_parts = false; + + add_horizontal_scaled_interval(1.2f); + // TRN CutGizmo: RadioButton Cut into ... + if (m_imgui->radio_button(_L("Objects"), !m_keep_as_parts)) + m_keep_as_parts = false; + ImGui::SameLine(); + // TRN CutGizmo: RadioButton Cut into ... + if (m_imgui->radio_button(_L("Parts"), m_keep_as_parts)) + m_keep_as_parts = true; + + if (m_keep_as_parts) { + m_keep_upper = m_keep_lower = true; + m_place_on_cut_upper = m_place_on_cut_lower = false; + m_rotate_upper = m_rotate_lower = false; + } + m_imgui->disabled_end(); + } + + ImGui::Separator(); + + m_imgui->disabled_begin(!can_perform_cut()); + if(m_imgui->button(_L("Perform cut"))) + perform_cut(m_parent.get_selection()); + m_imgui->disabled_end(); +} + +void GLGizmoCut3D::validate_connector_settings() +{ + if (m_connector_depth_ratio < 0.f) + m_connector_depth_ratio = 3.f; + if (m_connector_depth_ratio_tolerance < 0.f) + m_connector_depth_ratio_tolerance = 0.1f; + if (m_connector_size < 0.f) + m_connector_size = 2.5f; + if (m_connector_size_tolerance < 0.f) + m_connector_size_tolerance = 0.f; + if (m_connector_angle < 0.f || m_connector_angle > float(PI) ) + m_connector_angle = 0.f; + + if (m_connector_type == CutConnectorType::Undef) + m_connector_type = CutConnectorType::Plug; + if (m_connector_style == int(CutConnectorStyle::Undef)) + m_connector_style = int(CutConnectorStyle::Prism); + if (m_connector_shape_id == int(CutConnectorShape::Undef)) + m_connector_shape_id = int(CutConnectorShape::Circle); +} + +void GLGizmoCut3D::init_input_window_data(CutConnectors &connectors) +{ + m_imperial_units = wxGetApp().app_config->get_bool("use_inches"); + m_control_width = m_imgui->get_font_size() * 9.f; + + if (m_connectors_editing && m_selected_count > 0) { + float depth_ratio { UndefFloat }; + float depth_ratio_tolerance { UndefFloat }; + float radius { UndefFloat }; + float radius_tolerance { UndefFloat }; + float angle { UndefFloat }; + CutConnectorType type { CutConnectorType::Undef }; + CutConnectorStyle style { CutConnectorStyle::Undef }; + CutConnectorShape shape { CutConnectorShape::Undef }; + + bool is_init = false; + for (size_t idx = 0; idx < m_selected.size(); idx++) + if (m_selected[idx]) { + const CutConnector& connector = connectors[idx]; + if (!is_init) { + depth_ratio = connector.height; + depth_ratio_tolerance = connector.height_tolerance; + radius = connector.radius; + radius_tolerance = connector.radius_tolerance; + angle = connector.z_angle; + type = connector.attribs.type; + style = connector.attribs.style; + shape = connector.attribs.shape; + + if (m_selected_count == 1) + break; + is_init = true; + } + else { + if (!is_approx(depth_ratio, connector.height)) + depth_ratio = UndefFloat; + if (!is_approx(depth_ratio_tolerance, connector.height_tolerance)) + depth_ratio_tolerance = UndefFloat; + if (!is_approx(radius,connector.radius)) + radius = UndefFloat; + if (!is_approx(radius_tolerance, connector.radius_tolerance)) + radius_tolerance = UndefFloat; + if (!is_approx(angle, connector.z_angle)) + angle = UndefFloat; + + if (type != connector.attribs.type) + type = CutConnectorType::Undef; + if (style != connector.attribs.style) + style = CutConnectorStyle::Undef; + if (shape != connector.attribs.shape) + shape = CutConnectorShape::Undef; + } + } + + m_connector_depth_ratio = depth_ratio; + m_connector_depth_ratio_tolerance = depth_ratio_tolerance; + m_connector_size = 2.f * radius; + m_connector_size_tolerance = 2.f * radius_tolerance; + m_connector_type = type; + m_connector_angle = angle; + m_connector_style = int(style); + m_connector_shape_id = int(shape); + } + + if (m_label_width == 0.f) { + for (const auto& item : m_labels_map) { + const float width = m_imgui->calc_text_size(item.second).x; + if (m_label_width < width) + m_label_width = width; + } + m_label_width += m_imgui->scaled(1.f); + } +} + +void GLGizmoCut3D::render_input_window_warning() const +{ + if (! m_invalid_connectors_idxs.empty()) { + wxString out = /*wxString(ImGui::WarningMarkerSmall)*/ _L("Warning") + ": " + _L("Invalid connectors detected") + ":"; + if (m_info_stats.outside_cut_contour > size_t(0)) + out += "\n - " + format_wxstr(_L_PLURAL("%1$d connector is out of cut contour", "%1$d connectors are out of cut contour", m_info_stats.outside_cut_contour), + m_info_stats.outside_cut_contour); + if (m_info_stats.outside_bb > size_t(0)) + out += "\n - " + format_wxstr(_L_PLURAL("%1$d connector is out of object", "%1$d connectors are out of object", m_info_stats.outside_bb), + m_info_stats.outside_bb); + if (m_info_stats.is_overlap) + out += "\n - " + _L("Some connectors are overlapped"); + m_imgui->text(out); + } + if (!m_keep_upper && !m_keep_lower) + m_imgui->text(/*wxString(ImGui::WarningMarkerSmall)*/ _L("Warning") + ": " + _L("Select at least one object to keep after cutting.")); + if (!has_valid_contour()) + m_imgui->text(/*wxString(ImGui::WarningMarkerSmall)*/ _L("Warning") + ": " + _L("Cut plane is placed out of object")); + else if (!has_valid_groove()) + m_imgui->text(/*wxString(ImGui::WarningMarkerSmall)*/ _L("Warning") + ": " + _L("Cut plane with groove is invalid")); +} + +void GLGizmoCut3D::on_render_input_window(float x, float y, float bottom_limit) +{ + m_imgui->begin(get_name(), ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse); + + // adjust window position to avoid overlap the view toolbar + adjust_window_position(x, y, bottom_limit); + + CutConnectors& connectors = m_c->selection_info()->model_object()->cut_connectors; + + init_input_window_data(connectors); + + if (m_connectors_editing) // connectors mode + render_connectors_input_window(connectors); + else + render_cut_plane_input_window(connectors); + + render_input_window_warning(); + + m_imgui->end(); + + if (!m_connectors_editing) // connectors mode + render_debug_input_window(x); +} + +bool GLGizmoCut3D::is_outside_of_cut_contour(size_t idx, const CutConnectors& connectors, const Vec3d cur_pos) +{ + // check if connector pos is out of clipping plane + if (m_c->object_clipper() && m_c->object_clipper()->is_projection_inside_cut(cur_pos) == -1) { + m_info_stats.outside_cut_contour++; + return true; + } + + // check if connector bottom contour is out of clipping plane + const CutConnector& cur_connector = connectors[idx]; + const CutConnectorShape shape = CutConnectorShape(cur_connector.attribs.shape); + const int sectorCount = shape == CutConnectorShape::Triangle ? 3 : + shape == CutConnectorShape::Square ? 4 : + shape == CutConnectorShape::Circle ? 60: // supposably, 60 points are enough for conflict detection + shape == CutConnectorShape::Hexagon ? 6 : 1 ; + + indexed_triangle_set mesh; + auto& vertices = mesh.vertices; + vertices.reserve(sectorCount + 1); + + float fa = 2 * PI / sectorCount; + auto vec = Eigen::Vector2f(0, cur_connector.radius); + for (float angle = 0; angle < 2.f * PI; angle += fa) { + Vec2f p = Eigen::Rotation2Df(angle) * vec; + vertices.emplace_back(Vec3f(p(0), p(1), 0.f)); + } + its_transform(mesh, translation_transform(cur_pos) * m_rotation_m); + + for (const Vec3f& vertex : vertices) { + if (m_c->object_clipper()) { + int contour_idx = m_c->object_clipper()->is_projection_inside_cut(vertex.cast()); + bool is_invalid = (contour_idx == -1); + if (m_part_selection.valid() && ! is_invalid) { + assert(contour_idx >= 0); + const std::vector& ignored = *(m_part_selection.get_ignored_contours_ptr()); + is_invalid = (std::find(ignored.begin(), ignored.end(), size_t(contour_idx)) != ignored.end()); + } + if (is_invalid) { + m_info_stats.outside_cut_contour++; + return true; + } + } + } + + return false; +} + +bool GLGizmoCut3D::is_conflict_for_connector(size_t idx, const CutConnectors& connectors, const Vec3d cur_pos) +{ + if (is_outside_of_cut_contour(idx, connectors, cur_pos)) + return true; + + const CutConnector& cur_connector = connectors[idx]; + + const Transform3d matrix = translation_transform(cur_pos) * m_rotation_m * + scale_transform(Vec3f(cur_connector.radius, cur_connector.radius, cur_connector.height).cast()); + const BoundingBoxf3 cur_tbb = m_shapes[cur_connector.attribs].model.get_bounding_box().transformed(matrix); + + // check if connector's bounding box is inside the object's bounding box + if (!m_bounding_box.contains(cur_tbb)) { + m_info_stats.outside_bb++; + return true; + } + + // check if connectors are overlapping + for (size_t i = 0; i < connectors.size(); ++i) { + if (i == idx) + continue; + const CutConnector& connector = connectors[i]; + + if ((connector.pos - cur_connector.pos).norm() < double(connector.radius + cur_connector.radius)) { + m_info_stats.is_overlap = true; + return true; + } + } + + return false; +} + +void GLGizmoCut3D::check_and_update_connectors_state() +{ + m_info_stats.invalidate(); + m_invalid_connectors_idxs.clear(); + if (CutMode(m_mode) != CutMode::cutPlanar) + return; + const ModelObject* mo = m_c->selection_info()->model_object(); + auto inst_id = m_c->selection_info()->get_active_instance(); + if (inst_id < 0) + return; + const CutConnectors& connectors = mo->cut_connectors; + const ModelInstance* mi = mo->instances[inst_id]; + const Vec3d& instance_offset = mi->get_offset(); + const double sla_shift = double(m_c->selection_info()->get_sla_shift()); + + for (size_t i = 0; i < connectors.size(); ++i) { + const CutConnector& connector = connectors[i]; + Vec3d pos = connector.pos + instance_offset + sla_shift * Vec3d::UnitZ(); // recalculate connector position to world position + if (is_conflict_for_connector(i, connectors, pos)) + m_invalid_connectors_idxs.emplace_back(i); + } +} + +void GLGizmoCut3D::toggle_model_objects_visibility() +{ + bool has_active_volume = false; + std::vector>* raycasters = m_parent.get_raycasters_for_picking(SceneRaycaster::EType::Volume); + for (const std::shared_ptr &raycaster : *raycasters) + if (raycaster->is_active()) { + has_active_volume = true; + break; + } + + if (m_part_selection.valid() && has_active_volume) + m_parent.toggle_model_objects_visibility(false); + else if (!m_part_selection.valid() && !has_active_volume) { + const Selection& selection = m_parent.get_selection(); + const ModelObjectPtrs& model_objects = selection.get_model()->objects; + m_parent.toggle_model_objects_visibility(true, model_objects[selection.get_object_idx()], selection.get_instance_idx()); + } +} + +void GLGizmoCut3D::render_connectors() +{ + ::glEnable(GL_DEPTH_TEST); + + if (cut_line_processing() || + CutMode(m_mode) != CutMode::cutPlanar || + m_connector_mode == CutConnectorMode::Auto || !m_c->selection_info()) + return; + + const ModelObject* mo = m_c->selection_info()->model_object(); + auto inst_id = m_c->selection_info()->get_active_instance(); + if (inst_id < 0) + return; + const CutConnectors& connectors = mo->cut_connectors; + if (connectors.size() != m_selected.size()) { + // #ysFIXME + clear_selection(); + m_selected.resize(connectors.size(), false); + } + + ColorRGBA render_color = CONNECTOR_DEF_COLOR; + + const ModelInstance* mi = mo->instances[inst_id]; + const Vec3d& instance_offset = mi->get_offset(); + const double sla_shift = double(m_c->selection_info()->get_sla_shift()); + + const bool looking_forward = is_looking_forward(); + + for (size_t i = 0; i < connectors.size(); ++i) { + const CutConnector& connector = connectors[i]; + + float height = connector.height; + // recalculate connector position to world position + Vec3d pos = connector.pos + instance_offset + sla_shift * Vec3d::UnitZ(); + + // First decide about the color of the point. + assert(std::is_sorted(m_invalid_connectors_idxs.begin(), m_invalid_connectors_idxs.end())); + const bool conflict_connector = std::binary_search(m_invalid_connectors_idxs.begin(), m_invalid_connectors_idxs.end(), i); + if (conflict_connector) + render_color = CONNECTOR_ERR_COLOR; + else // default connector color + render_color = connector.attribs.type == CutConnectorType::Dowel ? DOWEL_COLOR : PLAG_COLOR; + + if (!m_connectors_editing) + render_color = CONNECTOR_ERR_COLOR; + else if (size_t(m_hover_id - m_connectors_group_id) == i) + render_color = conflict_connector ? HOVERED_ERR_COLOR : + connector.attribs.type == CutConnectorType::Dowel ? HOVERED_DOWEL_COLOR : HOVERED_PLAG_COLOR; + else if (m_selected[i]) + render_color = connector.attribs.type == CutConnectorType::Dowel ? SELECTED_DOWEL_COLOR : SELECTED_PLAG_COLOR; + + const Camera& camera = wxGetApp().plater()->get_camera(); + if (connector.attribs.type == CutConnectorType::Dowel && + connector.attribs.style == CutConnectorStyle::Prism) { + if (m_connectors_editing) { + height = 0.05f; + if (!looking_forward) + pos += 0.05 * m_clp_normal; + } + else { + if (looking_forward) + pos -= static_cast(height) * m_clp_normal; + else + pos += static_cast(height) * m_clp_normal; + height *= 2; + } + } + else if (!looking_forward) + pos += 0.05 * m_clp_normal; + + const Transform3d view_model_matrix = camera.get_view_matrix() * translation_transform(pos) * m_rotation_m * + rotation_transform(-connector.z_angle * Vec3d::UnitZ()) * + scale_transform(Vec3f(connector.radius, connector.radius, height).cast()); + + render_model(m_shapes[connector.attribs].model, render_color, view_model_matrix); + } +} + +bool GLGizmoCut3D::can_perform_cut() const +{ + if (! m_invalid_connectors_idxs.empty() || (!m_keep_upper && !m_keep_lower) || m_connectors_editing) + return false; + + if (CutMode(m_mode) == CutMode::cutTongueAndGroove) + return has_valid_groove(); + + if (m_part_selection.valid()) + return ! m_part_selection.is_one_object(); + + return true; +} + +bool GLGizmoCut3D::has_valid_groove() const +{ + if (CutMode(m_mode) != CutMode::cutTongueAndGroove) + return true; + + const float flaps_width = -2.f * m_groove.depth / tan(m_groove.flaps_angle); + if (flaps_width > m_groove.width) + return false; + + const Selection& selection = m_parent.get_selection(); + const auto&list = selection.get_volume_idxs(); + // is more volumes selected? + if (list.empty()) + return false; + + const Transform3d cp_matrix = translation_transform(m_plane_center) * m_rotation_m; + + for (size_t id = 0; id < m_groove_vertices.size(); id += 2) { + const Vec3d beg = cp_matrix * m_groove_vertices[id]; + const Vec3d end = cp_matrix * m_groove_vertices[id + 1]; + + bool intersection = false; + for (const unsigned int volume_idx : list) { + const GLVolume* glvol = selection.get_volume(volume_idx); + if (!glvol->is_modifier && + glvol->mesh_raycaster->intersects_line(beg, end - beg, glvol->world_matrix())) { + intersection = true; + break; + } + } + if (!intersection) + return false; + } + + return true; +} + +bool GLGizmoCut3D::has_valid_contour() const +{ + const auto clipper = m_c->object_clipper(); + return clipper && clipper->has_valid_contour(); +} + +void GLGizmoCut3D::apply_connectors_in_model(ModelObject* mo, int &dowels_count) +{ + if (CutMode(m_mode) == CutMode::cutTongueAndGroove) + return; + if (m_connector_mode == CutConnectorMode::Manual) { + clear_selection(); + + for (CutConnector&connector : mo->cut_connectors) { + connector.rotation_m = m_rotation_m; + + if (connector.attribs.type == CutConnectorType::Dowel) { + if (connector.attribs.style == CutConnectorStyle::Prism) + connector.height *= 2; + dowels_count ++; + } + else { + // calculate shift of the connector center regarding to the position on the cut plane + connector.pos += m_cut_normal * 0.5 * double(connector.height); + } + } + apply_cut_connectors(mo, _u8L("Connector")); + } +} + +Transform3d GLGizmoCut3D::get_cut_matrix(const Selection& selection) +{ + const int instance_idx = selection.get_instance_idx(); + const int object_idx = selection.get_object_idx(); + ModelObject* mo = selection.get_model()->objects[object_idx]; + if (!mo) + return Transform3d::Identity(); + + // m_cut_z is the distance from the bed. Subtract possible SLA elevation. + const double sla_shift_z = selection.get_first_volume()->get_sla_shift_z(); + + const Vec3d instance_offset = mo->instances[instance_idx]->get_offset(); + Vec3d cut_center_offset = m_plane_center - instance_offset; + cut_center_offset[Z] -= sla_shift_z; + + return translation_transform(cut_center_offset) * m_rotation_m; +} + +void update_object_cut_id(CutObjectBase& cut_id, ModelObjectCutAttributes attributes, const int dowels_count) +{ + // we don't save cut information, if result will not contains all parts of initial object + if (!attributes.has(ModelObjectCutAttribute::KeepUpper) || + !attributes.has(ModelObjectCutAttribute::KeepLower) || + attributes.has(ModelObjectCutAttribute::InvalidateCutInfo)) + return; + + if (cut_id.id().invalid()) + cut_id.init(); + // increase check sum, if it's needed + { + int cut_obj_cnt = -1; + if (attributes.has(ModelObjectCutAttribute::KeepUpper)) cut_obj_cnt++; + if (attributes.has(ModelObjectCutAttribute::KeepLower)) cut_obj_cnt++; + if (attributes.has(ModelObjectCutAttribute::CreateDowels)) cut_obj_cnt+= dowels_count; + if (cut_obj_cnt > 0) + cut_id.increase_check_sum(size_t(cut_obj_cnt)); + } +} + +void synchronize_model_after_cut(Model& model, const CutObjectBase& cut_id) +{ + for (ModelObject* obj : model.objects) + if (obj->is_cut() && obj->cut_id.has_same_id(cut_id) && !obj->cut_id.is_equal(cut_id)) + obj->cut_id.copy(cut_id); +} + +void GLGizmoCut3D::perform_cut(const Selection& selection) +{ + if (!can_perform_cut()) + return; + const int instance_idx = selection.get_instance_idx(); + const int object_idx = selection.get_object_idx(); + + wxCHECK_RET(instance_idx >= 0 && object_idx >= 0, "GLGizmoCut: Invalid object selection"); + + Plater* plater = wxGetApp().plater(); + ModelObject* mo = plater->model().objects[object_idx]; + if (!mo) + return; + + // deactivate CutGizmo and than perform a cut + m_parent.reset_all_gizmos(); + + // perform cut + { + Plater::TakeSnapshot snapshot(wxGetApp().plater(), _u8L("Cut by Plane")); + + // This shall delete the part selection class and deallocate the memory. + ScopeGuard part_selection_killer([this]() { m_part_selection = PartSelection(); }); + + const bool cut_with_groove = CutMode(m_mode) == CutMode::cutTongueAndGroove; + const bool cut_by_contour = !cut_with_groove && m_part_selection.valid(); + + ModelObject* cut_mo = cut_by_contour ? m_part_selection.model_object() : nullptr; + if (cut_mo) + cut_mo->cut_connectors = mo->cut_connectors; + else + cut_mo = mo; + + int dowels_count = 0; + const bool has_connectors = !mo->cut_connectors.empty(); + // update connectors pos as offset of its center before cut performing + apply_connectors_in_model(cut_mo , dowels_count); + + wxBusyCursor wait; + + ModelObjectCutAttributes attributes = only_if(has_connectors ? true : m_keep_upper, ModelObjectCutAttribute::KeepUpper) | + only_if(has_connectors ? true : m_keep_lower, ModelObjectCutAttribute::KeepLower) | + only_if(has_connectors ? false : m_keep_as_parts, ModelObjectCutAttribute::KeepAsParts) | + only_if(m_place_on_cut_upper, ModelObjectCutAttribute::PlaceOnCutUpper) | + only_if(m_place_on_cut_lower, ModelObjectCutAttribute::PlaceOnCutLower) | + only_if(m_rotate_upper, ModelObjectCutAttribute::FlipUpper) | + only_if(m_rotate_lower, ModelObjectCutAttribute::FlipLower) | + only_if(dowels_count > 0, ModelObjectCutAttribute::CreateDowels) | + only_if(!has_connectors && !cut_with_groove && cut_mo->cut_id.id().invalid(), ModelObjectCutAttribute::InvalidateCutInfo); + + // update cut_id for the cut object in respect to the attributes + update_object_cut_id(cut_mo->cut_id, attributes, dowels_count); + + Cut cut(cut_mo, instance_idx, get_cut_matrix(selection), attributes); + const ModelObjectPtrs& new_objects = cut_by_contour ? cut.perform_by_contour(m_part_selection.get_cut_parts(), dowels_count): + cut_with_groove ? cut.perform_with_groove(m_groove, m_rotation_m) : + cut.perform_with_plane(); + // save cut_id to post update synchronization + const CutObjectBase cut_id = cut_mo->cut_id; + + // update cut results on plater and in the model + plater->apply_cut_object_to_model(object_idx, new_objects); + + synchronize_model_after_cut(plater->model(), cut_id); + } +} + +// Unprojects the mouse position on the mesh and saves hit point and normal of the facet into pos_and_normal +// Return false if no intersection was found, true otherwise. +bool GLGizmoCut3D::unproject_on_cut_plane(const Vec2d& mouse_position, Vec3d& pos, Vec3d& pos_world, bool respect_contours/* = true*/) +{ + const float sla_shift = m_c->selection_info()->get_sla_shift(); + + const ModelObject* mo = m_c->selection_info()->model_object(); + const ModelInstance* mi = mo->instances[m_c->selection_info()->get_active_instance()]; + const Camera& camera = wxGetApp().plater()->get_camera(); + + // Calculate intersection with the clipping plane. + const ClippingPlane* cp = m_c->object_clipper()->get_clipping_plane(true); + Vec3d point; + Vec3d direction; + Vec3d hit; + MeshRaycaster::line_from_mouse_pos(mouse_position, Transform3d::Identity(), camera, point, direction); + Vec3d normal = -cp->get_normal().cast(); + double den = normal.dot(direction); + if (den != 0.) { + double t = (-cp->get_offset() - normal.dot(point))/den; + hit = (point + t * direction); + } else + return false; + + // Now check if the hit is not obscured by a selected part on this side of the plane. + // FIXME: This would be better solved by remembering which contours are active. We will + // probably need that anyway because there is not other way to find out which contours + // to render. If you want to uncomment it, fix it first. It does not work yet. + /*for (size_t id = 0; id < m_part_selection.parts.size(); ++id) { + if (! m_part_selection.parts[id].selected) { + Vec3f pos, normal; + const ModelObject* model_object = m_part_selection.model_object; + const Vec3d volume_offset = m_part_selection.model_object->volumes[id]->get_offset(); + Transform3d tr = model_object->instances[m_part_selection.instance_idx]->get_matrix() * model_object->volumes[id]->get_matrix(); + if (m_part_selection.parts[id].raycaster.unproject_on_mesh(mouse_position, tr, camera, pos, normal)) + return false; + } + }*/ + + if (respect_contours) + { + // Do not react to clicks outside a contour (or inside a contour that is ignored) + int cont_id = m_c->object_clipper()->is_projection_inside_cut(hit); + if (cont_id == -1) + return false; + if (m_part_selection.valid()) { + const std::vector& ign = *m_part_selection.get_ignored_contours_ptr(); + if (std::find(ign.begin(), ign.end(), cont_id) != ign.end()) + return false; + } + } + + + // recalculate hit to object's local position + Vec3d hit_d = hit; + hit_d -= mi->get_offset(); + hit_d[Z] -= sla_shift; + + // Return both the point and the facet normal. + pos = hit_d; + pos_world = hit; + + return true; +} + +void GLGizmoCut3D::clear_selection() +{ + m_selected.clear(); + m_selected_count = 0; +} + +void GLGizmoCut3D::reset_connectors() +{ + m_c->selection_info()->model_object()->cut_connectors.clear(); + update_raycasters_for_picking(); + clear_selection(); + check_and_update_connectors_state(); +} + +void GLGizmoCut3D::init_connector_shapes() +{ + for (const CutConnectorType& type : {CutConnectorType::Dowel, CutConnectorType::Plug, CutConnectorType::Snap}) + for (const CutConnectorStyle& style : {CutConnectorStyle::Frustum, CutConnectorStyle::Prism}) { + if (type == CutConnectorType::Dowel && style == CutConnectorStyle::Frustum) + continue; + for (const CutConnectorShape& shape : {CutConnectorShape::Circle, CutConnectorShape::Hexagon, CutConnectorShape::Square, CutConnectorShape::Triangle}) { + if (type == CutConnectorType::Snap && shape != CutConnectorShape::Circle) + continue; + const CutConnectorAttributes attribs = { type, style, shape }; + indexed_triangle_set its = get_connector_mesh(attribs); + m_shapes[attribs].model.init_from(its); + m_shapes[attribs].mesh_raycaster = std::make_unique(std::make_shared(std::move(its))); + } + } +} + +void GLGizmoCut3D::update_connector_shape() +{ + CutConnectorAttributes attribs = { m_connector_type, CutConnectorStyle(m_connector_style), CutConnectorShape(m_connector_shape_id) }; + + if (m_connector_type == CutConnectorType::Snap) { + indexed_triangle_set its = get_connector_mesh(attribs); + m_shapes[attribs].reset(); + m_shapes[attribs].model.init_from(its); + m_shapes[attribs].mesh_raycaster = std::make_unique(std::make_shared(std::move(its))); + + //const indexed_triangle_set its = get_connector_mesh(attribs); + //m_connector_mesh.clear(); + //m_connector_mesh = TriangleMesh(its); + } + + +} + +bool GLGizmoCut3D::cut_line_processing() const +{ + return !m_line_beg.isApprox(Vec3d::Zero()); +} + +void GLGizmoCut3D::discard_cut_line_processing() +{ + m_line_beg = m_line_end = Vec3d::Zero(); +} + +bool GLGizmoCut3D::process_cut_line(SLAGizmoEventType action, const Vec2d& mouse_position) +{ + const Camera& camera = wxGetApp().plater()->get_camera(); + + Vec3d pt; + Vec3d dir; + MeshRaycaster::line_from_mouse_pos(mouse_position, Transform3d::Identity(), camera, pt, dir); + dir.normalize(); + pt += dir; // Move the pt along dir so it is not clipped. + + if (action == SLAGizmoEventType::LeftDown && !cut_line_processing()) { + m_line_beg = pt; + m_line_end = pt; + on_unregister_raycasters_for_picking(); + return true; + } + + if (cut_line_processing()) { + if (CutMode(m_mode) == CutMode::cutTongueAndGroove) + m_groove_editing = true; + reset_cut_by_contours(); + + m_line_end = pt; + if (action == SLAGizmoEventType::LeftDown || action == SLAGizmoEventType::LeftUp) { + Vec3d line_dir = m_line_end - m_line_beg; + if (line_dir.norm() < 3.0) + return true; + + Vec3d cross_dir = line_dir.cross(dir).normalized(); + Eigen::Quaterniond q; + Transform3d m = Transform3d::Identity(); + m.matrix().block(0, 0, 3, 3) = q.setFromTwoVectors(Vec3d::UnitZ(), cross_dir).toRotationMatrix(); + + const Vec3d new_plane_center = m_bb_center + cross_dir * cross_dir.dot(pt - m_bb_center); + // update transformed bb + const auto new_tbb = transformed_bounding_box(new_plane_center, m); + const GLVolume* first_volume = m_parent.get_selection().get_first_volume(); + Vec3d instance_offset = first_volume->get_instance_offset(); + instance_offset[Z] += first_volume->get_sla_shift_z(); + + const Vec3d trans_center_pos = m.inverse() * (new_plane_center - instance_offset) + new_tbb.center(); + if (new_tbb.contains(trans_center_pos)) { + Plater::TakeSnapshot snapshot(wxGetApp().plater(), _u8L("Cut by line"), UndoRedo::SnapshotType::GizmoAction); + m_transformed_bounding_box = new_tbb; + set_center(new_plane_center); + m_start_dragging_m = m_rotation_m = m; + m_ar_plane_center = m_plane_center; + } + + m_angle_arc.reset(); + discard_cut_line_processing(); + + if (CutMode(m_mode) == CutMode::cutTongueAndGroove) { + m_groove_editing = false; + reset_cut_by_contours(); + } + } + else if (action == SLAGizmoEventType::Moving) + this->set_dirty(); + return true; + } + return false; +} + +bool GLGizmoCut3D::add_connector(CutConnectors& connectors, const Vec2d& mouse_position) +{ + if (!m_connectors_editing) + return false; + + Vec3d pos; + Vec3d pos_world; + if (unproject_on_cut_plane(mouse_position.cast(), pos, pos_world)) { + Plater::TakeSnapshot snapshot(wxGetApp().plater(), _u8L("Add connector"), UndoRedo::SnapshotType::GizmoAction); + unselect_all_connectors(); + + connectors.emplace_back(pos, m_rotation_m, + m_connector_size * 0.5f, m_connector_depth_ratio, + m_connector_size_tolerance * 0.5f, m_connector_depth_ratio_tolerance, + m_connector_angle, + CutConnectorAttributes( CutConnectorType(m_connector_type), + CutConnectorStyle(m_connector_style), + CutConnectorShape(m_connector_shape_id))); + m_selected.push_back(true); + m_selected_count = 1; + assert(m_selected.size() == connectors.size()); + update_raycasters_for_picking(); + m_parent.set_as_dirty(); + check_and_update_connectors_state(); + + return true; + } + return false; +} + +bool GLGizmoCut3D::delete_selected_connectors(CutConnectors& connectors) +{ + if (connectors.empty()) + return false; + + Plater::TakeSnapshot snapshot(wxGetApp().plater(), _u8L("Delete connector"), UndoRedo::SnapshotType::GizmoAction); + + // remove connectors + for (int i = int(connectors.size()) - 1; i >= 0; i--) + if (m_selected[i]) + connectors.erase(connectors.begin() + i); + // remove selections + m_selected.erase(std::remove_if(m_selected.begin(), m_selected.end(), [](const auto& selected) { + return selected; }), m_selected.end()); + m_selected_count = 0; + + assert(m_selected.size() == connectors.size()); + update_raycasters_for_picking(); + m_parent.set_as_dirty(); + check_and_update_connectors_state(); + return true; +} + +void GLGizmoCut3D::select_connector(int idx, bool select) +{ + m_selected[idx] = select; + if (select) + ++m_selected_count; + else + --m_selected_count; +} + +bool GLGizmoCut3D::is_selection_changed(bool alt_down, bool shift_down) +{ + if (m_hover_id >= m_connectors_group_id) { + if (alt_down) + select_connector(m_hover_id - m_connectors_group_id, false); + else { + if (!shift_down) + unselect_all_connectors(); + select_connector(m_hover_id - m_connectors_group_id, true); + } + return true; + } + return false; +} + +void GLGizmoCut3D::process_selection_rectangle(CutConnectors &connectors) +{ + GLSelectionRectangle::EState rectangle_status = m_selection_rectangle.get_state(); + + ModelObject* mo = m_c->selection_info()->model_object(); + int active_inst = m_c->selection_info()->get_active_instance(); + + // First collect positions of all the points in world coordinates. + Transformation trafo = mo->instances[active_inst]->get_transformation(); + trafo.set_offset(trafo.get_offset() + double(m_c->selection_info()->get_sla_shift()) * Vec3d::UnitZ()); + + std::vector points; + for (const CutConnector&connector : connectors) + points.push_back(connector.pos + trafo.get_offset()); + + // Now ask the rectangle which of the points are inside. + std::vector points_idxs = m_selection_rectangle.contains(points); + m_selection_rectangle.stop_dragging(); + + for (size_t idx : points_idxs) + select_connector(int(idx), rectangle_status == GLSelectionRectangle::EState::Select); +} + +bool GLGizmoCut3D::gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_position, bool shift_down, bool alt_down, bool control_down) +{ + if (is_dragging() || m_connector_mode == CutConnectorMode::Auto) + return false; + + if ( (m_hover_id < 0 || m_hover_id == CutPlane) && shift_down && ! m_connectors_editing && + (action == SLAGizmoEventType::LeftDown || action == SLAGizmoEventType::LeftUp || action == SLAGizmoEventType::Moving) ) + return process_cut_line(action, mouse_position); + + if (!m_keep_upper || !m_keep_lower) + return false; + + if (!m_connectors_editing) + return false; + + CutConnectors& connectors = m_c->selection_info()->model_object()->cut_connectors; + + if (action == SLAGizmoEventType::LeftDown) { + if (shift_down || alt_down) { + // left down with shift - show the selection rectangle: + if (m_hover_id == -1) + m_selection_rectangle.start_dragging(mouse_position, shift_down ? GLSelectionRectangle::EState::Select : GLSelectionRectangle::EState::Deselect); + } + else + // If there is no selection and no hovering, add new point + if (m_hover_id == -1 && !shift_down && !alt_down) + if (!add_connector(connectors, mouse_position)) + m_ldown_mouse_position = mouse_position; + return true; + } + + if (action == SLAGizmoEventType::LeftUp && !m_selection_rectangle.is_dragging()) { + if ((m_ldown_mouse_position - mouse_position).norm() < 5.) + unselect_all_connectors(); + return is_selection_changed(alt_down, shift_down); + } + + // left up with selection rectangle - select points inside the rectangle: + if ((action == SLAGizmoEventType::LeftUp || action == SLAGizmoEventType::ShiftUp || action == SLAGizmoEventType::AltUp) && m_selection_rectangle.is_dragging()) { + // Is this a selection or deselection rectangle? + process_selection_rectangle(connectors); + return true; + } + + // dragging the selection rectangle: + if (action == SLAGizmoEventType::Dragging) { + if (m_selection_rectangle.is_dragging()) { + m_selection_rectangle.dragging(mouse_position); + return true; + } + return false; + } + + if (action == SLAGizmoEventType::RightDown && !shift_down) { + // If any point is in hover state, this should initiate its move - return control back to GLCanvas: + if (m_hover_id < m_connectors_group_id) + return false; + unselect_all_connectors(); + select_connector(m_hover_id - m_connectors_group_id, true); + return delete_selected_connectors(connectors); + } + + if (action == SLAGizmoEventType::Delete) + return delete_selected_connectors(connectors); + + if (action == SLAGizmoEventType::SelectAll) { + select_all_connectors(); + return true; + } + + return false; +} + +CommonGizmosDataID GLGizmoCut3D::on_get_requirements() const { + return CommonGizmosDataID( + int(CommonGizmosDataID::SelectionInfo) + | int(CommonGizmosDataID::InstancesHider) + | int(CommonGizmosDataID::ObjectClipper)); +} + +void GLGizmoCut3D::data_changed(bool is_serializing) +{ + update_bb(); + if (auto oc = m_c->object_clipper()) + oc->set_behavior(m_connectors_editing, m_connectors_editing, double(m_contour_width)); +} + + + + +indexed_triangle_set GLGizmoCut3D::get_connector_mesh(CutConnectorAttributes connector_attributes) +{ + indexed_triangle_set connector_mesh; + + int sectorCount{ 1 }; + switch (CutConnectorShape(connector_attributes.shape)) { + case CutConnectorShape::Triangle: + sectorCount = 3; + break; + case CutConnectorShape::Square: + sectorCount = 4; + break; + case CutConnectorShape::Circle: + sectorCount = 360; + break; + case CutConnectorShape::Hexagon: + sectorCount = 6; + break; + default: + break; + } + + if (connector_attributes.type == CutConnectorType::Snap) + connector_mesh = its_make_snap(1.0, 1.0, m_snap_space_proportion, m_snap_bulge_proportion); + else if (connector_attributes.style == CutConnectorStyle::Prism) + connector_mesh = its_make_cylinder(1.0, 1.0, (2 * PI / sectorCount)); + else if (connector_attributes.type == CutConnectorType::Plug) + connector_mesh = its_make_frustum(1.0, 1.0, (2 * PI / sectorCount)); + else + connector_mesh = its_make_frustum_dowel(1.0, 1.0, sectorCount); + + return connector_mesh; +} + +void GLGizmoCut3D::apply_cut_connectors(ModelObject* mo, const std::string& connector_name) +{ + if (mo->cut_connectors.empty()) + return; + + using namespace Geometry; + + size_t connector_id = mo->cut_id.connectors_cnt(); + for (const CutConnector& connector : mo->cut_connectors) { + TriangleMesh mesh = TriangleMesh(get_connector_mesh(connector.attribs)); + // Mesh will be centered when loading. + ModelVolume* new_volume = mo->add_volume(std::move(mesh), ModelVolumeType::NEGATIVE_VOLUME); + + // Transform the new modifier to be aligned inside the instance + new_volume->set_transformation(translation_transform(connector.pos) * connector.rotation_m * + rotation_transform(-connector.z_angle * Vec3d::UnitZ()) * + scale_transform(Vec3f(connector.radius, connector.radius, connector.height).cast())); + + new_volume->cut_info = { connector.attribs.type, connector.radius_tolerance, connector.height_tolerance }; + new_volume->name = connector_name + "-" + std::to_string(++connector_id); + } + mo->cut_id.increase_connectors_cnt(mo->cut_connectors.size()); + + // delete all connectors + mo->cut_connectors.clear(); +} + + + } // namespace GUI } // namespace Slic3r diff --git a/src/slic3r/GUI/Gizmos/GLGizmoCut.hpp b/src/slic3r/GUI/Gizmos/GLGizmoCut.hpp index cf7c7ac0425..89c1b928330 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoCut.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoCut.hpp @@ -1,72 +1,391 @@ +///|/ Copyright (c) Prusa Research 2019 - 2023 Oleksandra Iushchenko @YuSanka, Lukáš Matěna @lukasmatena, Enrico Turri @enricoturri1966, Filip Sykala @Jony01, Vojtěch Bubník @bubnikv +///|/ +///|/ PrusaSlicer is released under the terms of the AGPLv3 or higher +///|/ #ifndef slic3r_GLGizmoCut_hpp_ #define slic3r_GLGizmoCut_hpp_ #include "GLGizmoBase.hpp" +#include "slic3r/GUI/GLSelectionRectangle.hpp" #include "slic3r/GUI/GLModel.hpp" +#include "slic3r/GUI/I18N.hpp" #include "libslic3r/TriangleMesh.hpp" -#include "libslic3r/ObjectID.hpp" +#include "libslic3r/Model.hpp" +#include "libslic3r/CutUtils.hpp" +#include "imgui/imgui.h" namespace Slic3r { + +enum class CutConnectorType : int; +class ModelVolume; +class GLShaderProgram; +struct CutConnectorAttributes; + namespace GUI { +class Selection; + +enum class SLAGizmoEventType : unsigned char; -class GLGizmoCut : public GLGizmoBase +namespace CommonGizmosDataObjects { class ObjectClipper; } + +class GLGizmoCut3D : public GLGizmoBase { - static const double Offset; - static const double Margin; - - double m_cut_z{ 0.0 }; - double m_max_z{ 0.0 }; - double m_start_z{ 0.0 }; - Vec3d m_drag_pos; - Vec3d m_drag_center; + enum GrabberID { + X = 0, + Y, + Z, + CutPlane, + CutPlaneZRotation, + CutPlaneXMove, + CutPlaneYMove, + Count, + }; + + Transform3d m_rotation_m{ Transform3d::Identity() }; + double m_snap_step{ 1.0 }; + int m_connectors_group_id; + + // archived values + Vec3d m_ar_plane_center { Vec3d::Zero() }; + Transform3d m_start_dragging_m{ Transform3d::Identity() }; + + Vec3d m_plane_center{ Vec3d::Zero() }; + // data to check position of the cut palne center on gizmo activation + Vec3d m_min_pos{ Vec3d::Zero() }; + Vec3d m_max_pos{ Vec3d::Zero() }; + Vec3d m_bb_center{ Vec3d::Zero() }; + Vec3d m_center_offset{ Vec3d::Zero() }; + + BoundingBoxf3 m_bounding_box; + BoundingBoxf3 m_transformed_bounding_box; + + // values from RotationGizmo + double m_radius{ 0.0 }; + double m_grabber_radius{ 0.0 }; + double m_grabber_connection_len{ 0.0 }; + Vec3d m_cut_plane_start_move_pos {Vec3d::Zero()}; + + double m_snap_coarse_in_radius{ 0.0 }; + double m_snap_coarse_out_radius{ 0.0 }; + double m_snap_fine_in_radius{ 0.0 }; + double m_snap_fine_out_radius{ 0.0 }; + + // dragging angel in hovered axes + double m_angle{ 0.0 }; + + TriangleMesh m_connector_mesh; + // workaround for using of the clipping plane normal + Vec3d m_clp_normal{ Vec3d::Ones() }; + + Vec3d m_line_beg{ Vec3d::Zero() }; + Vec3d m_line_end{ Vec3d::Zero() }; + + Vec2d m_ldown_mouse_position{ Vec2d::Zero() }; + + GLModel m_grabber_connection; + GLModel m_cut_line; + + PickingModel m_plane; + PickingModel m_sphere; + PickingModel m_cone; + PickingModel m_cube; + std::map m_shapes; + std::vector> m_raycasters; + + GLModel m_circle; + GLModel m_scale; + GLModel m_snap_radii; + GLModel m_reference_radius; + GLModel m_angle_arc; + + Vec3d m_old_center; + Vec3d m_cut_normal; + + struct InvalidConnectorsStatistics + { + unsigned int outside_cut_contour; + unsigned int outside_bb; + bool is_overlap; + + void invalidate() { + outside_cut_contour = 0; + outside_bb = 0; + is_overlap = false; + } + } m_info_stats; + bool m_keep_upper{ true }; bool m_keep_lower{ true }; + bool m_keep_as_parts{ false }; + bool m_place_on_cut_upper{ true }; + bool m_place_on_cut_lower{ false }; + bool m_rotate_upper{ false }; bool m_rotate_lower{ false }; - // BBS: m_do_segment - bool m_cut_to_parts {false}; - bool m_do_segment{ false }; - double m_segment_smoothing_alpha{ 0.5 }; - int m_segment_number{ 5 }; - struct CutContours - { - TriangleMesh mesh; - GLModel contours; - double cut_z{ 0.0 }; - Vec3d position{ Vec3d::Zero() }; - Vec3d shift{ Vec3d::Zero() }; - ObjectID object_id; - int instance_idx{ -1 }; + // Input params for cut with tongue and groove + Cut::Groove m_groove; + bool m_groove_editing { false }; + + bool m_is_slider_editing_done { false }; + + // Input params for cut with snaps + float m_snap_bulge_proportion{ 0.15f }; + float m_snap_space_proportion{ 0.3f }; + + bool m_hide_cut_plane{ false }; + bool m_connectors_editing{ false }; + bool m_cut_plane_as_circle{ false }; + + float m_connector_depth_ratio{ 3.f }; + float m_connector_size{ 2.5f }; + float m_connector_angle{ 0.f }; + + float m_connector_depth_ratio_tolerance{ 0.1f }; + float m_connector_size_tolerance{ 0.f }; + + float m_label_width{ 0.f }; + float m_control_width{ 200.f }; + bool m_imperial_units{ false }; + + float m_contour_width{ 0.4f }; + float m_cut_plane_radius_koef{ 1.5f }; + float m_shortcut_label_width{ -1.f }; + + mutable std::vector m_selected; // which pins are currently selected + int m_selected_count{ 0 }; + + GLSelectionRectangle m_selection_rectangle; + + std::vector m_invalid_connectors_idxs; + bool m_was_cut_plane_dragged { false }; + bool m_was_contour_selected { false }; + + // Vertices of the groove used to detection if groove is valid + std::vector m_groove_vertices; + + class PartSelection { + public: + PartSelection() = default; + PartSelection(const ModelObject* mo, const Transform3d& cut_matrix, int instance_idx, const Vec3d& center, const Vec3d& normal, const CommonGizmosDataObjects::ObjectClipper& oc); + PartSelection(const ModelObject* mo, int instance_idx_in); + ~PartSelection() { m_model.clear_objects(); } + + struct Part { + GLModel glmodel; + MeshRaycaster raycaster; + bool selected; + bool is_modifier; + }; + + void render(const Vec3d* normal, GLModel& sphere_model); + void toggle_selection(const Vec2d& mouse_pos); + void turn_over_selection(); + ModelObject* model_object() { return m_model.objects.front(); } + bool valid() const { return m_valid; } + bool is_one_object() const; + const std::vector& parts() const { return m_parts; } + const std::vector* get_ignored_contours_ptr() const { return (valid() ? &m_ignored_contours : nullptr); } + + std::vector get_cut_parts(); + + private: + Model m_model; + int m_instance_idx; + std::vector m_parts; + bool m_valid = false; + std::vector, std::vector>> m_contour_to_parts; // for each contour, there is a vector of parts above and a vector of parts below + std::vector m_ignored_contours; // contour that should not be rendered (the parts on both sides will both be parts of the same object) + + std::vector m_contour_points; // Debugging + std::vector> m_debug_pts; // Debugging + + void add_object(const ModelObject* object); }; - CutContours m_cut_contours; + PartSelection m_part_selection; -public: - GLGizmoCut(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id); + bool m_show_shortcuts{ false }; + std::vector> m_shortcuts; + + enum class CutMode { + cutPlanar + , cutTongueAndGroove + //, cutGrig + //,cutRadial + //,cutModular + }; + + enum class CutConnectorMode { + Auto + , Manual + }; + + std::vector m_modes; + size_t m_mode{ size_t(CutMode::cutPlanar) }; + + std::vector m_connector_modes; + CutConnectorMode m_connector_mode{ CutConnectorMode::Manual }; + + std::vector m_connector_types; + CutConnectorType m_connector_type; + + std::vector m_connector_styles; + int m_connector_style; + + std::vector m_connector_shapes; + int m_connector_shape_id; + + std::vector m_axis_names; + + std::map m_part_orientation_names; - double get_cut_z() const { return m_cut_z; } - void set_cut_z(double cut_z); + std::map m_labels_map; + +public: + GLGizmoCut3D(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id); std::string get_tooltip() const override; + bool unproject_on_cut_plane(const Vec2d& mouse_pos, Vec3d& pos, Vec3d& pos_world, bool respect_contours = true); + bool gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_position, bool shift_down, bool alt_down, bool control_down); + + bool is_in_editing_mode() const override { return m_connectors_editing; } + bool is_selection_rectangle_dragging() const override { return m_selection_rectangle.is_dragging(); } + bool is_looking_forward() const; + + /// + /// Drag of plane + /// + /// Keep information about mouse click + /// Return True when use the information otherwise False. + bool on_mouse(const wxMouseEvent &mouse_event) override; + + void shift_cut(double delta); + void rotate_vec3d_around_plane_center(Vec3d&vec); + void put_connectors_on_cut_plane(const Vec3d& cp_normal, double cp_offset); + void update_clipper(); + void invalidate_cut_plane(); + + BoundingBoxf3 bounding_box() const; + BoundingBoxf3 transformed_bounding_box(const Vec3d& plane_center, const Transform3d& rotation_m = Transform3d::Identity()) const; protected: - virtual bool on_init() override; - virtual void on_load(cereal::BinaryInputArchive& ar) override { ar(m_cut_z, m_keep_upper, m_keep_lower, m_rotate_lower); } - virtual void on_save(cereal::BinaryOutputArchive& ar) const override { ar(m_cut_z, m_keep_upper, m_keep_lower, m_rotate_lower); } - virtual std::string on_get_name() const override; - virtual void on_set_state() override; - virtual bool on_is_activable() const override; - virtual void on_start_dragging() override; - virtual void on_update(const UpdateData& data) override; - virtual void on_render() override; - virtual void on_render_for_picking() override; - virtual void on_render_input_window(float x, float y, float bottom_limit) override; + bool on_init() override; + void on_load(cereal::BinaryInputArchive&ar) override; + void on_save(cereal::BinaryOutputArchive&ar) const override; + std::string on_get_name() const override; + void on_set_state() override; + CommonGizmosDataID on_get_requirements() const override; + void on_set_hover_id() override; + bool on_is_activable() const override; + bool on_is_selectable() const override; + Vec3d mouse_position_in_local_plane(GrabberID axis, const Linef3&mouse_ray) const; + void dragging_grabber_move(const GLGizmoBase::UpdateData &data); + void dragging_grabber_rotation(const GLGizmoBase::UpdateData &data); + void dragging_connector(const GLGizmoBase::UpdateData &data); + void on_dragging(const UpdateData&data) override; + void on_start_dragging() override; + void on_stop_dragging() override; + void on_render() override; + + void render_debug_input_window(float x); + void adjust_window_position(float x, float y, float bottom_limit); + void unselect_all_connectors(); + void select_all_connectors(); + void render_shortcuts(); + void apply_selected_connectors(std::function apply_fn); + void render_connectors_input_window(CutConnectors &connectors); + void render_build_size(); + void reset_cut_plane(); + void set_connectors_editing(bool connectors_editing); + void flip_cut_plane(); + void process_contours(); + void reset_cut_by_contours(); + void render_flip_plane_button(bool disable_pred = false); + void add_vertical_scaled_interval(float interval); + void add_horizontal_scaled_interval(float interval); + void add_horizontal_shift(float shift); + void render_color_marker(float size, const ImU32& color); + void render_groove_float_input(const std::string &label, float &in_val, const float &init_val, float &in_tolerance); + void render_groove_angle_input(const std::string &label, float &in_val, const float &init_val, float min_val, float max_val); + bool render_angle_input(const std::string& label, float& in_val, const float& init_val, float min_val, float max_val); + void render_snap_specific_input(const std::string& label, const wxString& tooltip, float& in_val, const float& init_val, const float min_val, const float max_val); + void render_cut_plane_input_window(CutConnectors &connectors); + void init_input_window_data(CutConnectors &connectors); + void render_input_window_warning() const; + bool add_connector(CutConnectors&connectors, const Vec2d&mouse_position); + bool delete_selected_connectors(CutConnectors&connectors); + void select_connector(int idx, bool select); + bool is_selection_changed(bool alt_down, bool shift_down); + void process_selection_rectangle(CutConnectors &connectors); + + virtual void on_register_raycasters_for_picking() override; + virtual void on_unregister_raycasters_for_picking() override; + void update_raycasters_for_picking(); + void set_volumes_picking_state(bool state); + void update_raycasters_for_picking_transform(); + + void update_plane_model(); + + void on_render_input_window(float x, float y, float bottom_limit) override; + + bool wants_enter_leave_snapshots() const override { return true; } + std::string get_gizmo_entering_text() const override { return _u8L("Entering Cut gizmo"); } + std::string get_gizmo_leaving_text() const override { return _u8L("Leaving Cut gizmo"); } + std::string get_action_snapshot_name() const override { return _u8L("Cut gizmo editing"); } + + void data_changed(bool is_serializing) override; + Transform3d get_cut_matrix(const Selection& selection); private: - void perform_cut(const Selection& selection); - double calc_projection(const Linef3& mouse_ray) const; - BoundingBoxf3 bounding_box() const; - void update_contours(); + void set_center(const Vec3d¢er, bool update_tbb = false); + void switch_to_mode(size_t new_mode); + bool render_cut_mode_combo(); + bool render_combo(const std::string&label, const std::vector&lines, int&selection_idx); + bool render_double_input(const std::string& label, double& value_in); + bool render_slider_double_input(const std::string& label, float& value_in, float& tolerance_in, float min_val = -0.1f, float max_tolerance = -0.1f); + void render_move_center_input(int axis); + void render_connect_mode_radio_button(CutConnectorMode mode); + bool render_reset_button(const std::string& label_id, const std::string& tooltip) const; + bool render_connect_type_radio_button(CutConnectorType type); + bool is_outside_of_cut_contour(size_t idx, const CutConnectors& connectors, const Vec3d cur_pos); + bool is_conflict_for_connector(size_t idx, const CutConnectors& connectors, const Vec3d cur_pos); + void render_connectors(); + + bool can_perform_cut() const; + bool has_valid_groove() const; + bool has_valid_contour() const; + void apply_connectors_in_model(ModelObject* mo, int &dowels_count); + bool cut_line_processing() const; + void discard_cut_line_processing(); + + void apply_color_clip_plane_colors(); + void render_cut_plane(); + static void render_model(GLModel& model, const ColorRGBA& color, Transform3d view_model_matrix); + void render_line(GLModel& line_model, const ColorRGBA& color, Transform3d view_model_matrix, float width); + void render_rotation_snapping(GrabberID axis, const ColorRGBA& color); + void render_grabber_connection(const ColorRGBA& color, Transform3d view_matrix, double line_len_koef = 1.0); + void render_cut_plane_grabbers(); + void render_cut_line(); + void perform_cut(const Selection&selection); + void set_center_pos(const Vec3d¢er_pos, bool update_tbb = false); + void update_bb(); + void init_picking_models(); + void init_rendering_items(); + void render_clipper_cut(); + void clear_selection(); + void reset_connectors(); + void init_connector_shapes(); + void update_connector_shape(); + void validate_connector_settings(); + bool process_cut_line(SLAGizmoEventType action, const Vec2d& mouse_position); + void check_and_update_connectors_state(); + + void toggle_model_objects_visibility(); + + indexed_triangle_set its_make_groove_plane(); + + indexed_triangle_set get_connector_mesh(CutConnectorAttributes connector_attributes); + void apply_cut_connectors(ModelObject* mo, const std::string& connector_name); }; } // namespace GUI diff --git a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp index 5e113372e68..33983628552 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp @@ -20,8 +20,7 @@ #include "slic3r/GUI/Gizmos/GLGizmoFlatten.hpp" //#include "slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp" #include "slic3r/GUI/Gizmos/GLGizmoFdmSupports.hpp" -// BBS -#include "slic3r/GUI/Gizmos/GLGizmoAdvancedCut.hpp" +#include "slic3r/GUI/Gizmos/GLGizmoCut.hpp" //#include "slic3r/GUI/Gizmos/GLGizmoFaceDetector.hpp" //#include "slic3r/GUI/Gizmos/GLGizmoHollow.hpp" #include "slic3r/GUI/Gizmos/GLGizmoSeam.hpp" @@ -193,7 +192,7 @@ bool GLGizmosManager::init() m_gizmos.emplace_back(new GLGizmoRotate3D(m_parent, m_is_dark ? "toolbar_rotate_dark.svg" : "toolbar_rotate.svg", EType::Rotate, &m_object_manipulation)); m_gizmos.emplace_back(new GLGizmoScale3D(m_parent, m_is_dark ? "toolbar_scale_dark.svg" : "toolbar_scale.svg", EType::Scale, &m_object_manipulation)); m_gizmos.emplace_back(new GLGizmoFlatten(m_parent, m_is_dark ? "toolbar_flatten_dark.svg" : "toolbar_flatten.svg", EType::Flatten)); - m_gizmos.emplace_back(new GLGizmoAdvancedCut(m_parent, m_is_dark ? "toolbar_cut_dark.svg" : "toolbar_cut.svg", EType::Cut)); + m_gizmos.emplace_back(new GLGizmoCut3D(m_parent, m_is_dark ? "toolbar_cut_dark.svg" : "toolbar_cut.svg", EType::Cut)); m_gizmos.emplace_back(new GLGizmoMeshBoolean(m_parent, m_is_dark ? "toolbar_meshboolean_dark.svg" : "toolbar_meshboolean.svg", EType::MeshBoolean)); m_gizmos.emplace_back(new GLGizmoFdmSupports(m_parent, m_is_dark ? "toolbar_support_dark.svg" : "toolbar_support.svg", EType::FdmSupports)); m_gizmos.emplace_back(new GLGizmoSeam(m_parent, m_is_dark ? "toolbar_seam_dark.svg" : "toolbar_seam.svg", EType::Seam)); @@ -446,7 +445,7 @@ bool GLGizmosManager::gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_p else if (m_current == Measure) return dynamic_cast(m_gizmos[Measure].get())->gizmo_event(action, mouse_position, shift_down, alt_down, control_down); else if (m_current == Cut) - return dynamic_cast(m_gizmos[Cut].get())->gizmo_event(action, mouse_position, shift_down, alt_down, control_down); + return dynamic_cast(m_gizmos[Cut].get())->gizmo_event(action, mouse_position, shift_down, alt_down, control_down); else if (m_current == MeshBoolean) return dynamic_cast(m_gizmos[MeshBoolean].get())->gizmo_event(action, mouse_position, shift_down, alt_down, control_down); else @@ -861,13 +860,10 @@ bool GLGizmosManager::on_key(wxKeyEvent& evt) // m_parent.set_cursor(GLCanvas3D::Cross); processed = true; } - else*/ if (m_current == Cut) - { - // BBS -#if 0 + else*/ if (m_current == Cut) { auto do_move = [this, &processed](double delta_z) { - GLGizmoAdvancedCut* cut = dynamic_cast(get_current()); - cut->set_cut_z(delta_z + cut->get_cut_z()); + GLGizmoCut3D* cut = dynamic_cast(get_current()); + cut->shift_cut(delta_z); processed = true; }; @@ -875,10 +871,13 @@ bool GLGizmosManager::on_key(wxKeyEvent& evt) { case WXK_NUMPAD_UP: case WXK_UP: { do_move(1.0); break; } case WXK_NUMPAD_DOWN: case WXK_DOWN: { do_move(-1.0); break; } + case WXK_SHIFT : case WXK_ALT: { + processed = get_current()->is_in_editing_mode(); + } default: { break; } } -#endif - } else if (m_current == Simplify && keyCode == WXK_ESCAPE) { + } + else if (m_current == Simplify && keyCode == WXK_ESCAPE) { GLGizmoSimplify *simplify = dynamic_cast(get_current()); if (simplify != nullptr) processed = simplify->on_esc_key_down(); diff --git a/src/slic3r/GUI/ImGuiWrapper.cpp b/src/slic3r/GUI/ImGuiWrapper.cpp index 47b9ea21bea..56cff4b468c 100644 --- a/src/slic3r/GUI/ImGuiWrapper.cpp +++ b/src/slic3r/GUI/ImGuiWrapper.cpp @@ -511,10 +511,12 @@ void ImGuiWrapper::render() m_new_frame_open = false; } -ImVec2 ImGuiWrapper::calc_text_size(const wxString &text, float wrap_width) const +ImVec2 ImGuiWrapper::calc_text_size(const wxString &text, + bool hide_text_after_double_hash, + float wrap_width) const { auto text_utf8 = into_u8(text); - ImVec2 size = ImGui::CalcTextSize(text_utf8.c_str(), NULL, false, wrap_width); + ImVec2 size = ImGui::CalcTextSize(text_utf8.c_str(), NULL, hide_text_after_double_hash, wrap_width); /*#ifdef __linux__ size.x *= m_style_scaling; @@ -773,16 +775,30 @@ void ImGuiWrapper::end() ImGui::End(); } -bool ImGuiWrapper::button(const wxString &label) +bool ImGuiWrapper::button(const wxString &label, const wxString& tooltip) { auto label_utf8 = into_u8(label); - return ImGui::Button(label_utf8.c_str()); + const bool ret = ImGui::Button(label_utf8.c_str()); + + if (!tooltip.IsEmpty() && ImGui::IsItemHovered()) { + auto tooltip_utf8 = into_u8(tooltip); + ImGui::SetTooltip(tooltip_utf8.c_str(), nullptr); + } + + return ret; } -bool ImGuiWrapper::bbl_button(const wxString &label) +bool ImGuiWrapper::bbl_button(const wxString &label, const wxString& tooltip) { auto label_utf8 = into_u8(label); - return ImGui::BBLButton(label_utf8.c_str()); + const bool ret = ImGui::BBLButton(label_utf8.c_str()); + + if (!tooltip.IsEmpty() && ImGui::IsItemHovered()) { + auto tooltip_utf8 = into_u8(tooltip); + ImGui::SetTooltip(tooltip_utf8.c_str(), nullptr); + } + + return ret; } bool ImGuiWrapper::button(const wxString& label, float width, float height) @@ -791,6 +807,17 @@ bool ImGuiWrapper::button(const wxString& label, float width, float height) return ImGui::Button(label_utf8.c_str(), ImVec2(width, height)); } +bool ImGuiWrapper::button(const wxString& label, const ImVec2 &size, bool enable) +{ + disabled_begin(!enable); + + auto label_utf8 = into_u8(label); + bool res = ImGui::Button(label_utf8.c_str(), size); + + disabled_end(); + return (enable) ? res : false; +} + bool ImGuiWrapper::radio_button(const wxString &label, bool active) { auto label_utf8 = into_u8(label); @@ -965,6 +992,8 @@ bool ImGuiWrapper::slider_float(const char* label, float* v, float v_min, float m_last_slider_status.edited = ImGui::IsItemEdited(); m_last_slider_status.clicked = ImGui::IsItemClicked(); m_last_slider_status.deactivated_after_edit = ImGui::IsItemDeactivatedAfterEdit(); + if (!m_last_slider_status.can_take_snapshot) + m_last_slider_status.can_take_snapshot = ImGui::IsItemClicked(); if (!tooltip.empty() && ImGui::IsItemHovered()) this->tooltip(into_u8(tooltip).c_str(), max_tooltip_width); @@ -1103,25 +1132,34 @@ bool ImGuiWrapper::image_button(const wchar_t icon, const wxString& tooltip) return res; } -bool ImGuiWrapper::combo(const wxString& label, const std::vector& options, int& selection) +bool ImGuiWrapper::combo(const wxString& label, const std::vector& options, int& selection, ImGuiComboFlags flags/* = 0*/, float label_width/* = 0.0f*/, float item_width/* = 0.0f*/) +{ + return combo(into_u8(label), options, selection, flags, label_width, item_width); +} + +bool ImGuiWrapper::combo(const std::string& label, const std::vector& options, int& selection, ImGuiComboFlags flags/* = 0*/, float label_width/* = 0.0f*/, float item_width/* = 0.0f*/) { // this is to force the label to the left of the widget: - text(label); - ImGui::SameLine(); + const bool hidden_label = boost::starts_with(label, "##"); + if (!label.empty() && !hidden_label) { + text(label); + ImGui::SameLine(label_width); + } + ImGui::PushItemWidth(item_width); int selection_out = selection; bool res = false; const char *selection_str = selection < int(options.size()) && selection >= 0 ? options[selection].c_str() : ""; - if (ImGui::BeginCombo("", selection_str)) { + if (ImGui::BeginCombo(hidden_label ? label.c_str() : ("##" + label).c_str(), selection_str, flags)) { for (int i = 0; i < (int)options.size(); i++) { if (ImGui::Selectable(options[i].c_str(), i == selection)) { selection_out = i; + res = true; } } ImGui::EndCombo(); - res = true; } selection = selection_out; diff --git a/src/slic3r/GUI/ImGuiWrapper.hpp b/src/slic3r/GUI/ImGuiWrapper.hpp index 38c9bac8192..05468ab0426 100644 --- a/src/slic3r/GUI/ImGuiWrapper.hpp +++ b/src/slic3r/GUI/ImGuiWrapper.hpp @@ -74,6 +74,11 @@ class ImGuiWrapper bool edited { false }; bool clicked { false }; bool deactivated_after_edit { false }; + // flag to indicate possibility to take snapshot from the slider value + // It's used from Gizmos to take snapshots just from the very beginning of the editing + bool can_take_snapshot { false }; + // When Undo/Redo snapshot is taken, then call this function + void invalidate_snapshot() { can_take_snapshot = false; } }; ImGuiWrapper(); @@ -95,12 +100,13 @@ class ImGuiWrapper float scaled(float x) const { return x * m_font_size; } ImVec2 scaled(float x, float y) const { return ImVec2(x * m_font_size, y * m_font_size); } - ImVec2 calc_text_size(const wxString &text, float wrap_width = -1.0f) const; + ImVec2 calc_text_size(const wxString &text, bool hide_text_after_double_hash = false, float wrap_width = -1.0f) const; ImVec2 calc_button_size(const wxString &text, const ImVec2 &button_size = ImVec2(0, 0)) const; ImVec2 get_item_spacing() const; float get_slider_float_height() const; const LastSliderStatus& get_last_slider_status() const { return m_last_slider_status; } + LastSliderStatus& get_last_slider_status() { return m_last_slider_status; } void set_next_window_pos(float x, float y, int flag, float pivot_x = 0.0f, float pivot_y = 0.0f); void set_next_window_bg_alpha(float alpha); @@ -118,9 +124,10 @@ class ImGuiWrapper bool begin(const wxString& name, bool* close, int flags = 0); void end(); - bool button(const wxString &label); - bool bbl_button(const wxString &label); - bool button(const wxString& label, float width, float height); + bool button(const wxString &label, const wxString& tooltip = {}); + bool bbl_button(const wxString &label, const wxString& tooltip = {}); + bool button(const wxString& label, float width, float height); + bool button(const wxString& label, const ImVec2 &size, bool enable); // default size = ImVec2(0.f, 0.f) bool radio_button(const wxString &label, bool active); bool input_double(const std::string &label, const double &value, const std::string &format = "%.3f"); bool input_double(const wxString &label, const double &value, const std::string &format = "%.3f"); @@ -157,7 +164,9 @@ class ImGuiWrapper bool image_button(ImTextureID user_texture_id, const ImVec2& size, const ImVec2& uv0 = ImVec2(0.0, 0.0), const ImVec2& uv1 = ImVec2(1.0, 1.0), int frame_padding = -1, const ImVec4& bg_col = ImVec4(0.0, 0.0, 0.0, 0.0), const ImVec4& tint_col = ImVec4(1.0, 1.0, 1.0, 1.0), ImGuiButtonFlags flags = 0); bool image_button(const wchar_t icon, const wxString& tooltip = L""); - bool combo(const wxString& label, const std::vector& options, int& selection); // Use -1 to not mark any option as selected + // Use selection = -1 to not mark any option as selected + bool combo(const std::string& label, const std::vector& options, int& selection, ImGuiComboFlags flags = 0, float label_width = 0.0f, float item_width = 0.0f); + bool combo(const wxString& label, const std::vector& options, int& selection, ImGuiComboFlags flags = 0, float label_width = 0.0f, float item_width = 0.0f); bool undo_redo_list(const ImVec2& size, const bool is_undo, bool (*items_getter)(const bool, int, const char**), int& hovered, int& selected, int& mouse_wheel); void search_list(const ImVec2& size, bool (*items_getter)(int, const char** label, const char** tooltip), char* search_str, Search::OptionViewParameters &view_params, diff --git a/src/slic3r/GUI/MsgDialog.cpp b/src/slic3r/GUI/MsgDialog.cpp index 8a91b80b8f9..64060b69580 100644 --- a/src/slic3r/GUI/MsgDialog.cpp +++ b/src/slic3r/GUI/MsgDialog.cpp @@ -1,3 +1,7 @@ +///|/ Copyright (c) Prusa Research 2018 - 2023 Oleksandra Iushchenko @YuSanka, Lukáš Matěna @lukasmatena, Vojtěch Bubník @bubnikv, Enrico Turri @enricoturri1966, David Kocík @kocikdav, Lukáš Hejl @hejllukas, Vojtěch Král @vojtechkral +///|/ +///|/ PrusaSlicer is released under the terms of the AGPLv3 or higher +///|/ #include "MsgDialog.hpp" #include @@ -411,6 +415,58 @@ InfoDialog::InfoDialog(wxWindow* parent, const wxString &title, const wxString& finalize(); } +wxString get_wraped_wxString(const wxString& in, size_t line_len /*=80*/) +{ + wxString out; + + for (size_t i = 0; i < in.size();) { + // Overwrite the character (space or newline) starting at ibreak? + bool overwrite = false; + // UTF8 representation of wxString. + // Where to break the line, index of character at the start of a UTF-8 sequence. + size_t ibreak = size_t(-1); + // Overwrite the character at ibreak (it is a whitespace) or not? + size_t j = i; + for (size_t cnt = 0; j < in.size();) { + if (bool newline = in[j] == '\n'; in[j] == ' ' || in[j] == '\t' || newline) { + // Overwrite the whitespace. + ibreak = j ++; + overwrite = true; + if (newline) + break; + } else if (in[j] == '/' +#ifdef _WIN32 + || in[j] == '\\' +#endif // _WIN32 + ) { + // Insert after the slash. + ibreak = ++ j; + overwrite = false; + } else + j += get_utf8_sequence_length(in.c_str() + j, in.size() - j); + if (++ cnt == line_len) { + if (ibreak == size_t(-1)) { + ibreak = j; + overwrite = false; + } + break; + } + } + if (j == in.size()) { + out.append(in.begin() + i, in.end()); + break; + } + assert(ibreak != size_t(-1)); + out.append(in.begin() + i, in.begin() + ibreak); + out.append('\n'); + i = ibreak; + if (overwrite) + ++ i; + } + + return out; +} + // InfoDialog DownloadDialog::DownloadDialog(wxWindow *parent, const wxString &msg, const wxString &title, bool is_marked_msg /* = false*/, long style /* = wxOK | wxICON_INFORMATION*/) : MsgDialog(parent, title, msg, style), msg(msg) diff --git a/src/slic3r/GUI/MsgDialog.hpp b/src/slic3r/GUI/MsgDialog.hpp index c9b0ded3c55..a136d2eed19 100644 --- a/src/slic3r/GUI/MsgDialog.hpp +++ b/src/slic3r/GUI/MsgDialog.hpp @@ -1,3 +1,7 @@ +///|/ Copyright (c) Prusa Research 2018 - 2022 Oleksandra Iushchenko @YuSanka, Lukáš Matěna @lukasmatena, David Kocík @kocikdav, Lukáš Hejl @hejllukas, Vojtěch Bubník @bubnikv, Vojtěch Král @vojtechkral +///|/ +///|/ PrusaSlicer is released under the terms of the AGPLv3 or higher +///|/ #ifndef slic3r_MsgDialog_hpp_ #define slic3r_MsgDialog_hpp_ @@ -128,6 +132,8 @@ class WarningDialog : public MsgDialog virtual ~WarningDialog() = default; }; +wxString get_wraped_wxString(const wxString& text_in, size_t line_len = 80); + #if 1 // Generic static line, used intead of wxStaticLine //class StaticLine: public wxTextCtrl diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 4b3aa5d1709..93685502886 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -1,3 +1,22 @@ +///|/ Copyright (c) Prusa Research 2018 - 2023 Vojtěch Bubník @bubnikv, Lukáš Matěna @lukasmatena, Oleksandra Iushchenko @YuSanka, Enrico Turri @enricoturri1966, Tomáš Mészáros @tamasmeszaros, David Kocík @kocikdav, Lukáš Hejl @hejllukas, Pavel Mikuš @Godrak, Filip Sykala @Jony01, Vojtěch Král @vojtechkral +///|/ Copyright (c) 2022 Michael Kirsch +///|/ Copyright (c) 2021 Boleslaw Ciesielski +///|/ Copyright (c) 2019 John Drake @foxox +///|/ +///|/ ported from lib/Slic3r/GUI/Plater.pm: +///|/ Copyright (c) Prusa Research 2016 - 2019 Vojtěch Bubník @bubnikv, Vojtěch Král @vojtechkral, Enrico Turri @enricoturri1966, Oleksandra Iushchenko @YuSanka, Lukáš Matěna @lukasmatena, Tomáš Mészáros @tamasmeszaros +///|/ Copyright (c) 2018 Martin Loidl @LoidlM +///|/ Copyright (c) 2017 Matthias Gazzari @qtux +///|/ Copyright (c) Slic3r 2012 - 2016 Alessandro Ranellucci @alranel +///|/ Copyright (c) 2017 Joseph Lenox @lordofhyphens +///|/ Copyright (c) 2015 Daren Schwenke +///|/ Copyright (c) 2014 Mark Hindess +///|/ Copyright (c) 2012 Mike Sheldrake @mesheldrake +///|/ Copyright (c) 2012 Henrik Brix Andersen @henrikbrixandersen +///|/ Copyright (c) 2012 Sam Wong +///|/ +///|/ PrusaSlicer is released under the terms of the AGPLv3 or higher +///|/ #include "Plater.hpp" #include "libslic3r/Config.hpp" @@ -128,6 +147,7 @@ #include "Gizmos/GLGizmosManager.hpp" #endif // __APPLE__ +#include #include // Needs to be last because reasons :-/ #include "WipeTowerDialog.hpp" @@ -8273,14 +8293,6 @@ void Plater::add_model(bool imperial_units, std::string fname) wxGetApp().mainframe->update_title(); } } -std::array get_cut_plane(const BoundingBoxf3& bbox, const double& cut_height) { - std::array plane_pts; - plane_pts[0] = Vec3d(bbox.min(0), bbox.min(1), cut_height); - plane_pts[1] = Vec3d(bbox.max(0), bbox.min(1), cut_height); - plane_pts[2] = Vec3d(bbox.max(0), bbox.max(1), cut_height); - plane_pts[3] = Vec3d(bbox.min(0), bbox.max(1), cut_height); - return plane_pts; -} void Plater::calib_pa(const Calib_Params& params) { @@ -8403,6 +8415,36 @@ void Plater::_calib_pa_pattern(const Calib_Params& params) changed_objects({ 0 }); } +void Plater::cut_horizontal(size_t obj_idx, size_t instance_idx, double z, ModelObjectCutAttributes attributes) +{ + wxCHECK_RET(obj_idx < p->model.objects.size(), "obj_idx out of bounds"); + auto *object = p->model.objects[obj_idx]; + + wxCHECK_RET(instance_idx < object->instances.size(), "instance_idx out of bounds"); + + if (! attributes.has(ModelObjectCutAttribute::KeepUpper) && ! attributes.has(ModelObjectCutAttribute::KeepLower)) + return; + + wxBusyCursor wait; + const auto new_objects = Cut::cut_horizontal(object, instance_idx, z, attributes); + + remove(obj_idx); + p->load_model_objects(new_objects); + + // now process all updates of the 3d scene + update(); + + // Update InfoItems in ObjectList after update() to use of a correct value of the GLCanvas3D::is_sinking(), + // which is updated after a view3D->reload_scene(false, flags & (unsigned int)UpdateParams::FORCE_FULL_SCREEN_REFRESH) call + for (size_t idx = 0; idx < p->model.objects.size(); idx++) + wxGetApp().obj_list()->update_info_items(idx); + + Selection& selection = p->get_selection(); + size_t last_id = p->model.objects.size() - 1; + for (size_t i = 0; i < new_objects.size(); ++i) + selection.add_object((unsigned int)(last_id - i), i == 0); +} + void Plater::_calib_pa_tower(const Calib_Params& params) { add_model(false, Slic3r::resources_dir() + "/calib/pressure_advance/tower_with_seam.stl"); @@ -8439,8 +8481,7 @@ void Plater::_calib_pa_tower(const Calib_Params& params) { auto new_height = std::ceil((params.end - params.start) / params.step) + 1; auto obj_bb = model().objects[0]->bounding_box(); if (new_height < obj_bb.size().z()) { - std::array plane_pts = get_cut_plane(obj_bb, new_height); - cut(0, 0, plane_pts, ModelObjectCutAttribute::KeepLower); + cut_horizontal(0, 0, new_height, ModelObjectCutAttribute::KeepLower); } _calib_pa_select_added_objects(); @@ -8581,8 +8622,7 @@ void Plater::calib_temp(const Calib_Params& params) { // add EPSILON offset to avoid cutting at the exact location where the flat surface is auto new_height = block_count * 10.0 + EPSILON; if (new_height < obj_bb.size().z()) { - std::array plane_pts = get_cut_plane(obj_bb, new_height); - cut(0, 0, plane_pts, ModelObjectCutAttribute::KeepLower); + cut_horizontal(0, 0, new_height, ModelObjectCutAttribute::KeepLower); } } @@ -8592,8 +8632,7 @@ void Plater::calib_temp(const Calib_Params& params) { if(block_count > 0){ auto new_height = block_count * 10.0 + EPSILON; if (new_height < obj_bb.size().z()) { - std::array plane_pts = get_cut_plane(obj_bb, new_height); - cut(0, 0, plane_pts, ModelObjectCutAttribute::KeepUpper); + cut_horizontal(0, 0, new_height, ModelObjectCutAttribute::KeepUpper); } } @@ -8661,8 +8700,7 @@ void Plater::calib_max_vol_speed(const Calib_Params& params) auto obj_bb = obj->bounding_box(); auto height = (params.end - params.start + 1) / params.step; if (height < obj_bb.size().z()) { - std::array plane_pts = get_cut_plane(obj_bb, height); - cut(0, 0, plane_pts, ModelObjectCutAttribute::KeepLower); + cut_horizontal(0, 0, height, ModelObjectCutAttribute::KeepLower); } auto new_params = params; @@ -8710,8 +8748,7 @@ void Plater::calib_retraction(const Calib_Params& params) auto obj_bb = obj->bounding_box(); auto height = 1.0 + 0.4 + ((params.end - params.start)) / params.step; if (height < obj_bb.size().z()) { - std::array plane_pts = get_cut_plane(obj_bb, height); - cut(0, 0, plane_pts, ModelObjectCutAttribute::KeepLower); + cut_horizontal(0, 0, height, ModelObjectCutAttribute::KeepLower); } p->background_process.fff_print()->set_calib_params(params); @@ -8752,8 +8789,7 @@ void Plater::calib_VFA(const Calib_Params& params) auto obj_bb = model().objects[0]->bounding_box(); auto height = 5 * ((params.end - params.start) / params.step + 1); if (height < obj_bb.size().z()) { - std::array plane_pts = get_cut_plane(obj_bb, height); - cut(0, 0, plane_pts, ModelObjectCutAttribute::KeepLower); + cut_horizontal(0, 0, height, ModelObjectCutAttribute::KeepLower); } p->background_process.fff_print()->set_calib_params(params); @@ -9858,27 +9894,16 @@ void Plater::convert_unit(ConversionType conv_type) } } -// BBS: replace z with plane_points -void Plater::cut(size_t obj_idx, size_t instance_idx, std::array plane_points, ModelObjectCutAttributes attributes) +void Plater::apply_cut_object_to_model(size_t obj_idx, const ModelObjectPtrs& new_objects) { - wxCHECK_RET(obj_idx < p->model.objects.size(), "obj_idx out of bounds"); - auto *object = p->model.objects[obj_idx]; + model().delete_object(obj_idx); + sidebar().obj_list()->delete_object_from_list(obj_idx); - wxCHECK_RET(instance_idx < object->instances.size(), "instance_idx out of bounds"); - - if (! attributes.has(ModelObjectCutAttribute::KeepUpper) && ! attributes.has(ModelObjectCutAttribute::KeepLower)) - return; - - wxBusyCursor wait; - // BBS: replace z with plane_points - const auto new_objects = object->cut(instance_idx, plane_points, attributes); - - remove(obj_idx); - p->load_model_objects(new_objects); + // suppress to call selection update for Object List to avoid call of early Gizmos on/off update + p->load_model_objects(new_objects, false, false); // now process all updates of the 3d scene update(); - // Update InfoItems in ObjectList after update() to use of a correct value of the GLCanvas3D::is_sinking(), // which is updated after a view3D->reload_scene(false, flags & (unsigned int)UpdateParams::FORCE_FULL_SCREEN_REFRESH) call for (size_t idx = 0; idx < p->model.objects.size(); idx++) @@ -9888,62 +9913,10 @@ void Plater::cut(size_t obj_idx, size_t instance_idx, std::array plane size_t last_id = p->model.objects.size() - 1; for (size_t i = 0; i < new_objects.size(); ++i) selection.add_object((unsigned int)(last_id - i), i == 0); -} - -// BBS -void Plater::segment(size_t obj_idx, size_t instance_idx, double smoothing_alpha, int segment_number) -{ - wxCHECK_RET(obj_idx < p->model.objects.size(), "obj_idx out of bounds"); - auto* object = p->model.objects[obj_idx]; - - wxCHECK_RET(instance_idx < object->instances.size(), "instance_idx out of bounds"); - - Plater::TakeSnapshot snapshot(this, "Segment"); - - wxBusyCursor wait; - // real process - PresetBundle& preset_bundle = *wxGetApp().preset_bundle; - const auto print_tech = preset_bundle.printers.get_edited_preset().printer_technology(); - const size_t filament_cnt = print_tech != ptFFF ? 1 : preset_bundle.filament_presets.size(); - const auto new_objects = object->segment(instance_idx, filament_cnt, smoothing_alpha, segment_number); - - remove(obj_idx); - p->load_model_objects(new_objects); - - Selection& selection = p->get_selection(); - size_t last_id = p->model.objects.size() - 1; - for (size_t i = 0; i < new_objects.size(); ++i) - { - selection.add_object((unsigned int)(last_id - i), i == 0); - } -} - -// BBS -void Plater::merge(size_t obj_idx, std::vector& vol_indeces) -{ - wxCHECK_RET(obj_idx < p->model.objects.size(), "obj_idx out of bounds"); - auto* object = p->model.objects[obj_idx]; - - Plater::TakeSnapshot snapshot(this, "Merge"); - - wxBusyCursor wait; - // real process - PresetBundle& preset_bundle = *wxGetApp().preset_bundle; - const auto print_tech = preset_bundle.printers.get_edited_preset().printer_technology(); - // BBS - const size_t filament_cnt = print_tech != ptFFF ? 1 : preset_bundle.filament_presets.size(); - const auto new_objects = object->merge_volumes(vol_indeces); - - remove(obj_idx); - p->load_model_objects(new_objects); - - Selection& selection = p->get_selection(); - size_t last_id = p->model.objects.size() - 1; - for (size_t i = 0; i < new_objects.size(); ++i) - { - selection.add_object((unsigned int)(last_id - i), i == 0); - } + // UIThreadWorker w; + // arrange(w, true); + // w.wait_for_idle(); } void Plater::export_gcode(bool prefer_removable) diff --git a/src/slic3r/GUI/Plater.hpp b/src/slic3r/GUI/Plater.hpp index 62c505f5ad4..809a3ed8017 100644 --- a/src/slic3r/GUI/Plater.hpp +++ b/src/slic3r/GUI/Plater.hpp @@ -1,3 +1,19 @@ +///|/ Copyright (c) Prusa Research 2018 - 2023 Tomáš Mészáros @tamasmeszaros, Oleksandra Iushchenko @YuSanka, Enrico Turri @enricoturri1966, David Kocík @kocikdav, Lukáš Hejl @hejllukas, Vojtěch Bubník @bubnikv, Lukáš Matěna @lukasmatena, Pavel Mikuš @Godrak, Filip Sykala @Jony01, Vojtěch Král @vojtechkral +///|/ +///|/ ported from lib/Slic3r/GUI/Plater.pm: +///|/ Copyright (c) Prusa Research 2016 - 2019 Vojtěch Bubník @bubnikv, Vojtěch Král @vojtechkral, Enrico Turri @enricoturri1966, Oleksandra Iushchenko @YuSanka, Lukáš Matěna @lukasmatena, Tomáš Mészáros @tamasmeszaros +///|/ Copyright (c) 2018 Martin Loidl @LoidlM +///|/ Copyright (c) 2017 Matthias Gazzari @qtux +///|/ Copyright (c) Slic3r 2012 - 2016 Alessandro Ranellucci @alranel +///|/ Copyright (c) 2017 Joseph Lenox @lordofhyphens +///|/ Copyright (c) 2015 Daren Schwenke +///|/ Copyright (c) 2014 Mark Hindess +///|/ Copyright (c) 2012 Mike Sheldrake @mesheldrake +///|/ Copyright (c) 2012 Henrik Brix Andersen @henrikbrixandersen +///|/ Copyright (c) 2012 Sam Wong +///|/ +///|/ PrusaSlicer is released under the terms of the AGPLv3 or higher +///|/ #ifndef slic3r_Plater_hpp_ #define slic3r_Plater_hpp_ @@ -25,6 +41,7 @@ #include "libslic3r/PrintBase.hpp" #include "libslic3r/calib.hpp" +#include "libslic3r/CutUtils.hpp" #define FILAMENT_SYSTEM_COLORS_NUM 16 @@ -41,8 +58,6 @@ class BuildVolume; enum class BuildVolume_Type : unsigned char; class Model; class ModelObject; -enum class ModelObjectCutAttribute : int; -using ModelObjectCutAttributes = enum_bitmask; class ModelInstance; class Print; class SLAPrint; @@ -323,12 +338,7 @@ class Plater: public wxPanel void scale_selection_to_fit_print_volume(); void convert_unit(ConversionType conv_type); - // BBS: replace z with plane_points - void cut(size_t obj_idx, size_t instance_idx, std::array plane_points, ModelObjectCutAttributes attributes); - - // BBS: segment model with CGAL - void segment(size_t obj_idx, size_t instance_idx, double smoothing_alpha=0.5, int segment_number=5); - void merge(size_t obj_idx, std::vector& vol_indeces); + void apply_cut_object_to_model(size_t init_obj_idx, const ModelObjectPtrs& cut_objects); void send_to_printer(bool isall = false); void export_gcode(bool prefer_removable); @@ -742,6 +752,8 @@ class Plater: public wxPanel void _calib_pa_tower(const Calib_Params& params); void _calib_pa_select_added_objects(); + void cut_horizontal(size_t obj_idx, size_t instance_idx, double z, ModelObjectCutAttributes attributes); + friend class SuppressBackgroundProcessingUpdate; }; diff --git a/src/slic3r/Utils/CalibUtils.cpp b/src/slic3r/Utils/CalibUtils.cpp index a496d1ff34a..f1cafadd26f 100644 --- a/src/slic3r/Utils/CalibUtils.cpp +++ b/src/slic3r/Utils/CalibUtils.cpp @@ -4,6 +4,7 @@ #include "../GUI/DeviceManager.hpp" #include "../GUI/Jobs/ProgressIndicator.hpp" #include "../GUI/PartPlate.hpp" +#include "libslic3r/CutUtils.hpp" #include "libslic3r/Model.hpp" @@ -133,7 +134,7 @@ bool CalibUtils::validate_input_flow_ratio(wxString flow_ratio, float* output_va return true; } -static void cut_model(Model &model, std::array plane_points, ModelObjectCutAttributes attributes) +static void cut_model(Model &model, double z, ModelObjectCutAttributes attributes) { size_t obj_idx = 0; size_t instance_idx = 0; @@ -142,7 +143,7 @@ static void cut_model(Model &model, std::array plane_points, ModelObje auto* object = model.objects[0]; - const auto new_objects = object->cut(instance_idx, plane_points, attributes); + const auto new_objects = Cut::cut_horizontal(object, instance_idx, z, attributes); model.delete_object(obj_idx); for (ModelObject *model_object : new_objects) { @@ -173,16 +174,6 @@ static void read_model_from_file(const std::string& input_file, Model& model) object->ensure_on_bed(); } -std::array get_cut_plane_points(const BoundingBoxf3 &bbox, const double &cut_height) -{ - std::array plane_pts; - plane_pts[0] = Vec3d(bbox.min(0), bbox.min(1), cut_height); - plane_pts[1] = Vec3d(bbox.max(0), bbox.min(1), cut_height); - plane_pts[2] = Vec3d(bbox.max(0), bbox.max(1), cut_height); - plane_pts[3] = Vec3d(bbox.min(0), bbox.max(1), cut_height); - return plane_pts; -} - void CalibUtils::calib_PA(const X1CCalibInfos& calib_infos, int mode, wxString& error_message) { DeviceManager *dev = Slic3r::GUI::wxGetApp().getDeviceManager(); @@ -564,12 +555,7 @@ void CalibUtils::calib_temptue(const CalibInfo &calib_info, wxString &error_mess // add EPSILON offset to avoid cutting at the exact location where the flat surface is auto new_height = block_count * 10.0 + EPSILON; if (new_height < obj_bb.size().z()) { - std::array plane_pts; - plane_pts[0] = Vec3d(obj_bb.min(0), obj_bb.min(1), new_height); - plane_pts[1] = Vec3d(obj_bb.max(0), obj_bb.min(1), new_height); - plane_pts[2] = Vec3d(obj_bb.max(0), obj_bb.max(1), new_height); - plane_pts[3] = Vec3d(obj_bb.min(0), obj_bb.max(1), new_height); - cut_model(model, plane_pts, ModelObjectCutAttribute::KeepLower); + cut_model(model, new_height, ModelObjectCutAttribute::KeepLower); } } @@ -579,12 +565,7 @@ void CalibUtils::calib_temptue(const CalibInfo &calib_info, wxString &error_mess if (block_count > 0) { auto new_height = block_count * 10.0 + EPSILON; if (new_height < obj_bb.size().z()) { - std::array plane_pts; - plane_pts[0] = Vec3d(obj_bb.min(0), obj_bb.min(1), new_height); - plane_pts[1] = Vec3d(obj_bb.max(0), obj_bb.min(1), new_height); - plane_pts[2] = Vec3d(obj_bb.max(0), obj_bb.max(1), new_height); - plane_pts[3] = Vec3d(obj_bb.min(0), obj_bb.max(1), new_height); - cut_model(model, plane_pts, ModelObjectCutAttribute::KeepUpper); + cut_model(model, new_height, ModelObjectCutAttribute::KeepUpper); } } @@ -670,12 +651,7 @@ void CalibUtils::calib_max_vol_speed(const CalibInfo &calib_info, wxString &erro auto obj_bb = obj->bounding_box(); double height = (params.end - params.start + 1) / params.step; if (height < obj_bb.size().z()) { - std::array plane_pts; - plane_pts[0] = Vec3d(obj_bb.min(0), obj_bb.min(1), height); - plane_pts[1] = Vec3d(obj_bb.max(0), obj_bb.min(1), height); - plane_pts[2] = Vec3d(obj_bb.max(0), obj_bb.max(1), height); - plane_pts[3] = Vec3d(obj_bb.min(0), obj_bb.max(1), height); - cut_model(model, plane_pts, ModelObjectCutAttribute::KeepLower); + cut_model(model, height, ModelObjectCutAttribute::KeepLower); } auto new_params = params; @@ -731,12 +707,7 @@ void CalibUtils::calib_VFA(const CalibInfo &calib_info, wxString &error_message) auto obj_bb = model.objects[0]->bounding_box(); auto height = 5 * ((params.end - params.start) / params.step + 1); if (height < obj_bb.size().z()) { - std::array plane_pts; - plane_pts[0] = Vec3d(obj_bb.min(0), obj_bb.min(1), height); - plane_pts[1] = Vec3d(obj_bb.max(0), obj_bb.min(1), height); - plane_pts[2] = Vec3d(obj_bb.max(0), obj_bb.max(1), height); - plane_pts[3] = Vec3d(obj_bb.min(0), obj_bb.max(1), height); - cut_model(model, plane_pts, ModelObjectCutAttribute::KeepLower); + cut_model(model, height, ModelObjectCutAttribute::KeepLower); } else { error_message = _L("The start, end or step is not valid value."); @@ -790,8 +761,7 @@ void CalibUtils::calib_retraction(const CalibInfo &calib_info, wxString &error_m auto obj_bb = obj->bounding_box(); auto height = 1.0 + 0.4 + ((params.end - params.start)) / params.step; if (height < obj_bb.size().z()) { - std::array plane_pts = get_cut_plane_points(obj_bb, height); - cut_model(model, plane_pts, ModelObjectCutAttribute::KeepLower); + cut_model(model, height, ModelObjectCutAttribute::KeepLower); } DynamicPrintConfig full_config; From 3ec927a84139a61b45bf7c5145f8c1c9d56da45e Mon Sep 17 00:00:00 2001 From: Noisyfox Date: Wed, 1 Nov 2023 22:35:20 +0800 Subject: [PATCH 88/99] Cut: Use Orca color schema and dialog layout --- src/imgui/imconfig.h | 5 +- src/slic3r/GUI/Gizmos/GLGizmoCut.cpp | 429 ++++++++++++++------------- src/slic3r/GUI/Gizmos/GLGizmoCut.hpp | 13 +- 3 files changed, 238 insertions(+), 209 deletions(-) diff --git a/src/imgui/imconfig.h b/src/imgui/imconfig.h index e9cedd8f30e..9380ea16498 100644 --- a/src/imgui/imconfig.h +++ b/src/imgui/imconfig.h @@ -153,9 +153,7 @@ namespace ImGui // const wchar_t CustomSupportsMarker = 0x1D; // const wchar_t CustomSeamMarker = 0x1E; // const wchar_t MmuSegmentationMarker = 0x1F; - const wchar_t PlugMarker = 0x1E; - const wchar_t DowelMarker = 0x1F; - const wchar_t SnapMarker = 0x20; + // Do not forget use following letters only in wstring //BBS use 08xx to avoid unicode character which may be used const wchar_t DocumentationButton = 0x0800; @@ -200,7 +198,6 @@ namespace ImGui const wchar_t CloseBlockNotifHoverButton = 0x0834; const wchar_t BlockNotifErrorIcon = 0x0835; const wchar_t ClipboardBtnDarkIcon = 0x0836; - const wchar_t InfoMarkerSmall = 0x0837; // void MyFunction(const char* name, const MyMatrix44& v); } diff --git a/src/slic3r/GUI/Gizmos/GLGizmoCut.cpp b/src/slic3r/GUI/Gizmos/GLGizmoCut.cpp index 7f6e9fc1a81..cce7e9e9d07 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoCut.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoCut.cpp @@ -197,17 +197,7 @@ GLGizmoCut3D::GLGizmoCut3D(GLCanvas3D& parent, const std::string& icon_filename, m_connector_modes = { _u8L("Auto"), _u8L("Manual") }; - std::map connetor_types = { - {ImGui::PlugMarker , _u8L("Plug") }, - {ImGui::DowelMarker, _u8L("Dowel") }, - //TRN Connectors type next to "Plug" and "Dowel" - {ImGui::SnapMarker, _u8L("Snap") }, - }; - for (auto connector : connetor_types) { - std::string type_label = " " + connector.second + " "; - type_label += connector.first; - m_connector_types.push_back(type_label); - } + m_connector_types = { _u8L("Plug"), _u8L("Dowel"), _u8L("Snap") }; m_connector_styles = { _u8L("Prism"), _u8L("Frustum") // , _u8L("Claw") @@ -519,8 +509,10 @@ void GLGizmoCut3D::switch_to_mode(size_t new_mode) bool GLGizmoCut3D::render_cut_mode_combo() { ImGui::AlignTextToFramePadding(); + ImGuiWrapper::push_combo_style(m_parent.get_scale()); int selection_idx = int(m_mode); const bool is_changed = m_imgui->combo(_u8L("Mode"), m_modes, selection_idx, 0, m_label_width, m_control_width); + ImGuiWrapper::pop_combo_style(); if (is_changed) { Plater::TakeSnapshot snapshot(wxGetApp().plater(), _u8L("Change cut mode"), UndoRedo::SnapshotType::GizmoAction); @@ -533,11 +525,34 @@ bool GLGizmoCut3D::render_cut_mode_combo() bool GLGizmoCut3D::render_combo(const std::string& label, const std::vector& lines, int& selection_idx) { + ImGuiWrapper::push_combo_style(m_parent.get_scale()); ImGui::AlignTextToFramePadding(); - const bool is_changed = m_imgui->combo(label, lines, selection_idx, 0, m_label_width, m_control_width); + m_imgui->text(label); + ImGui::SameLine(m_label_width); + ImGui::PushItemWidth(m_editing_window_width); - //if (is_changed) - // update_connector_shape(); + size_t selection_out = selection_idx; + + const char* selected_str = (selection_idx >= 0 && selection_idx < int(lines.size())) ? lines[selection_idx].c_str() : ""; + if (ImGui::BBLBeginCombo(("##" + label).c_str(), selected_str, 0)) { + for (size_t line_idx = 0; line_idx < lines.size(); ++line_idx) { + ImGui::PushID(int(line_idx)); + if (ImGui::Selectable("", line_idx == selection_idx)) + selection_out = line_idx; + + ImGui::SameLine(); + ImGui::Text("%s", lines[line_idx].c_str()); + ImGui::PopID(); + } + + ImGui::EndCombo(); + } + + bool is_changed = selection_idx != selection_out; + selection_idx = selection_out; + + //if (is_changed) update_connector_shape(); + ImGuiWrapper::pop_combo_style(); return is_changed; } @@ -564,48 +579,72 @@ bool GLGizmoCut3D::render_double_input(const std::string& label, double& value_i bool GLGizmoCut3D::render_slider_double_input(const std::string& label, float& value_in, float& tolerance_in, float min_val/* = -0.1f*/, float max_tolerance/* = -0.1f*/) { - static constexpr const float UndefMinVal = -0.1f; + // -------- [ ] -------- [ ] + // slider_with + item_in_gap + first_input_width + item_out_gap + slider_with + item_in_gap + second_input_width + double slider_with = 0.24 * m_editing_window_width; // m_control_width * 0.35; + double item_in_gap = 0.01 * m_editing_window_width; + double item_out_gap = 0.01 * m_editing_window_width; + double first_input_width = 0.29 * m_editing_window_width; + double second_input_width = 0.29 * m_editing_window_width; + + constexpr float UndefMinVal = -0.1f; const float f_mm_to_in = static_cast(GizmoObjectManipulation::mm_to_in); - auto render_slider = [this, f_mm_to_in] - (const std::string& label, float& val, float def_val, float max_val, const wxString& tooltip) { - float min_val = val < 0.f ? UndefMinVal : def_val; - float value = val; - if (m_imperial_units) { - min_val *= f_mm_to_in; - value *= f_mm_to_in; - } - const float old_val = value; - const std::string format = val < 0.f ? UndefLabel : (m_imperial_units ? "%.4f " + _u8L("in") : "%.2f " + _u8L("mm")); + ImGui::AlignTextToFramePadding(); + m_imgui->text(label); + ImGui::SameLine(m_label_width); + ImGui::PushItemWidth(slider_with); - m_imgui->slider_float(label.c_str(), &value, min_val, max_val, format.c_str(), 1.f, true, tooltip); - val = value * (m_imperial_units ? static_cast(GizmoObjectManipulation::in_to_mm) : 1.f); + double left_width = m_label_width + slider_with + item_in_gap; - m_is_slider_editing_done |= m_imgui->get_last_slider_status().deactivated_after_edit; + bool m_imperial_units = false; - return !is_approx(old_val, value); - }; + float value = value_in; + if (m_imperial_units) + value *= f_mm_to_in; + float old_val = value; const BoundingBoxf3 bbox = m_bounding_box; const float mean_size = float((bbox.size().x() + bbox.size().y() + bbox.size().z()) / 9.0) * (m_imperial_units ? f_mm_to_in : 1.f); const float min_v = min_val > 0.f ? /*std::min(max_val, mean_size)*/min_val : 1.f; - m_imgui->text(label); + float min_size = value_in < 0.f ? UndefMinVal : min_v; + if (m_imperial_units) { + min_size *= f_mm_to_in; + } + std::string format = value_in < 0.f ? " " : m_imperial_units ? "%.4f " + _u8L("in") : "%.2f " + _u8L("mm"); - ImGui::SameLine(m_label_width); - ImGui::PushItemWidth(m_control_width * 0.7f); + m_imgui->bbl_slider_float_style(("##" + label).c_str(), &value, min_size, mean_size, format.c_str()); -// const bool is_value_changed = render_slider("##" + label, value_in, 1.f, mean_size, _L("Value")); - const bool is_value_changed = render_slider("##" + label, value_in, min_v, mean_size, _L("Value")); - - ImGui::SameLine(); - ImGui::PushItemWidth(m_control_width * 0.45f); + ImGui::SameLine(left_width); + ImGui::PushItemWidth(first_input_width); + ImGui::BBLDragFloat(("##input_" + label).c_str(), &value, 0.05f, min_size, mean_size, format.c_str()); + + value_in = value * float(m_imperial_units ? GizmoObjectManipulation::in_to_mm : 1.0); + + left_width += (first_input_width + item_out_gap); + ImGui::SameLine(left_width); + ImGui::PushItemWidth(slider_with); + + float tolerance = tolerance_in; + if (m_imperial_units) + tolerance *= f_mm_to_in; + float old_tolerance = tolerance; + // std::string format_t = tolerance_in < 0.f ? " " : "%.f %%"; + float min_tolerance = tolerance_in < 0.f ? UndefMinVal : 0.f; + const float max_tolerance_v = max_tolerance > 0.f ? std::min(max_tolerance, 0.5f * mean_size) : 0.5f * mean_size; + + m_imgui->bbl_slider_float_style(("##tolerance_" + label).c_str(), &tolerance, min_tolerance, max_tolerance_v, format.c_str(), 1.f, true, + _L("Tolerance")); -// const bool is_tolerance_changed = render_slider("##tolerance_" + label, tolerance_in, 0.f, 0.5f * mean_size, _L("Tolerance")); - const float max_tolerance_v = max_tolerance > 0.f ? std::min(max_tolerance, 0.5f * mean_size) : 0.5f * mean_size; - const bool is_tolerance_changed = render_slider("##tolerance_" + label, tolerance_in, 0.f, max_tolerance_v, _L("Tolerance")); + left_width += (slider_with + item_in_gap); + ImGui::SameLine(left_width); + ImGui::PushItemWidth(second_input_width); + ImGui::BBLDragFloat(("##tolerance_input_" + label).c_str(), &tolerance, 0.05f, min_tolerance, max_tolerance_v, format.c_str()); - return is_value_changed || is_tolerance_changed; + tolerance_in = tolerance * float(m_imperial_units ? GizmoObjectManipulation::in_to_mm : 1.0); + + return !is_approx(old_val, value) || !is_approx(old_tolerance, tolerance); } void GLGizmoCut3D::render_move_center_input(int axis) @@ -655,17 +694,15 @@ void GLGizmoCut3D::render_connect_mode_radio_button(CutConnectorMode mode) bool GLGizmoCut3D::render_reset_button(const std::string& label_id, const std::string& tooltip) const { - const ImGuiStyle& style = ImGui::GetStyle(); + const ImGuiStyle &style = ImGui::GetStyle(); - ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, { 1, style.ItemSpacing.y }); + ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, {1, style.ItemSpacing.y}); - ImGui::PushStyleColor(ImGuiCol_Button, { 0.25f, 0.25f, 0.25f, 0.0f }); - ImGui::PushStyleColor(ImGuiCol_ButtonHovered, { 0.4f, 0.4f, 0.4f, 1.0f }); - ImGui::PushStyleColor(ImGuiCol_ButtonActive, { 0.4f, 0.4f, 0.4f, 1.0f }); + ImGui::PushStyleColor(ImGuiCol_Button, {0.25f, 0.25f, 0.25f, 0.0f}); + ImGui::PushStyleColor(ImGuiCol_ButtonHovered, {0.4f, 0.4f, 0.4f, 1.0f}); + ImGui::PushStyleColor(ImGuiCol_ButtonActive, {0.4f, 0.4f, 0.4f, 1.0f}); - std::string btn_label; - btn_label += ImGui::RevertBtn; - const bool revert = ImGui::Button((btn_label +"##" + label_id).c_str()); + const bool revert = m_imgui->button(wxString(ImGui::RevertBtn) + "##" + label_id); ImGui::PopStyleColor(3); @@ -1178,12 +1215,14 @@ bool GLGizmoCut3D::on_init() const wxString alt = GUI::shortkey_alt_prefix(); const wxString shift = "Shift+"; - m_shortcuts.push_back(std::make_pair(_L("Left click"), _L("Add connector"))); - m_shortcuts.push_back(std::make_pair(_L("Right click"), _L("Remove connector"))); - m_shortcuts.push_back(std::make_pair(_L("Drag"), _L("Move connector"))); - m_shortcuts.push_back(std::make_pair(shift + _L("Left click"), _L("Add connector to selection"))); - m_shortcuts.push_back(std::make_pair(alt + _L("Left click"), _L("Remove connector from selection"))); - m_shortcuts.push_back(std::make_pair(ctrl + "A", _L("Select all connectors"))); + m_shortcuts_cut.push_back(std::make_pair(shift + _L("Drag"), _L("Draw cut line"))); + + m_shortcuts_connector.push_back(std::make_pair(_L("Left click"), _L("Add connector"))); + m_shortcuts_connector.push_back(std::make_pair(_L("Right click"), _L("Remove connector"))); + m_shortcuts_connector.push_back(std::make_pair(_L("Drag"), _L("Move connector"))); + m_shortcuts_connector.push_back(std::make_pair(shift + _L("Left click"), _L("Add connector to selection"))); + m_shortcuts_connector.push_back(std::make_pair(alt + _L("Left click"), _L("Remove connector from selection"))); + m_shortcuts_connector.push_back(std::make_pair(ctrl + "A", _L("Select all connectors"))); return true; } @@ -2197,26 +2236,6 @@ void GLGizmoCut3D::render_debug_input_window(float x) m_imgui->end(); } -void GLGizmoCut3D::adjust_window_position(float x, float y, float bottom_limit) -{ - static float last_y = 0.0f; - static float last_h = 0.0f; - - const float win_h = ImGui::GetWindowHeight(); - y = std::min(y, bottom_limit - win_h); - - ImGui::SetWindowPos(ImVec2(x, y), ImGuiCond_Always); - - if (!is_approx(last_h, win_h) || !is_approx(last_y, y)) { - // ask canvas for another frame to render the window in the correct position - m_imgui->set_requires_extra_frame(); - if (!is_approx(last_h, win_h)) - last_h = win_h; - if (!is_approx(last_y, y)) - last_y = y; - } -} - void GLGizmoCut3D::unselect_all_connectors() { std::fill(m_selected.begin(), m_selected.end(), false); @@ -2230,28 +2249,6 @@ void GLGizmoCut3D::select_all_connectors() m_selected_count = int(m_selected.size()); } -void GLGizmoCut3D::render_shortcuts() -{ - if (m_imgui->button("? " + (m_show_shortcuts ? wxString(ImGui::CollapseBtn) : wxString(ImGui::ExpandBtn)))) - m_show_shortcuts = !m_show_shortcuts; - - if (m_shortcut_label_width < 0.f) { - for (const auto& shortcut : m_shortcuts) { - const float width = m_imgui->calc_text_size(shortcut.first).x; - if (m_shortcut_label_width < width) - m_shortcut_label_width = width; - } - m_shortcut_label_width += +m_imgui->scaled(1.f); - } - - if (m_show_shortcuts) - for (const auto&shortcut : m_shortcuts ){ - m_imgui->text_colored(ImGuiWrapper::COL_ORANGE_LIGHT, shortcut.first); - ImGui::SameLine(m_shortcut_label_width); - m_imgui->text(shortcut.second); - } -} - void GLGizmoCut3D::apply_selected_connectors(std::function apply_fn) { for (size_t idx = 0; idx < m_selected.size(); idx++) @@ -2261,11 +2258,8 @@ void GLGizmoCut3D::apply_selected_connectors(std::function app update_raycasters_for_picking_transform(); } -void GLGizmoCut3D::render_connectors_input_window(CutConnectors &connectors) +void GLGizmoCut3D::render_connectors_input_window(CutConnectors &connectors, float x, float y, float bottom_limit) { - // add shortcuts panel - render_shortcuts(); - // Connectors section ImGui::Separator(); @@ -2290,11 +2284,13 @@ void GLGizmoCut3D::render_connectors_input_window(CutConnectors &connectors) render_flip_plane_button(m_connectors_editing && connectors.empty()); m_imgui->text(m_labels_map["Type"]); + ImGui::PushStyleColor(ImGuiCol_CheckMark, ImVec4(0.00f, 0.00f, 0.00f, 1.00f)); bool type_changed = render_connect_type_radio_button(CutConnectorType::Plug); type_changed |= render_connect_type_radio_button(CutConnectorType::Dowel); type_changed |= render_connect_type_radio_button(CutConnectorType::Snap); if (type_changed) apply_selected_connectors([this, &connectors] (size_t idx) { connectors[idx].attribs.type = CutConnectorType(m_connector_type); }); + ImGui::PopStyleColor(1); m_imgui->disabled_begin(m_connector_type != CutConnectorType::Plug); if (type_changed && m_connector_type == CutConnectorType::Dowel) { @@ -2343,17 +2339,27 @@ void GLGizmoCut3D::render_connectors_input_window(CutConnectors &connectors) ImGui::Separator(); + ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(6.0f, 10.0f)); + float get_cur_y = ImGui::GetContentRegionMax().y + ImGui::GetFrameHeight() + y; + show_tooltip_information(x, get_cur_y); + + float f_scale = m_parent.get_gizmos_manager().get_layout_scale(); + ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(6.0f, 4.0f * f_scale)); + + ImGui::SameLine(); if (m_imgui->button(_L("Confirm connectors"))) { unselect_all_connectors(); set_connectors_editing(false); } - ImGui::SameLine(m_label_width + 1.15f * m_control_width); + ImGui::SameLine(m_label_width + m_editing_window_width - m_imgui->calc_text_size(_L("Cancel")).x - m_imgui->get_style_scaling() * 8); if (m_imgui->button(_L("Cancel"))) { reset_connectors(); set_connectors_editing(false); } + + ImGui::PopStyleVar(2); } void GLGizmoCut3D::render_build_size() @@ -2547,18 +2553,30 @@ void GLGizmoCut3D::render_groove_float_input(const std::string& label, float& in bool GLGizmoCut3D::render_angle_input(const std::string& label, float& in_val, const float& init_val, float min_val, float max_val) { - bool is_changed{ false }; + // -------- [ ] + // slider_with + item_in_gap + input_width + double slider_with = 0.24 * m_editing_window_width; // m_control_width * 0.35; + double item_in_gap = 0.01 * m_editing_window_width; + double input_width = 0.29 * m_editing_window_width; + ImGui::AlignTextToFramePadding(); m_imgui->text(label); - ImGui::SameLine(m_label_width); - ImGui::PushItemWidth(m_control_width * 0.7f); + ImGui::PushItemWidth(slider_with); + + double left_width = m_label_width + slider_with + item_in_gap; + + bool is_changed{ false }; float val = rad2deg(in_val); const float old_val = val; const std::string format = "%.0f " + _u8L("°"); - m_imgui->slider_float(("##angle_" + label).c_str(), &val, min_val, max_val, format.c_str(), 1.f, true, from_u8(label)); + m_imgui->bbl_slider_float_style(("##angle_" + label).c_str(), &val, min_val, max_val, format.c_str(), 1.f, true, from_u8(label)); + + ImGui::SameLine(left_width); + ImGui::PushItemWidth(input_width); + ImGui::BBLDragFloat(("##angle_input_" + label).c_str(), &val, 0.05f, min_val, max_val, format.c_str()); m_is_slider_editing_done |= m_imgui->get_last_slider_status().deactivated_after_edit; if (!is_approx(old_val, val)) { @@ -2602,16 +2620,31 @@ void GLGizmoCut3D::render_groove_angle_input(const std::string& label, float& in void GLGizmoCut3D::render_snap_specific_input(const std::string& label, const wxString& tooltip, float& in_val, const float& init_val, const float min_val, const float max_val) { - m_imgui->text(label); + // -------- [ ] + // slider_with + item_in_gap + input_width + double slider_with = 0.24 * m_editing_window_width; // m_control_width * 0.35; + double item_in_gap = 0.01 * m_editing_window_width; + double input_width = 0.29 * m_editing_window_width; + ImGui::AlignTextToFramePadding(); + m_imgui->text(label); ImGui::SameLine(m_label_width); - ImGui::PushItemWidth(m_control_width * 0.7f); + ImGui::PushItemWidth(slider_with); + + double left_width = m_label_width + slider_with + item_in_gap; bool is_changed = false; const std::string format = "%.0f %%"; float val = in_val * 100.f; - if (m_imgui->slider_float(("##snap_" + label).c_str(), &val, min_val, max_val, format.c_str(), 1.f, true, tooltip)) { + const float old_val = val; + m_imgui->bbl_slider_float_style(("##snap_" + label).c_str(), &val, min_val, max_val, format.c_str(), 1.f, true, tooltip); + + ImGui::SameLine(left_width); + ImGui::PushItemWidth(input_width); + ImGui::BBLDragFloat(("##snap_input_" + label).c_str(), &val, 0.05f, min_val, max_val, format.c_str()); + + if (!is_approx(old_val, val)) { in_val = val * 0.01f; is_changed = true; } @@ -2632,18 +2665,11 @@ void GLGizmoCut3D::render_snap_specific_input(const std::string& label, const wx } } -void GLGizmoCut3D::render_cut_plane_input_window(CutConnectors &connectors) +void GLGizmoCut3D::render_cut_plane_input_window(CutConnectors &connectors, float x, float y, float bottom_limit) { // if (m_mode == size_t(CutMode::cutPlanar)) { CutMode mode = CutMode(m_mode); if (mode == CutMode::cutPlanar || mode == CutMode::cutTongueAndGroove) { - ImGui::AlignTextToFramePadding(); - m_imgui->text(wxString(ImGui::InfoMarkerSmall)); - ImGui::SameLine(); - m_imgui->text_colored(ImGuiWrapper::COL_ORANGE_LIGHT, - get_wraped_wxString(_L("Hold SHIFT key to draw a cut line"), 40)); - ImGui::Separator(); - const bool has_connectors = !connectors.empty(); m_imgui->disabled_begin(has_connectors); @@ -2703,98 +2729,65 @@ void GLGizmoCut3D::render_cut_plane_input_window(CutConnectors &connectors) // render "After Cut" section - ImVec2 label_size; - for (const auto& item : m_part_orientation_names) { - const ImVec2 text_size = m_imgui->calc_text_size(item.second); - if (label_size.x < text_size.x) - label_size.x = text_size.x; - if (label_size.y < text_size.y) - label_size.y = text_size.y; + float label_width = 0; + for (const wxString &label : {_L("Upper part"), _L("Lower part")}) { + const float width = m_imgui->calc_text_size(label).x + m_imgui->scaled(1.5f); + if (label_width < width) + label_width = width; } - const float h_shift = label_size.x + m_imgui->scaled(3.f); - const float marker_size = label_size.y; - auto render_part_name = [this, marker_size, has_connectors](const wxString& name, bool& keep_part, const ImU32& color) { + auto render_part_action_line = [this, label_width, &connectors](const wxString &label, const wxString &suffix, bool &keep_part, + bool &place_on_cut_part, bool &rotate_part) { bool keep = true; - add_horizontal_shift(m_imgui->scaled(1.2f)); - m_imgui->checkbox((m_keep_as_parts ? _L("Part") : _L("Object")) + " " + name, has_connectors ? keep : keep_part); - render_color_marker(marker_size, color); - }; + ImGui::AlignTextToFramePadding(); + m_imgui->text(label); - auto render_part_actions = [this, h_shift] (const wxString& suffix, const bool& keep_part, bool& place_on_cut_part, bool& rotate_part) - { - float shift = m_imgui->scaled(1.2f); - if (suffix == "##lower") - shift += h_shift; - m_imgui->disabled_begin(!keep_part || m_keep_as_parts); - add_horizontal_shift(shift); - if (m_imgui->radio_button(m_part_orientation_names.at("none") + suffix, !place_on_cut_part && !rotate_part)) { - rotate_part = false; - place_on_cut_part = false; - } + ImGui::SameLine(label_width); - add_horizontal_shift(shift); - if (m_imgui->radio_button(m_part_orientation_names.at("on_cut") + suffix, place_on_cut_part)) { - place_on_cut_part = !place_on_cut_part; - rotate_part = false; - } - - add_horizontal_shift(shift); - if (m_imgui->radio_button(m_part_orientation_names.at("flip") + suffix, rotate_part)) { - rotate_part = !rotate_part; - place_on_cut_part = false; - } + m_imgui->disabled_begin(!connectors.empty() || m_keep_as_parts); + m_imgui->bbl_checkbox(_L("Keep") + suffix, connectors.empty() ? keep_part : keep); m_imgui->disabled_end(); - }; - m_imgui->text(_L("Cut result") + ": "); - add_vertical_scaled_interval(0.5f); - - m_imgui->disabled_begin(has_connectors || m_keep_as_parts); - render_part_name("A", m_keep_upper, m_imgui->to_ImU32(UPPER_PART_COLOR)); - ImGui::SameLine(h_shift + ImGui::GetCurrentWindow()->WindowPadding.x); - render_part_name("B", m_keep_lower, m_imgui->to_ImU32(LOWER_PART_COLOR)); - m_imgui->disabled_end(); - - add_vertical_scaled_interval(0.5f); - - const ImVec2 pos = ImGui::GetCurrentWindow()->DC.CursorPos; - render_part_actions("##upper", m_keep_upper, m_place_on_cut_upper, m_rotate_upper); - - ImGui::GetCurrentWindow()->DC.CursorPos = pos; - render_part_actions("##lower", m_keep_lower, m_place_on_cut_lower, m_rotate_lower); - - add_vertical_scaled_interval(0.75f); + ImGui::SameLine(); - m_imgui->disabled_begin(has_connectors || m_part_selection.valid() || mode == CutMode::cutTongueAndGroove); - m_imgui->text(_L("Cut into") + ":"); + m_imgui->disabled_begin(!keep_part || m_keep_as_parts); + if (m_imgui->bbl_checkbox(_L("Place on cut") + suffix, place_on_cut_part)) + rotate_part = false; + ImGui::SameLine(); + if (m_imgui->bbl_checkbox(_L("Flip") + suffix, rotate_part)) + place_on_cut_part = false; + m_imgui->disabled_end(); + }; - if (m_part_selection.valid()) - m_keep_as_parts = false; + m_imgui->text(_L("After cut") + ": "); + render_part_action_line(_L("Upper part"), "##upper", m_keep_upper, m_place_on_cut_upper, m_rotate_upper); + render_part_action_line(_L("Lower part"), "##lower", m_keep_lower, m_place_on_cut_lower, m_rotate_lower); - add_horizontal_scaled_interval(1.2f); - // TRN CutGizmo: RadioButton Cut into ... - if (m_imgui->radio_button(_L("Objects"), !m_keep_as_parts)) - m_keep_as_parts = false; - ImGui::SameLine(); - // TRN CutGizmo: RadioButton Cut into ... - if (m_imgui->radio_button(_L("Parts"), m_keep_as_parts)) - m_keep_as_parts = true; - - if (m_keep_as_parts) { - m_keep_upper = m_keep_lower = true; - m_place_on_cut_upper = m_place_on_cut_lower = false; - m_rotate_upper = m_rotate_lower = false; - } + m_imgui->disabled_begin(has_connectors); + m_imgui->bbl_checkbox(_L("Cut to parts"), m_keep_as_parts); + if (m_keep_as_parts) { + m_keep_upper = true; + m_keep_lower = true; + } m_imgui->disabled_end(); } ImGui::Separator(); + ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(6.0f, 10.0f)); + float get_cur_y = ImGui::GetContentRegionMax().y + ImGui::GetFrameHeight() + y; + show_tooltip_information(x, get_cur_y); + + float f_scale = m_parent.get_gizmos_manager().get_layout_scale(); + ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(6.0f, 4.0f * f_scale)); + + ImGui::SameLine(); m_imgui->disabled_begin(!can_perform_cut()); if(m_imgui->button(_L("Perform cut"))) perform_cut(m_parent.get_selection()); m_imgui->disabled_end(); + + ImGui::PopStyleVar(2); } void GLGizmoCut3D::validate_connector_settings() @@ -2823,6 +2816,8 @@ void GLGizmoCut3D::init_input_window_data(CutConnectors &connectors) m_imperial_units = wxGetApp().app_config->get_bool("use_inches"); m_control_width = m_imgui->get_font_size() * 9.f; + m_editing_window_width = 1.45 * m_control_width + 11; + if (m_connectors_editing && m_selected_count > 0) { float depth_ratio { UndefFloat }; float depth_ratio_tolerance { UndefFloat }; @@ -2889,6 +2884,7 @@ void GLGizmoCut3D::init_input_window_data(CutConnectors &connectors) m_label_width = width; } m_label_width += m_imgui->scaled(1.f); + m_label_width += ImGui::GetStyle().WindowPadding.x; } } @@ -2916,28 +2912,65 @@ void GLGizmoCut3D::render_input_window_warning() const void GLGizmoCut3D::on_render_input_window(float x, float y, float bottom_limit) { - m_imgui->begin(get_name(), ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse); - - // adjust window position to avoid overlap the view toolbar - adjust_window_position(x, y, bottom_limit); + GizmoImguiSetNextWIndowPos(x, y, ImGuiCond_Always, 0.0f, 0.0f); + ImGuiWrapper::push_toolbar_style(m_parent.get_scale()); + GizmoImguiBegin(get_name(), ImGuiWindowFlags_NoMove | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoTitleBar); CutConnectors& connectors = m_c->selection_info()->model_object()->cut_connectors; init_input_window_data(connectors); if (m_connectors_editing) // connectors mode - render_connectors_input_window(connectors); + render_connectors_input_window(connectors, x, y, bottom_limit); else - render_cut_plane_input_window(connectors); + render_cut_plane_input_window(connectors, x, y, bottom_limit); render_input_window_warning(); - m_imgui->end(); + GizmoImguiEnd(); + + // Orca + ImGuiWrapper::pop_toolbar_style(); if (!m_connectors_editing) // connectors mode render_debug_input_window(x); } +void GLGizmoCut3D::show_tooltip_information(float x, float y) +{ + auto &shortcuts = m_connectors_editing ? m_shortcuts_connector : m_shortcuts_cut; + + float caption_max = 0.f; + for (const auto &short_cut : shortcuts) { + caption_max = std::max(caption_max, m_imgui->calc_text_size(short_cut.first).x); + } + + ImTextureID normal_id = m_parent.get_gizmos_manager().get_icon_texture_id(GLGizmosManager::MENU_ICON_NAME::IC_TOOLBAR_TOOLTIP); + ImTextureID hover_id = m_parent.get_gizmos_manager().get_icon_texture_id(GLGizmosManager::MENU_ICON_NAME::IC_TOOLBAR_TOOLTIP_HOVER); + + caption_max += m_imgui->calc_text_size(": ").x + 35.f; + + float font_size = ImGui::GetFontSize(); + ImVec2 button_size = ImVec2(font_size * 1.8, font_size * 1.3); + ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 0.0f); + ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, {0, ImGui::GetStyle().FramePadding.y}); + ImGui::ImageButton3(normal_id, hover_id, button_size); + + if (ImGui::IsItemHovered()) { + ImGui::BeginTooltip2(ImVec2(x, y)); + auto draw_text_with_caption = [this, &caption_max](const wxString &caption, const wxString &text) { + m_imgui->text_colored(ImGuiWrapper::COL_ACTIVE, caption); + ImGui::SameLine(caption_max); + m_imgui->text_colored(ImGuiWrapper::COL_WINDOW_BG, text); + }; + + for (const auto &short_cut : shortcuts) + draw_text_with_caption(short_cut.first + ": ", short_cut.second); + ImGui::EndTooltip(); + } + ImGui::PopStyleVar(2); +} + bool GLGizmoCut3D::is_outside_of_cut_contour(size_t idx, const CutConnectors& connectors, const Vec3d cur_pos) { // check if connector pos is out of clipping plane diff --git a/src/slic3r/GUI/Gizmos/GLGizmoCut.hpp b/src/slic3r/GUI/Gizmos/GLGizmoCut.hpp index 89c1b928330..2c36dbd2a51 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoCut.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoCut.hpp @@ -145,11 +145,11 @@ class GLGizmoCut3D : public GLGizmoBase float m_label_width{ 0.f }; float m_control_width{ 200.f }; + double m_editing_window_width; bool m_imperial_units{ false }; float m_contour_width{ 0.4f }; float m_cut_plane_radius_koef{ 1.5f }; - float m_shortcut_label_width{ -1.f }; mutable std::vector m_selected; // which pins are currently selected int m_selected_count{ 0 }; @@ -204,8 +204,8 @@ class GLGizmoCut3D : public GLGizmoBase PartSelection m_part_selection; - bool m_show_shortcuts{ false }; - std::vector> m_shortcuts; + std::vector> m_shortcuts_cut; + std::vector> m_shortcuts_connector; enum class CutMode { cutPlanar @@ -288,12 +288,10 @@ class GLGizmoCut3D : public GLGizmoBase void on_render() override; void render_debug_input_window(float x); - void adjust_window_position(float x, float y, float bottom_limit); void unselect_all_connectors(); void select_all_connectors(); - void render_shortcuts(); void apply_selected_connectors(std::function apply_fn); - void render_connectors_input_window(CutConnectors &connectors); + void render_connectors_input_window(CutConnectors &connectors, float x, float y, float bottom_limit); void render_build_size(); void reset_cut_plane(); void set_connectors_editing(bool connectors_editing); @@ -309,7 +307,7 @@ class GLGizmoCut3D : public GLGizmoBase void render_groove_angle_input(const std::string &label, float &in_val, const float &init_val, float min_val, float max_val); bool render_angle_input(const std::string& label, float& in_val, const float& init_val, float min_val, float max_val); void render_snap_specific_input(const std::string& label, const wxString& tooltip, float& in_val, const float& init_val, const float min_val, const float max_val); - void render_cut_plane_input_window(CutConnectors &connectors); + void render_cut_plane_input_window(CutConnectors &connectors, float x, float y, float bottom_limit); void init_input_window_data(CutConnectors &connectors); void render_input_window_warning() const; bool add_connector(CutConnectors&connectors, const Vec2d&mouse_position); @@ -327,6 +325,7 @@ class GLGizmoCut3D : public GLGizmoBase void update_plane_model(); void on_render_input_window(float x, float y, float bottom_limit) override; + void show_tooltip_information(float x, float y); bool wants_enter_leave_snapshots() const override { return true; } std::string get_gizmo_entering_text() const override { return _u8L("Entering Cut gizmo"); } From 090a9247cb36c03ff7f7158f5fdd3e0e93aeca8a Mon Sep 17 00:00:00 2001 From: Noisyfox Date: Wed, 1 Nov 2023 23:48:34 +0800 Subject: [PATCH 89/99] Cut: Fix model rendering --- resources/shaders/110/gouraud.fs | 65 ++++++++++++++++++------------- resources/shaders/110/gouraud.vs | 4 ++ resources/shaders/140/gouraud.fs | 67 +++++++++++++++++++------------- resources/shaders/140/gouraud.vs | 4 ++ src/slic3r/GUI/3DScene.cpp | 15 +++++++ src/slic3r/GUI/GLCanvas3D.cpp | 35 +++++++++++++---- src/slic3r/GUI/Selection.cpp | 22 +++++++++++ src/slic3r/GUI/Selection.hpp | 2 + 8 files changed, 151 insertions(+), 63 deletions(-) diff --git a/resources/shaders/110/gouraud.fs b/resources/shaders/110/gouraud.fs index fce2a6f39f0..6f354ff9a6b 100644 --- a/resources/shaders/110/gouraud.fs +++ b/resources/shaders/110/gouraud.fs @@ -29,6 +29,9 @@ struct SlopeDetection }; uniform vec4 uniform_color; +uniform bool use_color_clip_plane; +uniform vec4 uniform_color_clip_plane_1; +uniform vec4 uniform_color_clip_plane_2; uniform SlopeDetection slope; //BBS: add outline_color @@ -42,6 +45,7 @@ uniform bool is_outline; uniform PrintVolumeDetection print_volume; varying vec3 clipping_planes_dots; +varying float color_clip_plane_dot; // x = diffuse, y = specular; varying vec2 intensity; @@ -54,45 +58,50 @@ void main() { if (any(lessThan(clipping_planes_dots, ZERO))) discard; - vec3 color = uniform_color.rgb; - float alpha = uniform_color.a; + + vec4 color; + if (use_color_clip_plane) { + color.rgb = (color_clip_plane_dot < 0.0) ? uniform_color_clip_plane_1.rgb : uniform_color_clip_plane_2.rgb; + color.a = uniform_color.a; + } + else + color = uniform_color; if (slope.actived) { if(world_pos.z<0.1&&world_pos.z>-0.1) { - color = LightBlue; - alpha = 0.8; + color.rgb = LightBlue; + color.a = 0.8; } else if( world_normal_z < slope.normal_z - EPSILON) { - color = color * 0.5 + LightRed * 0.5; - alpha = 0.8; + color.rgb = color.rgb * 0.5 + LightRed * 0.5; + color.a = 0.8; } } - // if the fragment is outside the print volume -> use darker color - vec3 pv_check_min = ZERO; - vec3 pv_check_max = ZERO; + // if the fragment is outside the print volume -> use darker color + vec3 pv_check_min = ZERO; + vec3 pv_check_max = ZERO; if (print_volume.type == 0) { - // rectangle - pv_check_min = world_pos.xyz - vec3(print_volume.xy_data.x, print_volume.xy_data.y, print_volume.z_data.x); - pv_check_max = world_pos.xyz - vec3(print_volume.xy_data.z, print_volume.xy_data.w, print_volume.z_data.y); - color = (any(lessThan(pv_check_min, ZERO)) || any(greaterThan(pv_check_max, ZERO))) ? mix(color, ZERO, 0.3333) : color; - } - else if (print_volume.type == 1) { - // circle - float delta_radius = print_volume.xy_data.z - distance(world_pos.xy, print_volume.xy_data.xy); - pv_check_min = vec3(delta_radius, 0.0, world_pos.z - print_volume.z_data.x); - pv_check_max = vec3(0.0, 0.0, world_pos.z - print_volume.z_data.y); - color = (any(lessThan(pv_check_min, ZERO)) || any(greaterThan(pv_check_max, ZERO))) ? mix(color, ZERO, 0.3333) : color; - } - - //BBS: add outline_color - if (is_outline) - gl_FragColor = uniform_color; + // rectangle + pv_check_min = world_pos.xyz - vec3(print_volume.xy_data.x, print_volume.xy_data.y, print_volume.z_data.x); + pv_check_max = world_pos.xyz - vec3(print_volume.xy_data.z, print_volume.xy_data.w, print_volume.z_data.y); + } + else if (print_volume.type == 1) { + // circle + float delta_radius = print_volume.xy_data.z - distance(world_pos.xy, print_volume.xy_data.xy); + pv_check_min = vec3(delta_radius, 0.0, world_pos.z - print_volume.z_data.x); + pv_check_max = vec3(0.0, 0.0, world_pos.z - print_volume.z_data.y); + } + color.rgb = (any(lessThan(pv_check_min, ZERO)) || any(greaterThan(pv_check_max, ZERO))) ? mix(color.rgb, ZERO, 0.3333) : color.rgb; + + //BBS: add outline_color + if (is_outline) + gl_FragColor = uniform_color; #ifdef ENABLE_ENVIRONMENT_MAP else if (use_environment_tex) - gl_FragColor = vec4(0.45 * texture2D(environment_tex, normalize(eye_normal).xy * 0.5 + 0.5).xyz + 0.8 * color * intensity.x, alpha); + gl_FragColor = vec4(0.45 * texture(environment_tex, normalize(eye_normal).xy * 0.5 + 0.5).xyz + 0.8 * color.rgb * intensity.x, color.a); #endif - else - gl_FragColor = vec4(vec3(intensity.y) + color * intensity.x, alpha); + else + gl_FragColor = vec4(vec3(intensity.y) + color.rgb * intensity.x, color.a); } \ No newline at end of file diff --git a/resources/shaders/110/gouraud.vs b/resources/shaders/110/gouraud.vs index 0e8562871b3..ff3a190c799 100644 --- a/resources/shaders/110/gouraud.vs +++ b/resources/shaders/110/gouraud.vs @@ -35,6 +35,8 @@ uniform SlopeDetection slope; uniform vec2 z_range; // Clipping plane - general orientation. Used by the SLA gizmo. uniform vec4 clipping_plane; +// Color clip plane - general orientation. Used by the cut gizmo. +uniform vec4 color_clip_plane; attribute vec3 v_position; attribute vec3 v_normal; @@ -43,6 +45,7 @@ attribute vec3 v_normal; varying vec2 intensity; varying vec3 clipping_planes_dots; +varying float color_clip_plane_dot; varying vec4 world_pos; varying float world_normal_z; @@ -74,4 +77,5 @@ void main() gl_Position = projection_matrix * position; // Fill in the scalars for fragment shader clipping. Fragments with any of these components lower than zero are discarded. clipping_planes_dots = vec3(dot(world_pos, clipping_plane), world_pos.z - z_range.x, z_range.y - world_pos.z); + color_clip_plane_dot = dot(world_pos, color_clip_plane); } diff --git a/resources/shaders/140/gouraud.fs b/resources/shaders/140/gouraud.fs index bff8434aa92..84bce5c035b 100644 --- a/resources/shaders/140/gouraud.fs +++ b/resources/shaders/140/gouraud.fs @@ -29,6 +29,9 @@ struct SlopeDetection }; uniform vec4 uniform_color; +uniform bool use_color_clip_plane; +uniform vec4 uniform_color_clip_plane_1; +uniform vec4 uniform_color_clip_plane_2; uniform SlopeDetection slope; //BBS: add outline_color @@ -42,6 +45,7 @@ uniform bool is_outline; uniform PrintVolumeDetection print_volume; in vec3 clipping_planes_dots; +in float color_clip_plane_dot; // x = diffuse, y = specular; in vec2 intensity; @@ -50,49 +54,56 @@ in vec4 world_pos; in float world_normal_z; in vec3 eye_normal; +out vec4 out_color; + void main() { if (any(lessThan(clipping_planes_dots, ZERO))) discard; - vec3 color = uniform_color.rgb; - float alpha = uniform_color.a; + + vec4 color; + if (use_color_clip_plane) { + color.rgb = (color_clip_plane_dot < 0.0) ? uniform_color_clip_plane_1.rgb : uniform_color_clip_plane_2.rgb; + color.a = uniform_color.a; + } + else + color = uniform_color; if (slope.actived) { if(world_pos.z<0.1&&world_pos.z>-0.1) { - color = LightBlue; - alpha = 0.8; + color.rgb = LightBlue; + color.a = 0.8; } else if( world_normal_z < slope.normal_z - EPSILON) { - color = color * 0.5 + LightRed * 0.5; - alpha = 0.8; + color.rgb = color.rgb * 0.5 + LightRed * 0.5; + color.a = 0.8; } } - // if the fragment is outside the print volume -> use darker color - vec3 pv_check_min = ZERO; - vec3 pv_check_max = ZERO; + // if the fragment is outside the print volume -> use darker color + vec3 pv_check_min = ZERO; + vec3 pv_check_max = ZERO; if (print_volume.type == 0) { - // rectangle - pv_check_min = world_pos.xyz - vec3(print_volume.xy_data.x, print_volume.xy_data.y, print_volume.z_data.x); - pv_check_max = world_pos.xyz - vec3(print_volume.xy_data.z, print_volume.xy_data.w, print_volume.z_data.y); - color = (any(lessThan(pv_check_min, ZERO)) || any(greaterThan(pv_check_max, ZERO))) ? mix(color, ZERO, 0.3333) : color; - } - else if (print_volume.type == 1) { - // circle - float delta_radius = print_volume.xy_data.z - distance(world_pos.xy, print_volume.xy_data.xy); - pv_check_min = vec3(delta_radius, 0.0, world_pos.z - print_volume.z_data.x); - pv_check_max = vec3(0.0, 0.0, world_pos.z - print_volume.z_data.y); - color = (any(lessThan(pv_check_min, ZERO)) || any(greaterThan(pv_check_max, ZERO))) ? mix(color, ZERO, 0.3333) : color; - } - - //BBS: add outline_color - if (is_outline) - gl_FragColor = uniform_color; + // rectangle + pv_check_min = world_pos.xyz - vec3(print_volume.xy_data.x, print_volume.xy_data.y, print_volume.z_data.x); + pv_check_max = world_pos.xyz - vec3(print_volume.xy_data.z, print_volume.xy_data.w, print_volume.z_data.y); + } + else if (print_volume.type == 1) { + // circle + float delta_radius = print_volume.xy_data.z - distance(world_pos.xy, print_volume.xy_data.xy); + pv_check_min = vec3(delta_radius, 0.0, world_pos.z - print_volume.z_data.x); + pv_check_max = vec3(0.0, 0.0, world_pos.z - print_volume.z_data.y); + } + color.rgb = (any(lessThan(pv_check_min, ZERO)) || any(greaterThan(pv_check_max, ZERO))) ? mix(color.rgb, ZERO, 0.3333) : color.rgb; + + //BBS: add outline_color + if (is_outline) + out_color = uniform_color; #ifdef ENABLE_ENVIRONMENT_MAP else if (use_environment_tex) - gl_FragColor = vec4(0.45 * texture(environment_tex, normalize(eye_normal).xy * 0.5 + 0.5).xyz + 0.8 * color * intensity.x, alpha); + out_color = vec4(0.45 * texture(environment_tex, normalize(eye_normal).xy * 0.5 + 0.5).xyz + 0.8 * color.rgb * intensity.x, color.a); #endif - else - gl_FragColor = vec4(vec3(intensity.y) + color * intensity.x, alpha); + else + out_color = vec4(vec3(intensity.y) + color.rgb * intensity.x, color.a); } \ No newline at end of file diff --git a/resources/shaders/140/gouraud.vs b/resources/shaders/140/gouraud.vs index 8e657205fbc..72dd4ff1bf1 100644 --- a/resources/shaders/140/gouraud.vs +++ b/resources/shaders/140/gouraud.vs @@ -35,6 +35,8 @@ uniform SlopeDetection slope; uniform vec2 z_range; // Clipping plane - general orientation. Used by the SLA gizmo. uniform vec4 clipping_plane; +// Color clip plane - general orientation. Used by the cut gizmo. +uniform vec4 color_clip_plane; in vec3 v_position; in vec3 v_normal; @@ -43,6 +45,7 @@ in vec3 v_normal; out vec2 intensity; out vec3 clipping_planes_dots; +out float color_clip_plane_dot; out vec4 world_pos; out float world_normal_z; @@ -74,4 +77,5 @@ void main() gl_Position = projection_matrix * position; // Fill in the scalars for fragment shader clipping. Fragments with any of these components lower than zero are discarded. clipping_planes_dots = vec3(dot(world_pos, clipping_plane), world_pos.z - z_range.x, z_range.y - world_pos.z); + color_clip_plane_dot = dot(world_pos, color_clip_plane); } diff --git a/src/slic3r/GUI/3DScene.cpp b/src/slic3r/GUI/3DScene.cpp index 3b735d8275b..7325941ed01 100644 --- a/src/slic3r/GUI/3DScene.cpp +++ b/src/slic3r/GUI/3DScene.cpp @@ -1,3 +1,14 @@ +///|/ Copyright (c) Prusa Research 2016 - 2023 Lukáš Matěna @lukasmatena, Enrico Turri @enricoturri1966, Oleksandra Iushchenko @YuSanka, Tomáš Mészáros @tamasmeszaros, Vojtěch Bubník @bubnikv, Filip Sykala @Jony01, Lukáš Hejl @hejllukas, David Kocík @kocikdav, Vojtěch Král @vojtechkral +///|/ Copyright (c) 2017 Eyal Soha @eyal0 +///|/ Copyright (c) Slic3r 2015 Alessandro Ranellucci @alranel +///|/ +///|/ ported from lib/Slic3r/GUI/3DScene.pm: +///|/ Copyright (c) Prusa Research 2016 - 2019 Vojtěch Bubník @bubnikv, Enrico Turri @enricoturri1966, Oleksandra Iushchenko @YuSanka +///|/ Copyright (c) Slic3r 2013 - 2016 Alessandro Ranellucci @alranel +///|/ Copyright (c) 2013 Guillaume Seguin @iXce +///|/ +///|/ PrusaSlicer is released under the terms of the AGPLv3 or higher +///|/ #include #include "3DScene.hpp" @@ -869,6 +880,10 @@ void GLVolumeCollection::render(GLVolumeCollection::ERenderType type, bool disab shader->set_uniform("uniform_color", volume.first->render_color); shader->set_uniform("z_range", m_z_range); shader->set_uniform("clipping_plane", m_clipping_plane); + shader->set_uniform("use_color_clip_plane", m_use_color_clip_plane); + shader->set_uniform("color_clip_plane", m_color_clip_plane); + shader->set_uniform("uniform_color_clip_plane_1", m_color_clip_plane_colors[0]); + shader->set_uniform("uniform_color_clip_plane_2", m_color_clip_plane_colors[1]); //BOOST_LOG_TRIVIAL(info) << boost::format("set uniform_color to {%1%, %2%, %3%, %4%}, with_outline=%5%, selected %6%") // %volume.first->render_color[0]%volume.first->render_color[1]%volume.first->render_color[2]%volume.first->render_color[3] // %with_outline%volume.first->selected; diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index dcf2713fb5d..0a0f631644b 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -1341,21 +1341,31 @@ ModelInstanceEPrintVolumeState GLCanvas3D::check_volumes_outside_state() const void GLCanvas3D::toggle_sla_auxiliaries_visibility(bool visible, const ModelObject* mo, int instance_idx) { + if (current_printer_technology() != ptSLA) + return; + m_render_sla_auxiliaries = visible; + std::vector>* raycasters = get_raycasters_for_picking(SceneRaycaster::EType::Volume); + for (GLVolume* vol : m_volumes.volumes) { if (vol->composite_id.object_id >= 1000 && vol->composite_id.object_id < 1000 + wxGetApp().plater()->get_partplate_list().get_plate_count()) continue; // the wipe tower - if ((mo == nullptr || m_model->objects[vol->composite_id.object_id] == mo) - && (instance_idx == -1 || vol->composite_id.instance_id == instance_idx) - && vol->composite_id.volume_id < 0) + if ((mo == nullptr || m_model->objects[vol->composite_id.object_id] == mo) + && (instance_idx == -1 || vol->composite_id.instance_id == instance_idx) + && vol->composite_id.volume_id < 0) { vol->is_active = visible; + auto it = std::find_if(raycasters->begin(), raycasters->end(), [vol](std::shared_ptr item) { return item->get_raycaster() == vol->mesh_raycaster.get(); }); + if (it != raycasters->end()) + (*it)->set_active(vol->is_active); + } } } void GLCanvas3D::toggle_model_objects_visibility(bool visible, const ModelObject* mo, int instance_idx, const ModelVolume* mv) { + std::vector>* raycasters = get_raycasters_for_picking(SceneRaycaster::EType::Volume); for (GLVolume* vol : m_volumes.volumes) { // BBS: add partplate logic if (vol->composite_id.object_id >= 1000 && @@ -1367,6 +1377,8 @@ void GLCanvas3D::toggle_model_objects_visibility(bool visible, const ModelObject && (instance_idx == -1 || vol->composite_id.instance_id == instance_idx) && (mv == nullptr || m_model->objects[vol->composite_id.object_id]->volumes[vol->composite_id.volume_id] == mv)) { vol->is_active = visible; + if (!vol->is_modifier) + vol->color.a(1.f); if (instance_idx == -1) { vol->force_native_color = false; @@ -1374,10 +1386,12 @@ void GLCanvas3D::toggle_model_objects_visibility(bool visible, const ModelObject } else { const GLGizmosManager& gm = get_gizmos_manager(); auto gizmo_type = gm.get_current_type(); - if ( (gizmo_type == GLGizmosManager::FdmSupports - || gizmo_type == GLGizmosManager::Seam) - && ! vol->is_modifier) + if ( (gizmo_type == GLGizmosManager::FdmSupports + || gizmo_type == GLGizmosManager::Seam + || gizmo_type == GLGizmosManager::Cut) + && !vol->is_modifier) { vol->force_neutral_color = true; + } else if (gizmo_type == GLGizmosManager::MmuSegmentation) vol->is_active = false; else @@ -1385,7 +1399,12 @@ void GLCanvas3D::toggle_model_objects_visibility(bool visible, const ModelObject } } } + + auto it = std::find_if(raycasters->begin(), raycasters->end(), [vol](std::shared_ptr item) { return item->get_raycaster() == vol->mesh_raycaster.get(); }); + if (it != raycasters->end()) + (*it)->set_active(vol->is_active); } + if (visible && !mo) toggle_sla_auxiliaries_visibility(true, mo, instance_idx); @@ -4003,6 +4022,7 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) if (/*m_gizmos.get_current_type() != GLGizmosManager::SlaSupports &&*/ m_gizmos.get_current_type() != GLGizmosManager::FdmSupports && m_gizmos.get_current_type() != GLGizmosManager::Seam + && m_gizmos.get_current_type() != GLGizmosManager::Cut && m_gizmos.get_current_type() != GLGizmosManager::MmuSegmentation) { m_rectangle_selection.start_dragging(m_mouse.position, evt.ShiftDown() ? GLSelectionRectangle::Select : GLSelectionRectangle::Deselect); m_dirty = true; @@ -4052,7 +4072,8 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) int volume_idx = get_first_hover_volume_idx(); BoundingBoxf3 volume_bbox = m_volumes.volumes[volume_idx]->transformed_bounding_box(); volume_bbox.offset(1.0); - if ((!any_gizmo_active || !evt.CmdDown()) && volume_bbox.contains(m_mouse.scene_position)) { + const bool is_cut_connector_selected = m_selection.is_any_connector(); + if ((!any_gizmo_active || !evt.CmdDown()) && volume_bbox.contains(m_mouse.scene_position) && !is_cut_connector_selected) { m_volumes.volumes[volume_idx]->hover = GLVolume::HS_None; // The dragging operation is initiated. m_mouse.drag.move_volume_idx = volume_idx; diff --git a/src/slic3r/GUI/Selection.cpp b/src/slic3r/GUI/Selection.cpp index 05bb7cdcc2c..9e385ab54c9 100644 --- a/src/slic3r/GUI/Selection.cpp +++ b/src/slic3r/GUI/Selection.cpp @@ -644,6 +644,28 @@ void Selection::volumes_changed(const std::vector &map_volume_old_to_new this->set_bounding_boxes_dirty(); } +bool Selection::is_any_connector() const +{ + const int obj_idx = get_object_idx(); + + if ((is_any_volume() || is_any_modifier() || is_mixed()) && // some solid_part AND/OR modifier is selected + obj_idx >= 0 && m_model->objects[obj_idx]->is_cut()) { + const ModelVolumePtrs& obj_volumes = m_model->objects[obj_idx]->volumes; + for (size_t vol_idx = 0; vol_idx < obj_volumes.size(); vol_idx++) + if (obj_volumes[vol_idx]->is_cut_connector()) + for (const GLVolume* v : *m_volumes) + if (v->object_idx() == obj_idx && v->volume_idx() == (int)vol_idx && v->selected) + return true; + } + return false; +} + +bool Selection::is_any_cut_volume() const +{ + const int obj_idx = get_object_idx(); + return is_any_volume() && obj_idx >= 0 && m_model->objects[obj_idx]->is_cut(); +} + bool Selection::is_single_full_instance() const { if (m_type == SingleFullInstance) diff --git a/src/slic3r/GUI/Selection.hpp b/src/slic3r/GUI/Selection.hpp index 594c7996079..e130cb18bea 100644 --- a/src/slic3r/GUI/Selection.hpp +++ b/src/slic3r/GUI/Selection.hpp @@ -249,6 +249,8 @@ class Selection bool is_single_volume() const { return m_type == SingleVolume; } bool is_multiple_volume() const { return m_type == MultipleVolume; } bool is_any_volume() const { return is_single_volume() || is_multiple_volume(); } + bool is_any_connector() const; + bool is_any_cut_volume() const; bool is_mixed() const { return m_type == Mixed; } bool is_from_single_instance() const { return get_instance_idx() != -1; } bool is_from_single_object() const; From 018b2744db93773f863555edcef0f01688e9a4c9 Mon Sep 17 00:00:00 2001 From: Noisyfox Date: Sat, 4 Nov 2023 11:39:38 +0800 Subject: [PATCH 90/99] Text: Fix text moving grabber --- src/slic3r/GUI/Gizmos/GLGizmoText.cpp | 97 +++++++++++---------------- src/slic3r/GUI/Gizmos/GLGizmoText.hpp | 4 ++ 2 files changed, 44 insertions(+), 57 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoText.cpp b/src/slic3r/GUI/Gizmos/GLGizmoText.cpp index 5982e269629..e8825954e40 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoText.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoText.cpp @@ -145,12 +145,13 @@ bool GLGizmoText::on_init() m_scale = m_imgui->get_font_size(); m_shortcut_key = WXK_CONTROL_T; + m_grabbers.push_back(Grabber()); + reset_text_info(); m_desc["rotate_text_caption"] = _L("Shift + Mouse move up or dowm"); m_desc["rotate_text"] = _L("Rotate text"); - m_grabbers.push_back(Grabber()); return true; } @@ -252,13 +253,8 @@ bool GLGizmoText::gizmo_event(SLAGizmoEventType action, const Vec2d &mouse_posit m_mouse_position = mouse_position; } else if (action == SLAGizmoEventType::LeftDown) { - if (!selection.is_empty() && get_hover_id() != -1) { - //start_dragging(); - return true; - } - if (m_is_modify) - return true; + return false; Plater *plater = wxGetApp().plater(); if (!plater) @@ -319,6 +315,40 @@ bool GLGizmoText::gizmo_event(SLAGizmoEventType action, const Vec2d &mouse_posit return true; } +bool GLGizmoText::on_mouse(const wxMouseEvent &mouse_event) +{ + // wxCoord == int --> wx/types.h + Vec2i mouse_coord(mouse_event.GetX(), mouse_event.GetY()); + Vec2d mouse_pos = mouse_coord.cast(); + bool control_down = mouse_event.CmdDown(); + + if (mouse_event.Moving()) { + gizmo_event(SLAGizmoEventType::Moving, mouse_pos, mouse_event.ShiftDown(), mouse_event.AltDown(), control_down); + } + + // when control is down we allow scene pan and rotation even when clicking + // over some object + bool grabber_contains_mouse = (get_hover_id() != -1); + + if (mouse_event.LeftDown()) { + if ((!control_down || grabber_contains_mouse) && + gizmo_event(SLAGizmoEventType::LeftDown, mouse_pos, mouse_event.ShiftDown(), mouse_event.AltDown(), false)) + // the gizmo got the event and took some action, there is no need + // to do anything more + return true; + } + + return use_grabbers(mouse_event); +} + +void GLGizmoText::on_register_raycasters_for_picking() +{ + // the gizmo grabbers are rendered on top of the scene, so the raytraced picker should take it into account + m_parent.set_raycaster_gizmos_on_top(true); +} + +void GLGizmoText::on_unregister_raycasters_for_picking() { m_parent.set_raycaster_gizmos_on_top(false); } + void GLGizmoText::on_set_state() { if (m_state == EState::On) { @@ -445,13 +475,12 @@ void GLGizmoText::on_render() m_grabbers[0].center = m_mouse_position_world; m_grabbers[0].enabled = true; - //ColorRGBA color = picking_color_component(0); - //m_grabbers[0].color = color; GLShaderProgram *shader = wxGetApp().get_shader("gouraud_light"); if (shader != nullptr) { shader->start_using(); - //m_grabbers[0].render_for_picking(mean_size); + shader->set_uniform("emission_factor", 0.1f); + render_grabbers(mean_size); shader->stop_using(); } @@ -466,53 +495,6 @@ void GLGizmoText::on_render() plater->update(); } -/* -void GLGizmoText::on_render_for_picking() -{ - glsafe(::glDisable(GL_DEPTH_TEST)); - - int obejct_idx, volume_idx; - ModelVolume *model_volume = get_selected_single_volume(obejct_idx, volume_idx); - if (model_volume && !model_volume->get_text_info().m_text.empty()) { - if (m_grabbers.size() == 1) { - ModelObject *mo = m_c->selection_info()->model_object(); - if (m_is_modify) { - const Selection &selection = m_parent.get_selection(); - mo = selection.get_model()->objects[m_object_idx]; - } - if (mo == nullptr) return; - - const Selection & selection = m_parent.get_selection(); - const ModelInstance *mi = mo->instances[selection.get_instance_idx()]; - - // Precalculate transformations of individual meshes. - std::vector trafo_matrices; - for (const ModelVolume *mv : mo->volumes) { - if (mv->is_model_part()) { - trafo_matrices.emplace_back(mi->get_transformation().get_matrix() * mv->get_matrix()); - } - } - - m_mouse_position_world = trafo_matrices[m_rr.mesh_id] * Vec3d(m_rr.hit(0), m_rr.hit(1), m_rr.hit(2)); - - float mean_size = (float) (GLGizmoBase::Grabber::FixedGrabberSize); - m_grabbers[0].center = m_mouse_position_world; - m_grabbers[0].enabled = true; - ColorRGBA color = picking_color_component(0); - m_grabbers[0].color = color; - - GLShaderProgram *shader = wxGetApp().get_shader("flat"); - if (shader != nullptr) { - shader->start_using(); - m_grabbers[0].render_for_picking(mean_size); - - shader->stop_using(); - } - } - } -} -*/ - void GLGizmoText::on_dragging(const UpdateData &data) { Vec2d mouse_pos = Vec2d(data.mouse_pos.x(), data.mouse_pos.y()); @@ -943,6 +925,7 @@ void GLGizmoText::reset_text_info() m_keep_horizontal = false; m_is_modify = false; + m_grabbers[0].enabled = false; } bool GLGizmoText::update_text_positions(const std::vector& texts) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoText.hpp b/src/slic3r/GUI/Gizmos/GLGizmoText.hpp index 801eaddcd77..e187c722110 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoText.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoText.hpp @@ -83,6 +83,8 @@ class GLGizmoText : public GLGizmoBase bool gizmo_event(SLAGizmoEventType action, const Vec2d &mouse_position, bool shift_down, bool alt_down, bool control_down); + bool on_mouse(const wxMouseEvent &mouse_event) override; + bool is_mesh_point_clipped(const Vec3d &point, const Transform3d &trafo) const; BoundingBoxf3 bounding_box() const; @@ -99,6 +101,8 @@ class GLGizmoText : public GLGizmoBase virtual void on_set_state() override; virtual CommonGizmosDataID on_get_requirements() const override; virtual void on_render_input_window(float x, float y, float bottom_limit); + virtual void on_register_raycasters_for_picking() override; + virtual void on_unregister_raycasters_for_picking() override; void show_tooltip_information(float x, float y); From 28e2995a0163b969b1e51e6f47fd829f2411bf2e Mon Sep 17 00:00:00 2001 From: Noisyfox Date: Sun, 5 Nov 2023 16:02:39 +0800 Subject: [PATCH 91/99] Cut: Fix crashing in programming cut. Also fixes the cut z offset. --- src/libslic3r/CutUtils.cpp | 6 ------ src/libslic3r/CutUtils.hpp | 2 -- src/slic3r/GUI/Plater.cpp | 19 ++++--------------- src/slic3r/Utils/CalibUtils.cpp | 4 +++- 4 files changed, 7 insertions(+), 24 deletions(-) diff --git a/src/libslic3r/CutUtils.cpp b/src/libslic3r/CutUtils.cpp index 8dd8fd7901f..5d3ec25c347 100644 --- a/src/libslic3r/CutUtils.cpp +++ b/src/libslic3r/CutUtils.cpp @@ -653,11 +653,5 @@ const ModelObjectPtrs& Cut::perform_with_groove(const Groove& groove, const Tran return m_model.objects; } -ModelObjectPtrs Cut::cut_horizontal(const ModelObject *object, size_t instance_idx, double z, ModelObjectCutAttributes attributes) -{ - Cut cut(object, instance_idx, Geometry::translation_transform(z * Vec3d::UnitZ()), attributes); - return cut.perform_with_plane(); -} - } // namespace Slic3r diff --git a/src/libslic3r/CutUtils.hpp b/src/libslic3r/CutUtils.hpp index d2bf88db549..4607489b277 100644 --- a/src/libslic3r/CutUtils.hpp +++ b/src/libslic3r/CutUtils.hpp @@ -63,8 +63,6 @@ class Cut { const ModelObjectPtrs& perform_by_contour(std::vector parts, int dowels_count); const ModelObjectPtrs& perform_with_groove(const Groove& groove, const Transform3d& rotation_m, bool keep_as_parts = false); - static ModelObjectPtrs cut_horizontal(const ModelObject *object, size_t instance_idx, double z, ModelObjectCutAttributes attributes); - }; // namespace Cut diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 93685502886..b3f123bfc42 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -8426,23 +8426,12 @@ void Plater::cut_horizontal(size_t obj_idx, size_t instance_idx, double z, Model return; wxBusyCursor wait; - const auto new_objects = Cut::cut_horizontal(object, instance_idx, z, attributes); - remove(obj_idx); - p->load_model_objects(new_objects); + const Vec3d instance_offset = object->instances[instance_idx]->get_offset(); + Cut cut(object, instance_idx, Geometry::translation_transform(z * Vec3d::UnitZ() - instance_offset), attributes); + const auto new_objects = cut.perform_with_plane(); - // now process all updates of the 3d scene - update(); - - // Update InfoItems in ObjectList after update() to use of a correct value of the GLCanvas3D::is_sinking(), - // which is updated after a view3D->reload_scene(false, flags & (unsigned int)UpdateParams::FORCE_FULL_SCREEN_REFRESH) call - for (size_t idx = 0; idx < p->model.objects.size(); idx++) - wxGetApp().obj_list()->update_info_items(idx); - - Selection& selection = p->get_selection(); - size_t last_id = p->model.objects.size() - 1; - for (size_t i = 0; i < new_objects.size(); ++i) - selection.add_object((unsigned int)(last_id - i), i == 0); + apply_cut_object_to_model(obj_idx, new_objects); } void Plater::_calib_pa_tower(const Calib_Params& params) { diff --git a/src/slic3r/Utils/CalibUtils.cpp b/src/slic3r/Utils/CalibUtils.cpp index f1cafadd26f..8186f4dfc20 100644 --- a/src/slic3r/Utils/CalibUtils.cpp +++ b/src/slic3r/Utils/CalibUtils.cpp @@ -143,7 +143,9 @@ static void cut_model(Model &model, double z, ModelObjectCutAttributes attribute auto* object = model.objects[0]; - const auto new_objects = Cut::cut_horizontal(object, instance_idx, z, attributes); + const Vec3d instance_offset = object->instances[instance_idx]->get_offset(); + Cut cut(object, instance_idx, Geometry::translation_transform(z * Vec3d::UnitZ() - instance_offset), attributes); + const auto new_objects = cut.perform_with_plane(); model.delete_object(obj_idx); for (ModelObject *model_object : new_objects) { From e57f68a266b2075abebca07901c8736369d47156 Mon Sep 17 00:00:00 2001 From: Noisyfox Date: Mon, 6 Nov 2023 20:42:02 +0800 Subject: [PATCH 92/99] Fix painter gizmos crash on macOS --- src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp | 11 ----------- src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.hpp | 1 - src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp | 11 ----------- src/slic3r/GUI/Gizmos/GLGizmoPainterBase.hpp | 2 -- 4 files changed, 25 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp index d8912b7647d..d9a396ba104 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp @@ -913,10 +913,6 @@ void GLMmSegmentationGizmo3DScene::release_geometry() { glsafe(::glDeleteBuffers(1, &triangle_indices_VBO_id)); triangle_indices_VBO_id = 0; } - if (this->vertices_VAO_id) { - glsafe(::glDeleteVertexArrays(1, &this->vertices_VAO_id)); - this->vertices_VAO_id = 0; - } this->clear(); } @@ -933,7 +929,6 @@ void GLMmSegmentationGizmo3DScene::render(size_t triangle_indices_idx) const if (shader == nullptr) return; - glsafe(::glBindVertexArray(this->vertices_VAO_id)); // the following binding is needed to set the vertex attributes glsafe(::glBindBuffer(GL_ARRAY_BUFFER, this->vertices_VBO_id)); const GLint position_id = shader->get_attrib_location("v_position"); @@ -954,7 +949,6 @@ void GLMmSegmentationGizmo3DScene::render(size_t triangle_indices_idx) const glsafe(::glDisableVertexAttribArray(position_id)); glsafe(::glBindBuffer(GL_ARRAY_BUFFER, 0)); - glsafe(::glBindVertexArray(0)); } void GLMmSegmentationGizmo3DScene::finalize_vertices() @@ -962,16 +956,11 @@ void GLMmSegmentationGizmo3DScene::finalize_vertices() assert(this->vertices_VAO_id == 0); assert(this->vertices_VBO_id == 0); if (!this->vertices.empty()) { - glsafe(::glGenVertexArrays(1, &this->vertices_VAO_id)); - glsafe(::glBindVertexArray(this->vertices_VAO_id)); - glsafe(::glGenBuffers(1, &this->vertices_VBO_id)); glsafe(::glBindBuffer(GL_ARRAY_BUFFER, this->vertices_VBO_id)); glsafe(::glBufferData(GL_ARRAY_BUFFER, this->vertices.size() * sizeof(float), this->vertices.data(), GL_STATIC_DRAW)); glsafe(::glBindBuffer(GL_ARRAY_BUFFER, 0)); this->vertices.clear(); - - glsafe(::glBindVertexArray(0)); } } diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.hpp b/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.hpp index 0343c6c3247..d816735c686 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.hpp @@ -57,7 +57,6 @@ class GLMmSegmentationGizmo3DScene // IDs of the Vertex Array Objects, into which the geometry has been loaded. // Zero if the VBOs are not sent to GPU yet. - unsigned int vertices_VAO_id{ 0 }; unsigned int vertices_VBO_id{0}; std::vector triangle_indices_VBO_ids; }; diff --git a/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp b/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp index 8b33edfcb8e..6bf8a526abb 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp @@ -1508,7 +1508,6 @@ void TriangleSelectorPatch::render(int triangle_indices_idx) if (shader == nullptr) return; - glsafe(::glBindVertexArray(this->m_vertices_VAO_ids[triangle_indices_idx])); // the following binding is needed to set the vertex attributes glsafe(::glBindBuffer(GL_ARRAY_BUFFER, this->m_vertices_VBO_ids[triangle_indices_idx])); const GLint position_id = shader->get_attrib_location("v_position"); @@ -1529,7 +1528,6 @@ void TriangleSelectorPatch::render(int triangle_indices_idx) glsafe(::glDisableVertexAttribArray(position_id)); glsafe(::glBindBuffer(GL_ARRAY_BUFFER, 0)); - glsafe(::glBindVertexArray(0)); } void TriangleSelectorPatch::release_geometry() @@ -1542,10 +1540,6 @@ void TriangleSelectorPatch::release_geometry() glsafe(::glDeleteBuffers(1, &vertice_VBO_id)); vertice_VBO_id = 0; } - for (auto &vertice_VAO_id : m_vertices_VAO_ids) { - glsafe(::glDeleteVertexArrays(1, &vertice_VAO_id)); - vertice_VAO_id = 0; - } for (auto& triangle_indices_VBO_id : m_triangle_indices_VBO_ids) { glsafe(::glDeleteBuffers(1, &triangle_indices_VBO_id)); triangle_indices_VBO_id = 0; @@ -1570,7 +1564,6 @@ void TriangleSelectorPatch::finalize_vertices() void TriangleSelectorPatch::finalize_triangle_indices() { m_vertices_VBO_ids.resize(m_triangle_patches.size()); - m_vertices_VAO_ids.resize(m_triangle_patches.size()); m_triangle_indices_VBO_ids.resize(m_triangle_patches.size()); m_triangle_indices_sizes.resize(m_triangle_patches.size()); assert(std::all_of(m_triangle_indices_VBO_ids.cbegin(), m_triangle_indices_VBO_ids.cend(), [](const auto& ti_VBO_id) { return ti_VBO_id == 0; })); @@ -1578,9 +1571,6 @@ void TriangleSelectorPatch::finalize_triangle_indices() for (size_t buffer_idx = 0; buffer_idx < m_triangle_patches.size(); ++buffer_idx) { std::vector& patch_vertices = m_triangle_patches[buffer_idx].patch_vertices; if (!patch_vertices.empty()) { - glsafe(::glGenVertexArrays(1, &m_vertices_VAO_ids[buffer_idx])); - glsafe(::glBindVertexArray(m_vertices_VAO_ids[buffer_idx])); - glsafe(::glGenBuffers(1, &m_vertices_VBO_ids[buffer_idx])); glsafe(::glBindBuffer(GL_ARRAY_BUFFER, m_vertices_VBO_ids[buffer_idx])); glsafe(::glBufferData(GL_ARRAY_BUFFER, patch_vertices.size() * sizeof(float), patch_vertices.data(), GL_STATIC_DRAW)); @@ -1599,7 +1589,6 @@ void TriangleSelectorPatch::finalize_triangle_indices() //BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(", Line %1%: buffer_idx %2%, vertices size %3%, buffer id %4%")%__LINE__%buffer_idx%triangle_indices.size()%m_triangle_indices_VBO_ids[buffer_idx]; triangle_indices.clear(); } - glsafe(::glBindVertexArray(0)); } } diff --git a/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.hpp b/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.hpp index 4252ae7e0aa..4ea9412ffa7 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.hpp @@ -138,7 +138,6 @@ class TriangleSelectorPatch : public TriangleSelectorGUI { void clear() { // BBS - this->m_vertices_VAO_ids.clear(); this->m_vertices_VBO_ids.clear(); this->m_triangle_indices_VBO_ids.clear(); this->m_triangle_indices_sizes.clear(); @@ -167,7 +166,6 @@ class TriangleSelectorPatch : public TriangleSelectorGUI { // IDs of the Vertex Array Objects, into which the geometry has been loaded. // Zero if the VBOs are not sent to GPU yet. //unsigned int m_vertices_VBO_id{ 0 }; - std::vector m_vertices_VAO_ids; std::vector m_vertices_VBO_ids; std::vector m_triangle_indices_VBO_ids; From 483475ff484fa064db46795bc07c30c9d6fcfd1f Mon Sep 17 00:00:00 2001 From: Noisyfox Date: Wed, 8 Nov 2023 09:12:17 +0800 Subject: [PATCH 93/99] Fix canvas background in dark mode --- src/slic3r/GUI/GLCanvas3D.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 0a0f631644b..9d3ffa0270e 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -6820,7 +6820,7 @@ void GLCanvas3D::_render_background() GLShaderProgram* shader = wxGetApp().get_shader("background"); if (shader != nullptr) { shader->start_using(); - shader->set_uniform("top_color", use_error_color ? ERROR_BG_LIGHT_COLOR : DEFAULT_BG_LIGHT_COLOR); + shader->set_uniform("top_color", bottom_color); shader->set_uniform("bottom_color", bottom_color); m_background.render(); shader->stop_using(); From 7984b4dc48b14fc7d6e44b1376214826875b2a73 Mon Sep 17 00:00:00 2001 From: Noisyfox Date: Fri, 10 Nov 2023 10:54:02 +0800 Subject: [PATCH 94/99] Fix complie error after merge --- src/slic3r/GUI/Tab.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index b55d349ed30..2a55597425d 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -3233,8 +3233,8 @@ void TabPrinter::build_fff() optgroup->append_single_option_line(option); optgroup = page->new_optgroup(L("Change extrusion role G-code"), L"param_gcode", 0); - optgroup->m_on_change = [this, optgroup](const t_config_option_key& opt_key, const boost::any& value) { - validate_custom_gcode_cb(this, optgroup, opt_key, value); + optgroup->m_on_change = [this, &optgroup_title = optgroup->title](const t_config_option_key &opt_key, const boost::any &value) { + validate_custom_gcode_cb(this, optgroup_title, opt_key, value); }; option = optgroup->get_option("change_extrusion_role_gcode"); From ee8ea0df044789a810b5e58d05a5200032348b35 Mon Sep 17 00:00:00 2001 From: Noisyfox Date: Fri, 10 Nov 2023 23:02:11 +0800 Subject: [PATCH 95/99] Rewrite bed raycaster registering that fixes crash when creating new project --- src/slic3r/GUI/GLCanvas3D.cpp | 6 ++++++ src/slic3r/GUI/PartPlate.cpp | 39 ++++++++++------------------------- src/slic3r/GUI/PartPlate.hpp | 10 +++++---- 3 files changed, 23 insertions(+), 32 deletions(-) diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 9d3ffa0270e..a6e981513ec 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -2672,6 +2672,7 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re m_selection.volumes_changed(map_glvolume_old_to_new); // @Enrico suggest this solution to preven accessing pointer on caster without data + m_scene_raycaster.remove_raycasters(SceneRaycaster::EType::Bed); m_scene_raycaster.remove_raycasters(SceneRaycaster::EType::Volume); m_gizmos.update_data(); m_gizmos.update_assemble_view_data(); @@ -2725,6 +2726,11 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re #endif } + // refresh bed raycasters for picking + if (m_canvas_type == ECanvasType::CanvasView3D) { + wxGetApp().plater()->get_partplate_list().register_raycasters_for_picking(*this); + } + // refresh volume raycasters for picking for (size_t i = 0; i < m_volumes.volumes.size(); ++i) { const GLVolume* v = m_volumes.volumes[i]; diff --git a/src/slic3r/GUI/PartPlate.cpp b/src/slic3r/GUI/PartPlate.cpp index 5d8ba2e08f6..edbb541a748 100644 --- a/src/slic3r/GUI/PartPlate.cpp +++ b/src/slic3r/GUI/PartPlate.cpp @@ -148,7 +148,6 @@ PartPlate::PartPlate(PartPlateList *partplate_list, Vec3d origin, int width, int PartPlate::~PartPlate() { - unregister_raycasters_for_picking(); clear(); //if (m_quadric != nullptr) // ::gluDeleteQuadric(m_quadric); @@ -996,13 +995,6 @@ void PartPlate::render_only_numbers(bool bottom) } } -void PartPlate::register_rectangle_for_picking(PickingModel &model, int id) -{ - wxGetApp().plater()->canvas3D()->add_raycaster_for_picking(SceneRaycaster::EType::Bed, id, *model.mesh_raycaster, Transform3d::Identity()); - - picking_ids.emplace_back(id); -} - /* void PartPlate::render_label(GLCanvas3D& canvas) const { std::string label = (boost::format("Plate %1%") % (m_plate_index + 1)).str(); @@ -1221,25 +1213,20 @@ void PartPlate::render_right_arrow(const ColorRGBA render_color, bool use_lighti } */ -void PartPlate::register_raycasters_for_picking() +static void register_model_for_picking(GLCanvas3D &canvas, PickingModel &model, int id) { - unregister_raycasters_for_picking(); - - picking_ids.reserve(6); - register_rectangle_for_picking(m_triangles, picking_id_component(0)); - register_rectangle_for_picking(m_del_icon, picking_id_component(1)); - register_rectangle_for_picking(m_orient_icon, picking_id_component(2)); - register_rectangle_for_picking(m_arrange_icon, picking_id_component(3)); - register_rectangle_for_picking(m_lock_icon, picking_id_component(4)); - if (m_partplate_list->render_plate_settings) - register_rectangle_for_picking(m_plate_settings_icon, picking_id_component(5)); + canvas.add_raycaster_for_picking(SceneRaycaster::EType::Bed, id, *model.mesh_raycaster, Transform3d::Identity()); } -void PartPlate::unregister_raycasters_for_picking() { - for (int picking_id : picking_ids) { - wxGetApp().plater()->canvas3D()->remove_raycasters_for_picking(SceneRaycaster::EType::Bed, picking_id); - } - picking_ids.clear(); +void PartPlate::register_raycasters_for_picking(GLCanvas3D &canvas) +{ + register_model_for_picking(canvas, m_triangles, picking_id_component(0)); + register_model_for_picking(canvas, m_del_icon, picking_id_component(1)); + register_model_for_picking(canvas, m_orient_icon, picking_id_component(2)); + register_model_for_picking(canvas, m_arrange_icon, picking_id_component(3)); + register_model_for_picking(canvas, m_lock_icon, picking_id_component(4)); + if (m_partplate_list->render_plate_settings) + register_model_for_picking(canvas, m_plate_settings_icon, picking_id_component(5)); } int PartPlate::picking_id_component(int idx) const @@ -2448,8 +2435,6 @@ bool PartPlate::set_shape(const Pointfs& shape, const Pointfs& exclude_areas, Ve calc_vertex_for_number(0, false, m_plate_idx_icon); // calc vertex for plate name generate_plate_name_texture(); - - register_raycasters_for_picking(); } calc_height_limit(); @@ -3361,8 +3346,6 @@ int PartPlateList::delete_plate(int index) return -1; } - plate->unregister_raycasters_for_picking(); - if (m_plater) { // In GUI mode // BBS: add wipe tower logic diff --git a/src/slic3r/GUI/PartPlate.hpp b/src/slic3r/GUI/PartPlate.hpp index 7b5eee70e3a..ced713a1f0d 100644 --- a/src/slic3r/GUI/PartPlate.hpp +++ b/src/slic3r/GUI/PartPlate.hpp @@ -131,7 +131,6 @@ class PartPlate : public ObjectBase PickingModel m_plate_settings_icon; GLModel m_plate_idx_icon; GLTexture m_texture; - std::vector picking_ids; float m_scale_factor{ 1.0f }; GLUquadricObject* m_quadric; @@ -181,9 +180,7 @@ class PartPlate : public ObjectBase void render_icons(bool bottom, bool only_name = false, int hover_id = -1); void render_only_numbers(bool bottom); void render_plate_name_texture(); - void register_rectangle_for_picking(PickingModel &model, int id); - void register_raycasters_for_picking(); - void unregister_raycasters_for_picking(); + void register_raycasters_for_picking(GLCanvas3D& canvas); int picking_id_component(int idx) const; public: @@ -744,6 +741,11 @@ class PartPlateList : public ObjectBase void render(const Transform3d& view_matrix, const Transform3d& projection_matrix, bool bottom, bool only_current = false, bool only_body = false, int hover_id = -1, bool render_cali = false); void set_render_option(bool bedtype_texture, bool plate_settings); void set_render_cali(bool value = true) { render_cali_logo = value; } + void register_raycasters_for_picking(GLCanvas3D& canvas) + { + for (auto plate : m_plate_list) + plate->register_raycasters_for_picking(canvas); + } BoundingBoxf3& get_bounding_box() { return m_bounding_box; } //int select_plate_by_hover_id(int hover_id); int select_plate_by_obj(int obj_index, int instance_index); From 799b0965f5fed77ef64ba76f01e033ca35e3ebbc Mon Sep 17 00:00:00 2001 From: YuSanka Date: Sat, 11 Nov 2023 12:50:41 +0800 Subject: [PATCH 96/99] Fix for prusa3d/PrusaSlicer#11487 - Cut Connectors Broken when assigning part to other side + Added check objects after cut + CutUtils: Ensuring that volumes start with solid parts after solid parts merging for proper slicing (cherry picked from commit prusa3d/PrusaSlicer@a9410edc2ccadf12f725cf96eaf9080b378797ca) --- src/libslic3r/CutUtils.cpp | 5 +++++ src/libslic3r/CutUtils.hpp | 2 -- src/slic3r/GUI/Gizmos/GLGizmoCut.cpp | 29 ++++++++++++++++++++++++++++ 3 files changed, 34 insertions(+), 2 deletions(-) diff --git a/src/libslic3r/CutUtils.cpp b/src/libslic3r/CutUtils.cpp index 5d3ec25c347..cdda3097aca 100644 --- a/src/libslic3r/CutUtils.cpp +++ b/src/libslic3r/CutUtils.cpp @@ -395,6 +395,9 @@ static void distribute_modifiers_from_object(ModelObject* from_obj, const int in for (ModelVolume* vol : from_obj->volumes) if (!vol->is_model_part()) { + // Don't add modifiers which are processed connectors + if (vol->cut_info.is_connector && !vol->cut_info.is_processed) + continue; auto bb = vol->mesh().transformed_bounding_box(inst_matrix * vol->get_matrix()); // Don't add modifiers which are not intersecting with solid parts if (obj1_bb.intersects(bb)) @@ -425,6 +428,8 @@ static void merge_solid_parts_inside_object(ModelObjectPtrs& objects) if (mv->is_model_part() && !mv->is_cut_connector()) mo->delete_volume(i); } + // Ensuring that volumes start with solid parts for proper slicing + mo->sort_volumes(true); } } } diff --git a/src/libslic3r/CutUtils.hpp b/src/libslic3r/CutUtils.hpp index 4607489b277..5067aaaff1b 100644 --- a/src/libslic3r/CutUtils.hpp +++ b/src/libslic3r/CutUtils.hpp @@ -65,8 +65,6 @@ class Cut { }; // namespace Cut - - } // namespace Slic3r #endif /* slic3r_CutUtils_hpp_ */ diff --git a/src/slic3r/GUI/Gizmos/GLGizmoCut.cpp b/src/slic3r/GUI/Gizmos/GLGizmoCut.cpp index cce7e9e9d07..c0267c9888c 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoCut.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoCut.cpp @@ -3290,6 +3290,32 @@ void update_object_cut_id(CutObjectBase& cut_id, ModelObjectCutAttributes attrib } } +static void check_objects_after_cut(const ModelObjectPtrs& objects) +{ + std::vector err_objects_names; + for (const ModelObject* object : objects) { + std::vector connectors_names; + connectors_names.reserve(object->volumes.size()); + for (const ModelVolume* vol : object->volumes) + if (vol->cut_info.is_connector) + connectors_names.push_back(vol->name); + const size_t connectors_count = connectors_names.size(); + sort_remove_duplicates(connectors_names); + if (connectors_count != connectors_names.size()) + err_objects_names.push_back(object->name); + } + if (err_objects_names.empty()) + return; + + wxString names = from_u8(err_objects_names[0]); + for (size_t i = 1; i < err_objects_names.size(); i++) + names += ", " + from_u8(err_objects_names[i]); + WarningDialog(wxGetApp().plater(), format_wxstr("Objects(%1%) have duplicated connectors. " + "Some connectors may be missing in slicing result.\n" + "Please report to PrusaSlicer team in which scenario this issue happened.\n" + "Thank you.", names)).ShowModal(); +} + void synchronize_model_after_cut(Model& model, const CutObjectBase& cut_id) { for (ModelObject* obj : model.objects) @@ -3354,6 +3380,9 @@ void GLGizmoCut3D::perform_cut(const Selection& selection) const ModelObjectPtrs& new_objects = cut_by_contour ? cut.perform_by_contour(m_part_selection.get_cut_parts(), dowels_count): cut_with_groove ? cut.perform_with_groove(m_groove, m_rotation_m) : cut.perform_with_plane(); + + check_objects_after_cut(new_objects); + // save cut_id to post update synchronization const CutObjectBase cut_id = cut_mo->cut_id; From 6510fd40548e316ffa476f6a31331bcf58fc67a2 Mon Sep 17 00:00:00 2001 From: Noisyfox Date: Sat, 11 Nov 2023 16:27:44 +0800 Subject: [PATCH 97/99] Hide raycast debug window --- src/libslic3r/Technologies.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libslic3r/Technologies.hpp b/src/libslic3r/Technologies.hpp index 461e3d8ea3d..d8dc5a7d42b 100644 --- a/src/libslic3r/Technologies.hpp +++ b/src/libslic3r/Technologies.hpp @@ -60,7 +60,7 @@ // Enable fit print volume command for circular printbeds #define ENABLE_ENHANCED_PRINT_VOLUME_FIT (1 && ENABLE_2_4_0_BETA2) // Enable picking using raytracing -#define ENABLE_RAYCAST_PICKING_DEBUG (1) +#define ENABLE_RAYCAST_PICKING_DEBUG 0 #endif // _prusaslicer_technologies_h_ From 67c1f40eae41e38191c82931e407960371df6406 Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Fri, 17 Nov 2023 09:32:45 +0800 Subject: [PATCH 98/99] Fixed a crash when deleting the last object with autocenter enabled (prusa3d/PrusaSlicer#11186). (cherry picked from commit prusa3d/PrusaSlicer@926af1ab8d24f5b4f8500be16d673b0ccdcd6101) --- src/libslic3r/Model.cpp | 8 ++ src/libslic3r/Model.hpp | 2 + src/slic3r/GUI/GUI_ObjectList.cpp | 119 +++++++++++++++--------------- 3 files changed, 70 insertions(+), 59 deletions(-) diff --git a/src/libslic3r/Model.cpp b/src/libslic3r/Model.cpp index 2d0ff44ca35..1cd76fc2c5e 100644 --- a/src/libslic3r/Model.cpp +++ b/src/libslic3r/Model.cpp @@ -2289,6 +2289,14 @@ int ModelObject::get_repaired_errors_count(const int vol_idx /*= -1*/) const stats.facets_reversed + stats.backwards_edges; } +bool ModelObject::has_solid_mesh() const +{ + for (const ModelVolume* volume : volumes) + if (volume->is_model_part()) + return true; + return false; +} + void ModelVolume::set_material_id(t_model_material_id material_id) { m_material_id = material_id; diff --git a/src/libslic3r/Model.hpp b/src/libslic3r/Model.hpp index 0705012c765..02220c2aad6 100644 --- a/src/libslic3r/Model.hpp +++ b/src/libslic3r/Model.hpp @@ -523,6 +523,8 @@ class ModelObject final : public ObjectBase // Get count of errors in the mesh( or all object's meshes, if volume index isn't defined) int get_repaired_errors_count(const int vol_idx = -1) const; + // Detect if object has at least one solid mash + bool has_solid_mesh() const; bool is_cut() const { return cut_id.id().valid(); } bool has_connectors() const; private: diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp index 4d632d17eb0..bbe4de5ea58 100644 --- a/src/slic3r/GUI/GUI_ObjectList.cpp +++ b/src/slic3r/GUI/GUI_ObjectList.cpp @@ -1,3 +1,9 @@ +///|/ Copyright (c) Prusa Research 2018 - 2023 Oleksandra Iushchenko @YuSanka, Enrico Turri @enricoturri1966, Lukáš Matěna @lukasmatena, Lukáš Hejl @hejllukas, Tomáš Mészáros @tamasmeszaros, Vojtěch Bubník @bubnikv, Pavel Mikuš @Godrak, David Kocík @kocikdav, Filip Sykala @Jony01, Vojtěch Král @vojtechkral +///|/ Copyright (c) 2021 Mathias Rasmussen +///|/ Copyright (c) 2020 rongith +///|/ +///|/ PrusaSlicer is released under the terms of the AGPLv3 or higher +///|/ #include "libslic3r/libslic3r.h" #include "libslic3r/PresetBundle.hpp" #include "GUI_ObjectList.hpp" @@ -3030,48 +3036,6 @@ bool ObjectList::can_split_instances() return selection.is_multiple_full_instance() || selection.is_single_full_instance(); } -bool ObjectList::can_merge_to_multipart_object() const -{ - if (has_selected_cut_object()) - return false; - - if (printer_technology() == ptSLA) - return false; - - wxDataViewItemArray sels; - GetSelections(sels); - if (sels.IsEmpty()) - return false; - - // should be selected just objects - for (wxDataViewItem item : sels) { - if (!(m_objects_model->GetItemType(item) & (itObject | itInstance))) - return false; - } - - return true; -} - -bool ObjectList::can_merge_to_single_object() const -{ - int obj_idx = get_selected_obj_idx(); - if (obj_idx < 0) - return false; - - // selected object should be multipart - return (*m_objects)[obj_idx]->volumes.size() > 1; -} - -bool ObjectList::can_mesh_boolean() const -{ - int obj_idx = get_selected_obj_idx(); - if (obj_idx < 0) - return false; - - // selected object should be multi mesh - return (*m_objects)[obj_idx]->volumes.size() > 1 || ((*m_objects)[obj_idx]->volumes.size() == 1 && (*m_objects)[obj_idx]->volumes[0]->is_splittable()); -} - bool ObjectList::has_selected_cut_object() const { wxDataViewItemArray sels; @@ -3081,7 +3045,9 @@ bool ObjectList::has_selected_cut_object() const for (wxDataViewItem item : sels) { const int obj_idx = m_objects_model->GetObjectIdByItem(item); - if (obj_idx >= 0 && object(obj_idx)->is_cut()) + // ys_FIXME: The obj_idx= 0 && obj_idx < int(m_objects->size()) && object(obj_idx)->is_cut()) return true; } @@ -3100,15 +3066,16 @@ void ObjectList::invalidate_cut_info_for_selection() void ObjectList::invalidate_cut_info_for_object(int obj_idx) { - ModelObject *init_obj = object(obj_idx); - if (!init_obj->is_cut()) return; + ModelObject* init_obj = object(obj_idx); + if (!init_obj->is_cut()) + return; - take_snapshot("Invalidate cut info"); + take_snapshot(_u8L("Invalidate cut info")); const CutObjectBase cut_id = init_obj->cut_id; // invalidate cut for related objects (which have the same cut_id) for (size_t idx = 0; idx < m_objects->size(); idx++) - if (ModelObject *obj = object(int(idx)); obj->cut_id.is_equal(cut_id)) { + if (ModelObject* obj = object(int(idx)); obj->cut_id.is_equal(cut_id)) { obj->invalidate_cut(); update_info_items(idx); add_volumes_to_object_in_list(idx); @@ -3129,26 +3096,20 @@ void ObjectList::delete_all_connectors_for_selection() void ObjectList::delete_all_connectors_for_object(int obj_idx) { - ModelObject *init_obj = object(obj_idx); + ModelObject* init_obj = object(obj_idx); if (!init_obj->is_cut()) return; - take_snapshot("Delete all connectors"); - - auto has_solid_mesh = [](ModelObject* obj) { - for (const ModelVolume *volume : obj->volumes) - if (volume->is_model_part()) return true; - return false; - }; + take_snapshot(_u8L("Delete all connectors")); const CutObjectBase cut_id = init_obj->cut_id; // Delete all connectors for related objects (which have the same cut_id) - Model &model = wxGetApp().plater()->model(); - for (int idx = int(m_objects->size()) - 1; idx >= 0; idx--) - if (ModelObject *obj = object(idx); obj->cut_id.is_equal(cut_id)) { + Model& model = wxGetApp().plater()->model(); + for (int idx = int(m_objects->size())-1; idx >= 0; idx--) + if (ModelObject* obj = object(idx); obj->cut_id.is_equal(cut_id)) { obj->delete_connectors(); - if (obj->volumes.empty() || !has_solid_mesh(obj)) { + if (obj->volumes.empty() || !obj->has_solid_mesh()) { model.delete_object(idx); m_objects_model->Delete(m_objects_model->GetItemById(idx)); continue; @@ -3162,6 +3123,46 @@ void ObjectList::delete_all_connectors_for_object(int obj_idx) update_lock_icons_for_model(); } +bool ObjectList::can_merge_to_multipart_object() const +{ + if (has_selected_cut_object()) + return false; + + if (printer_technology() == ptSLA) + return false; + + wxDataViewItemArray sels; + GetSelections(sels); + if (sels.IsEmpty()) + return false; + + // should be selected just objects + for (wxDataViewItem item : sels) + if (!(m_objects_model->GetItemType(item) & (itObject | itInstance))) + return false; + + return true; +} + +bool ObjectList::can_merge_to_single_object() const +{ + int obj_idx = get_selected_obj_idx(); + if (obj_idx < 0) + return false; + + // selected object should be multipart + return (*m_objects)[obj_idx]->volumes.size() > 1; +} + +bool ObjectList::can_mesh_boolean() const +{ + int obj_idx = get_selected_obj_idx(); + if (obj_idx < 0) + return false; + + // selected object should be multi mesh + return (*m_objects)[obj_idx]->volumes.size() > 1 || ((*m_objects)[obj_idx]->volumes.size() == 1 && (*m_objects)[obj_idx]->volumes[0]->is_splittable()); +} // NO_PARAMETERS function call means that changed object index will be determine from Selection() void ObjectList::changed_object(const int obj_idx/* = -1*/) const From 67fe5ee7f52fc18ce484bc2f2356298cfff7d696 Mon Sep 17 00:00:00 2001 From: Noisyfox Date: Sat, 18 Nov 2023 14:51:22 +0800 Subject: [PATCH 99/99] Bring back anti-aliasing to toolbar icons (#2739) --- src/slic3r/GUI/GLTexture.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/slic3r/GUI/GLTexture.cpp b/src/slic3r/GUI/GLTexture.cpp index d71110973b0..4de7c7c7a68 100644 --- a/src/slic3r/GUI/GLTexture.cpp +++ b/src/slic3r/GUI/GLTexture.cpp @@ -420,9 +420,9 @@ bool GLTexture::load_from_svg_files_as_sprites_array(const std::vector