Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/supermerill/SuperSlicer.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/xs/src
diff options
context:
space:
mode:
authorEnrico Turri <enricoturri@seznam.cz>2018-01-16 16:59:06 +0300
committerEnrico Turri <enricoturri@seznam.cz>2018-01-16 16:59:06 +0300
commitc63e6b74fa15d69bb0ca9ab5b62f8cfd3129d616 (patch)
tree05481256f2d8642a49e26261fa44507ca412c05b /xs/src
parent9e0dd2a96a12bb187767a702145c776ab5ea9d19 (diff)
GCode Preview - Added legend texture
Diffstat (limited to 'xs/src')
-rw-r--r--xs/src/libslic3r/GCode/Analyzer.cpp112
-rw-r--r--xs/src/libslic3r/GCode/Analyzer.hpp27
-rw-r--r--xs/src/slic3r/GUI/3DScene.cpp224
-rw-r--r--xs/src/slic3r/GUI/3DScene.hpp43
4 files changed, 397 insertions, 9 deletions
diff --git a/xs/src/libslic3r/GCode/Analyzer.cpp b/xs/src/libslic3r/GCode/Analyzer.cpp
index 5372ff302..ae857e37e 100644
--- a/xs/src/libslic3r/GCode/Analyzer.cpp
+++ b/xs/src/libslic3r/GCode/Analyzer.cpp
@@ -436,6 +436,16 @@ GCodeAnalyzer::PreviewData::Color::Color(float r, float g, float b, float a)
rgba[3] = a;
}
+std::vector<unsigned char> GCodeAnalyzer::PreviewData::Color::as_bytes() const
+{
+ std::vector<unsigned char> ret;
+ for (unsigned int i = 0; i < 4; ++i)
+ {
+ ret.push_back((unsigned char)(255.0f * rgba[i]));
+ }
+ return ret;
+}
+
GCodeAnalyzer::PreviewData::Extrusion::Layer::Layer(float z, const ExtrusionPaths& paths)
: z(z)
, paths(paths)
@@ -491,6 +501,11 @@ void GCodeAnalyzer::PreviewData::Range::set_from(const Range& other)
max = other.max;
}
+float GCodeAnalyzer::PreviewData::Range::step_size() const
+{
+ return (max - min) / (float)Colors_Count;
+}
+
const GCodeAnalyzer::PreviewData::Color& GCodeAnalyzer::PreviewData::Range::get_color_at_max() const
{
return colors[Colors_Count - 1];
@@ -498,12 +513,13 @@ const GCodeAnalyzer::PreviewData::Color& GCodeAnalyzer::PreviewData::Range::get_
const GCodeAnalyzer::PreviewData::Color& GCodeAnalyzer::PreviewData::Range::get_color_at(float value) const
{
- return empty() ? get_color_at_max() : colors[clamp((unsigned int)0, Colors_Count - 1, (unsigned int)((value - min) / _step()))];
+ return empty() ? get_color_at_max() : colors[clamp((unsigned int)0, Colors_Count - 1, (unsigned int)((value - min) / step_size()))];
}
-float GCodeAnalyzer::PreviewData::Range::_step() const
+GCodeAnalyzer::PreviewData::LegendItem::LegendItem(const std::string& text, const GCodeAnalyzer::PreviewData::Color& color)
+ : text(text)
+ , color(color)
{
- return (max - min) / (float)Colors_Count;
}
const GCodeAnalyzer::PreviewData::Color GCodeAnalyzer::PreviewData::Extrusion::Default_Extrusion_Role_Colors[Num_Extrusion_Roles] =
@@ -523,6 +539,23 @@ const GCodeAnalyzer::PreviewData::Color GCodeAnalyzer::PreviewData::Extrusion::D
Color(0.0f, 0.0f, 0.0f, 1.0f) // erMixed
};
+const std::string GCodeAnalyzer::PreviewData::Extrusion::Default_Extrusion_Role_Names[Num_Extrusion_Roles]
+{
+ "None",
+ "Perimeter",
+ "External perimeter",
+ "Overhang perimeter",
+ "Internal infill",
+ "Solid infill",
+ "Top solid infill",
+ "Bridge infill",
+ "Gap fill",
+ "Skirt",
+ "Support material",
+ "Support material interface",
+ "Mixed"
+};
+
const GCodeAnalyzer::PreviewData::Extrusion::EViewType GCodeAnalyzer::PreviewData::Extrusion::Default_View_Type = GCodeAnalyzer::PreviewData::Extrusion::FeatureType;
void GCodeAnalyzer::PreviewData::Extrusion::set_default()
@@ -534,6 +567,11 @@ void GCodeAnalyzer::PreviewData::Extrusion::set_default()
::memcpy((void*)ranges.width.colors, (const void*)Range::Default_Colors, Range::Colors_Count * sizeof(Color));
::memcpy((void*)ranges.feedrate.colors, (const void*)Range::Default_Colors, Range::Colors_Count * sizeof(Color));
+ for (unsigned int i = 0; i < Num_Extrusion_Roles; ++i)
+ {
+ role_names[i] = Default_Extrusion_Role_Names[i];
+ }
+
role_flags = 0;
for (unsigned int i = 0; i < Num_Extrusion_Roles; ++i)
{
@@ -628,6 +666,74 @@ const GCodeAnalyzer::PreviewData::Color& GCodeAnalyzer::PreviewData::get_extrusi
return extrusion.ranges.feedrate.get_color_at(feedrate);
}
+std::string GCodeAnalyzer::PreviewData::get_legend_title() const
+{
+ switch (extrusion.view_type)
+ {
+ case Extrusion::FeatureType:
+ return "Feature type";
+ case Extrusion::Height:
+ return "Height (mm)";
+ case Extrusion::Width:
+ return "Width (mm)";
+ case Extrusion::Feedrate:
+ return "Speed (mm/min)";
+ }
+
+ return "";
+}
+
+GCodeAnalyzer::PreviewData::LegendItemsList GCodeAnalyzer::PreviewData::get_legend_items() const
+{
+ struct Helper
+ {
+ static void FillListFromRange(LegendItemsList& list, const Range& range, unsigned int decimals, float scale_factor)
+ {
+ list.reserve(Range::Colors_Count);
+ float step = range.step_size();
+ for (unsigned int i = 0; i < Range::Colors_Count; ++i)
+ {
+ char buf[32];
+ sprintf(buf, "%.*f/%.*f", decimals, scale_factor * (range.min + (float)i * step), decimals, scale_factor * (range.min + (float)(i + 1) * step));
+ list.emplace_back(buf, range.colors[i]);
+ }
+ }
+ };
+
+ LegendItemsList items;
+
+ switch (extrusion.view_type)
+ {
+ case Extrusion::FeatureType:
+ {
+ items.reserve(erMixed - erPerimeter + 1);
+ for (unsigned int i = (unsigned int)erPerimeter; i < (unsigned int)erMixed; ++i)
+ {
+ items.emplace_back(extrusion.role_names[i], extrusion.role_colors[i]);
+ }
+
+ break;
+ }
+ case Extrusion::Height:
+ {
+ Helper::FillListFromRange(items, extrusion.ranges.height, 3, 1.0f);
+ break;
+ }
+ case Extrusion::Width:
+ {
+ Helper::FillListFromRange(items, extrusion.ranges.width, 3, 1.0f);
+ break;
+ }
+ case Extrusion::Feedrate:
+ {
+ Helper::FillListFromRange(items, extrusion.ranges.feedrate, 0, 60.0f);
+ break;
+ }
+ }
+
+ return items;
+}
+
GCodeAnalyzer::GCodeAnalyzer()
{
reset();
diff --git a/xs/src/libslic3r/GCode/Analyzer.hpp b/xs/src/libslic3r/GCode/Analyzer.hpp
index 2f5dafb3c..26c525b4c 100644
--- a/xs/src/libslic3r/GCode/Analyzer.hpp
+++ b/xs/src/libslic3r/GCode/Analyzer.hpp
@@ -206,9 +206,9 @@ public:
ExtrusionRole extrusion_role;
unsigned int extruder_id;
double mm3_per_mm;
- float width;
- float height;
- float feedrate;
+ float width; // mm
+ float height; // mm
+ float feedrate; // mm/s
Metadata();
Metadata(ExtrusionRole extrusion_role, unsigned int extruder_id, double mm3_per_mm, float width, float height, float feedrate);
@@ -264,6 +264,8 @@ public:
Color();
Color(float r, float g, float b, float a);
+ std::vector<unsigned char> as_bytes() const;
+
static const Color Dummy;
};
@@ -282,14 +284,22 @@ public:
bool empty() const;
void update_from(float value);
void set_from(const Range& other);
+ float step_size() const;
const Color& get_color_at(float value) const;
const Color& get_color_at_max() const;
+ };
- private:
- float _step() const;
+ struct LegendItem
+ {
+ std::string text;
+ Color color;
+
+ LegendItem(const std::string& text, const Color& color);
};
+ typedef std::vector<LegendItem> LegendItemsList;
+
struct Extrusion
{
enum EViewType : unsigned char
@@ -303,7 +313,8 @@ public:
static const unsigned int Num_Extrusion_Roles = (unsigned int)erMixed + 1;
static const Color Default_Extrusion_Role_Colors[Num_Extrusion_Roles];
- static const EViewType Default_View_Type;
+ static const std::string Default_Extrusion_Role_Names[Num_Extrusion_Roles];
+ static const EViewType Default_View_Type;
struct Ranges
{
@@ -324,6 +335,7 @@ public:
EViewType view_type;
Color role_colors[Num_Extrusion_Roles];
+ std::string role_names[Num_Extrusion_Roles];
Ranges ranges;
LayersList layers;
unsigned int role_flags;
@@ -411,6 +423,9 @@ public:
const Color& get_extrusion_height_color(float height) const;
const Color& get_extrusion_width_color(float width) const;
const Color& get_extrusion_feedrate_color(float feedrate) const;
+
+ std::string get_legend_title() const;
+ LegendItemsList get_legend_items() const;
};
private:
diff --git a/xs/src/slic3r/GUI/3DScene.cpp b/xs/src/slic3r/GUI/3DScene.cpp
index 60e3ac722..676d75c2f 100644
--- a/xs/src/slic3r/GUI/3DScene.cpp
+++ b/xs/src/slic3r/GUI/3DScene.cpp
@@ -8,9 +8,11 @@
#include "../../libslic3r/Geometry.hpp"
#include "../../libslic3r/Print.hpp"
#include "../../libslic3r/Slicing.hpp"
+//############################################################################################################
#if ENRICO_GCODE_PREVIEW
#include "GCode/Analyzer.hpp"
#endif // ENRICO_GCODE_PREVIEW
+//############################################################################################################
#include <stdio.h>
#include <stdlib.h>
@@ -23,6 +25,15 @@
#include <tbb/parallel_for.h>
#include <tbb/spin_mutex.h>
+//############################################################################################################
+#if ENRICO_GCODE_PREVIEW
+#include <wx/bitmap.h>
+#include <wx/dcmemory.h>
+#include <wx/image.h>
+#include <wx/settings.h>
+#endif // ENRICO_GCODE_PREVIEW
+//############################################################################################################
+
namespace Slic3r {
void GLIndexedVertexArray::load_mesh_flat_shading(const TriangleMesh &mesh)
@@ -1098,6 +1109,197 @@ void _3DScene::GCodePreviewData::reset()
}
_3DScene::GCodePreviewData _3DScene::s_gcode_preview_data;
+_3DScene::LegendTexture _3DScene::s_legend_texture;
+
+const unsigned char _3DScene::LegendTexture::Squares_Border_Color[3] = { 64, 64, 64 };
+const unsigned char _3DScene::LegendTexture::Background_Color[3] = { 9, 91, 134 };
+const unsigned char _3DScene::LegendTexture::Opacity = 255;
+
+_3DScene::LegendTexture::LegendTexture()
+ : m_tex_id(0)
+ , m_tex_width(0)
+ , m_tex_height(0)
+{
+}
+
+_3DScene::LegendTexture::~LegendTexture()
+{
+ _destroy_texture();
+}
+
+bool _3DScene::LegendTexture::generate_texture(const Print& print)
+{
+ _destroy_texture();
+
+ // collects items to render
+ const std::string& title = print.gcode_preview.get_legend_title();
+ const GCodeAnalyzer::PreviewData::LegendItemsList& items = print.gcode_preview.get_legend_items();
+
+ unsigned int items_count = (unsigned int)items.size();
+ if (items_count == 0)
+ // nothing to render, return
+ return false;
+
+ wxMemoryDC memDC;
+ // select default font
+ memDC.SetFont(wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT));
+
+ // calculates texture size
+ wxCoord w, h;
+ memDC.GetTextExtent(title, &w, &h);
+ unsigned int title_width = (unsigned int)w;
+ unsigned int title_height = (unsigned int)h;
+
+ unsigned int max_text_width = 0;
+ unsigned int max_text_height = 0;
+ for (const GCodeAnalyzer::PreviewData::LegendItem& item : items)
+ {
+ memDC.GetTextExtent(item.text, &w, &h);
+ max_text_width = std::max(max_text_width, (unsigned int)w);
+ max_text_height = std::max(max_text_height, (unsigned int)h);
+ }
+
+ m_tex_width = std::max(2 * Px_Border + title_width, 2 * (Px_Border + Px_Square_Contour) + Px_Square + Px_Text_Offset + max_text_width);
+ m_tex_height = 2 * (Px_Border + Px_Square_Contour) + title_height + Px_Title_Offset + items_count * Px_Square;
+ if (items_count > 1)
+ m_tex_height += (items_count - 1) * Px_Square_Contour;
+
+ // generates bitmap
+ wxBitmap bitmap(m_tex_width, m_tex_height);
+
+#if defined(__APPLE__) || defined(_MSC_VER)
+ bitmap.UseAlpha();
+#endif
+
+ memDC.SelectObject(bitmap);
+ memDC.SetBackground(wxBrush(wxColour(Background_Color[0], Background_Color[1], Background_Color[2])));
+ memDC.Clear();
+
+ memDC.SetTextForeground(*wxWHITE);
+
+ // draw title
+ unsigned int title_x = Px_Border;
+ unsigned int title_y = Px_Border;
+ memDC.DrawText(title, title_x, title_y);
+
+ // draw icons contours as background
+ unsigned int squares_contour_x = Px_Border;
+ unsigned int squares_contour_y = Px_Border + title_height + Px_Title_Offset;
+ unsigned int squares_contour_width = Px_Square + 2 * Px_Square_Contour;
+ unsigned int squares_contour_height = items_count * Px_Square + 2 * Px_Square_Contour;
+ if (items_count > 1)
+ squares_contour_height += (items_count - 1) * Px_Square_Contour;
+
+ wxColour color(Squares_Border_Color[0], Squares_Border_Color[1], Squares_Border_Color[2]);
+ wxPen pen(color);
+ wxBrush brush(color);
+ memDC.SetPen(pen);
+ memDC.SetBrush(brush);
+ memDC.DrawRectangle(wxRect(squares_contour_x, squares_contour_y, squares_contour_width, squares_contour_height));
+
+ // draw items (colored icon + text)
+ unsigned int icon_x = squares_contour_x + Px_Square_Contour;
+ unsigned int icon_x_inner = icon_x + 1;
+ unsigned int icon_y = squares_contour_y + Px_Square_Contour;
+ unsigned int icon_y_step = Px_Square + Px_Square_Contour;
+
+ unsigned int text_x = icon_x + Px_Square + Px_Text_Offset;
+ unsigned int text_y_offset = (Px_Square - max_text_height) / 2;
+
+ unsigned int px_inner_square = Px_Square - 2;
+
+ for (const GCodeAnalyzer::PreviewData::LegendItem& item : items)
+ {
+ // draw darker icon perimeter
+ const std::vector<unsigned char>& item_color_bytes = item.color.as_bytes();
+ wxImage::HSVValue dark_hsv = wxImage::RGBtoHSV(wxImage::RGBValue(item_color_bytes[0], item_color_bytes[1], item_color_bytes[2]));
+ dark_hsv.value *= 0.75;
+ wxImage::RGBValue dark_rgb = wxImage::HSVtoRGB(dark_hsv);
+ color.Set(dark_rgb.red, dark_rgb.green, dark_rgb.blue, item_color_bytes[3]);
+ pen.SetColour(color);
+ brush.SetColour(color);
+ memDC.SetPen(pen);
+ memDC.SetBrush(brush);
+ memDC.DrawRectangle(wxRect(icon_x, icon_y, Px_Square, Px_Square));
+
+ // draw icon interior
+ color.Set(item_color_bytes[0], item_color_bytes[1], item_color_bytes[2], item_color_bytes[3]);
+ pen.SetColour(color);
+ brush.SetColour(color);
+ memDC.SetPen(pen);
+ memDC.SetBrush(brush);
+ memDC.DrawRectangle(wxRect(icon_x_inner, icon_y + 1, px_inner_square, px_inner_square));
+
+ // draw text
+ memDC.DrawText(item.text, text_x, icon_y + text_y_offset);
+
+ // update y
+ icon_y += icon_y_step;
+ }
+
+ memDC.SelectObject(wxNullBitmap);
+
+ return _create_texture(print, bitmap);
+}
+
+unsigned int _3DScene::LegendTexture::get_texture_id() const
+{
+ return m_tex_id;
+}
+
+unsigned int _3DScene::LegendTexture::get_texture_width() const
+{
+ return m_tex_width;
+}
+
+unsigned int _3DScene::LegendTexture::get_texture_height() const
+{
+ return m_tex_height;
+}
+
+bool _3DScene::LegendTexture::_create_texture(const Print& print, const wxBitmap& bitmap)
+{
+ if ((m_tex_width == 0) || (m_tex_height == 0))
+ return false;
+
+ wxImage image = bitmap.ConvertToImage();
+ image.SetMaskColour(Background_Color[0], Background_Color[1], Background_Color[2]);
+
+ // prepare buffer
+ std::vector<unsigned char> buffer(4 * m_tex_width * m_tex_height, 0);
+ for (unsigned int h = 0; h < m_tex_height; ++h)
+ {
+ unsigned int hh = h * m_tex_width;
+ for (unsigned int w = 0; w < m_tex_width; ++w)
+ {
+ unsigned char* px_ptr = buffer.data() + 4 * (hh + w);
+ *px_ptr++ = image.GetRed(w, h);
+ *px_ptr++ = image.GetGreen(w, h);
+ *px_ptr++ = image.GetBlue(w, h);
+ *px_ptr++ = image.IsTransparent(w, h) ? 0 : Opacity;
+ }
+ }
+
+ // sends buffer to gpu
+ ::glGenTextures(1, &m_tex_id);
+ ::glBindTexture(GL_TEXTURE_2D, m_tex_id);
+ ::glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, (GLsizei)m_tex_width, (GLsizei)m_tex_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, (const GLvoid*)buffer.data());
+ ::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ ::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ ::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 1);
+ ::glBindTexture(GL_TEXTURE_2D, 0);
+
+ return true;
+}
+
+void _3DScene::LegendTexture::_destroy_texture()
+{
+ if (m_tex_id > 0)
+ {
+ ::glDeleteTextures(1, &m_tex_id);
+ m_tex_id = 0;
+ }
+}
#endif // ENRICO_GCODE_PREVIEW
//############################################################################################################
@@ -1145,10 +1347,27 @@ void _3DScene::load_gcode_preview(const Print* print, GLVolumeCollection* volume
_load_gcode_travel_paths(*print, *volumes, use_VBOs);
_load_gcode_retractions(*print, *volumes, use_VBOs);
_load_gcode_unretractions(*print, *volumes, use_VBOs);
+
+ _generate_legend_texture(*print);
}
_update_gcode_volumes_visibility(*print, *volumes);
}
+
+unsigned int _3DScene::get_legend_texture_id()
+{
+ return s_legend_texture.get_texture_id();
+}
+
+unsigned int _3DScene::get_legend_texture_width()
+{
+ return s_legend_texture.get_texture_width();
+}
+
+unsigned int _3DScene::get_legend_texture_height()
+{
+ return s_legend_texture.get_texture_height();
+}
#endif // ENRICO_GCODE_PREVIEW
//############################################################################################################
@@ -1847,6 +2066,11 @@ void _3DScene::_update_gcode_volumes_visibility(const Print& print, GLVolumeColl
}
}
}
+
+void _3DScene::_generate_legend_texture(const Print& print)
+{
+ s_legend_texture.generate_texture(print);
+}
#endif // ENRICO_GCODE_PREVIEW
//############################################################################################################
diff --git a/xs/src/slic3r/GUI/3DScene.hpp b/xs/src/slic3r/GUI/3DScene.hpp
index 8e16136d5..f869304aa 100644
--- a/xs/src/slic3r/GUI/3DScene.hpp
+++ b/xs/src/slic3r/GUI/3DScene.hpp
@@ -7,6 +7,12 @@
#include "../../libslic3r/TriangleMesh.hpp"
#include "../../libslic3r/Utils.hpp"
+//############################################################################################################
+#if ENRICO_GCODE_PREVIEW
+class wxBitmap;
+#endif // ENRICO_GCODE_PREVIEW
+//############################################################################################################
+
namespace Slic3r {
class Print;
@@ -389,6 +395,38 @@ class _3DScene
};
static GCodePreviewData s_gcode_preview_data;
+
+ class LegendTexture
+ {
+ static const unsigned int Px_Title_Offset = 5;
+ static const unsigned int Px_Text_Offset = 5;
+ static const unsigned int Px_Square = 20;
+ static const unsigned int Px_Square_Contour = 1;
+ static const unsigned int Px_Border = Px_Square / 2;
+ static const unsigned char Squares_Border_Color[3];
+ static const unsigned char Background_Color[3];
+ static const unsigned char Opacity;
+
+ unsigned int m_tex_id;
+ unsigned int m_tex_width;
+ unsigned int m_tex_height;
+
+ public:
+ LegendTexture();
+ ~LegendTexture();
+
+ bool generate_texture(const Print& print);
+
+ unsigned int get_texture_id() const;
+ unsigned int get_texture_width() const;
+ unsigned int get_texture_height() const;
+
+ private:
+ bool _create_texture(const Print& print, const wxBitmap& bitmap);
+ void _destroy_texture();
+ };
+
+ static LegendTexture s_legend_texture;
#endif // ENRICO_GCODE_PREVIEW
//############################################################################################################
public:
@@ -397,6 +435,9 @@ public:
//############################################################################################################
#if ENRICO_GCODE_PREVIEW
static void load_gcode_preview(const Print* print, GLVolumeCollection* volumes, bool use_VBOs);
+ static unsigned int get_legend_texture_id();
+ static unsigned int get_legend_texture_width();
+ static unsigned int get_legend_texture_height();
#endif // ENRICO_GCODE_PREVIEW
//############################################################################################################
@@ -432,6 +473,8 @@ private:
static void _load_gcode_unretractions(const Print& print, GLVolumeCollection& volumes, bool use_VBOs);
// sets gcode geometry visibility according to user selection
static void _update_gcode_volumes_visibility(const Print& print, GLVolumeCollection& volumes);
+ // generates the legend texture in dependence of the current shown view type
+ static void _generate_legend_texture(const Print& print);
#endif // ENRICO_GCODE_PREVIEW
//############################################################################################################
};