Merge branch 'et_gcode_viewer' of https://github.com/prusa3d/PrusaSlicer into et_gcode_viewer

This commit is contained in:
Enrico Turri 2020-04-20 16:34:45 +02:00
commit 04691cbcb1
15 changed files with 382 additions and 85 deletions

View file

@ -13,7 +13,7 @@ const vec3 LIGHT_TOP_DIR = vec3(-0.4574957, 0.4574957, 0.7624929);
const vec3 LIGHT_FRONT_DIR = vec3(0.0, 0.0, 1.0);
#define LIGHT_FRONT_DIFFUSE (0.3 * INTENSITY_CORRECTION)
uniform vec4 uniform_color;
uniform vec3 uniform_color;
varying vec3 eye_position;
varying vec3 eye_normal;
@ -41,5 +41,5 @@ void main()
// if (world_normal_z < 0.0)
// intensity.x *= (1.0 + world_normal_z * (1.0 - INTENSITY_AMBIENT));
gl_FragColor = vec4(vec3(intensity.y, intensity.y, intensity.y) + uniform_color.rgb * intensity.x, uniform_color.a);
gl_FragColor = vec4(vec3(intensity.y, intensity.y, intensity.y) + uniform_color * intensity.x, 1.0);
}

View file

@ -13,7 +13,7 @@ const vec3 LIGHT_TOP_DIR = vec3(-0.4574957, 0.4574957, 0.7624929);
const vec3 LIGHT_FRONT_DIR = vec3(0.0, 0.0, 1.0);
#define LIGHT_FRONT_DIFFUSE (0.3 * INTENSITY_CORRECTION)
uniform vec4 uniform_color;
uniform vec3 uniform_color;
varying vec3 eye_position;
varying vec3 eye_normal;
@ -41,5 +41,5 @@ void main()
// if (world_normal_z < 0.0)
// intensity.x *= (1.0 + world_normal_z * (1.0 - INTENSITY_AMBIENT));
gl_FragColor = vec4(vec3(intensity.y, intensity.y, intensity.y) + uniform_color.rgb * intensity.x, uniform_color.a);
gl_FragColor = vec4(vec3(intensity.y, intensity.y, intensity.y) + uniform_color * intensity.x, 1.0);
}

View file

@ -13,7 +13,7 @@ const vec3 LIGHT_TOP_DIR = vec3(-0.4574957, 0.4574957, 0.7624929);
const vec3 LIGHT_FRONT_DIR = vec3(0.0, 0.0, 1.0);
#define LIGHT_FRONT_DIFFUSE (0.3 * INTENSITY_CORRECTION)
uniform vec4 uniform_color;
uniform vec3 uniform_color;
varying vec3 eye_position;
varying vec3 eye_normal;
@ -41,5 +41,5 @@ void main()
// if (world_normal_z < 0.0)
// intensity.x *= (1.0 + world_normal_z * (1.0 - INTENSITY_AMBIENT));
gl_FragColor = vec4(vec3(intensity.y, intensity.y, intensity.y) + uniform_color.rgb * intensity.x, uniform_color.a);
gl_FragColor = vec4(vec3(intensity.y, intensity.y, intensity.y) + uniform_color * intensity.x, 1.0);
}

View file

@ -13,7 +13,7 @@ const vec3 LIGHT_TOP_DIR = vec3(-0.4574957, 0.4574957, 0.7624929);
const vec3 LIGHT_FRONT_DIR = vec3(0.0, 0.0, 1.0);
#define LIGHT_FRONT_DIFFUSE (0.3 * INTENSITY_CORRECTION)
uniform vec4 uniform_color;
uniform vec3 uniform_color;
varying vec3 eye_position;
varying vec3 eye_normal;
@ -41,5 +41,5 @@ void main()
// if (world_normal_z < 0.0)
// intensity.x *= (1.0 + world_normal_z * (1.0 - INTENSITY_AMBIENT));
gl_FragColor = vec4(vec3(intensity.y, intensity.y, intensity.y) + uniform_color.rgb * intensity.x, uniform_color.a);
gl_FragColor = vec4(vec3(intensity.y, intensity.y, intensity.y) + uniform_color * intensity.x, 1.0);
}

View file

@ -13,7 +13,7 @@ const vec3 LIGHT_TOP_DIR = vec3(-0.4574957, 0.4574957, 0.7624929);
const vec3 LIGHT_FRONT_DIR = vec3(0.0, 0.0, 1.0);
#define LIGHT_FRONT_DIFFUSE (0.3 * INTENSITY_CORRECTION)
uniform vec4 uniform_color;
uniform vec3 uniform_color;
varying vec3 eye_position;
varying vec3 eye_normal;
@ -41,5 +41,5 @@ void main()
// if (world_normal_z < 0.0)
// intensity.x *= (1.0 + world_normal_z * (1.0 - INTENSITY_AMBIENT));
gl_FragColor = vec4(vec3(intensity.y, intensity.y, intensity.y) + uniform_color.rgb * intensity.x, uniform_color.a);
gl_FragColor = vec4(vec3(intensity.y, intensity.y, intensity.y) + uniform_color * intensity.x, 1.0);
}

View file

