Added class GCodeViewer -> basic render of gcode toolpaths using dedicated shaders

This commit is contained in:
enricoturri1966 2020-04-14 10:02:08 +02:00
parent 4df141815b
commit c3eb65c461
18 changed files with 652 additions and 13 deletions

View file

@ -0,0 +1,45 @@
#version 110
#define INTENSITY_AMBIENT 0.3
#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.0, 0.0, 1.0);
#define LIGHT_FRONT_DIFFUSE (0.3 * INTENSITY_CORRECTION)
uniform vec4 uniform_color;
varying vec3 eye_position;
varying vec3 eye_normal;
//varying float world_normal_z;
// x = tainted, y = specular;
vec2 intensity;
void main()
{
vec3 normal = normalize(eye_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;
intensity.y = LIGHT_TOP_SPECULAR * pow(max(dot(-normalize(eye_position), 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;
// // darkens fragments whose normal points downward
// 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);
}

View file

@ -0,0 +1,15 @@
#version 110
varying vec3 eye_position;
varying vec3 eye_normal;
//// world z component of the normal used to darken the lower side of the toolpaths
//varying float world_normal_z;
void main()
{
eye_position = (gl_ModelViewMatrix * gl_Vertex).xyz;
eye_normal = gl_NormalMatrix * vec3(0.0, 0.0, 1.0);
// eye_normal = gl_NormalMatrix * gl_Normal;
// world_normal_z = gl_Normal.z;
gl_Position = ftransform();
}

View file

@ -0,0 +1,45 @@
#version 110
#define INTENSITY_AMBIENT 0.3
#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.0, 0.0, 1.0);
#define LIGHT_FRONT_DIFFUSE (0.3 * INTENSITY_CORRECTION)
uniform vec4 uniform_color;
varying vec3 eye_position;
varying vec3 eye_normal;
//varying float world_normal_z;
// x = tainted, y = specular;
vec2 intensity;
void main()
{
vec3 normal = normalize(eye_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;
intensity.y = LIGHT_TOP_SPECULAR * pow(max(dot(-normalize(eye_position), 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;
// // darkens fragments whose normal points downward
// 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);
}

View file

@ -0,0 +1,15 @@
#version 110
varying vec3 eye_position;
varying vec3 eye_normal;
//// world z component of the normal used to darken the lower side of the toolpaths
//varying float world_normal_z;
void main()
{
eye_position = (gl_ModelViewMatrix * gl_Vertex).xyz;
eye_normal = gl_NormalMatrix * vec3(0.0, 0.0, 1.0);
// eye_normal = gl_NormalMatrix * gl_Normal;
// world_normal_z = gl_Normal.z;
gl_Position = ftransform();
}

View file

@ -0,0 +1,45 @@
#version 110
#define INTENSITY_AMBIENT 0.3
#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.0, 0.0, 1.0);
#define LIGHT_FRONT_DIFFUSE (0.3 * INTENSITY_CORRECTION)
uniform vec4 uniform_color;
varying vec3 eye_position;
varying vec3 eye_normal;
//varying float world_normal_z;
// x = tainted, y = specular;
vec2 intensity;
void main()
{
vec3 normal = normalize(eye_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;
intensity.y = LIGHT_TOP_SPECULAR * pow(max(dot(-normalize(eye_position), 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;
// // darkens fragments whose normal points downward
// 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);
}

View file

@ -0,0 +1,15 @@
#version 110
varying vec3 eye_position;
varying vec3 eye_normal;
//// world z component of the normal used to darken the lower side of the toolpaths
//varying float world_normal_z;
void main()
{
eye_position = (gl_ModelViewMatrix * gl_Vertex).xyz;
eye_normal = gl_NormalMatrix * vec3(0.0, 0.0, 1.0);
// eye_normal = gl_NormalMatrix * gl_Normal;
// world_normal_z = gl_Normal.z;
gl_Position = ftransform();
}

View file

@ -0,0 +1,45 @@
#version 110
#define INTENSITY_AMBIENT 0.3
#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.0, 0.0, 1.0);
#define LIGHT_FRONT_DIFFUSE (0.3 * INTENSITY_CORRECTION)
uniform vec4 uniform_color;
varying vec3 eye_position;
varying vec3 eye_normal;
//varying float world_normal_z;
// x = tainted, y = specular;
vec2 intensity;
void main()
{
vec3 normal = normalize(eye_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;
intensity.y = LIGHT_TOP_SPECULAR * pow(max(dot(-normalize(eye_position), 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;
// // darkens fragments whose normal points downward
// 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);
}

View file

@ -0,0 +1,15 @@
#version 110
varying vec3 eye_position;
varying vec3 eye_normal;
//// world z component of the normal used to darken the lower side of the toolpaths
//varying float world_normal_z;
void main()
{
eye_position = (gl_ModelViewMatrix * gl_Vertex).xyz;
eye_normal = gl_NormalMatrix * vec3(0.0, 0.0, 1.0);
// eye_normal = gl_NormalMatrix * gl_Normal;
// world_normal_z = gl_Normal.z;
gl_Position = ftransform();
}

View file

@ -0,0 +1,45 @@
#version 110
#define INTENSITY_AMBIENT 0.3
#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.0, 0.0, 1.0);
#define LIGHT_FRONT_DIFFUSE (0.3 * INTENSITY_CORRECTION)
uniform vec4 uniform_color;
varying vec3 eye_position;
varying vec3 eye_normal;
//varying float world_normal_z;
// x = tainted, y = specular;
vec2 intensity;
void main()
{
vec3 normal = normalize(eye_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;
intensity.y = LIGHT_TOP_SPECULAR * pow(max(dot(-normalize(eye_position), 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;
// // darkens fragments whose normal points downward
// 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);
}

View file

@ -0,0 +1,15 @@
#version 110
varying vec3 eye_position;
varying vec3 eye_normal;
//// world z component of the normal used to darken the lower side of the toolpaths
//varying float world_normal_z;
void main()
{
eye_position = (gl_ModelViewMatrix * gl_Vertex).xyz;
eye_normal = gl_NormalMatrix * vec3(0.0, 0.0, 1.0);
// eye_normal = gl_NormalMatrix * gl_Normal;
// world_normal_z = gl_Normal.z;
gl_Position = ftransform();
}

View file

@ -38,6 +38,8 @@ void GCodeProcessor::CpColor::reset()
current = 0;
}
unsigned int GCodeProcessor::Result::id = 0;
void GCodeProcessor::apply_config(const PrintConfig& config)
{
m_parser.apply_config(config);

View file

@ -39,17 +39,6 @@ namespace Slic3r {
Relative
};
enum class EMoveType : unsigned char
{
Noop,
Retract,
Unretract,
Tool_change,
Travel,
Extrude,
Num_Types
};
struct CachedPosition
{
AxisCoords position; // mm
@ -67,6 +56,17 @@ namespace Slic3r {
};
public:
enum class EMoveType : unsigned char
{
Noop,
Retract,
Unretract,
Tool_change,
Travel,
Extrude,
Count
};
struct MoveVertex
{
EMoveType type{ EMoveType::Noop };
@ -98,8 +98,9 @@ namespace Slic3r {
struct Result
{
static unsigned int id;
std::vector<MoveVertex> moves;
void reset() { moves = std::vector<MoveVertex>(); }
void reset() { ++id; moves = std::vector<MoveVertex>(); }
};
private:

View file

@ -56,6 +56,8 @@ set(SLIC3R_GUI_SOURCES
GUI/GLTexture.cpp
GUI/GLToolbar.hpp
GUI/GLToolbar.cpp
GUI/GCodeViewer.hpp
GUI/GCodeViewer.cpp
GUI/Preferences.cpp
GUI/Preferences.hpp
GUI/Preset.cpp

View file

@ -0,0 +1,242 @@
#include "libslic3r/libslic3r.h"
#include "GCodeViewer.hpp"
#include "3DScene.hpp"
#if ENABLE_GCODE_VIEWER
#include <GL/glew.h>
#include <boost/log/trivial.hpp>
#include <array>
namespace Slic3r {
namespace GUI {
static unsigned char buffer_id(GCodeProcessor::EMoveType type) {
return static_cast<unsigned char>(type) - static_cast<unsigned char>(GCodeProcessor::EMoveType::Retract);
}
static GCodeProcessor::EMoveType buffer_type(unsigned char id) {
return static_cast<GCodeProcessor::EMoveType>(static_cast<unsigned char>(GCodeProcessor::EMoveType::Retract) + id);
}
void GCodeViewer::generate(const GCodeProcessor::Result& gcode_result)
{
if (m_last_result_id == gcode_result.id)
return;
m_last_result_id = gcode_result.id;
// release gpu memory, if used
reset_buffers();
// convert data
size_t vertices_count = gcode_result.moves.size();
for (size_t i = 0; i < vertices_count; ++i)
{
// skip first vertex
if (i == 0)
continue;
const GCodeProcessor::MoveVertex& prev = gcode_result.moves[i - 1];
const GCodeProcessor::MoveVertex& curr = gcode_result.moves[i];
Buffer& buffer = m_buffers[buffer_id(curr.type)];
switch (curr.type)
{
case GCodeProcessor::EMoveType::Tool_change:
case GCodeProcessor::EMoveType::Retract:
case GCodeProcessor::EMoveType::Unretract:
{
for (int j = 0; j < 3; ++j)
{
buffer.data.insert(buffer.data.end(), curr.position[j]);
}
break;
}
case GCodeProcessor::EMoveType::Extrude:
case GCodeProcessor::EMoveType::Travel:
{
for (int j = 0; j < 3; ++j)
{
buffer.data.insert(buffer.data.end(), prev.position[j]);
}
for (int j = 0; j < 3; ++j)
{
buffer.data.insert(buffer.data.end(), curr.position[j]);
}
break;
}
default:
{
continue;
}
}
}
// send data to gpu
for (Buffer& buffer : m_buffers)
{
glsafe(::glGenBuffers(1, &buffer.vbo_id));
glsafe(::glBindBuffer(GL_ARRAY_BUFFER, buffer.vbo_id));
glsafe(::glBufferData(GL_ARRAY_BUFFER, buffer.data.size() * sizeof(float), buffer.data.data(), GL_STATIC_DRAW));
glsafe(::glBindBuffer(GL_ARRAY_BUFFER, 0));
}
}
void GCodeViewer::render() const
{
auto set_color = [](GLint current_program_id, const std::array<float, 4>& 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()));
return;
}
}
BOOST_LOG_TRIVIAL(error) << "Unable to find uniform_color uniform";
};
unsigned char begin_id = buffer_id(GCodeProcessor::EMoveType::Retract);
unsigned char end_id = buffer_id(GCodeProcessor::EMoveType::Count);
glsafe(::glEnable(GL_DEPTH_TEST));
for (unsigned char i = begin_id; i < end_id; ++i)
{
const Buffer& buffer = m_buffers[i];
if (buffer.vbo_id == 0)
continue;
const Shader& shader = m_shaders[i];
if (shader.is_initialized())
{
shader.start_using();
GLint current_program_id;
glsafe(::glGetIntegerv(GL_CURRENT_PROGRAM, &current_program_id));
GCodeProcessor::EMoveType type = buffer_type(i);
glsafe(::glBindBuffer(GL_ARRAY_BUFFER, buffer.vbo_id));
glsafe(::glVertexPointer(3, GL_FLOAT, Buffer::stride(type), (const void*)0));
glsafe(::glEnableClientState(GL_VERTEX_ARRAY));
switch (type)
{
case GCodeProcessor::EMoveType::Tool_change:
case GCodeProcessor::EMoveType::Retract:
case GCodeProcessor::EMoveType::Unretract:
{
std::array<float, 4> color = { 0.0f, 1.0f, 0.0f, 1.0f };
set_color(current_program_id, color);
glsafe(::glDrawArrays(GL_POINTS, 0, (GLsizei)buffer.data.size() / Buffer::record_size(type)));
break;
}
case GCodeProcessor::EMoveType::Extrude:
{
std::array<float, 4> color = { 1.0f, 0.0f, 0.0f, 1.0f };
set_color(current_program_id, color);
glsafe(::glDrawArrays(GL_LINES, 0, (GLsizei)buffer.data.size() / Buffer::record_size(type)));
break;
}
case GCodeProcessor::EMoveType::Travel:
{
std::array<float, 4> color = { 1.0f, 1.0f, 0.0f, 1.0f };
set_color(current_program_id, color);
glsafe(::glDrawArrays(GL_LINES, 0, (GLsizei)buffer.data.size() / Buffer::record_size(type)));
break;
}
default:
{
break;
}
}
glsafe(::glDisableClientState(GL_VERTEX_ARRAY));
glsafe(::glBindBuffer(GL_ARRAY_BUFFER, 0));
shader.stop_using();
}
}
}
bool GCodeViewer::init_shaders()
{
unsigned char begin_id = buffer_id(GCodeProcessor::EMoveType::Retract);
unsigned char end_id = buffer_id(GCodeProcessor::EMoveType::Count);
for (unsigned char i = begin_id; i < end_id; ++i)
{
Shader& shader = m_shaders[i];
std::string vertex_shader_src;
std::string fragment_shader_src;
GCodeProcessor::EMoveType type = buffer_type(i);
switch (type)
{
case GCodeProcessor::EMoveType::Tool_change:
{
vertex_shader_src = "toolchanges.vs";
fragment_shader_src = "toolchanges.fs";
break;
}
case GCodeProcessor::EMoveType::Retract:
{
vertex_shader_src = "retractions.vs";
fragment_shader_src = "retractions.fs";
break;
}
case GCodeProcessor::EMoveType::Unretract:
{
vertex_shader_src = "unretractions.vs";
fragment_shader_src = "unretractions.fs";
break;
}
case GCodeProcessor::EMoveType::Extrude:
{
vertex_shader_src = "extrusions.vs";
fragment_shader_src = "extrusions.fs";
break;
}
case GCodeProcessor::EMoveType::Travel:
{
vertex_shader_src = "travels.vs";
fragment_shader_src = "travels.fs";
break;
}
default:
{
break;
}
}
if (!shader.init(vertex_shader_src, fragment_shader_src))
{
BOOST_LOG_TRIVIAL(error) << "Unable to initialize toolpaths shader: please, check that the files " << vertex_shader_src << " and " << fragment_shader_src << " are available";
return false;
}
}
return true;
}
void GCodeViewer::reset_buffers()
{
for (Buffer& buffer : m_buffers)
{
// release gpu memory
if (buffer.vbo_id > 0)
glsafe(::glDeleteBuffers(1, &buffer.vbo_id));
// release cpu memory
buffer.data = std::vector<float>();
}
}
} // namespace GUI
} // namespace Slic3r
#endif // ENABLE_GCODE_VIEWER

View file

@ -0,0 +1,63 @@
#ifndef slic3r_GCodeViewer_hpp_
#define slic3r_GCodeViewer_hpp_
#if ENABLE_GCODE_VIEWER
#include "GLShader.hpp"
#include "libslic3r/GCode/GCodeProcessor.hpp"
#include <vector>
namespace Slic3r {
namespace GUI {
class GCodeViewer
{
struct Buffer
{
unsigned int vbo_id{ 0 };
std::vector<float> data;
static size_t stride(GCodeProcessor::EMoveType type)
{
return 3 * sizeof(float);
}
static size_t record_size(GCodeProcessor::EMoveType type)
{
switch (type)
{
case GCodeProcessor::EMoveType::Tool_change:
case GCodeProcessor::EMoveType::Retract:
case GCodeProcessor::EMoveType::Unretract: { return 3; }
case GCodeProcessor::EMoveType::Extrude:
case GCodeProcessor::EMoveType::Travel: { return 6; }
default: { return 0; }
}
}
};
std::vector<Buffer> m_buffers{ static_cast<size_t>(GCodeProcessor::EMoveType::Extrude) };
std::vector<Shader> m_shaders{ static_cast<size_t>(GCodeProcessor::EMoveType::Extrude) };
unsigned int m_last_result_id{ 0 };
public:
GCodeViewer() = default;
~GCodeViewer() { reset_buffers(); }
bool init() { return init_shaders(); }
void generate(const GCodeProcessor::Result& gcode_result);
void render() const;
private:
bool init_shaders();
void reset_buffers();
};
} // namespace GUI
} // namespace Slic3r
#endif // ENABLE_GCODE_VIEWER
#endif // slic3r_GCodeViewer_hpp_

View file

@ -1678,6 +1678,14 @@ bool GLCanvas3D::init()
return false;
}
#if ENABLE_GCODE_VIEWER
if (!m_main_toolbar.is_enabled())
{
if (!m_gcode_viewer.init())
return false;
}
#endif // ENABLE_GCODE_VIEWER
// 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);
@ -2109,6 +2117,9 @@ void GLCanvas3D::render()
_render_background();
_render_objects();
#if ENABLE_GCODE_VIEWER
_render_gcode();
#endif // ENABLE_GCODE_VIEWER
_render_sla_slices();
_render_selection();
#if ENABLE_NON_STATIC_CANVAS_MANAGER
@ -2783,6 +2794,8 @@ void GLCanvas3D::load_gcode_preview_2(const GCodeProcessor::Result& gcode_result
out << v.to_string() << "\n";
}
out.close();
m_gcode_viewer.generate(gcode_result);
#endif // ENABLE_GCODE_VIEWER_DEBUG_OUTPUT
}
#endif // ENABLE_GCODE_VIEWER
@ -5440,6 +5453,13 @@ void GLCanvas3D::_render_objects() const
m_camera_clipping_plane = ClippingPlane::ClipsNothing();
}
#if ENABLE_GCODE_VIEWER
void GLCanvas3D::_render_gcode() const
{
m_gcode_viewer.render();
}
#endif // ENABLE_GCODE_VIEWER
void GLCanvas3D::_render_selection() const
{
float scale_factor = 1.0;

View file

@ -21,6 +21,7 @@
#endif // !ENABLE_NON_STATIC_CANVAS_MANAGER
#if ENABLE_GCODE_VIEWER
#include "libslic3r/GCode/GCodeProcessor.hpp"
#include "GCodeViewer.hpp"
#endif // ENABLE_GCODE_VIEWER
#include <float.h>
@ -468,6 +469,10 @@ private:
bool m_extra_frame_requested;
mutable GLVolumeCollection m_volumes;
#if ENABLE_GCODE_VIEWER
GCodeViewer m_gcode_viewer;
#endif // ENABLE_GCODE_VIEWER
Selection m_selection;
const DynamicPrintConfig* m_config;
Model* m_model;
@ -764,6 +769,9 @@ private:
void _render_background() const;
void _render_bed(float theta, bool show_axes) const;
void _render_objects() const;
#if ENABLE_GCODE_VIEWER
void _render_gcode() const;
#endif // ENABLE_GCODE_VIEWER
void _render_selection() const;
#if ENABLE_RENDER_SELECTION_CENTER
void _render_selection_center() const;

View file

@ -946,9 +946,10 @@ void Preview::load_print_as_fff(bool keep_z_range)
m_canvas->set_selected_extruder(0);
if (gcode_preview_data_valid) {
// Load the real G-code preview.
m_canvas->load_gcode_preview(*m_gcode_preview_data, colors);
#if ENABLE_GCODE_VIEWER
m_canvas->load_gcode_preview_2(*m_gcode_result);
#else
m_canvas->load_gcode_preview(*m_gcode_preview_data, colors);
#endif // ENABLE_GCODE_VIEWER
m_loaded = true;
} else {