@ -306,7 +306,11 @@ double ExtrusionLoop::min_mm3_per_mm() const
std::string ExtrusionEntity::role_to_string(ExtrusionRole role)
{
switch (role) {
#if ENABLE_GCODE_VIEWER
case erNone : return L("Unknown");
#else
case erNone : return L("None");
#endif // ENABLE_GCODE_VIEWER
case erPerimeter : return L("Perimeter");
case erExternalPerimeter : return L("External perimeter");
case erOverhangPerimeter : return L("Overhang perimeter");

View file

@ -56,8 +56,7 @@ public:
// Color mapping to convert a float into a smooth rainbow of 10 colors.
class RangeBase
{
public:
public:
virtual void reset() = 0;
virtual bool empty() const = 0;
virtual float min() const = 0;
@ -73,7 +72,7 @@ public:
// Color mapping converting a float in a range between a min and a max into a smooth rainbow of 10 colors.
class Range : public RangeBase
{
public:
public:
Range();
// RangeBase Overrides
@ -97,8 +96,7 @@ public:
template <typename EnumRangeType>
class MultiRange : public RangeBase
{
public:
public:
void reset() override
{
bounds = decltype(bounds){};
@ -160,8 +158,7 @@ public:
mode.set(static_cast<std::size_t>(range_type_value), enable);
}
private:
private:
// Interval bounds
struct Bounds
{

View file

@ -58,7 +58,7 @@
// Enable G-Code viewer
#define ENABLE_GCODE_VIEWER (1 && ENABLE_2_3_0_ALPHA1)
#define ENABLE_GCODE_VIEWER_DEBUG_OUTPUT (1 && ENABLE_GCODE_VIEWER)
#define ENABLE_GCODE_VIEWER_DEBUG_OUTPUT (0 && ENABLE_GCODE_VIEWER)
#endif // _prusaslicer_technologies_h_

View file

@ -2096,7 +2096,7 @@ ConfigWizard::ConfigWizard(wxWindow *parent)
p->add_page(p->page_filaments = new PageMaterials(this, &p->filaments,
_(L("Filament Profiles Selection")), _(L("Filaments")), _(L("Type:")) ));
p->add_page(p->page_sla_materials = new PageMaterials(this, &p->sla_materials,
_(L("SLA Material Profiles Selection")) + " ", _(L("SLA Materials")), _(L("Layer height:")) ));
_(L("SLA Material Profiles Selection")) + " ", _(L("SLA Materials")), _(L("Type:")) ));
p->add_page(p->page_update = new PageUpdate(this));

View file

@ -6,6 +6,8 @@
#include "GUI_App.hpp"
#include "PresetBundle.hpp"
#include "Camera.hpp"
#include "I18N.hpp"
#include "libslic3r/I18N.hpp"
#include <GL/glew.h>
#include <boost/log/trivial.hpp>
@ -57,28 +59,65 @@ bool GCodeViewer::IBuffer::init_shader(const std::string& vertex_shader_src, con
return true;
}
void GCodeViewer::IBuffer::add_path(GCodeProcessor::EMoveType type, ExtrusionRole role)
void GCodeViewer::IBuffer::add_path(const GCodeProcessor::MoveVertex& move)
{
unsigned int id = static_cast<unsigned int>(data.size());
paths.push_back({ type, role, id, id });
paths.push_back({ move.type, move.extrusion_role, id, id, move.height, move.width, move.feedrate });
}
const std::array<std::array<float, 4>, erCount> GCodeViewer::Default_Extrusion_Role_Colors {{
{ 0.00f, 0.00f, 0.00f, 1.0f }, // erNone
{ 1.00f, 1.00f, 0.40f, 1.0f }, // erPerimeter
{ 1.00f, 0.65f, 0.00f, 1.0f }, // erExternalPerimeter
{ 0.00f, 0.00f, 1.00f, 1.0f }, // erOverhangPerimeter
{ 0.69f, 0.19f, 0.16f, 1.0f }, // erInternalInfill
{ 0.84f, 0.20f, 0.84f, 1.0f }, // erSolidInfill
{ 1.00f, 0.10f, 0.10f, 1.0f }, // erTopSolidInfill
{ 0.60f, 0.60f, 1.00f, 1.0f }, // erBridgeInfill
{ 1.00f, 1.00f, 1.00f, 1.0f }, // erGapFill
{ 0.52f, 0.48f, 0.13f, 1.0f }, // erSkirt
{ 0.00f, 1.00f, 0.00f, 1.0f }, // erSupportMaterial
{ 0.00f, 0.50f, 0.00f, 1.0f }, // erSupportMaterialInterface
{ 0.70f, 0.89f, 0.67f, 1.0f }, // erWipeTower
{ 0.16f, 0.80f, 0.58f, 1.0f }, // erCustom
{ 0.00f, 0.00f, 0.00f, 1.0f } // erMixed
std::array<float, 3> GCodeViewer::Extrusions::Range::get_color_at(float value, const std::array<std::array<float, 3>, Default_Range_Colors_Count>& colors) const
{
// Input value scaled to the color range
const float step = step_size();
const float global_t = (step != 0.0f) ? std::max(0.0f, value - min) / step : 0.0f; // lower limit of 0.0f
const size_t color_max_idx = colors.size() - 1;
// Compute the two colors just below (low) and above (high) the input value
const size_t color_low_idx = std::clamp<size_t>(static_cast<size_t>(global_t), 0, color_max_idx);
const size_t color_high_idx = std::clamp<size_t>(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<float>(color_low_idx), 0.0f, 1.0f);
// Interpolate between the low and high colors in RGB space to find exactly which color the input value should get
std::array<float, 3> ret;
for (unsigned int i = 0; i < 3; ++i)
{
ret[i] = lerp(colors[color_low_idx][i], colors[color_high_idx][i], local_t);
}
return ret;
}
const std::array<std::array<float, 3>, erCount> GCodeViewer::Default_Extrusion_Role_Colors {{
{ 1.00f, 1.00f, 1.00f }, // erNone
{ 1.00f, 1.00f, 0.40f }, // erPerimeter
{ 1.00f, 0.65f, 0.00f }, // erExternalPerimeter
{ 0.00f, 0.00f, 1.00f }, // erOverhangPerimeter
{ 0.69f, 0.19f, 0.16f }, // erInternalInfill
{ 0.84f, 0.20f, 0.84f }, // erSolidInfill
{ 1.00f, 0.10f, 0.10f }, // erTopSolidInfill
{ 0.60f, 0.60f, 1.00f }, // erBridgeInfill
{ 1.00f, 1.00f, 1.00f }, // erGapFill
{ 0.52f, 0.48f, 0.13f }, // erSkirt
{ 0.00f, 1.00f, 0.00f }, // erSupportMaterial
{ 0.00f, 0.50f, 0.00f }, // erSupportMaterialInterface
{ 0.70f, 0.89f, 0.67f }, // erWipeTower
{ 0.16f, 0.80f, 0.58f }, // erCustom
{ 0.00f, 0.00f, 0.00f } // erMixed
}};
const std::array<std::array<float, 3>, GCodeViewer::Default_Range_Colors_Count> GCodeViewer::Default_Range_Colors {{
{ 0.043f, 0.173f, 0.478f },
{ 0.075f, 0.349f, 0.522f },
{ 0.110f, 0.533f, 0.569f },
{ 0.016f, 0.839f, 0.059f },
{ 0.667f, 0.949f, 0.000f },
{ 0.988f, 0.975f, 0.012f },
{ 0.961f, 0.808f, 0.039f },
{ 0.890f, 0.533f, 0.125f },
{ 0.820f, 0.408f, 0.188f },
{ 0.761f, 0.322f, 0.235f }
}};
void GCodeViewer::load(const GCodeProcessor::Result& gcode_result, const Print& print, bool initialized)
@ -95,6 +134,42 @@ void GCodeViewer::load(const GCodeProcessor::Result& gcode_result, const Print&
load_shells(print, initialized);
}
void GCodeViewer::refresh_toolpaths_ranges(const GCodeProcessor::Result& gcode_result)
{
if (m_vertices.vertices_count == 0)
return;
m_extrusions.reset_ranges();
for (size_t i = 0; i < m_vertices.vertices_count; ++i)
{
// skip first vertex
if (i == 0)
continue;
const GCodeProcessor::MoveVertex& curr = gcode_result.moves[i];
switch (curr.type)
{
case GCodeProcessor::EMoveType::Extrude:
case GCodeProcessor::EMoveType::Travel:
{
if (m_buffers[buffer_id(curr.type)].visible)
{
m_extrusions.ranges.height.update_from(curr.height);
m_extrusions.ranges.width.update_from(curr.width);
m_extrusions.ranges.feedrate.update_from(curr.feedrate);
}
break;
}
default:
{
break;
}
}
}
}
void GCodeViewer::reset()
{
m_vertices.reset();
@ -104,9 +179,12 @@ void GCodeViewer::reset()
buffer.reset();
}
m_bounding_box = BoundingBoxf3();
m_extrusions.reset_role_visibility_flags();
m_extrusions.reset_ranges();
m_shells.volumes.clear();
m_layers_zs = std::vector<double>();
m_roles = std::vector<ExtrusionRole>();
}
void GCodeViewer::render() const
@ -114,6 +192,7 @@ void GCodeViewer::render() const
glsafe(::glEnable(GL_DEPTH_TEST));
render_toolpaths();
render_shells();
render_overlay();
}
bool GCodeViewer::is_toolpath_visible(GCodeProcessor::EMoveType type) const
@ -198,13 +277,14 @@ void GCodeViewer::load_toolpaths(const GCodeProcessor::Result& gcode_result)
if (m_vertices.vertices_count == 0)
return;
// vertex data -> extract from result
// vertex data / bounding box -> extract from result
std::vector<float> vertices_data;
for (const GCodeProcessor::MoveVertex& move : gcode_result.moves)
{
for (int j = 0; j < 3; ++j)
{
vertices_data.insert(vertices_data.end(), move.position[j]);
m_bounding_box.merge(move.position.cast<double>());
}
}
@ -235,16 +315,16 @@ void GCodeViewer::load_toolpaths(const GCodeProcessor::Result& gcode_result)
case GCodeProcessor::EMoveType::Retract:
case GCodeProcessor::EMoveType::Unretract:
{
buffer.add_path(curr.type, curr.extrusion_role);
buffer.add_path(curr);
buffer.data.push_back(static_cast<unsigned int>(i));
break;
}
case GCodeProcessor::EMoveType::Extrude:
case GCodeProcessor::EMoveType::Travel:
{
if (prev.type != curr.type)
if (prev.type != curr.type || !buffer.paths.back().matches(curr))
{
buffer.add_path(curr.type, curr.extrusion_role);
buffer.add_path(curr);
buffer.data.push_back(static_cast<unsigned int>(i - 1));
}
@ -275,17 +355,17 @@ void GCodeViewer::load_toolpaths(const GCodeProcessor::Result& gcode_result)
}
}
// layers zs -> extract from result
// layers zs / roles -> extract from result
for (const GCodeProcessor::MoveVertex& move : gcode_result.moves)
{
if (move.type == GCodeProcessor::EMoveType::Extrude)
m_layers_zs.emplace_back(move.position[2]);
m_roles.emplace_back(move.extrusion_role);
}
// layers zs -> sort
std::sort(m_layers_zs.begin(), m_layers_zs.end());
// layers zs -> replace intervals of layers with similar top positions with their average value.
std::sort(m_layers_zs.begin(), m_layers_zs.end());
int n = int(m_layers_zs.size());
int k = 0;
for (int i = 0; i < n;) {
@ -298,6 +378,10 @@ void GCodeViewer::load_toolpaths(const GCodeProcessor::Result& gcode_result)
if (k < n)
m_layers_zs.erase(m_layers_zs.begin() + k, m_layers_zs.end());
// roles -> remove duplicates
std::sort(m_roles.begin(), m_roles.end());
m_roles.erase(std::unique(m_roles.begin(), m_roles.end()), m_roles.end());
auto end_time = std::chrono::high_resolution_clock::now();
std::cout << "toolpaths generation time: " << std::chrono::duration_cast<std::chrono::milliseconds>(end_time - start_time).count() << "ms \n";
}
@ -356,39 +440,27 @@ void GCodeViewer::load_shells(const Print& print, bool initialized)
void GCodeViewer::render_toolpaths() const
{
auto extrusion_color = [this](const Path& path) {
std::array<float, 4> color;
std::array<float, 3> color;
switch (m_view_type)
{
case EViewType::FeatureType:
{
unsigned int color_id = static_cast<unsigned int>(path.role);
if (color_id >= erCount)
color_id = 0;
color = m_extrusions.role_colors[color_id];
break;
}
case EViewType::Height:
case EViewType::Width:
case EViewType::Feedrate:
case EViewType::FeatureType: { color = m_extrusions.role_colors[static_cast<unsigned int>(path.role)]; break; }
case EViewType::Height: { color = m_extrusions.ranges.height.get_color_at(path.height, m_extrusions.ranges.colors); break; }
case EViewType::Width: { color = m_extrusions.ranges.width.get_color_at(path.width, m_extrusions.ranges.colors); break; }
case EViewType::Feedrate: { color = m_extrusions.ranges.feedrate.get_color_at(path.feedrate, m_extrusions.ranges.colors); break; }
case EViewType::FanSpeed:
case EViewType::VolumetricRate:
case EViewType::Tool:
case EViewType::ColorPrint:
default:
{
color = { 1.0f, 1.0f, 1.0f, 1.0f };
break;
}
default: { color = { 1.0f, 1.0f, 1.0f }; break; }
}
return color;
};
auto set_color = [](GLint current_program_id, const std::array<float, 4>& color) {
auto set_color = [](GLint current_program_id, const std::array<float, 3>& color) {
if (current_program_id > 0) {
GLint color_id = (current_program_id > 0) ? ::glGetUniformLocation(current_program_id, "uniform_color") : -1;
if (color_id >= 0) {
glsafe(::glUniform4fv(color_id, 1, (const GLfloat*)color.data()));
glsafe(::glUniform3fv(color_id, 1, (const GLfloat*)color.data()));
return;
}
}
@ -432,7 +504,7 @@ void GCodeViewer::render_toolpaths() const
{
case GCodeProcessor::EMoveType::Tool_change:
{
std::array<float, 4> color = { 1.0f, 1.0f, 1.0f, 1.0f };
std::array<float, 3> color = { 1.0f, 1.0f, 1.0f };
set_color(current_program_id, color);
glsafe(::glEnable(GL_PROGRAM_POINT_SIZE));
glsafe(::glDrawElements(GL_POINTS, (GLsizei)buffer.data_size, GL_UNSIGNED_INT, nullptr));
@ -441,7 +513,7 @@ void GCodeViewer::render_toolpaths() const
}
case GCodeProcessor::EMoveType::Retract:
{
std::array<float, 4> color = { 1.0f, 0.0f, 1.0f, 1.0f };
std::array<float, 3> color = { 1.0f, 0.0f, 1.0f };
set_color(current_program_id, color);
glsafe(::glEnable(GL_PROGRAM_POINT_SIZE));
glsafe(::glDrawElements(GL_POINTS, (GLsizei)buffer.data_size, GL_UNSIGNED_INT, nullptr));
@ -450,7 +522,7 @@ void GCodeViewer::render_toolpaths() const
}
case GCodeProcessor::EMoveType::Unretract:
{
std::array<float, 4> color = { 0.0f, 1.0f, 0.0f, 1.0f };
std::array<float, 3> color = { 0.0f, 1.0f, 0.0f };
set_color(current_program_id, color);
glsafe(::glEnable(GL_PROGRAM_POINT_SIZE));
glsafe(::glDrawElements(GL_POINTS, (GLsizei)buffer.data_size, GL_UNSIGNED_INT, nullptr));
@ -471,7 +543,7 @@ void GCodeViewer::render_toolpaths() const
}
case GCodeProcessor::EMoveType::Travel:
{
std::array<float, 4> color = { 1.0f, 1.0f, 0.0f, 1.0f };
std::array<float, 3> color = { 1.0f, 1.0f, 0.0f };
set_color(current_program_id, color);
for (const Path& path : buffer.paths)
{
@ -504,6 +576,108 @@ void GCodeViewer::render_shells() const
// glsafe(::glDepthMask(GL_TRUE));
}
void GCodeViewer::render_overlay() const
{
static const ImVec4 ORANGE(1.0f, 0.49f, 0.22f, 1.0f);
static const float ICON_BORDER_SIZE = 25.0f;
static const ImU32 ICON_BORDER_COLOR = ImGui::GetColorU32(ImVec4(0.0f, 0.0f, 0.0f, 1.0f));
static const float GAP_ICON_TEXT = 5.0f;
if (!m_legend_enabled || m_roles.empty())
return;
ImGuiWrapper& imgui = *wxGetApp().imgui();
imgui.set_next_window_pos(0, 0, ImGuiCond_Always);
ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f);
imgui.begin(_L("Legend"), ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoMove);
ImDrawList* draw_list = ImGui::GetWindowDrawList();
auto add_range = [this, draw_list, &imgui](const Extrusions::Range& range, unsigned int decimals) {
auto add_item = [this, draw_list, &imgui](int i, float value, unsigned int decimals) {
ImVec2 pos(ImGui::GetCursorPosX() + 2.0f, ImGui::GetCursorPosY() + 2.0f);
draw_list->AddRect(ImVec2(pos.x, pos.y), ImVec2(pos.x + ICON_BORDER_SIZE, pos.y + ICON_BORDER_SIZE), ICON_BORDER_COLOR, 0.0f, 0);
const std::array<float, 3>& color = m_extrusions.ranges.colors[i];
ImU32 fill_color = ImGui::GetColorU32(ImVec4(color[0], color[1], color[2], 1.0f));
draw_list->AddRectFilled(ImVec2(pos.x + 1.0f, pos.y + 1.0f), ImVec2(pos.x + ICON_BORDER_SIZE - 1.0f, pos.y + ICON_BORDER_SIZE - 1.0f), fill_color);
ImGui::SetCursorPosX(pos.x + ICON_BORDER_SIZE + GAP_ICON_TEXT);
ImGui::AlignTextToFramePadding();
char buf[1024];
::sprintf(buf, "%.*f", decimals, value);
imgui.text(buf);
};
float step_size = range.step_size();
if (step_size == 0.0f)
add_item(0, range.min, decimals);
else
{
for (int i = Default_Range_Colors_Count - 1; i >= 0; --i)
{
add_item(i, range.min + static_cast<float>(i) * step_size, decimals);
}
}
};
ImGui::PushStyleColor(ImGuiCol_Text, ORANGE);
switch (m_view_type)
{
case EViewType::FeatureType: { imgui.text(Slic3r::I18N::translate(L("Feature type"))); break; }
case EViewType::Height: { imgui.text(Slic3r::I18N::translate(L("Height (mm)"))); break; }
case EViewType::Width: { imgui.text(Slic3r::I18N::translate(L("Width (mm)"))); break; }
case EViewType::Feedrate: { imgui.text(Slic3r::I18N::translate(L("Speed (mm/s)"))); break; }
case EViewType::FanSpeed: { imgui.text(Slic3r::I18N::translate(L("Fan Speed (%)"))); break; }
case EViewType::VolumetricRate: { imgui.text(Slic3r::I18N::translate(L("Volumetric flow rate (mm³/s)"))); break; }
case EViewType::Tool: { imgui.text(Slic3r::I18N::translate(L("Tool"))); break; }
case EViewType::ColorPrint: { imgui.text(Slic3r::I18N::translate(L("Color Print"))); break; }
}
ImGui::PopStyleColor();
ImGui::Separator();
switch (m_view_type)
{
case EViewType::FeatureType:
{
for (ExtrusionRole role : m_roles)
{
ImVec2 pos(ImGui::GetCursorPosX() + 2.0f, ImGui::GetCursorPosY() + 2.0f);
draw_list->AddRect(ImVec2(pos.x, pos.y), ImVec2(pos.x + ICON_BORDER_SIZE, pos.y + ICON_BORDER_SIZE), ICON_BORDER_COLOR, 0.0f, 0);
const std::array<float, 3>& color = m_extrusions.role_colors[static_cast<unsigned int>(role)];
ImU32 fill_color = ImGui::GetColorU32(ImVec4(color[0], color[1], color[2], 1.0));
draw_list->AddRectFilled(ImVec2(pos.x + 1.0f, pos.y + 1.0f), ImVec2(pos.x + ICON_BORDER_SIZE - 1.0f, pos.y + ICON_BORDER_SIZE - 1.0f), fill_color);
ImGui::SetCursorPosX(pos.x + ICON_BORDER_SIZE + GAP_ICON_TEXT);
ImGui::AlignTextToFramePadding();
imgui.text(Slic3r::I18N::translate(ExtrusionEntity::role_to_string(role)));
}
break;
}
case EViewType::Height:
{
add_range(m_extrusions.ranges.height, 3);
break;
}
case EViewType::Width:
{
add_range(m_extrusions.ranges.width, 3);
break;
}
case EViewType::Feedrate:
{
add_range(m_extrusions.ranges.feedrate, 1);
break;
}
case EViewType::FanSpeed: { break; }
case EViewType::VolumetricRate: { break; }
case EViewType::Tool: { break; }
case EViewType::ColorPrint: { break; }
}
imgui.end();
ImGui::PopStyleVar();
}
} // namespace GUI
} // namespace Slic3r

View file

@ -7,13 +7,17 @@
#include "3DScene.hpp"
#include "libslic3r/GCode/GCodeProcessor.hpp"
#include <float.h>
namespace Slic3r {
class Print;
namespace GUI {
class GCodeViewer
{
static const std::array<std::array<float, 4>, erCount> Default_Extrusion_Role_Colors;
static const std::array<std::array<float, 3>, erCount> Default_Extrusion_Role_Colors;
static const size_t Default_Range_Colors_Count = 10;
static const std::array<std::array<float, 3>, Default_Range_Colors_Count> Default_Range_Colors;
// buffer containing vertices data
struct VBuffer
@ -29,14 +33,20 @@ class GCodeViewer
static size_t vertex_size_bytes() { return vertex_size() * sizeof(float); }
};
// Used to identify different toolpath sub-types inside a IBuffer
struct Path
{
GCodeProcessor::EMoveType type{ GCodeProcessor::EMoveType::Noop };
ExtrusionRole role{ erNone };
unsigned int first{ 0 };
unsigned int last{ 0 };
float height{ 0.0f };
float width{ 0.0f };
float feedrate{ 0.0f };
bool matches(GCodeProcessor::EMoveType type, ExtrusionRole role) const { return this->type == type && this->role == role; }
bool matches(const GCodeProcessor::MoveVertex& move) const {
return type == move.type && role == move.extrusion_role && height == move.height && width == move.width && feedrate == move.feedrate;
}
};
// buffer containing indices data and shader for a specific toolpath type
@ -51,8 +61,7 @@ class GCodeViewer
void reset();
bool init_shader(const std::string& vertex_shader_src, const std::string& fragment_shader_src);
void add_path(GCodeProcessor::EMoveType type, ExtrusionRole role);
void add_path(const GCodeProcessor::MoveVertex& move);
};
struct Shells
@ -62,10 +71,57 @@ class GCodeViewer
Shader shader;
};
// helper to render extrusion paths
struct Extrusions
{
std::array<std::array<float, 4>, erCount> role_colors;
struct Range
{
float min;
float max;
Range() { reset(); }
void update_from(const float value)
{
min = std::min(min, value);
max = std::max(max, value);
}
void reset()
{
min = FLT_MAX;
max = -FLT_MAX;
}
float step_size() const { return (max - min) / (static_cast<float>(Default_Range_Colors_Count) - 1.0f); }
std::array<float, 3> get_color_at(float value, const std::array<std::array<float, 3>, Default_Range_Colors_Count>& colors) const;
};
struct Ranges
{
std::array<std::array<float, 3>, Default_Range_Colors_Count> colors;
// Color mapping by layer height.
Range height;
// Color mapping by extrusion width.
Range width;
// Color mapping by feedrate.
Range feedrate;
// // Color mapping by fan speed.
// Range fan_speed;
// // Color mapping by volumetric extrusion rate.
// Range volumetric_rate;
void reset() {
height.reset();
width.reset();
feedrate.reset();
}
};
std::array<std::array<float, 3>, erCount> role_colors;
unsigned int role_visibility_flags{ 0 };
Ranges ranges;
void reset_role_visibility_flags() {
role_visibility_flags = 0;
@ -75,6 +131,8 @@ class GCodeViewer
}
}
void reset_ranges() { ranges.reset(); }
static bool is_role_visible(unsigned int flags, ExtrusionRole role) {
return role < erCount && (flags & (1 << role)) != 0;
}
@ -97,12 +155,15 @@ public:
private:
VBuffer m_vertices;
std::vector<IBuffer> m_buffers{ static_cast<size_t>(GCodeProcessor::EMoveType::Extrude) };
BoundingBoxf3 m_bounding_box;
unsigned int m_last_result_id{ 0 };
std::vector<double> m_layers_zs;
std::vector<ExtrusionRole> m_roles;
Extrusions m_extrusions;
Shells m_shells;
EViewType m_view_type{ EViewType::FeatureType };
bool m_legend_enabled{ true };
public:
GCodeViewer() = default;
@ -110,13 +171,18 @@ public:
bool init() {
m_extrusions.role_colors = Default_Extrusion_Role_Colors;
m_extrusions.ranges.colors = Default_Range_Colors;
set_toolpath_move_type_visible(GCodeProcessor::EMoveType::Extrude, true);
return init_shaders();
}
void load(const GCodeProcessor::Result& gcode_result, const Print& print, bool initialized);
void refresh_toolpaths_ranges(const GCodeProcessor::Result& gcode_result);
void reset();
void render() const;
const BoundingBoxf3& get_bounding_box() const { return m_bounding_box; }
const std::vector<double>& get_layers_zs() const { return m_layers_zs; };
EViewType get_view_type() const { return m_view_type; }
@ -134,12 +200,16 @@ public:
bool are_shells_visible() const { return m_shells.visible; }
void set_shells_visible(bool visible) { m_shells.visible = visible; }
bool is_legend_enabled() const { return m_legend_enabled; }
void enable_legend(bool enable) { m_legend_enabled = enable; }
private:
bool init_shaders();
void load_toolpaths(const GCodeProcessor::Result& gcode_result);
void load_shells(const Print& print, bool initialized);
void render_toolpaths() const;
void render_shells() const;
void render_overlay() const;
};
} // namespace GUI

View file

@ -901,6 +901,7 @@ void GLCanvas3D::WarningTexture::msw_rescale(const GLCanvas3D& canvas)
generate(m_msg_text, canvas, true, m_is_colored_red);
}
#if !ENABLE_GCODE_VIEWER
const unsigned char GLCanvas3D::LegendTexture::Squares_Border_Color[3] = { 64, 64, 64 };
const unsigned char GLCanvas3D::LegendTexture::Default_Background_Color[3] = { (unsigned char)(DEFAULT_BG_LIGHT_COLOR[0] * 255.0f), (unsigned char)(DEFAULT_BG_LIGHT_COLOR[1] * 255.0f), (unsigned char)(DEFAULT_BG_LIGHT_COLOR[2] * 255.0f) };
const unsigned char GLCanvas3D::LegendTexture::Error_Background_Color[3] = { (unsigned char)(ERROR_BG_LIGHT_COLOR[0] * 255.0f), (unsigned char)(ERROR_BG_LIGHT_COLOR[1] * 255.0f), (unsigned char)(ERROR_BG_LIGHT_COLOR[2] * 255.0f) };
@ -1267,6 +1268,7 @@ void GLCanvas3D::LegendTexture::render(const GLCanvas3D& canvas) const
GLTexture::render_sub_texture(m_id, left, right, bottom, top, uvs);
}
}
#endif // !ENABLE_GCODE_VIEWER
void GLCanvas3D::Labels::render(const std::vector<const ModelInstance*>& sorted_instances) const
{
@ -1574,7 +1576,9 @@ GLCanvas3D::GLCanvas3D(wxGLCanvas* canvas, Bed3D& bed, Camera& camera, GLToolbar
, m_dirty(true)
, m_initialized(false)
, m_apply_zoom_to_volumes_filter(false)
#if !ENABLE_GCODE_VIEWER
, m_legend_texture_enabled(false)
#endif // !ENABLE_GCODE_VIEWER
, m_picking_enabled(false)
, m_moving_enabled(false)
, m_dynamic_background_enabled(false)
@ -1759,6 +1763,8 @@ void GLCanvas3D::toggle_sla_auxiliaries_visibility(bool visible, const ModelObje
m_render_sla_auxiliaries = visible;
for (GLVolume* vol : m_volumes.volumes) {
if (vol->composite_id.object_id == 1000)
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)
@ -1941,7 +1947,11 @@ void GLCanvas3D::enable_layers_editing(bool enable)
void GLCanvas3D::enable_legend_texture(bool enable)
{
#if ENABLE_GCODE_VIEWER
m_gcode_viewer.enable_legend(enable);
#else
m_legend_texture_enabled = enable;
#endif // ENABLE_GCODE_VIEWER
}
void GLCanvas3D::enable_picking(bool enable)
@ -2825,7 +2835,7 @@ static void load_gcode_retractions(const GCodePreviewData::Retraction& retractio
#endif // !ENABLE_GCODE_VIEWER
#if ENABLE_GCODE_VIEWER
void GLCanvas3D::load_gcode_preview_2(const GCodeProcessor::Result& gcode_result)
void GLCanvas3D::load_gcode_preview(const GCodeProcessor::Result& gcode_result)
{
#if ENABLE_GCODE_VIEWER_DEBUG_OUTPUT
static unsigned int last_result_id = 0;
@ -2841,9 +2851,13 @@ void GLCanvas3D::load_gcode_preview_2(const GCodeProcessor::Result& gcode_result
}
out.close();
}
m_gcode_viewer.load(gcode_result , *this->fff_print(), m_initialized);
#endif // ENABLE_GCODE_VIEWER_DEBUG_OUTPUT
m_gcode_viewer.load(gcode_result, *this->fff_print(), m_initialized);
}
void GLCanvas3D::refresh_toolpaths_ranges(const GCodeProcessor::Result& gcode_result)
{
m_gcode_viewer.refresh_toolpaths_ranges(gcode_result);
}
#endif // ENABLE_GCODE_VIEWER
@ -2950,6 +2964,7 @@ void GLCanvas3D::load_preview(const std::vector<std::string>& str_tool_colors, c
_update_toolpath_volumes_outside_state();
_show_warning_texture_if_needed(WarningTexture::ToolpathOutside);
#if !ENABLE_GCODE_VIEWER
if (color_print_values.empty())
reset_legend_texture();
else {
@ -2958,6 +2973,7 @@ void GLCanvas3D::load_preview(const std::vector<std::string>& str_tool_colors, c
const std::vector<float> tool_colors = _parse_colors(str_tool_colors);
_generate_legend_texture(preview_data, tool_colors);
}
#endif // !ENABLE_GCODE_VIEWER
}
void GLCanvas3D::bind_event_handlers()
@ -4077,6 +4093,7 @@ Vec2d GLCanvas3D::get_local_mouse_position() const
return Vec2d(factor * mouse_pos.x, factor * mouse_pos.y);
}
#if !ENABLE_GCODE_VIEWER
void GLCanvas3D::reset_legend_texture()
{
if (m_legend_texture.get_id() != 0)
@ -4085,6 +4102,7 @@ void GLCanvas3D::reset_legend_texture()
m_legend_texture.reset();
}
}
#endif // !ENABLE_GCODE_VIEWER
void GLCanvas3D::set_tooltip(const std::string& tooltip) const
{
@ -5213,6 +5231,12 @@ BoundingBoxf3 GLCanvas3D::_max_bounding_box(bool include_gizmos, bool include_be
#else
bb.merge(m_bed.get_bounding_box(include_bed_model));
#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
#if ENABLE_GCODE_VIEWER
if (!m_main_toolbar.is_enabled())
bb.merge(m_gcode_viewer.get_bounding_box());
#endif // ENABLE_GCODE_VIEWER
return bb;
}
@ -5547,7 +5571,9 @@ void GLCanvas3D::_render_overlays() const
_render_gizmos_overlay();
_render_warning_texture();
#if !ENABLE_GCODE_VIEWER
_render_legend_texture();
#endif // !ENABLE_GCODE_VIEWER
// main toolbar and undoredo toolbar need to be both updated before rendering because both their sizes are needed
// to correctly place them
@ -5591,6 +5617,7 @@ void GLCanvas3D::_render_warning_texture() const
m_warning_texture.render(*this);
}
#if !ENABLE_GCODE_VIEWER
void GLCanvas3D::_render_legend_texture() const
{
if (!m_legend_texture_enabled)
@ -5598,6 +5625,7 @@ void GLCanvas3D::_render_legend_texture() const
m_legend_texture.render(*this);
}
#endif // !ENABLE_GCODE_VIEWER
void GLCanvas3D::_render_volumes_for_picking() const
{
@ -7087,10 +7115,12 @@ std::vector<float> GLCanvas3D::_parse_colors(const std::vector<std::string>& col
return output;
}
#if !ENABLE_GCODE_VIEWER
void GLCanvas3D::_generate_legend_texture(const GCodePreviewData& preview_data, const std::vector<float>& tool_colors)
{
m_legend_texture.generate(preview_data, tool_colors, *this, true);
}
#endif // !ENABLE_GCODE_VIEWER
void GLCanvas3D::_set_warning_texture(WarningTexture::Warning warning, bool state)
{

View file

@ -345,6 +345,7 @@ private:
bool generate(const std::string& msg, const GLCanvas3D& canvas, bool compress, bool red_colored = false);
};
#if !ENABLE_GCODE_VIEWER
class LegendTexture : public GUI::GLTexture
{
static const int Px_Title_Offset = 5;
@ -371,6 +372,7 @@ private:
void render(const GLCanvas3D& canvas) const;
};
#endif // !ENABLE_GCODE_VIEWER
#if ENABLE_RENDER_STATISTICS
struct RenderStats
@ -445,7 +447,9 @@ private:
std::unique_ptr<RetinaHelper> m_retina_helper;
#endif
bool m_in_render;
#if !ENABLE_GCODE_VIEWER
LegendTexture m_legend_texture;
#endif // !ENABLE_GCODE_VIEWER
WarningTexture m_warning_texture;
wxTimer m_timer;
#if !ENABLE_NON_STATIC_CANVAS_MANAGER
@ -483,7 +487,9 @@ private:
bool m_initialized;
bool m_apply_zoom_to_volumes_filter;
mutable std::vector<int> m_hover_volume_idxs;
#if !ENABLE_GCODE_VIEWER
bool m_legend_texture_enabled;
#endif // !ENABLE_GCODE_VIEWER
bool m_picking_enabled;
bool m_moving_enabled;
bool m_dynamic_background_enabled;
@ -658,7 +664,8 @@ public:
void reload_scene(bool refresh_immediately, bool force_full_scene_refresh = false);
#if ENABLE_GCODE_VIEWER
void load_gcode_preview_2(const GCodeProcessor::Result& gcode_result);
void load_gcode_preview(const GCodeProcessor::Result& gcode_result);
void refresh_toolpaths_ranges(const GCodeProcessor::Result& gcode_result);
#else
void load_gcode_preview(const GCodePreviewData& preview_data, const std::vector<std::string>& str_tool_colors);
#endif // ENABLE_GCODE_VIEWER
@ -679,7 +686,9 @@ public:
Size get_canvas_size() const;
Vec2d get_local_mouse_position() const;
#if !ENABLE_GCODE_VIEWER
void reset_legend_texture();
#endif // !ENABLE_GCODE_VIEWER
void set_tooltip(const std::string& tooltip) const;
@ -790,7 +799,9 @@ private:
#endif // ENABLE_RENDER_SELECTION_CENTER
void _render_overlays() const;
void _render_warning_texture() const;
#if !ENABLE_GCODE_VIEWER
void _render_legend_texture() const;
#endif // !ENABLE_GCODE_VIEWER
void _render_volumes_for_picking() const;
void _render_current_gizmo() const;
void _render_gizmos_overlay() const;
@ -852,8 +863,10 @@ private:
void _update_sla_shells_outside_state();
void _show_warning_texture_if_needed(WarningTexture::Warning warning);
#if !ENABLE_GCODE_VIEWER
// generates the legend texture in dependence of the current shown view type
void _generate_legend_texture(const GCodePreviewData& preview_data, const std::vector<float>& tool_colors);
#endif // !ENABLE_GCODE_VIEWER
// generates a warning texture containing the given message
void _set_warning_texture(WarningTexture::Warning warning, bool state);

View file

@ -479,8 +479,9 @@ void Preview::reload_print(bool keep_volumes)
m_canvas->reset_volumes();
#if ENABLE_GCODE_VIEWER
m_canvas->reset_gcode_toolpaths();
#endif // ENABLE_GCODE_VIEWER
#else
m_canvas->reset_legend_texture();
#endif // ENABLE_GCODE_VIEWER
m_loaded = false;
#ifdef __linux__
m_volumes_cleanup_required = false;
@ -937,7 +938,9 @@ void Preview::load_print_as_fff(bool keep_z_range)
if (! has_layers)
{
reset_sliders(true);
#if !ENABLE_GCODE_VIEWER
m_canvas->reset_legend_texture();
#endif // !ENABLE_GCODE_VIEWER
m_canvas_widget->Refresh();
return;
}
@ -981,7 +984,8 @@ void Preview::load_print_as_fff(bool keep_z_range)
if (gcode_preview_data_valid) {
// Load the real G-code preview.
#if ENABLE_GCODE_VIEWER
m_canvas->load_gcode_preview_2(*m_gcode_result);
m_canvas->load_gcode_preview(*m_gcode_result);
m_canvas->refresh_toolpaths_ranges(*m_gcode_result);
#else
m_canvas->load_gcode_preview(*m_gcode_preview_data, colors);
#endif // ENABLE_GCODE_VIEWER

View file

@ -101,10 +101,14 @@ void GLGizmoFdmSupports::render_triangles(const Selection& selection) const
glsafe(::glPushMatrix());
glsafe(::glMultMatrixd(trafo_matrix.data()));
glsafe(::glColor4f(0.2f, 0.2f, 1.0f, 0.5f));
m_ivas[mesh_id][0].render();
glsafe(::glColor4f(1.f, 0.2f, 0.2f, 0.5f));
m_ivas[mesh_id][1].render();
// Now render both enforcers and blockers.
for (int i=0; i<2; ++i) {
if (m_ivas[mesh_id][i].has_VBOs()) {
glsafe(::glColor4f(i ? 1.f : 0.2f, 0.2f, i ? 0.2f : 1.0f, 0.5f));
m_ivas[mesh_id][i].render();
}
}
glsafe(::glPopMatrix());
}
}
@ -448,7 +452,8 @@ void GLGizmoFdmSupports::update_vertex_buffers(const ModelVolume* mv,
iva.push_triangle(3*triangle_cnt, 3*triangle_cnt+1, 3*triangle_cnt+2);
++triangle_cnt;
}
iva.finalize_geometry(true);
if (! m_selected_facets[mesh_id].empty())
iva.finalize_geometry(true);
}
}