Port libvgcode from PrusaSlicer 2.8.0

Includes (but is not limited to) the following commits:

SPE-2218 - libvgcode - Fixed color of wipe moves for speed range view
SPE-2218 - libvgcode - Fixed detection of fan speed range
SPE-2218 - libvgcode - Fixed detection of temperature range
SPE-2218 - libvgcode - Fixed colors for Actual volumetric flow rate view
SPE-2214 - Fixed detection of toolpaths bounding box in GCodeViewer
SPE-2206 - Modified LibBGCode.cmake to get latest version of libbgcode which fixed parsing of gcode lines G4
libvgcode - Fixed potential out of bound access in ViewerImpl::update_view_full_range()
Tech ENABLE_GL_CORE_PROFILE set as default
Tech ENABLE_OPENGL_ES replaced by build option SLIC3R_OPENGL_ES
libvgcode - Precompiler definition of ENABLE_OPENGL_ES moved into CMakeLists.txt
Added missing include
libvgcode - Textures setup modified to work when building using emscripten
libvgcode - small optimization
libvgcode - fixed OpenGLWrapper::unload_opengl()
libvgcode - CMakeLists.txt modified to work with emscripten
libvgcode - Replace 'glVertexAttribIPointer()' with 'glVertexAttribPointer()' in SegmentTemplate::init() for OpenGL ES
libvgcode - Replace 'xor' with '^' Bitset.hpp
libvgcode - Newer glad library for OpenGL 4.6 and OpenGL ES 3.0
libvgcode - Alternate fix in method ViewerImpl::update_heights_widths() for OpenGL ES
libvgcode - Fixes in glAssertRecentCallImpl()
libvgcode - Fixes in method ViewerImpl::update_heights_widths() for OpenGL ES
Fixed ES shaders so they work with OpenGL ES 3.0
libvgcode - Use multiple plain textures in place of texture buffers for OpenGL ES
libvgcode - Use plain textures in place of texture buffers for OpenGL ES (partial implementation using one texture per buffer)
libvgcode - refactoring of class OpenGLWrapper
libvgcode - small refactoring in shaders
libvgcode - replacement of glMapBuffer() call for OpenGL ES
Fixed warning
libvgcode - Changes into CMakeLists.txt
Fixed debug export of gcode data to be configuration indipendent
Disabled tech ENABLE_NEW_GCODE_VIEWER_DEBUG
Removed obsolete tech ENABLE_GCODE_VIEWER_DATA_CHECKING
Code cleanup and techs removal - completed
Code cleanup and techs removal - step 1
SPE-1872: Implemented G2/G3 lines discretization for gcfMarlinFirmware firmware flavour
SPE-1872: Corrections into GCodeProcessor::process_G2_G3() to match firmware code
SPE-1872: Actual speed profile - Further enhancements of imgui debug window
SPE-1872: Actual speed profile - Rework in its calculation + enhanced imgui debug window
SPE-1872: New imgui widget to show actual speed profile
SPE-1872: Fixed actual speed for seam moves and at extrusion/travel/wipe start
SPE-1872: Fixed rendering of wipe moves when actual speed view is selected
SPE-1872: Actual speed profile extended to travel and wipe moves
SPE-1872: Fixes in function recalculate_trapezoids() and method GCodeProcessor::TimeMachine::calculate_time() to smooth actual speed profile
SPE-1872: Added debug graphic to show move actual speed profile
SPE-1872: libvgcode library: replace volumetric flow rate data with mm3_per_mm to reduce memory usage
SPE-1872: Added visualization of actual volumetric flow rate
SPE-1872: Fixes in calculating actual speed
SPE-1872: Added visualization of actual speed in gcode preview
SPE-2124: Added command line option 'opengl-aa' to allow the user to turn on the automatic selection of max number of supported samples for OpenGL antialising
#12117: Reduced moire patterns by using the highest number of samples available for multisampling
New gcode visualization integration - Partially enabled imgui debug window
New gcode visualization integration - Fixed center of gravity calculation and rendering
New gcode visualization library - Interface for estimated times
New gcode visualization library - Tool marker rendering
New gcode visualization library - Axes aligned bounding boxes calculation
Removed obsolete debug code
New gcode visualization library - Added statistic of used memory
New gcode visualization library - Separation of tool colors and color changes colors to simplify client code
Added missing include
New gcode visualization library - Added print color changes detection
New gcode visualization library - Modified OpenGL ES context detection
New gcode visualization library - Another makefile cleanup
New gcode visualization library - Makefiles cleanup
New gcode visualization library - Added suppression of error 'This function or variable may be unsafe' in VS2022
New gcode visualization library - Compatibility with OpenGL ES
New gcode visualization library - Interface cleanup and documentation
New gcode visualization library - Extended interface to give access to estimated times
New gcode visualization integration - Toggling of top layer only view state
New gcode visualization integration - Removed imperial units from tool position data
Small refactoring
New gcode visualization library - Custom values for travel and wipe moves radius
New gcode visualization library - Allow customization of range colors
New gcode visualization library - Partial update of interface comments/documentation
New gcode visualization integration - Follow-up of 35ee55e29bb231fd01a2eb71ae293832a37ca65d - Better fix for toolpaths visible range when toggling options' visibility
New gcode visualization integration - Fixed toolpaths reset
New gcode visualization library - Fixed method set_option_color()
New gcode visualization library - Fixed method ViewerImpl::set_extrusion_role_color()
New gcode visualization library - Added methods to release gpu resources on demand.
New gcode visualization library - Travel and wipe moves as options
New gcode visualization integration - Fixed toolpaths visible range when toggling options' visibility
New gcode visualization integration - Fixed management of gcode preview view type
New gcode visualization - Fixed wrong include
New gcode visualization - Added missing headers
New gcode visualization - Refactoring + added missing headers
New gcode visualization - New code set as standalone library + embed glad library to load OpenGL functions
New gcode visualization - Fixed errors and warnings when building the new code as a standalone library
New gcode visualization integration - Fixed layers ordering in pre-gcode preview
New gcode visualization integration - Fixed objects' tool colors in pre-gcode preview
Code cleanup
New gcode visualization integration - Tool position properties data window
New gcode visualization integration - Fixed in export toolpaths to obj
New gcode visualization - Inlining in source code
Refactoring
New gcode visualization integration - Export toolpaths to obj
Some refactoring and warning fix
New gcode visualization integration - Customizable travel moves colors
New gcode visualization integration - Customizable options colors
New gcode visualization integration - Customizable extrusion roles colors
New gcode visualization integration - Fixed pre-gcode preview layers times
New gcode visualization integration - Modify pre-gcode preview to use the new toolpaths renderer, objects WIP
New gcode visualization - Modify pre-gcode preview to use the new toolpaths renderer, WIP (brim/skirt/wipe tower)
New gcode visualization integration - Do not reset visible range when toggling options/roles visibility
New gcode visualization - Fixed color of first vertex of top layer (when top layer only option is enabled)
New gcode visualization - Customizable travels and wipes segment radius
New gcode visualization integration - Removed tech ENABLE_GCODE_VIEWER_STATISTICS
New gcode visualization integration - Added check of OpenGL version
New gcode visualization integration - Removed GCodeProcessorResult::spiral_vase_layers
Another bunch of warnings fixes
Fixed warnings
New gcode visualization integration - Removal of old visualization
Fixed includes
New gcode visualization integration - File structure of new code separated in api + src
New gcode visualization integration - View ranges management moved to new visualizer
New gcode visualization integration - Fixed top layer only visualization for MMU printers
New gcode visualization integration - Removed dependency on imgui from new visualizer
Some refactoring
New gcode visualization integration - Removed dependency on Slic3r::GCodeProcessorResult from new visualizer
New gcode visualization integration - Moves' data conversion moved to client side
New gcode visualization: layers times refactoring
A bunch of fixes for the new gcode visualization
New gcode visualization: render in gray color layers containing pause print or custom gcode options when in Color Print view
New gcode visualization integration - Tool colors
New gcode visualization integration - Layers times
New gcode visualization integration - Travels and Extrusion roles times
Fixed detection of start/end of contiguous extrusion paths
New gcode visualization integration - Extrusion roles
New gcode visualization integration - Colors
New gcode visualization integration - Tool position
Center of gravity and tool marker may both be rendered with fixed screen size and a scaling factor
Fixed rendering of options in new gcode visualization
Tool marker NOT rendered by the new visualization code
Center of gravity marker NOT rendered by the new visualization code
Fixed toolpaths_cog shaders
Tool position window for new gcode visualization
Top layer only coloring for neww gcode visualization
Refactoring in preview's new visualization
Hidden imgui debug dialog for new visualization in preview
Synchronization of moves between old and new visualization
Fixed missing gcode window in new visualization
Rendering of debug imgui dialog moved from class libvgcode::Viewer to class libvgcode::Toolpaths + warnings fixing
Some functionality moved from class libvgcode::Viewer to class libvgcode::Toolpaths
Some refactoring and cleanup
Refatoring of PathVertex and Toolpaths::load()
SPE-1982: Tech ENABLE_NEW_GCODE_VIEWER - 1st installment of new toolpaths rendering code (WIP)
This commit is contained in:
Andrew Sun
2025-09-15 03:17:10 -04:00
parent c59255a605
commit c92328c9cc
105 changed files with 18929 additions and 5354 deletions

View File

@@ -153,6 +153,8 @@ namespace ImGui
// const wchar_t CustomSupportsMarker = 0x1D;
// const wchar_t CustomSeamMarker = 0x1E;
// const wchar_t MmuSegmentationMarker = 0x1F;
const wchar_t HorizontalHide = 0xB1;
const wchar_t HorizontalShow = 0xB2;
// Do not forget use following letters only in wstring
//BBS use 08xx to avoid unicode character which may be used

View File

@@ -0,0 +1,46 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Generator: Adobe Illustrator 24.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg
version="1.0"
id="Layer_1"
x="0px"
y="0px"
viewBox="0 0 16 16"
enable-background="new 0 0 16 16"
xml:space="preserve"
sodipodi:docname="hide_horizontal.svg"
inkscape:version="1.1 (c68e22c387, 2021-05-23)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg"><defs
id="defs945">
</defs><sodipodi:namedview
id="namedview943"
pagecolor="#505050"
bordercolor="#eeeeee"
borderopacity="1"
inkscape:pageshadow="0"
inkscape:pageopacity="0"
inkscape:pagecheckerboard="0"
showgrid="false"
inkscape:zoom="50.75"
inkscape:cx="7.9901478"
inkscape:cy="8.0098522"
inkscape:window-width="1920"
inkscape:window-height="1001"
inkscape:window-x="3191"
inkscape:window-y="-9"
inkscape:window-maximized="1"
inkscape:current-layer="Layer_1" />
<polygon
fill="#ed6b21"
points="1,8 1,11 8,16 15,11 15,8 "
style="stroke:none;stroke-width:1"
id="polygon937"
transform="translate(0,-4)" />
</svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@@ -0,0 +1,46 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Generator: Adobe Illustrator 24.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg
version="1.0"
id="Layer_1"
x="0px"
y="0px"
viewBox="0 0 16 16"
enable-background="new 0 0 16 16"
xml:space="preserve"
sodipodi:docname="show_horizontal.svg"
inkscape:version="1.1 (c68e22c387, 2021-05-23)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg"><defs
id="defs1127">
</defs><sodipodi:namedview
id="namedview1125"
pagecolor="#505050"
bordercolor="#eeeeee"
borderopacity="1"
inkscape:pageshadow="0"
inkscape:pageopacity="0"
inkscape:pagecheckerboard="0"
showgrid="false"
inkscape:zoom="50.75"
inkscape:cx="7.9901478"
inkscape:cy="8.0098522"
inkscape:window-width="1920"
inkscape:window-height="1001"
inkscape:window-x="3191"
inkscape:window-y="-9"
inkscape:window-maximized="1"
inkscape:current-layer="Layer_1" />
<polygon
fill="#ed6b21"
points="15,7 15,5 8,0 1,5 1,7 1,8 15,8 "
style="stroke:none;stroke-width:1"
id="polygon1119"
transform="translate(0,4)" />
</svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@@ -5,7 +5,9 @@ uniform vec4 bottom_color;
in vec2 tex_coord;
out vec4 out_color;
void main()
{
gl_FragColor = mix(bottom_color, top_color, tex_coord.y);
out_color = mix(bottom_color, top_color, tex_coord.y);
}

View File

@@ -0,0 +1,34 @@
#version 150
// see as reference: https://github.com/mhalber/Lines/blob/master/geometry_shader_lines.h
// https://stackoverflow.com/questions/52928678/dashed-line-in-opengl3
const float aa_radius = 0.5;
uniform float dash_size;
uniform float gap_size;
uniform vec4 uniform_color;
in float line_width;
// x = v tex coord, y = s coord
in vec2 seg_params;
out vec4 out_color;
void main()
{
float inv_stride = 1.0 / (dash_size + gap_size);
if (gap_size > 0.0 && fract(seg_params.y * inv_stride) > dash_size * inv_stride)
discard;
// We render a quad that is fattened by r, giving total width of the line to be w+r. We want smoothing to happen
// around w, so that the edge is properly smoothed out. As such, in the smoothstep function we have:
// Far edge : 1.0 = (w+r) / (w+r)
// Close edge : 1.0 - (2r / (w+r)) = (w+r)/(w+r) - 2r/(w+r)) = (w-r) / (w+r)
// This way the smoothing is centered around 'w'.
out_color = uniform_color;
float inv_line_width = 1.0 / line_width;
float aa = 1.0 - smoothstep(1.0 - (2.0 * aa_radius * inv_line_width), 1.0, abs(seg_params.x * inv_line_width));
out_color.a *= aa;
}

View File

@@ -0,0 +1,50 @@
#version 150
// see as reference: https://github.com/mhalber/Lines/blob/master/geometry_shader_lines.h
// https://stackoverflow.com/questions/52928678/dashed-line-in-opengl3
layout(lines) in;
layout(triangle_strip, max_vertices = 4) out;
const float aa_radius = 0.5;
uniform vec2 viewport_size;
uniform float width;
in float coord_s[];
out float line_width;
// x = v tex coord, y = s coord
out vec2 seg_params;
void main()
{
vec2 ndc_0 = gl_in[0].gl_Position.xy / gl_in[0].gl_Position.w;
vec2 ndc_1 = gl_in[1].gl_Position.xy / gl_in[1].gl_Position.w;
vec2 dir = normalize((ndc_1 - ndc_0) * viewport_size);
vec2 normal_dir = vec2(-dir.y, dir.x);
line_width = max(1.0, width) + 2.0 * aa_radius;
float half_line_width = 0.5 * line_width;
vec2 normal = vec2(line_width / viewport_size[0], line_width / viewport_size[1]) * normal_dir;
seg_params = vec2(-half_line_width, coord_s[0]);
gl_Position = vec4((ndc_0 + normal) * gl_in[0].gl_Position.w, gl_in[0].gl_Position.zw);
EmitVertex();
seg_params = vec2(-half_line_width, coord_s[0]);
gl_Position = vec4((ndc_0 - normal) * gl_in[0].gl_Position.w, gl_in[0].gl_Position.zw);
EmitVertex();
seg_params = vec2(half_line_width, coord_s[1]);
gl_Position = vec4((ndc_1 + normal) * gl_in[1].gl_Position.w, gl_in[1].gl_Position.zw);
EmitVertex();
seg_params = vec2(half_line_width, coord_s[1]);
gl_Position = vec4((ndc_1 - normal) * gl_in[1].gl_Position.w, gl_in[1].gl_Position.zw);
EmitVertex();
EndPrimitive();
}

View File

@@ -0,0 +1,18 @@
#version 150
// see as reference: https://github.com/mhalber/Lines/blob/master/geometry_shader_lines.h
// https://stackoverflow.com/questions/52928678/dashed-line-in-opengl3
uniform mat4 view_model_matrix;
uniform mat4 projection_matrix;
// v_position.w = coordinate along the line
in vec4 v_position;
out float coord_s;
void main()
{
coord_s = v_position.w;
gl_Position = projection_matrix * view_model_matrix * vec4(v_position.xyz, 1.0);
}

View File

@@ -2,7 +2,9 @@
uniform vec4 uniform_color;
out vec4 out_color;
void main()
{
gl_FragColor = uniform_color;
out_color = uniform_color;
}

View File

@@ -4,7 +4,9 @@ uniform sampler2D uniform_texture;
in vec2 tex_coord;
out vec4 out_color;
void main()
{
gl_FragColor = texture(uniform_texture, tex_coord);
out_color = texture(uniform_texture, tex_coord);
}

View File

@@ -6,7 +6,9 @@ uniform float emission_factor;
// x = tainted, y = specular;
in vec2 intensity;
out vec4 out_color;
void main()
{
gl_FragColor = vec4(vec3(intensity.y) + uniform_color.rgb * (intensity.x + emission_factor), uniform_color.a);
out_color = vec4(vec3(intensity.y) + uniform_color.rgb * (intensity.x + emission_factor), uniform_color.a);
}

View File

@@ -6,7 +6,9 @@ uniform float emission_factor;
// x = tainted, y = specular;
in vec2 intensity;
out vec4 out_color;
void main()
{
gl_FragColor = vec4(vec3(intensity.y) + uniform_color.rgb * (intensity.x + emission_factor), uniform_color.a);
out_color = vec4(vec3(intensity.y) + uniform_color.rgb * (intensity.x + emission_factor), uniform_color.a);
}

View File

@@ -5,7 +5,9 @@ uniform sampler2D Texture;
in vec2 Frag_UV;
in vec4 Frag_Color;
out vec4 out_color;
void main()
{
gl_FragColor = Frag_Color * texture(Texture, Frag_UV.st);
out_color = Frag_Color * texture(Texture, Frag_UV.st);
}

View File

@@ -2,7 +2,9 @@
uniform vec4 uniform_color;
out vec4 out_color;
void main()
{
gl_FragColor = uniform_color;
out_color = uniform_color;
}

View File

@@ -9,13 +9,15 @@ in vec2 intensity;
//varying float drop;
in vec4 world_pos;
out vec4 out_color;
void main()
{
if (world_pos.z < 0.0)
discard;
if(ban_light){
gl_FragColor = uniform_color;
out_color = uniform_color;
} else{
gl_FragColor = vec4(vec3(intensity.y) + uniform_color.rgb * (intensity.x + emission_factor), uniform_color.a);
out_color = vec4(vec3(intensity.y) + uniform_color.rgb * (intensity.x + emission_factor), uniform_color.a);
}
}

View File

@@ -15,6 +15,8 @@ in vec2 intensity;
in float object_z;
out vec4 out_color;
void main()
{
float object_z_row = z_to_texture_row * object_z;
@@ -37,5 +39,5 @@ void main()
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);
out_color = vec4(vec3(intensity.y), 1.0) + intensity.x * mix(color, vec4(1.0, 1.0, 0.0, 1.0), z_blend);
}

View File

@@ -13,6 +13,7 @@ add_subdirectory(libslic3r)
if (SLIC3R_GUI)
# imgui, imguizmo, and hidapi are now included from deps_src
add_subdirectory(libvgcode)
if(WIN32)
message(STATUS "WXWIN environment set to: $ENV{WXWIN}")

View File

@@ -348,7 +348,7 @@ bool BuildVolume::all_paths_inside(const GCodeProcessorResult& paths, const Boun
const Vec2f c = unscaled<float>(m_circle.center);
const float r = unscaled<double>(m_circle.radius) + epsilon;
const float r2 = sqr(r);
return m_max_print_height == 0.0 ?
return m_max_print_height == 0.0 ?
std::all_of(paths.moves.begin(), paths.moves.end(), [move_valid, c, r2](const GCodeProcessorResult::MoveVertex &move)
{ return ! move_valid(move) || (to_2d(move.position) - c).squaredNorm() <= r2; }) :
std::all_of(paths.moves.begin(), paths.moves.end(), [move_valid, c, r2, z = m_max_print_height + epsilon](const GCodeProcessorResult::MoveVertex& move)
@@ -379,40 +379,6 @@ inline bool all_inside_vertices_normals_interleaved(const std::vector<float> &pa
return true;
}
bool BuildVolume::all_paths_inside_vertices_and_normals_interleaved(const std::vector<float>& paths, const Eigen::AlignedBox<float, 3>& paths_bbox, bool ignore_bottom) const
{
assert(paths.size() % 6 == 0);
static constexpr const double epsilon = BedEpsilon;
switch (m_type) {
case BuildVolume_Type::Rectangle:
{
BoundingBox3Base<Vec3d> build_volume = this->bounding_volume().inflated(epsilon);
if (m_max_print_height == 0.0)
build_volume.max.z() = std::numeric_limits<double>::max();
if (ignore_bottom)
build_volume.min.z() = -std::numeric_limits<double>::max();
return build_volume.contains(paths_bbox.min().cast<double>()) && build_volume.contains(paths_bbox.max().cast<double>());
}
case BuildVolume_Type::Circle:
{
const Vec2f c = unscaled<float>(m_circle.center);
const float r = unscaled<double>(m_circle.radius) + float(epsilon);
const float r2 = sqr(r);
return m_max_print_height == 0.0 ?
all_inside_vertices_normals_interleaved(paths, [c, r2](Vec3f p) { return (to_2d(p) - c).squaredNorm() <= r2; }) :
all_inside_vertices_normals_interleaved(paths, [c, r2, z = m_max_print_height + epsilon](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 m_max_print_height == 0.0 ?
all_inside_vertices_normals_interleaved(paths, [this](Vec3f p) { return Geometry::inside_convex_polygon(m_top_bottom_convex_hull_decomposition_bed, to_2d(p).cast<double>()); }) :
all_inside_vertices_normals_interleaved(paths, [this, z = m_max_print_height + epsilon](Vec3f p) { return Geometry::inside_convex_polygon(m_top_bottom_convex_hull_decomposition_bed, to_2d(p).cast<double>()) && p.z() <= z; });
default:
return true;
}
}
std::string_view BuildVolume::type_name(BuildVolume_Type type)
{
using namespace std::literals;

View File

@@ -91,8 +91,6 @@ public:
// Called on final G-code paths.
//FIXME The test does not take the thickness of the extrudates into account!
bool all_paths_inside(const GCodeProcessorResult& paths, const BoundingBoxf3& paths_bbox, bool ignore_bottom = true) const;
// 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<float>& paths, const Eigen::AlignedBox<float, 3>& bbox, bool ignore_bottom = true) const;
const std::pair<std::vector<Vec2d>, std::vector<Vec2d>>& top_bottom_convex_hull_decomposition_scene() const { return m_top_bottom_convex_hull_decomposition_scene; }
const std::pair<std::vector<Vec2d>, std::vector<Vec2d>>& top_bottom_convex_hull_decomposition_bed() const { return m_top_bottom_convex_hull_decomposition_bed; }

View File

@@ -1840,9 +1840,6 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato
m_max_layer_z = 0.f;
m_last_width = 0.f;
m_is_role_based_fan_on.fill(false);
#if ENABLE_GCODE_VIEWER_DATA_CHECKING
m_last_mm3_per_mm = 0.;
#endif // ENABLE_GCODE_VIEWER_DATA_CHECKING
m_fan_mover.release();
@@ -5558,14 +5555,6 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description,
gcode += buf;
}
#if ENABLE_GCODE_VIEWER_DATA_CHECKING
if (last_was_wipe_tower || (m_last_mm3_per_mm != path.mm3_per_mm)) {
m_last_mm3_per_mm = path.mm3_per_mm;
sprintf(buf, ";%s%f\n", GCodeProcessor::Mm3_Per_Mm_Tag.c_str(), m_last_mm3_per_mm);
gcode += buf;
}
#endif // ENABLE_GCODE_VIEWER_DATA_CHECKING
if (last_was_wipe_tower || std::abs(m_last_height - path.height) > EPSILON) {
m_last_height = path.height;
sprintf(buf, ";%s%g\n", GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Height).c_str(), m_last_height);

View File

@@ -544,9 +544,6 @@ private:
float m_last_layer_z{ 0.0f };
float m_max_layer_z{ 0.0f };
float m_last_width{ 0.0f };
#if ENABLE_GCODE_VIEWER_DATA_CHECKING
double m_last_mm3_per_mm;
#endif // ENABLE_GCODE_VIEWER_DATA_CHECKING
// Always check gcode placeholders when building in debug mode.
#if !defined(NDEBUG)

View File

@@ -106,10 +106,6 @@ const float GCodeProcessor::Wipe_Height = 0.05f;
bool GCodeProcessor::s_IsBBLPrinter = true;
#if ENABLE_GCODE_VIEWER_DATA_CHECKING
const std::string GCodeProcessor::Mm3_Per_Mm_Tag = "MM3_PER_MM:";
#endif // ENABLE_GCODE_VIEWER_DATA_CHECKING
static void set_option_value(ConfigOptionFloats& option, size_t id, float value)
{
if (id < option.values.size())
@@ -135,7 +131,7 @@ static float intersection_distance(float initial_rate, float final_rate, float a
static float speed_from_distance(float initial_feedrate, float distance, float acceleration)
{
// to avoid invalid negative numbers due to numerical errors
float value = std::max(0.0f, sqr(initial_feedrate) + 2.0f * acceleration * distance);
const float value = std::max(0.0f, sqr(initial_feedrate) + 2.0f * acceleration * distance);
return ::sqrt(value);
}
@@ -144,7 +140,7 @@ static float speed_from_distance(float initial_feedrate, float distance, float a
static float max_allowable_speed(float acceleration, float target_velocity, float distance)
{
// to avoid invalid negative numbers due to numerical errors
float value = std::max(0.0f, sqr(target_velocity) - 2.0f * acceleration * distance);
const float value = std::max(0.0f, sqr(target_velocity) - 2.0f * acceleration * distance);
return std::sqrt(value);
}
@@ -167,30 +163,18 @@ void GCodeProcessor::CpColor::reset()
float GCodeProcessor::Trapezoid::acceleration_time(float entry_feedrate, float acceleration) const
{
return acceleration_time_from_distance(entry_feedrate, accelerate_until, acceleration);
}
float GCodeProcessor::Trapezoid::cruise_time() const
{
return (cruise_feedrate != 0.0f) ? cruise_distance() / cruise_feedrate : 0.0f;
return acceleration_time_from_distance(entry_feedrate, acceleration_distance(), acceleration);
}
float GCodeProcessor::Trapezoid::deceleration_time(float distance, float acceleration) const
{
return acceleration_time_from_distance(cruise_feedrate, (distance - decelerate_after), -acceleration);
}
float GCodeProcessor::Trapezoid::cruise_distance() const
{
return decelerate_after - accelerate_until;
return acceleration_time_from_distance(cruise_feedrate, deceleration_distance(distance), -acceleration);
}
void GCodeProcessor::TimeBlock::calculate_trapezoid()
{
trapezoid.cruise_feedrate = feedrate_profile.cruise;
float accelerate_distance = std::max(0.0f, estimated_acceleration_distance(feedrate_profile.entry, feedrate_profile.cruise, acceleration));
float decelerate_distance = std::max(0.0f, estimated_acceleration_distance(feedrate_profile.cruise, feedrate_profile.exit, -acceleration));
const float decelerate_distance = std::max(0.0f, estimated_acceleration_distance(feedrate_profile.cruise, feedrate_profile.exit, -acceleration));
float cruise_distance = distance - accelerate_distance - decelerate_distance;
// Not enough space to reach the nominal feedrate.
@@ -201,18 +185,13 @@ void GCodeProcessor::TimeBlock::calculate_trapezoid()
cruise_distance = 0.0f;
trapezoid.cruise_feedrate = speed_from_distance(feedrate_profile.entry, accelerate_distance, acceleration);
}
else
trapezoid.cruise_feedrate = feedrate_profile.cruise;
trapezoid.accelerate_until = accelerate_distance;
trapezoid.decelerate_after = accelerate_distance + cruise_distance;
}
float GCodeProcessor::TimeBlock::time() const
{
return trapezoid.acceleration_time(feedrate_profile.entry, acceleration)
+ trapezoid.cruise_time()
+ trapezoid.deceleration_time(distance, acceleration);
}
void GCodeProcessor::TimeMachine::State::reset()
{
feedrate = 0.0f;
@@ -248,53 +227,60 @@ void GCodeProcessor::TimeMachine::reset()
gcode_time.reset();
blocks = std::vector<TimeBlock>();
g1_times_cache = std::vector<G1LinesCacheItem>();
std::fill(moves_time.begin(), moves_time.end(), 0.0f);
std::fill(roles_time.begin(), roles_time.end(), 0.0f);
layers_time = std::vector<float>();
first_layer_time = 0.0f;
prepare_time = 0.0f;
}
void GCodeProcessor::TimeMachine::simulate_st_synchronize(float additional_time)
static void planner_forward_pass_kernel(const GCodeProcessor::TimeBlock& prev, GCodeProcessor::TimeBlock& curr)
{
if (!enabled)
return;
calculate_time(0, additional_time);
}
static void planner_forward_pass_kernel(GCodeProcessor::TimeBlock& prev, GCodeProcessor::TimeBlock& curr)
{
// If the previous block is an acceleration block, but it is not long enough to complete the
// full speed change within the block, we need to adjust the entry speed accordingly. Entry
// speeds have already been reset, maximized, and reverse planned by reverse planner.
// If nominal length is true, max junction speed is guaranteed to be reached. No need to recheck.
if (!prev.flags.nominal_length) {
if (prev.feedrate_profile.entry < curr.feedrate_profile.entry) {
float entry_speed = std::min(curr.feedrate_profile.entry, max_allowable_speed(-prev.acceleration, prev.feedrate_profile.entry, prev.distance));
// Check for junction speed change
if (curr.feedrate_profile.entry != entry_speed) {
curr.feedrate_profile.entry = entry_speed;
curr.flags.recalculate = true;
}
//
// C:\prusa\firmware\Prusa-Firmware-Buddy\lib\Marlin\Marlin\src\module\planner.cpp
// Line 954
//
// If the previous block is an acceleration block, too short to complete the full speed
// change, adjust the entry speed accordingly. Entry speeds have already been reset,
// maximized, and reverse-planned. If nominal length is set, max junction speed is
// guaranteed to be reached. No need to recheck.
if (!prev.flags.nominal_length && prev.feedrate_profile.entry < curr.feedrate_profile.entry) {
// Compute the maximum allowable speed
const float new_entry_speed = max_allowable_speed(-prev.acceleration, prev.feedrate_profile.entry, prev.distance);
// If true, current block is full-acceleration and we can move the planned pointer forward.
if (new_entry_speed < curr.feedrate_profile.entry) {
// Always <= max_entry_speed_sqr. Backward pass sets this.
curr.feedrate_profile.entry = new_entry_speed;
curr.flags.recalculate = true;
}
}
}
void planner_reverse_pass_kernel(GCodeProcessor::TimeBlock& curr, GCodeProcessor::TimeBlock& next)
static void planner_reverse_pass_kernel(GCodeProcessor::TimeBlock& curr, const GCodeProcessor::TimeBlock& next)
{
// If entry speed is already at the maximum entry speed, no need to recheck. Block is cruising.
// If not, block in state of acceleration or deceleration. Reset entry speed to maximum and
// check for maximum allowable speed reductions to ensure maximum possible planned speed.
if (curr.feedrate_profile.entry != curr.max_entry_speed) {
// If nominal length true, max junction speed is guaranteed to be reached. Only compute
// for max allowable speed if block is decelerating and nominal length is false.
if (!curr.flags.nominal_length && curr.max_entry_speed > next.feedrate_profile.entry)
curr.feedrate_profile.entry = std::min(curr.max_entry_speed, max_allowable_speed(-curr.acceleration, next.feedrate_profile.entry, curr.distance));
else
curr.feedrate_profile.entry = curr.max_entry_speed;
curr.flags.recalculate = true;
//
// C:\prusa\firmware\Prusa-Firmware-Buddy\lib\Marlin\Marlin\src\module\planner.cpp
// Line 857
//
// If entry speed is already at the maximum entry speed, and there was no change of speed
// in the next block, there is no need to recheck. Block is cruising and there is no need to
// compute anything for this block,
// If not, block entry speed needs to be recalculated to ensure maximum possible planned speed.
const float max_entry_speed = curr.max_entry_speed;
// Compute maximum entry speed decelerating over the current block from its exit speed.
// If not at the maximum entry speed, or the previous block entry speed changed
if (curr.feedrate_profile.entry != max_entry_speed || next.flags.recalculate) {
// If nominal length true, max junction speed is guaranteed to be reached.
// If a block can de/ac-celerate from nominal speed to zero within the length of the block, then
// the current block and next block junction speeds are guaranteed to always be at their maximum
// junction speeds in deceleration and acceleration, respectively. This is due to how the current
// block nominal speed limits both the current and next maximum junction speeds. Hence, in both
// the reverse and forward planners, the corresponding block junction speed will always be at the
// the maximum junction speed and may always be ignored for any speed reduction checks.
const float new_entry_speed = curr.flags.nominal_length ? max_entry_speed :
std::min(max_entry_speed, max_allowable_speed(-curr.acceleration, next.feedrate_profile.entry, curr.distance));
if (curr.feedrate_profile.entry != new_entry_speed) {
// Just Set the new entry speed.
curr.feedrate_profile.entry = new_entry_speed;
curr.flags.recalculate = true;
}
}
}
@@ -304,7 +290,7 @@ static void recalculate_trapezoids(std::vector<GCodeProcessor::TimeBlock>& block
GCodeProcessor::TimeBlock* next = nullptr;
for (size_t i = 0; i < blocks.size(); ++i) {
GCodeProcessor::TimeBlock& b = blocks[i];
GCodeProcessor::TimeBlock& b = blocks[i];
curr = next;
next = &b;
@@ -313,10 +299,8 @@ static void recalculate_trapezoids(std::vector<GCodeProcessor::TimeBlock>& block
// Recalculate if current block entry or exit junction speed has changed.
if (curr->flags.recalculate || next->flags.recalculate) {
// NOTE: Entry and exit factors always > 0 by all previous logic operations.
GCodeProcessor::TimeBlock block = *curr;
block.feedrate_profile.exit = next->feedrate_profile.entry;
block.calculate_trapezoid();
curr->trapezoid = block.trapezoid;
curr->feedrate_profile.exit = next->feedrate_profile.entry;
curr->calculate_trapezoid();
curr->flags.recalculate = false; // Reset current only to ensure next trapezoid is computed
}
}
@@ -324,15 +308,13 @@ static void recalculate_trapezoids(std::vector<GCodeProcessor::TimeBlock>& block
// Last/newest block in buffer. Always recalculated.
if (next != nullptr) {
GCodeProcessor::TimeBlock block = *next;
block.feedrate_profile.exit = next->safe_feedrate;
block.calculate_trapezoid();
next->trapezoid = block.trapezoid;
next->feedrate_profile.exit = next->safe_feedrate;
next->calculate_trapezoid();
next->flags.recalculate = false;
}
}
void GCodeProcessor::TimeMachine::calculate_time(size_t keep_last_n_blocks, float additional_time)
void GCodeProcessor::TimeMachine::calculate_time(GCodeProcessorResult& result, PrintEstimatedStatistics::ETimeMode mode, size_t keep_last_n_blocks, float additional_time)
{
if (!enabled || blocks.size() < 2)
return;
@@ -345,12 +327,13 @@ void GCodeProcessor::TimeMachine::calculate_time(size_t keep_last_n_blocks, floa
}
// reverse_pass
for (int i = static_cast<int>(blocks.size()) - 1; i > 0; --i)
for (int i = static_cast<int>(blocks.size()) - 1; i > 0; --i) {
planner_reverse_pass_kernel(blocks[i - 1], blocks[i]);
}
recalculate_trapezoids(blocks);
size_t n_blocks_process = blocks.size() - keep_last_n_blocks;
const size_t n_blocks_process = blocks.size() - keep_last_n_blocks;
for (size_t i = 0; i < n_blocks_process; ++i) {
const TimeBlock& block = blocks[i];
float block_time = block.time();
@@ -358,22 +341,102 @@ void GCodeProcessor::TimeMachine::calculate_time(size_t keep_last_n_blocks, floa
block_time += additional_time;
time += block_time;
result.moves[block.move_id].time[static_cast<size_t>(mode)] = block_time;
gcode_time.cache += block_time;
//BBS: don't calculate travel of start gcode into travel time
if (!block.flags.prepare_stage || block.move_type != EMoveType::Travel)
moves_time[static_cast<size_t>(block.move_type)] += block_time;
roles_time[static_cast<size_t>(block.role)] += block_time;
if (block.layer_id >= layers_time.size()) {
const size_t curr_size = layers_time.size();
layers_time.resize(block.layer_id);
for (size_t i = curr_size; i < layers_time.size(); ++i) {
layers_time[i] = 0.0f;
}
}
layers_time[block.layer_id - 1] += block_time;
//BBS
if (block.flags.prepare_stage)
prepare_time += block_time;
if (block.layer_id == 1)
first_layer_time += block_time;
// detect actual speed moves required to render toolpaths using actual speed
if (mode == PrintEstimatedStatistics::ETimeMode::Normal) {
GCodeProcessorResult::MoveVertex& curr_move = result.moves[block.move_id];
if (curr_move.type != EMoveType::Extrude &&
curr_move.type != EMoveType::Travel &&
curr_move.type != EMoveType::Wipe)
continue;
assert(curr_move.actual_feedrate == 0.0f);
GCodeProcessorResult::MoveVertex& prev_move = result.moves[block.move_id - 1];
const bool interpolate = (prev_move.type == curr_move.type);
if (!interpolate &&
prev_move.type != EMoveType::Extrude &&
prev_move.type != EMoveType::Travel &&
prev_move.type != EMoveType::Wipe)
prev_move.actual_feedrate = block.feedrate_profile.entry;
if (EPSILON < block.trapezoid.accelerate_until && block.trapezoid.accelerate_until < block.distance - EPSILON) {
const float t = block.trapezoid.accelerate_until / block.distance;
const Vec3f position = lerp(prev_move.position, curr_move.position, t);
if ((position - prev_move.position).norm() > EPSILON &&
(position - curr_move.position).norm() > EPSILON) {
const float delta_extruder = interpolate ? lerp(prev_move.delta_extruder, curr_move.delta_extruder, t) : curr_move.delta_extruder;
const float feedrate = interpolate ? lerp(prev_move.feedrate, curr_move.feedrate, t) : curr_move.feedrate;
const float width = interpolate ? lerp(prev_move.width, curr_move.width, t) : curr_move.width;
const float height = interpolate ? lerp(prev_move.height, curr_move.height, t) : curr_move.height;
const float mm3_per_mm = interpolate ? lerp(prev_move.mm3_per_mm, curr_move.mm3_per_mm, t) : curr_move.mm3_per_mm;
const float fan_speed = interpolate ? lerp(prev_move.fan_speed, curr_move.fan_speed, t) : curr_move.fan_speed;
const float temperature = interpolate ? lerp(prev_move.temperature, curr_move.temperature, t) : curr_move.temperature;
actual_speed_moves.push_back({
block.move_id,
position,
block.trapezoid.cruise_feedrate,
delta_extruder,
feedrate,
width,
height,
mm3_per_mm,
fan_speed,
temperature
});
}
}
const bool has_deceleration = block.trapezoid.deceleration_distance(block.distance) > EPSILON;
if (has_deceleration && block.trapezoid.decelerate_after > block.trapezoid.accelerate_until + EPSILON) {
const float t = block.trapezoid.decelerate_after / block.distance;
const Vec3f position = lerp(prev_move.position, curr_move.position, t);
if ((position - prev_move.position).norm() > EPSILON &&
(position - curr_move.position).norm() > EPSILON) {
const float delta_extruder = interpolate ? lerp(prev_move.delta_extruder, curr_move.delta_extruder, t) : curr_move.delta_extruder;
const float feedrate = interpolate ? lerp(prev_move.feedrate, curr_move.feedrate, t) : curr_move.feedrate;
const float width = interpolate ? lerp(prev_move.width, curr_move.width, t) : curr_move.width;
const float height = interpolate ? lerp(prev_move.height, curr_move.height, t) : curr_move.height;
const float mm3_per_mm = interpolate ? lerp(prev_move.mm3_per_mm, curr_move.mm3_per_mm, t) : curr_move.mm3_per_mm;
const float fan_speed = interpolate ? lerp(prev_move.fan_speed, curr_move.fan_speed, t) : curr_move.fan_speed;
const float temperature = interpolate ? lerp(prev_move.temperature, curr_move.temperature, t) : curr_move.temperature;
actual_speed_moves.push_back({
block.move_id,
position,
block.trapezoid.cruise_feedrate,
delta_extruder,
feedrate,
width,
height,
mm3_per_mm,
fan_speed,
temperature
});
}
}
const bool is_cruise_only = block.trapezoid.is_cruise_only(block.distance);
actual_speed_moves.push_back({
block.move_id,
std::nullopt,
(is_cruise_only || !has_deceleration) ? block.trapezoid.cruise_feedrate : block.feedrate_profile.exit,
std::nullopt,
std::nullopt,
std::nullopt,
std::nullopt,
std::nullopt,
std::nullopt,
std::nullopt
});
}
g1_times_cache.push_back({ block.g1_line_id, block.remaining_internal_g1_lines, time });
// update times for remaining time to printer stop placeholders
auto it_stop_time = std::lower_bound(stop_times.begin(), stop_times.end(), block.g1_line_id,
@@ -551,34 +614,6 @@ void GCodeProcessor::UsedFilaments::process_caches(GCodeProcessor* processor)
process_total_volume_cache(processor);
}
#if ENABLE_GCODE_VIEWER_STATISTICS
void GCodeProcessorResult::reset() {
//BBS: add mutex for protection of gcode result
lock();
moves = std::vector<GCodeProcessorResult::MoveVertex>();
printable_area = Pointfs();
//BBS: add bed exclude area
bed_exclude_area = Pointfs();
//BBS: add toolpath_outside
toolpath_outside = false;
//BBS: add label_object_enabled
label_object_enabled = false;
timelapse_warning_code = 0;
printable_height = 0.0f;
settings_ids.reset();
extruders_count = 0;
extruder_colors = std::vector<std::string>();
filament_diameters = std::vector<float>(MIN_EXTRUDERS_COUNT, DEFAULT_FILAMENT_DIAMETER);
filament_densities = std::vector<float>(MIN_EXTRUDERS_COUNT, DEFAULT_FILAMENT_DENSITY);
custom_gcode_per_print_z = std::vector<CustomGCode::Item>();
spiral_vase_layers = std::vector<std::pair<float, std::pair<size_t, size_t>>>();
time = 0;
//BBS: add mutex for protection of gcode result
unlock();
}
#else
void GCodeProcessorResult::reset() {
//BBS: add mutex for protection of gcode result
lock();
@@ -604,7 +639,7 @@ void GCodeProcessorResult::reset() {
filament_densities = std::vector<float>(MIN_EXTRUDERS_COUNT, DEFAULT_FILAMENT_DENSITY);
filament_costs = std::vector<float>(MIN_EXTRUDERS_COUNT, DEFAULT_FILAMENT_COST);
custom_gcode_per_print_z = std::vector<CustomGCode::Item>();
spiral_vase_layers = std::vector<std::pair<float, std::pair<size_t, size_t>>>();
spiral_vase_mode = false; // TODO???
bed_match_result = BedMatchResult(true);
warnings.clear();
@@ -613,7 +648,6 @@ void GCodeProcessorResult::reset() {
//BBS: add logs
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(" %1%: this=%2% reset finished")%__LINE__%this;
}
#endif // ENABLE_GCODE_VIEWER_STATISTICS
const std::vector<std::pair<GCodeProcessor::EProducer, std::string>> GCodeProcessor::Producers = {
//BBS: OrcaSlicer is also "bambu". Otherwise the time estimation didn't work.
@@ -794,6 +828,7 @@ void GCodeProcessor::apply_config(const PrintConfig& config)
const ConfigOptionBool* spiral_vase = config.option<ConfigOptionBool>("spiral_mode");
if (spiral_vase != nullptr)
m_detect_layer_based_on_tag = spiral_vase->value;
// TODO: m_result.spiral_vase_mode = spiral_vase->value;
const ConfigOptionBool* has_scarf_joint_seam = config.option<ConfigOptionBool>("has_scarf_joint_seam");
if (has_scarf_joint_seam != nullptr)
@@ -1101,6 +1136,7 @@ void GCodeProcessor::apply_config(const DynamicPrintConfig& config)
const ConfigOptionBool* spiral_vase = config.option<ConfigOptionBool>("spiral_mode");
if (spiral_vase != nullptr)
m_detect_layer_based_on_tag = spiral_vase->value;
// TODO: m_result.spiral_vase_mode = spiral_vase->value;
const ConfigOptionBool* has_scarf_joint_seam = config.option<ConfigOptionBool>("has_scarf_joint_seam");
if (has_scarf_joint_seam != nullptr)
@@ -1192,12 +1228,6 @@ void GCodeProcessor::reset()
m_seams_count = 0;
m_preheat_time = 0.f;
m_preheat_steps = 1;
#if ENABLE_GCODE_VIEWER_DATA_CHECKING
m_mm3_per_mm_compare.reset();
m_height_compare.reset();
m_width_compare.reset();
#endif // ENABLE_GCODE_VIEWER_DATA_CHECKING
}
static inline const char* skip_whitespaces(const char *begin, const char *end) {
@@ -1216,10 +1246,6 @@ void GCodeProcessor::process_file(const std::string& filename, std::function<voi
{
CNumericLocalesSetter locales_setter;
#if ENABLE_GCODE_VIEWER_STATISTICS
m_start_time = std::chrono::high_resolution_clock::now();
#endif // ENABLE_GCODE_VIEWER_STATISTICS
// pre-processing
// parse the gcode file to detect its producer
{
@@ -1283,10 +1309,6 @@ void GCodeProcessor::initialize(const std::string& filename)
{
assert(is_decimal_separator_point());
#if ENABLE_GCODE_VIEWER_STATISTICS
m_start_time = std::chrono::high_resolution_clock::now();
#endif // ENABLE_GCODE_VIEWER_STATISTICS
// process gcode
m_result.filename = filename;
m_result.id = ++s_result_id;
@@ -1312,11 +1334,12 @@ void GCodeProcessor::finalize(bool post_process)
}
}
calculate_time(m_result);
// process the time blocks
for (size_t i = 0; i < static_cast<size_t>(PrintEstimatedStatistics::ETimeMode::Count); ++i) {
TimeMachine& machine = m_time_processor.machines[i];
TimeMachine::CustomGCodeTime& gcode_time = machine.gcode_time;
machine.calculate_time();
if (gcode_time.needed && gcode_time.cache != 0.0f)
gcode_time.times.push_back({ CustomGCode::ColorChange, gcode_time.cache });
}
@@ -1324,31 +1347,23 @@ void GCodeProcessor::finalize(bool post_process)
m_used_filaments.process_caches(this);
update_estimated_times_stats();
auto time_mode = m_result.print_statistics.modes[static_cast<size_t>(PrintEstimatedStatistics::ETimeMode::Normal)];
// TODO
// auto time_mode = m_result.print_statistics.modes[static_cast<size_t>(PrintEstimatedStatistics::ETimeMode::Normal)];
//
// auto it = std::find_if(time_mode.roles_times.begin(), time_mode.roles_times.end(), [](const std::pair<ExtrusionRole, float>& item) { return erCustom == item.first; });
// auto prepare_time = (it != time_mode.roles_times.end()) ? it->second : 0.0f;
//
// //update times for results
// for (size_t i = 0; i < m_result.moves.size(); i++) {
// //field layer_duration contains the layer id for the move in which the layer_duration has to be set.
// size_t layer_id = size_t(m_result.moves[i].layer_duration);
// std::vector<float>& layer_times = m_result.print_statistics.modes[static_cast<size_t>(PrintEstimatedStatistics::ETimeMode::Normal)].layers_times;
// if (layer_times.size() > layer_id - 1 && layer_id > 0)
// m_result.moves[i].layer_duration = layer_id == 1 ? std::max(0.f,layer_times[layer_id - 1] - prepare_time) : layer_times[layer_id - 1];
// else
// m_result.moves[i].layer_duration = 0;
// }
auto it = std::find_if(time_mode.roles_times.begin(), time_mode.roles_times.end(), [](const std::pair<ExtrusionRole, float>& item) { return erCustom == item.first; });
auto prepare_time = (it != time_mode.roles_times.end()) ? it->second : 0.0f;
//update times for results
for (size_t i = 0; i < m_result.moves.size(); i++) {
//field layer_duration contains the layer id for the move in which the layer_duration has to be set.
size_t layer_id = size_t(m_result.moves[i].layer_duration);
std::vector<float>& layer_times = m_result.print_statistics.modes[static_cast<size_t>(PrintEstimatedStatistics::ETimeMode::Normal)].layers_times;
if (layer_times.size() > layer_id - 1 && layer_id > 0)
m_result.moves[i].layer_duration = layer_id == 1 ? std::max(0.f,layer_times[layer_id - 1] - prepare_time) : layer_times[layer_id - 1];
else
m_result.moves[i].layer_duration = 0;
}
#if ENABLE_GCODE_VIEWER_DATA_CHECKING
std::cout << "\n";
m_mm3_per_mm_compare.output();
m_height_compare.output();
m_width_compare.output();
#endif // ENABLE_GCODE_VIEWER_DATA_CHECKING
#if ENABLE_GCODE_VIEWER_STATISTICS
m_result.time = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::high_resolution_clock::now() - m_start_time).count();
#endif // ENABLE_GCODE_VIEWER_STATISTICS
//BBS: update slice warning
update_slice_warnings();
@@ -1386,32 +1401,6 @@ std::vector<std::pair<CustomGCode::Type, std::pair<float, float>>> GCodeProcesso
return ret;
}
std::vector<std::pair<EMoveType, float>> GCodeProcessor::get_moves_time(PrintEstimatedStatistics::ETimeMode mode) const
{
std::vector<std::pair<EMoveType, float>> ret;
if (mode < PrintEstimatedStatistics::ETimeMode::Count) {
for (size_t i = 0; i < m_time_processor.machines[static_cast<size_t>(mode)].moves_time.size(); ++i) {
float time = m_time_processor.machines[static_cast<size_t>(mode)].moves_time[i];
if (time > 0.0f)
ret.push_back({ static_cast<EMoveType>(i), time });
}
}
return ret;
}
std::vector<std::pair<ExtrusionRole, float>> GCodeProcessor::get_roles_time(PrintEstimatedStatistics::ETimeMode mode) const
{
std::vector<std::pair<ExtrusionRole, float>> ret;
if (mode < PrintEstimatedStatistics::ETimeMode::Count) {
for (size_t i = 0; i < m_time_processor.machines[static_cast<size_t>(mode)].roles_time.size(); ++i) {
float time = m_time_processor.machines[static_cast<size_t>(mode)].roles_time[i];
if (time > 0.0f)
ret.push_back({ static_cast<ExtrusionRole>(i), time });
}
}
return ret;
}
ConfigSubstitutions load_from_superslicer_gcode_file(const std::string& filename, DynamicPrintConfig& config, ForwardCompatibilitySubstitutionRule compatibility_rule)
{
// for reference, see: ConfigBase::load_from_gcode_file()
@@ -1445,11 +1434,9 @@ void GCodeProcessor::apply_config_superslicer(const std::string& filename)
apply_config(config);
}
std::vector<float> GCodeProcessor::get_layers_time(PrintEstimatedStatistics::ETimeMode mode) const
float GCodeProcessor::get_first_layer_time(PrintEstimatedStatistics::ETimeMode mode) const
{
return (mode < PrintEstimatedStatistics::ETimeMode::Count) ?
m_time_processor.machines[static_cast<size_t>(mode)].layers_time :
std::vector<float>();
return (mode < PrintEstimatedStatistics::ETimeMode::Count) ? m_time_processor.machines[static_cast<size_t>(mode)].first_layer_time : 0.0f;
}
void GCodeProcessor::apply_config_simplify3d(const std::string& filename)
@@ -2074,29 +2061,8 @@ void GCodeProcessor::process_tags(const std::string_view comment, bool producers
// layer change tag
if (comment == reserved_tag(ETags::Layer_Change)) {
++m_layer_id;
if (m_detect_layer_based_on_tag) {
if (m_result.moves.empty() || m_result.spiral_vase_layers.empty())
// add a placeholder for layer height. the actual value will be set inside process_G1() method
m_result.spiral_vase_layers.push_back({ FLT_MAX, { 0, 0 } });
else {
const size_t move_id = m_result.moves.size() - 1 - m_seams_count;
if (!m_result.spiral_vase_layers.empty())
m_result.spiral_vase_layers.back().second.second = move_id;
// add a placeholder for layer height. the actual value will be set inside process_G1() method
m_result.spiral_vase_layers.push_back({ FLT_MAX, { move_id, move_id } });
}
}
return;
}
#if ENABLE_GCODE_VIEWER_DATA_CHECKING
// mm3_per_mm print tag
if (boost::starts_with(comment, Mm3_Per_Mm_Tag)) {
if (! parse_number(comment.substr(Mm3_Per_Mm_Tag.size()), m_mm3_per_mm_compare.last_tag_value))
BOOST_LOG_TRIVIAL(error) << "GCodeProcessor encountered an invalid value for Mm3_Per_Mm (" << comment << ").";
return;
}
#endif // ENABLE_GCODE_VIEWER_DATA_CHECKING
}
bool GCodeProcessor::process_producers_tags(const std::string_view comment)
@@ -2665,9 +2631,6 @@ void GCodeProcessor::process_G1(const GCodeReader::GCodeLine& line, const std::o
}
// volume extruded filament / tool displacement = area toolpath cross section
m_mm3_per_mm = area_toolpath_cross_section;
#if ENABLE_GCODE_VIEWER_DATA_CHECKING
m_mm3_per_mm_compare.update(area_toolpath_cross_section, m_extrusion_role);
#endif // ENABLE_GCODE_VIEWER_DATA_CHECKING
if (m_forced_height > 0.0f)
m_height = m_forced_height;
@@ -2685,10 +2648,6 @@ void GCodeProcessor::process_G1(const GCodeReader::GCodeLine& line, const std::o
m_extruded_last_z = m_end_position[Z];
m_options_z_corrector.update(m_height);
#if ENABLE_GCODE_VIEWER_DATA_CHECKING
m_height_compare.update(m_height, m_extrusion_role);
#endif // ENABLE_GCODE_VIEWER_DATA_CHECKING
if (m_forced_width > 0.0f)
m_width = m_forced_width;
else if (m_extrusion_role == erExternalPerimeter)
@@ -2706,10 +2665,6 @@ void GCodeProcessor::process_G1(const GCodeReader::GCodeLine& line, const std::o
// clamp width to avoid artifacts which may arise from wrong values of m_height
m_width = std::min(m_width, std::max(2.0f, 4.0f * m_height));
#if ENABLE_GCODE_VIEWER_DATA_CHECKING
m_width_compare.update(m_width, m_extrusion_role);
#endif // ENABLE_GCODE_VIEWER_DATA_CHECKING
}
else if (type == EMoveType::Unretract && m_flushing) {
float volume_flushed_filament = area_filament_cross_section * delta_pos[E];
@@ -2765,6 +2720,7 @@ void GCodeProcessor::process_G1(const GCodeReader::GCodeLine& line, const std::o
block.role = (type != EMoveType::Travel || m_extrusion_role == erCustom) ? m_extrusion_role : erNone;
block.distance = distance;
block.g1_line_id = m_g1_line_id;
block.move_id = static_cast<unsigned int>(m_result.moves.size());
block.remaining_internal_g1_lines = remaining_internal_g1_lines.has_value() ? *remaining_internal_g1_lines : 0;
block.layer_id = std::max<unsigned int>(1, m_layer_id);
block.flags.prepare_stage = m_processing_start_custom_gcode;
@@ -2945,11 +2901,11 @@ void GCodeProcessor::process_G1(const GCodeReader::GCodeLine& line, const std::o
prev = curr;
blocks.push_back(block);
if (blocks.size() > TimeProcessor::Planner::refresh_threshold)
machine.calculate_time(TimeProcessor::Planner::queue_size);
}
if (m_time_processor.machines[0].blocks.size() > TimeProcessor::Planner::refresh_threshold)
calculate_time(m_result, TimeProcessor::Planner::queue_size);
const Vec3f plate_offset = {(float) m_x_offset, (float) m_y_offset, 0.0f};
if (m_seams_detector.is_active()) {
@@ -2993,20 +2949,6 @@ void GCodeProcessor::process_G1(const GCodeReader::GCodeLine& line, const std::o
m_seams_detector.set_first_vertex(m_result.moves.back().position - m_extruder_offsets[m_extruder_id] - plate_offset);
}
if (m_detect_layer_based_on_tag && !m_result.spiral_vase_layers.empty()) {
if (delta_pos[Z] >= 0.0 && type == EMoveType::Extrude) {
const float current_z = static_cast<float>(m_end_position[Z]);
// replace layer height placeholder with correct value
if (m_result.spiral_vase_layers.back().first == FLT_MAX) {
m_result.spiral_vase_layers.back().first = current_z;
} else {
m_result.spiral_vase_layers.back().first = std::max(m_result.spiral_vase_layers.back().first, current_z);
}
}
if (!m_result.moves.empty())
m_result.spiral_vase_layers.back().second.second = m_result.moves.size() - 1 - m_seams_count;
}
// store move
store_move_vertex(type);
}
@@ -3382,7 +3324,7 @@ void GCodeProcessor::process_G2_G3(const GCodeReader::GCodeLine& line)
blocks.push_back(block);
if (blocks.size() > TimeProcessor::Planner::refresh_threshold)
machine.calculate_time(TimeProcessor::Planner::queue_size);
machine.calculate_time(m_result, PrintEstimatedStatistics::ETimeMode::Normal, TimeProcessor::Planner::queue_size);
}
//BBS: seam detector
@@ -3426,21 +3368,22 @@ void GCodeProcessor::process_G2_G3(const GCodeReader::GCodeLine& line)
m_seams_detector.set_first_vertex(m_result.moves.back().position - m_extruder_offsets[m_extruder_id] - plate_offset);
}
// Orca: we now use spiral_vase_layers for proper layer detect when scarf joint is enabled,
// and this is needed if the layer has only arc moves
if (m_detect_layer_based_on_tag && !m_result.spiral_vase_layers.empty()) {
if (delta_pos[Z] >= 0.0 && type == EMoveType::Extrude) {
const float current_z = static_cast<float>(m_end_position[Z]);
// replace layer height placeholder with correct value
if (m_result.spiral_vase_layers.back().first == FLT_MAX) {
m_result.spiral_vase_layers.back().first = current_z;
} else {
m_result.spiral_vase_layers.back().first = std::max(m_result.spiral_vase_layers.back().first, current_z);
}
}
if (!m_result.moves.empty())
m_result.spiral_vase_layers.back().second.second = m_result.moves.size() - 1 - m_seams_count;
}
// TODO
// // Orca: we now use spiral_vase_layers for proper layer detect when scarf joint is enabled,
// // and this is needed if the layer has only arc moves
// if (m_detect_layer_based_on_tag && !m_result.spiral_vase_layers.empty()) {
// if (delta_pos[Z] >= 0.0 && type == EMoveType::Extrude) {
// const float current_z = static_cast<float>(m_end_position[Z]);
// // replace layer height placeholder with correct value
// if (m_result.spiral_vase_layers.back().first == FLT_MAX) {
// m_result.spiral_vase_layers.back().first = current_z;
// } else {
// m_result.spiral_vase_layers.back().first = std::max(m_result.spiral_vase_layers.back().first, current_z);
// }
// }
// if (!m_result.moves.empty())
// m_result.spiral_vase_layers.back().second.second = m_result.moves.size() - 1 - m_seams_count;
// }
//BBS: store move
store_move_vertex(type, m_move_path_type);
@@ -4788,13 +4731,15 @@ void GCodeProcessor::store_move_vertex(EMoveType type, EMovePathType path_type)
Vec3f(m_end_position[X] + m_x_offset, m_end_position[Y] + m_y_offset, m_processing_start_custom_gcode ? m_first_layer_height : m_end_position[Z]- m_z_offset) + m_extruder_offsets[m_extruder_id],
static_cast<float>(m_end_position[E] - m_start_position[E]),
m_feedrate,
0.0f, // actual feedrate
m_width,
m_height,
m_mm3_per_mm,
m_travel_dist,
m_fan_speed,
m_extruder_temps[m_extruder_id],
static_cast<float>(m_result.moves.size()),
{ 0.0f, 0.0f }, // time
std::max<unsigned int>(1, m_layer_id) - 1,
static_cast<float>(m_layer_id), //layer_duration: set later
//BBS: add arc move related data
path_type,
@@ -4954,6 +4899,9 @@ int GCodeProcessor::get_filament_vitrification_temperature(size_t extrude_id)
void GCodeProcessor::process_custom_gcode_time(CustomGCode::Type code)
{
//FIXME this simulates st_synchronize! is it correct?
// The estimated time may be longer than the real print time.
simulate_st_synchronize();
for (size_t i = 0; i < static_cast<size_t>(PrintEstimatedStatistics::ETimeMode::Count); ++i) {
TimeMachine& machine = m_time_processor.machines[i];
if (!machine.enabled)
@@ -4961,9 +4909,6 @@ void GCodeProcessor::process_custom_gcode_time(CustomGCode::Type code)
TimeMachine::CustomGCodeTime& gcode_time = machine.gcode_time;
gcode_time.needed = true;
//FIXME this simulates st_synchronize! is it correct?
// The estimated time may be longer than the real print time.
machine.simulate_st_synchronize();
if (gcode_time.cache != 0.0f) {
gcode_time.times.push_back({ code, gcode_time.cache });
gcode_time.cache = 0.0f;
@@ -4985,11 +4930,69 @@ void GCodeProcessor::process_filaments(CustomGCode::Type code)
}
}
void GCodeProcessor::calculate_time(GCodeProcessorResult& result, size_t keep_last_n_blocks, float additional_time)
{
// calculate times
std::vector<TimeMachine::ActualSpeedMove> actual_speed_moves;
for (size_t i = 0; i < static_cast<size_t>(PrintEstimatedStatistics::ETimeMode::Count); ++i) {
TimeMachine& machine = m_time_processor.machines[i];
machine.calculate_time(m_result, static_cast<PrintEstimatedStatistics::ETimeMode>(i), keep_last_n_blocks, additional_time);
if (static_cast<PrintEstimatedStatistics::ETimeMode>(i) == PrintEstimatedStatistics::ETimeMode::Normal)
actual_speed_moves = std::move(machine.actual_speed_moves);
}
// insert actual speed moves into the move list
unsigned int inserted_actual_speed_moves_count = 0;
std::vector<GCodeProcessorResult::MoveVertex> new_moves;
std::map<unsigned int, unsigned int> id_map;
for (auto it = actual_speed_moves.begin(); it != actual_speed_moves.end(); ++it) {
const unsigned int base_id = it->move_id + inserted_actual_speed_moves_count;
if (it->position.has_value()) {
// insert actual speed move into the move list
// clone from existing move
GCodeProcessorResult::MoveVertex new_move = result.moves[base_id];
// override modified parameters
new_move.time = { 0.0f, 0.0f };
new_move.position = *it->position;
new_move.actual_feedrate = it->actual_feedrate;
new_move.delta_extruder = *it->delta_extruder;
new_move.feedrate = *it->feedrate;
new_move.width = *it->width;
new_move.height = *it->height;
new_move.mm3_per_mm = *it->mm3_per_mm;
new_move.fan_speed = *it->fan_speed;
new_move.temperature = *it->temperature;
// new_move.internal_only = true; // TODO
new_moves.push_back(new_move);
}
else {
result.moves.insert(result.moves.begin() + base_id, new_moves.begin(), new_moves.end());
id_map[it->move_id] = base_id + new_moves.size();
// update move actual speed
result.moves[base_id + new_moves.size()].actual_feedrate = it->actual_feedrate;
inserted_actual_speed_moves_count += new_moves.size();
// synchronize seams actual speed
if (base_id + new_moves.size() + 1 < result.moves.size()) {
GCodeProcessorResult::MoveVertex& move = result.moves[base_id + new_moves.size() + 1];
if (move.type == EMoveType::Seam)
move.actual_feedrate = it->actual_feedrate;
}
new_moves.clear();
}
}
// synchronize blocks' move_ids with after moves for actual speed insertion
for (size_t i = 0; i < static_cast<size_t>(PrintEstimatedStatistics::ETimeMode::Count); ++i) {
for (GCodeProcessor::TimeBlock& block : m_time_processor.machines[i].blocks) {
auto it = id_map.find(block.move_id);
block.move_id = (it != id_map.end()) ? it->second : block.move_id + inserted_actual_speed_moves_count;
}
}
}
void GCodeProcessor::simulate_st_synchronize(float additional_time)
{
for (size_t i = 0; i < static_cast<size_t>(PrintEstimatedStatistics::ETimeMode::Count); ++i) {
m_time_processor.machines[i].simulate_st_synchronize(additional_time);
}
calculate_time(m_result, 0, additional_time);
}
void GCodeProcessor::update_estimated_times_stats()
@@ -4999,9 +5002,6 @@ void GCodeProcessor::update_estimated_times_stats()
data.time = get_time(mode);
data.prepare_time = get_prepare_time(mode);
data.custom_gcode_times = get_custom_gcode_times(mode, true);
data.moves_times = get_moves_time(mode);
data.roles_times = get_roles_time(mode);
data.layers_times = get_layers_time(mode);
};
update_mode(PrintEstimatedStatistics::ETimeMode::Normal);

View File

@@ -56,21 +56,12 @@ class Print;
float time;
float prepare_time;
std::vector<std::pair<CustomGCode::Type, std::pair<float, float>>> custom_gcode_times;
std::vector<std::pair<EMoveType, float>> moves_times;
std::vector<std::pair<ExtrusionRole, float>> roles_times;
std::vector<float> layers_times;
void reset() {
time = 0.0f;
prepare_time = 0.0f;
custom_gcode_times.clear();
custom_gcode_times.shrink_to_fit();
moves_times.clear();
moves_times.shrink_to_fit();
roles_times.clear();
roles_times.shrink_to_fit();
layers_times.clear();
layers_times.shrink_to_fit();
}
};
@@ -159,13 +150,15 @@ class Print;
Vec3f position{ Vec3f::Zero() }; // mm
float delta_extruder{ 0.0f }; // mm
float feedrate{ 0.0f }; // mm/s
float actual_feedrate{ 0.0f }; // mm/s
float width{ 0.0f }; // mm
float height{ 0.0f }; // mm
float mm3_per_mm{ 0.0f };
float travel_dist{ 0.0f }; // mm
float fan_speed{ 0.0f }; // percentage
float temperature{ 0.0f }; // Celsius degrees
float time{ 0.0f }; // s
std::array<float, static_cast<size_t>(PrintEstimatedStatistics::ETimeMode::Count)> time{ 0.0f, 0.0f }; // s
unsigned int layer_id{ 0 };
float layer_duration{ 0.0f }; // s (layer id before finalize)
@@ -175,6 +168,7 @@ class Print;
std::vector<Vec3f> interpolation_points; // interpolation points of arc for drawing
float volumetric_rate() const { return feedrate * mm3_per_mm; }
float actual_volumetric_rate() const { return actual_feedrate * mm3_per_mm; }
//BBS: new function to support arc move
bool is_arc_move_with_interpolation_points() const {
return (move_path_type == EMovePathType::Arc_move_ccw || move_path_type == EMovePathType::Arc_move_cw) && interpolation_points.size();
@@ -219,15 +213,12 @@ class Print;
std::vector<int> filament_vitrification_temperature;
PrintEstimatedStatistics print_statistics;
std::vector<CustomGCode::Item> custom_gcode_per_print_z;
std::vector<std::pair<float, std::pair<size_t, size_t>>> spiral_vase_layers;
bool spiral_vase_mode;
//BBS
std::vector<SliceWarning> warnings;
int nozzle_hrc;
NozzleType nozzle_type;
BedType bed_type = BedType::btCount;
#if ENABLE_GCODE_VIEWER_STATISTICS
int64_t time{ 0 };
#endif // ENABLE_GCODE_VIEWER_STATISTICS
void reset();
//BBS: add mutex for protection of gcode result
@@ -253,7 +244,7 @@ class Print;
filament_costs = other.filament_costs;
print_statistics = other.print_statistics;
custom_gcode_per_print_z = other.custom_gcode_per_print_z;
spiral_vase_layers = other.spiral_vase_layers;
spiral_vase_mode = other.spiral_vase_mode;
warnings = other.warnings;
bed_type = other.bed_type;
bed_match_result = other.bed_match_result;
@@ -312,10 +303,6 @@ class Print;
static bool s_IsBBLPrinter;
#if ENABLE_GCODE_VIEWER_DATA_CHECKING
static const std::string Mm3_Per_Mm_Tag;
#endif // ENABLE_GCODE_VIEWER_DATA_CHECKING
private:
using AxisCoords = std::array<double, 4>;
using ExtruderColors = std::vector<unsigned char>;
@@ -364,9 +351,12 @@ class Print;
float cruise_feedrate{ 0.0f }; // mm/sec
float acceleration_time(float entry_feedrate, float acceleration) const;
float cruise_time() const;
float cruise_time() const { return (cruise_feedrate != 0.0f) ? cruise_distance() / cruise_feedrate : 0.0f; }
float deceleration_time(float distance, float acceleration) const;
float cruise_distance() const;
float acceleration_distance() const { return accelerate_until; }
float cruise_distance() const { return decelerate_after - accelerate_until; }
float deceleration_distance(float distance) const { return distance - decelerate_after; }
bool is_cruise_only(float distance) const { return std::abs(cruise_distance() - distance) < EPSILON; }
};
struct TimeBlock
@@ -380,6 +370,7 @@ class Print;
EMoveType move_type{ EMoveType::Noop };
ExtrusionRole role{ erNone };
unsigned int move_id{ 0 };
unsigned int g1_line_id{ 0 };
unsigned int remaining_internal_g1_lines{ 0 };
unsigned int layer_id{ 0 };
@@ -394,7 +385,10 @@ class Print;
// Calculates this block's trapezoid
void calculate_trapezoid();
float time() const;
float time() const {
return trapezoid.acceleration_time(feedrate_profile.entry, acceleration) +
trapezoid.cruise_time() + trapezoid.deceleration_time(distance, acceleration);
}
};
@@ -434,6 +428,20 @@ class Print;
float elapsed_time;
};
struct ActualSpeedMove
{
unsigned int move_id{ 0 };
std::optional<Vec3f> position;
float actual_feedrate{ 0.0f };
std::optional<float> delta_extruder;
std::optional<float> feedrate;
std::optional<float> width;
std::optional<float> height;
std::optional<float> mm3_per_mm;
std::optional<float> fan_speed;
std::optional<float> temperature;
};
bool enabled;
float acceleration; // mm/s^2
// hard limit for the acceleration, to which the firmware will clamp.
@@ -459,17 +467,14 @@ class Print;
CustomGCodeTime gcode_time;
std::vector<TimeBlock> blocks;
std::vector<G1LinesCacheItem> g1_times_cache;
std::array<float, static_cast<size_t>(EMoveType::Count)> moves_time;
std::array<float, static_cast<size_t>(ExtrusionRole::erCount)> roles_time;
std::vector<float> layers_time;
float first_layer_time;
std::vector<ActualSpeedMove> actual_speed_moves;
//BBS: prepare stage time before print model, including start gcode time and mostly same with start gcode time
float prepare_time;
void reset();
// Simulates firmware st_synchronize() call
void simulate_st_synchronize(float additional_time = 0.0f);
void calculate_time(size_t keep_last_n_blocks = 0, float additional_time = 0.0f);
void calculate_time(GCodeProcessorResult& result, PrintEstimatedStatistics::ETimeMode mode, size_t keep_last_n_blocks = 0, float additional_time = 0.0f);
};
struct TimeProcessor
@@ -733,9 +738,6 @@ class Print;
float m_preheat_time;
int m_preheat_steps;
bool m_disable_m73;
#if ENABLE_GCODE_VIEWER_STATISTICS
std::chrono::time_point<std::chrono::high_resolution_clock> m_start_time;
#endif // ENABLE_GCODE_VIEWER_STATISTICS
enum class EProducer
{
@@ -762,12 +764,6 @@ class Print;
GCodeProcessorResult m_result;
static unsigned int s_result_id;
#if ENABLE_GCODE_VIEWER_DATA_CHECKING
DataChecker m_mm3_per_mm_compare{ "mm3_per_mm", 0.01f };
DataChecker m_height_compare{ "height", 0.01f };
DataChecker m_width_compare{ "width", 0.01f };
#endif // ENABLE_GCODE_VIEWER_DATA_CHECKING
public:
GCodeProcessor();
@@ -798,9 +794,7 @@ class Print;
std::string get_time_dhm(PrintEstimatedStatistics::ETimeMode mode) const;
std::vector<std::pair<CustomGCode::Type, std::pair<float, float>>> get_custom_gcode_times(PrintEstimatedStatistics::ETimeMode mode, bool include_remaining) const;
std::vector<std::pair<EMoveType, float>> get_moves_time(PrintEstimatedStatistics::ETimeMode mode) const;
std::vector<std::pair<ExtrusionRole, float>> get_roles_time(PrintEstimatedStatistics::ETimeMode mode) const;
std::vector<float> get_layers_time(PrintEstimatedStatistics::ETimeMode mode) const;
float get_first_layer_time(PrintEstimatedStatistics::ETimeMode mode) const;
//BBS: set offset for gcode writer
void set_xy_offset(double x, double y) { m_x_offset = x; m_y_offset = y; }
@@ -972,6 +966,8 @@ class Print;
void process_custom_gcode_time(CustomGCode::Type code);
void process_filaments(CustomGCode::Type code);
void calculate_time(GCodeProcessorResult& result, size_t keep_last_n_blocks = 0, float additional_time = 0.0f);
// Simulates firmware st_synchronize() call
void simulate_st_synchronize(float additional_time = 0.0f);

View File

@@ -71,12 +71,9 @@ public:
m_extrusion_flow(0.f),
m_preview_suppressed(false),
m_elapsed_time(0.f),
#if ENABLE_GCODE_VIEWER_DATA_CHECKING
m_default_analyzer_line_width(line_width),
#endif // ENABLE_GCODE_VIEWER_DATA_CHECKING
m_gcode_flavor(flavor),
m_filpar(filament_parameters)
{
m_gcode_flavor(flavor),
m_filpar(filament_parameters)
{
// ORCA: This class is only used by BBL printers, so set the parameter appropriately.
// This fixes an issue where the wipe tower was using BBL tags resulting in statistics for purging in the purge tower not being displayed.
GCodeProcessor::s_IsBBLPrinter = true;
@@ -96,18 +93,6 @@ public:
return *this;
}
#if ENABLE_GCODE_VIEWER_DATA_CHECKING
WipeTowerWriter& change_analyzer_mm3_per_mm(float len, float e) {
static const float area = float(M_PI) * 1.75f * 1.75f / 4.f;
float mm3_per_mm = (len == 0.f ? 0.f : area * e / len);
// adds tag for processor:
std::stringstream str;
str << ";" << GCodeProcessor::Mm3_Per_Mm_Tag << mm3_per_mm << "\n";
m_gcode += str.str();
return *this;
}
#endif // ENABLE_GCODE_VIEWER_DATA_CHECKING
WipeTowerWriter& set_initial_position(const Vec2f &pos, float width = 0.f, float depth = 0.f, float internal_angle = 0.f) {
m_wipe_tower_width = width;
m_wipe_tower_depth = depth;
@@ -145,13 +130,8 @@ public:
// Suppress / resume G-code preview in Slic3r. Slic3r will have difficulty to differentiate the various
// filament loading and cooling moves from normal extrusion moves. Therefore the writer
// is asked to suppres output of some lines, which look like extrusions.
#if ENABLE_GCODE_VIEWER_DATA_CHECKING
WipeTowerWriter& suppress_preview() { change_analyzer_line_width(0.f); m_preview_suppressed = true; return *this; }
WipeTowerWriter& resume_preview() { change_analyzer_line_width(m_default_analyzer_line_width); m_preview_suppressed = false; return *this; }
#else
WipeTowerWriter& suppress_preview() { m_preview_suppressed = true; return *this; }
WipeTowerWriter& resume_preview() { m_preview_suppressed = false; return *this; }
#endif // ENABLE_GCODE_VIEWER_DATA_CHECKING
WipeTowerWriter& resume_preview() { m_preview_suppressed = false; return *this; }
WipeTowerWriter& feedrate(float f)
{
@@ -190,12 +170,9 @@ public:
Vec2f rot(this->rotate(Vec2f(x,y))); // this is where we want to go
if (! m_preview_suppressed && e > 0.f && len > 0.f) {
#if ENABLE_GCODE_VIEWER_DATA_CHECKING
change_analyzer_mm3_per_mm(len, e);
#endif // ENABLE_GCODE_VIEWER_DATA_CHECKING
// Width of a squished extrusion, corrected for the roundings of the squished extrusions.
// Width of a squished extrusion, corrected for the roundings of the squished extrusions.
// This is left zero if it is a travel move.
float width = e * m_filpar[0].filament_area / (len * m_layer_height);
float width = e * m_filpar[0].filament_area / (len * m_layer_height);
// Correct for the roundings of a squished extrusion.
width += m_layer_height * float(1. - M_PI / 4.);
if (m_extrusions.empty() || m_extrusions.back().pos != rotated_current_pos)
@@ -524,9 +501,6 @@ private:
float m_wipe_tower_depth = 0.f;
unsigned m_last_fan_speed = 0;
int current_temp = -1;
#if ENABLE_GCODE_VIEWER_DATA_CHECKING
const float m_default_analyzer_line_width;
#endif // ENABLE_GCODE_VIEWER_DATA_CHECKING
float m_used_filament_length = 0.f;
GCodeFlavor m_gcode_flavor;
const std::vector<WipeTower::FilamentParameters>& m_filpar;

View File

@@ -18,10 +18,6 @@
#define DISABLE_INSTANCES_SYNCH 0
// Use wxDataViewRender instead of wxDataViewCustomRenderer
#define ENABLE_NONCUSTOM_DATA_VIEW_RENDERING 0
// Enable G-Code viewer statistics imgui dialog
#define ENABLE_GCODE_VIEWER_STATISTICS 0
// Enable G-Code viewer comparison between toolpaths height and width detected from gcode and calculated at gcode generation
#define ENABLE_GCODE_VIEWER_DATA_CHECKING 0
// Enable project dirty state manager debug window
#define ENABLE_PROJECT_DIRTY_STATE_DEBUG_WINDOW 0
@@ -62,5 +58,9 @@
// Enable picking using raytracing
#define ENABLE_RAYCAST_PICKING_DEBUG 0
// Enable imgui debug dialog for new gcode viewer (using libvgcode)
#define ENABLE_NEW_GCODE_VIEWER_DEBUG 0
// Enable extension of tool position imgui dialog to show actual speed profile
#define ENABLE_ACTUAL_SPEED_DEBUG 1
#endif // _prusaslicer_technologies_h_

View File

@@ -81,6 +81,7 @@ extern unsigned get_logging_level();
extern void trace(unsigned int level, const char *message);
// Format memory allocated, separate thousands by comma.
extern std::string format_memsize_MB(size_t n);
extern std::string format_memsize(size_t bytes, unsigned int decimals = 1);
// Return string to be added to the boost::log output to inform about the current process memory allocation.
// The string is non-empty if the loglevel >= info (3) or ignore_loglevel==true.
// Latter is used to get the memory info from SysInfoDialog.

View File

@@ -1337,6 +1337,42 @@ std::string format_memsize_MB(size_t n)
return out + "MB";
}
std::string format_memsize(size_t bytes, unsigned int decimals)
{
static constexpr const float kb = 1024.0f;
static constexpr const float mb = 1024.0f * kb;
static constexpr const float gb = 1024.0f * mb;
static constexpr const float tb = 1024.0f * gb;
const float f_bytes = static_cast<float>(bytes);
if (f_bytes < kb)
return std::to_string(bytes) + " bytes";
else if (f_bytes < mb) {
const float f_kb = f_bytes / kb;
char buf[64];
sprintf(buf, "%.*f", decimals, f_kb);
return std::to_string(bytes) + " bytes (" + std::string(buf) + "KB)";
}
else if (f_bytes < gb) {
const float f_mb = f_bytes / mb;
char buf[64];
sprintf(buf, "%.*f", decimals, f_mb);
return std::to_string(bytes) + " bytes (" + std::string(buf) + "MB)";
}
else if (f_bytes < tb) {
const float f_gb = f_bytes / gb;
char buf[64];
sprintf(buf, "%.*f", decimals, f_gb);
return std::to_string(bytes) + " bytes (" + std::string(buf) + "GB)";
}
else {
const float f_tb = f_bytes / tb;
char buf[64];
sprintf(buf, "%.*f", decimals, f_tb);
return std::to_string(bytes) + " bytes (" + std::string(buf) + "TB)";
}
}
// Returns platform-specific string to be used as log output or parsed in SysInfoDialog.
// The latter parses the string with (semi)colons as separators, it should look about as
// "desc1: value1; desc2: value2" or similar (spaces should not matter).

View File

@@ -0,0 +1,80 @@
cmake_minimum_required(VERSION 3.13)
project(libvgcode)
# glad library
if (EMSCRIPTEN OR SLIC3R_OPENGL_ES)
set(GLAD_SOURCES
glad/include/glad/gles2.h
glad/include/KHR/khrplatform.h
glad/src/gles2.c
)
else ()
set(GLAD_SOURCES
glad/include/glad/gl.h
glad/include/KHR/khrplatform.h
glad/src/gl.c
)
endif ()
set(LIBVGCODE_SOURCES
# API
include/ColorPrint.hpp
include/ColorRange.hpp
include/GCodeInputData.hpp
include/PathVertex.hpp
include/Types.hpp
include/Viewer.hpp
# source
src/Bitset.hpp
src/Bitset.cpp
src/CogMarker.hpp
src/CogMarker.cpp
src/ColorPrint.cpp
src/ColorRange.cpp
src/ExtrusionRoles.hpp
src/ExtrusionRoles.cpp
src/GCodeInputData.cpp
src/Layers.hpp
src/Layers.cpp
src/OpenGLUtils.hpp
src/OpenGLUtils.cpp
src/OptionTemplate.hpp
src/OptionTemplate.cpp
src/PathVertex.cpp
src/Range.hpp
src/Range.cpp
src/SegmentTemplate.hpp
src/SegmentTemplate.cpp
src/Settings.hpp
src/Settings.cpp
src/Shaders.hpp
src/ShadersES.hpp
src/ToolMarker.hpp
src/ToolMarker.cpp
src/Types.cpp
src/Utils.hpp
src/Utils.cpp
src/Viewer.cpp
src/ViewerImpl.hpp
src/ViewerImpl.cpp
src/ViewRange.hpp
src/ViewRange.cpp
${GLAD_SOURCES}
)
add_library(libvgcode STATIC ${LIBVGCODE_SOURCES})
if (EMSCRIPTEN OR SLIC3R_OPENGL_ES)
add_compile_definitions(ENABLE_OPENGL_ES)
endif()
if (WIN32)
foreach(_source IN ITEMS ${LIBVGCODE_SOURCES})
get_filename_component(_source_path "${_source}" PATH)
string(REPLACE "/" "\\" _group_path "${_source_path}")
source_group("${_group_path}" FILES "${_source}")
endforeach()
endif ()
# glad includes
include_directories(glad/include)

View File

@@ -0,0 +1,311 @@
#ifndef __khrplatform_h_
#define __khrplatform_h_
/*
** Copyright (c) 2008-2018 The Khronos Group Inc.
**
** Permission is hereby granted, free of charge, to any person obtaining a
** copy of this software and/or associated documentation files (the
** "Materials"), to deal in the Materials without restriction, including
** without limitation the rights to use, copy, modify, merge, publish,
** distribute, sublicense, and/or sell copies of the Materials, and to
** permit persons to whom the Materials are furnished to do so, subject to
** the following conditions:
**
** The above copyright notice and this permission notice shall be included
** in all copies or substantial portions of the Materials.
**
** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
*/
/* Khronos platform-specific types and definitions.
*
* The master copy of khrplatform.h is maintained in the Khronos EGL
* Registry repository at https://github.com/KhronosGroup/EGL-Registry
* The last semantic modification to khrplatform.h was at commit ID:
* 67a3e0864c2d75ea5287b9f3d2eb74a745936692
*
* Adopters may modify this file to suit their platform. Adopters are
* encouraged to submit platform specific modifications to the Khronos
* group so that they can be included in future versions of this file.
* Please submit changes by filing pull requests or issues on
* the EGL Registry repository linked above.
*
*
* See the Implementer's Guidelines for information about where this file
* should be located on your system and for more details of its use:
* http://www.khronos.org/registry/implementers_guide.pdf
*
* This file should be included as
* #include <KHR/khrplatform.h>
* by Khronos client API header files that use its types and defines.
*
* The types in khrplatform.h should only be used to define API-specific types.
*
* Types defined in khrplatform.h:
* khronos_int8_t signed 8 bit
* khronos_uint8_t unsigned 8 bit
* khronos_int16_t signed 16 bit
* khronos_uint16_t unsigned 16 bit
* khronos_int32_t signed 32 bit
* khronos_uint32_t unsigned 32 bit
* khronos_int64_t signed 64 bit
* khronos_uint64_t unsigned 64 bit
* khronos_intptr_t signed same number of bits as a pointer
* khronos_uintptr_t unsigned same number of bits as a pointer
* khronos_ssize_t signed size
* khronos_usize_t unsigned size
* khronos_float_t signed 32 bit floating point
* khronos_time_ns_t unsigned 64 bit time in nanoseconds
* khronos_utime_nanoseconds_t unsigned time interval or absolute time in
* nanoseconds
* khronos_stime_nanoseconds_t signed time interval in nanoseconds
* khronos_boolean_enum_t enumerated boolean type. This should
* only be used as a base type when a client API's boolean type is
* an enum. Client APIs which use an integer or other type for
* booleans cannot use this as the base type for their boolean.
*
* Tokens defined in khrplatform.h:
*
* KHRONOS_FALSE, KHRONOS_TRUE Enumerated boolean false/true values.
*
* KHRONOS_SUPPORT_INT64 is 1 if 64 bit integers are supported; otherwise 0.
* KHRONOS_SUPPORT_FLOAT is 1 if floats are supported; otherwise 0.
*
* Calling convention macros defined in this file:
* KHRONOS_APICALL
* KHRONOS_APIENTRY
* KHRONOS_APIATTRIBUTES
*
* These may be used in function prototypes as:
*
* KHRONOS_APICALL void KHRONOS_APIENTRY funcname(
* int arg1,
* int arg2) KHRONOS_APIATTRIBUTES;
*/
#if defined(__SCITECH_SNAP__) && !defined(KHRONOS_STATIC)
# define KHRONOS_STATIC 1
#endif
/*-------------------------------------------------------------------------
* Definition of KHRONOS_APICALL
*-------------------------------------------------------------------------
* This precedes the return type of the function in the function prototype.
*/
#if defined(KHRONOS_STATIC)
/* If the preprocessor constant KHRONOS_STATIC is defined, make the
* header compatible with static linking. */
# define KHRONOS_APICALL
#elif defined(_WIN32)
# define KHRONOS_APICALL __declspec(dllimport)
#elif defined (__SYMBIAN32__)
# define KHRONOS_APICALL IMPORT_C
#elif defined(__ANDROID__)
# define KHRONOS_APICALL __attribute__((visibility("default")))
#else
# define KHRONOS_APICALL
#endif
/*-------------------------------------------------------------------------
* Definition of KHRONOS_APIENTRY
*-------------------------------------------------------------------------
* This follows the return type of the function and precedes the function
* name in the function prototype.
*/
#if defined(_WIN32) && !defined(_WIN32_WCE) && !defined(__SCITECH_SNAP__)
/* Win32 but not WinCE */
# define KHRONOS_APIENTRY __stdcall
#else
# define KHRONOS_APIENTRY
#endif
/*-------------------------------------------------------------------------
* Definition of KHRONOS_APIATTRIBUTES
*-------------------------------------------------------------------------
* This follows the closing parenthesis of the function prototype arguments.
*/
#if defined (__ARMCC_2__)
#define KHRONOS_APIATTRIBUTES __softfp
#else
#define KHRONOS_APIATTRIBUTES
#endif
/*-------------------------------------------------------------------------
* basic type definitions
*-----------------------------------------------------------------------*/
#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || defined(__GNUC__) || defined(__SCO__) || defined(__USLC__)
/*
* Using <stdint.h>
*/
#include <stdint.h>
typedef int32_t khronos_int32_t;
typedef uint32_t khronos_uint32_t;
typedef int64_t khronos_int64_t;
typedef uint64_t khronos_uint64_t;
#define KHRONOS_SUPPORT_INT64 1
#define KHRONOS_SUPPORT_FLOAT 1
/*
* To support platform where unsigned long cannot be used interchangeably with
* inptr_t (e.g. CHERI-extended ISAs), we can use the stdint.h intptr_t.
* Ideally, we could just use (u)intptr_t everywhere, but this could result in
* ABI breakage if khronos_uintptr_t is changed from unsigned long to
* unsigned long long or similar (this results in different C++ name mangling).
* To avoid changes for existing platforms, we restrict usage of intptr_t to
* platforms where the size of a pointer is larger than the size of long.
*/
#if defined(__SIZEOF_LONG__) && defined(__SIZEOF_POINTER__)
#if __SIZEOF_POINTER__ > __SIZEOF_LONG__
#define KHRONOS_USE_INTPTR_T
#endif
#endif
#elif defined(__VMS ) || defined(__sgi)
/*
* Using <inttypes.h>
*/
#include <inttypes.h>
typedef int32_t khronos_int32_t;
typedef uint32_t khronos_uint32_t;
typedef int64_t khronos_int64_t;
typedef uint64_t khronos_uint64_t;
#define KHRONOS_SUPPORT_INT64 1
#define KHRONOS_SUPPORT_FLOAT 1
#elif defined(_WIN32) && !defined(__SCITECH_SNAP__)
/*
* Win32
*/
typedef __int32 khronos_int32_t;
typedef unsigned __int32 khronos_uint32_t;
typedef __int64 khronos_int64_t;
typedef unsigned __int64 khronos_uint64_t;
#define KHRONOS_SUPPORT_INT64 1
#define KHRONOS_SUPPORT_FLOAT 1
#elif defined(__sun__) || defined(__digital__)
/*
* Sun or Digital
*/
typedef int khronos_int32_t;
typedef unsigned int khronos_uint32_t;
#if defined(__arch64__) || defined(_LP64)
typedef long int khronos_int64_t;
typedef unsigned long int khronos_uint64_t;
#else
typedef long long int khronos_int64_t;
typedef unsigned long long int khronos_uint64_t;
#endif /* __arch64__ */
#define KHRONOS_SUPPORT_INT64 1
#define KHRONOS_SUPPORT_FLOAT 1
#elif 0
/*
* Hypothetical platform with no float or int64 support
*/
typedef int khronos_int32_t;
typedef unsigned int khronos_uint32_t;
#define KHRONOS_SUPPORT_INT64 0
#define KHRONOS_SUPPORT_FLOAT 0
#else
/*
* Generic fallback
*/
#include <stdint.h>
typedef int32_t khronos_int32_t;
typedef uint32_t khronos_uint32_t;
typedef int64_t khronos_int64_t;
typedef uint64_t khronos_uint64_t;
#define KHRONOS_SUPPORT_INT64 1
#define KHRONOS_SUPPORT_FLOAT 1
#endif
/*
* Types that are (so far) the same on all platforms
*/
typedef signed char khronos_int8_t;
typedef unsigned char khronos_uint8_t;
typedef signed short int khronos_int16_t;
typedef unsigned short int khronos_uint16_t;
/*
* Types that differ between LLP64 and LP64 architectures - in LLP64,
* pointers are 64 bits, but 'long' is still 32 bits. Win64 appears
* to be the only LLP64 architecture in current use.
*/
#ifdef KHRONOS_USE_INTPTR_T
typedef intptr_t khronos_intptr_t;
typedef uintptr_t khronos_uintptr_t;
#elif defined(_WIN64)
typedef signed long long int khronos_intptr_t;
typedef unsigned long long int khronos_uintptr_t;
#else
typedef signed long int khronos_intptr_t;
typedef unsigned long int khronos_uintptr_t;
#endif
#if defined(_WIN64)
typedef signed long long int khronos_ssize_t;
typedef unsigned long long int khronos_usize_t;
#else
typedef signed long int khronos_ssize_t;
typedef unsigned long int khronos_usize_t;
#endif
#if KHRONOS_SUPPORT_FLOAT
/*
* Float type
*/
typedef float khronos_float_t;
#endif
#if KHRONOS_SUPPORT_INT64
/* Time types
*
* These types can be used to represent a time interval in nanoseconds or
* an absolute Unadjusted System Time. Unadjusted System Time is the number
* of nanoseconds since some arbitrary system event (e.g. since the last
* time the system booted). The Unadjusted System Time is an unsigned
* 64 bit value that wraps back to 0 every 584 years. Time intervals
* may be either signed or unsigned.
*/
typedef khronos_uint64_t khronos_utime_nanoseconds_t;
typedef khronos_int64_t khronos_stime_nanoseconds_t;
#endif
/*
* Dummy value used to pad enum types to 32 bits.
*/
#ifndef KHRONOS_MAX_ENUM
#define KHRONOS_MAX_ENUM 0x7FFFFFFF
#endif
/*
* Enumerated boolean type
*
* Values other than zero should be considered to be true. Therefore
* comparisons should not be made against KHRONOS_TRUE.
*/
typedef enum {
KHRONOS_FALSE = 0,
KHRONOS_TRUE = 1,
KHRONOS_BOOLEAN_ENUM_FORCE_SIZE = KHRONOS_MAX_ENUM
} khronos_boolean_enum_t;
#endif /* __khrplatform_h_ */

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

1786
src/libvgcode/glad/src/gl.c Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,877 @@
/**
* SPDX-License-Identifier: (WTFPL OR CC0-1.0) AND Apache-2.0
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <glad/gles2.h>
#ifndef GLAD_IMPL_UTIL_C_
#define GLAD_IMPL_UTIL_C_
#ifdef _MSC_VER
#define GLAD_IMPL_UTIL_SSCANF sscanf_s
#else
#define GLAD_IMPL_UTIL_SSCANF sscanf
#endif
#endif /* GLAD_IMPL_UTIL_C_ */
#ifdef __cplusplus
extern "C" {
#endif
int GLAD_GL_ES_VERSION_2_0 = 0;
int GLAD_GL_ES_VERSION_3_0 = 0;
PFNGLACTIVETEXTUREPROC glad_glActiveTexture = NULL;
PFNGLATTACHSHADERPROC glad_glAttachShader = NULL;
PFNGLBEGINQUERYPROC glad_glBeginQuery = NULL;
PFNGLBEGINTRANSFORMFEEDBACKPROC glad_glBeginTransformFeedback = NULL;
PFNGLBINDATTRIBLOCATIONPROC glad_glBindAttribLocation = NULL;
PFNGLBINDBUFFERPROC glad_glBindBuffer = NULL;
PFNGLBINDBUFFERBASEPROC glad_glBindBufferBase = NULL;
PFNGLBINDBUFFERRANGEPROC glad_glBindBufferRange = NULL;
PFNGLBINDFRAMEBUFFERPROC glad_glBindFramebuffer = NULL;
PFNGLBINDRENDERBUFFERPROC glad_glBindRenderbuffer = NULL;
PFNGLBINDSAMPLERPROC glad_glBindSampler = NULL;
PFNGLBINDTEXTUREPROC glad_glBindTexture = NULL;
PFNGLBINDTRANSFORMFEEDBACKPROC glad_glBindTransformFeedback = NULL;
PFNGLBINDVERTEXARRAYPROC glad_glBindVertexArray = NULL;
PFNGLBLENDCOLORPROC glad_glBlendColor = NULL;
PFNGLBLENDEQUATIONPROC glad_glBlendEquation = NULL;
PFNGLBLENDEQUATIONSEPARATEPROC glad_glBlendEquationSeparate = NULL;
PFNGLBLENDFUNCPROC glad_glBlendFunc = NULL;
PFNGLBLENDFUNCSEPARATEPROC glad_glBlendFuncSeparate = NULL;
PFNGLBLITFRAMEBUFFERPROC glad_glBlitFramebuffer = NULL;
PFNGLBUFFERDATAPROC glad_glBufferData = NULL;
PFNGLBUFFERSUBDATAPROC glad_glBufferSubData = NULL;
PFNGLCHECKFRAMEBUFFERSTATUSPROC glad_glCheckFramebufferStatus = NULL;
PFNGLCLEARPROC glad_glClear = NULL;
PFNGLCLEARBUFFERFIPROC glad_glClearBufferfi = NULL;
PFNGLCLEARBUFFERFVPROC glad_glClearBufferfv = NULL;
PFNGLCLEARBUFFERIVPROC glad_glClearBufferiv = NULL;
PFNGLCLEARBUFFERUIVPROC glad_glClearBufferuiv = NULL;
PFNGLCLEARCOLORPROC glad_glClearColor = NULL;
PFNGLCLEARDEPTHFPROC glad_glClearDepthf = NULL;
PFNGLCLEARSTENCILPROC glad_glClearStencil = NULL;
PFNGLCLIENTWAITSYNCPROC glad_glClientWaitSync = NULL;
PFNGLCOLORMASKPROC glad_glColorMask = NULL;
PFNGLCOMPILESHADERPROC glad_glCompileShader = NULL;
PFNGLCOMPRESSEDTEXIMAGE2DPROC glad_glCompressedTexImage2D = NULL;
PFNGLCOMPRESSEDTEXIMAGE3DPROC glad_glCompressedTexImage3D = NULL;
PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC glad_glCompressedTexSubImage2D = NULL;
PFNGLCOMPRESSEDTEXSUBIMAGE3DPROC glad_glCompressedTexSubImage3D = NULL;
PFNGLCOPYBUFFERSUBDATAPROC glad_glCopyBufferSubData = NULL;
PFNGLCOPYTEXIMAGE2DPROC glad_glCopyTexImage2D = NULL;
PFNGLCOPYTEXSUBIMAGE2DPROC glad_glCopyTexSubImage2D = NULL;
PFNGLCOPYTEXSUBIMAGE3DPROC glad_glCopyTexSubImage3D = NULL;
PFNGLCREATEPROGRAMPROC glad_glCreateProgram = NULL;
PFNGLCREATESHADERPROC glad_glCreateShader = NULL;
PFNGLCULLFACEPROC glad_glCullFace = NULL;
PFNGLDELETEBUFFERSPROC glad_glDeleteBuffers = NULL;
PFNGLDELETEFRAMEBUFFERSPROC glad_glDeleteFramebuffers = NULL;
PFNGLDELETEPROGRAMPROC glad_glDeleteProgram = NULL;
PFNGLDELETEQUERIESPROC glad_glDeleteQueries = NULL;
PFNGLDELETERENDERBUFFERSPROC glad_glDeleteRenderbuffers = NULL;
PFNGLDELETESAMPLERSPROC glad_glDeleteSamplers = NULL;
PFNGLDELETESHADERPROC glad_glDeleteShader = NULL;
PFNGLDELETESYNCPROC glad_glDeleteSync = NULL;
PFNGLDELETETEXTURESPROC glad_glDeleteTextures = NULL;
PFNGLDELETETRANSFORMFEEDBACKSPROC glad_glDeleteTransformFeedbacks = NULL;
PFNGLDELETEVERTEXARRAYSPROC glad_glDeleteVertexArrays = NULL;
PFNGLDEPTHFUNCPROC glad_glDepthFunc = NULL;
PFNGLDEPTHMASKPROC glad_glDepthMask = NULL;
PFNGLDEPTHRANGEFPROC glad_glDepthRangef = NULL;
PFNGLDETACHSHADERPROC glad_glDetachShader = NULL;
PFNGLDISABLEPROC glad_glDisable = NULL;
PFNGLDISABLEVERTEXATTRIBARRAYPROC glad_glDisableVertexAttribArray = NULL;
PFNGLDRAWARRAYSPROC glad_glDrawArrays = NULL;
PFNGLDRAWARRAYSINSTANCEDPROC glad_glDrawArraysInstanced = NULL;
PFNGLDRAWBUFFERSPROC glad_glDrawBuffers = NULL;
PFNGLDRAWELEMENTSPROC glad_glDrawElements = NULL;
PFNGLDRAWELEMENTSINSTANCEDPROC glad_glDrawElementsInstanced = NULL;
PFNGLDRAWRANGEELEMENTSPROC glad_glDrawRangeElements = NULL;
PFNGLENABLEPROC glad_glEnable = NULL;
PFNGLENABLEVERTEXATTRIBARRAYPROC glad_glEnableVertexAttribArray = NULL;
PFNGLENDQUERYPROC glad_glEndQuery = NULL;
PFNGLENDTRANSFORMFEEDBACKPROC glad_glEndTransformFeedback = NULL;
PFNGLFENCESYNCPROC glad_glFenceSync = NULL;
PFNGLFINISHPROC glad_glFinish = NULL;
PFNGLFLUSHPROC glad_glFlush = NULL;
PFNGLFLUSHMAPPEDBUFFERRANGEPROC glad_glFlushMappedBufferRange = NULL;
PFNGLFRAMEBUFFERRENDERBUFFERPROC glad_glFramebufferRenderbuffer = NULL;
PFNGLFRAMEBUFFERTEXTURE2DPROC glad_glFramebufferTexture2D = NULL;
PFNGLFRAMEBUFFERTEXTURELAYERPROC glad_glFramebufferTextureLayer = NULL;
PFNGLFRONTFACEPROC glad_glFrontFace = NULL;
PFNGLGENBUFFERSPROC glad_glGenBuffers = NULL;
PFNGLGENFRAMEBUFFERSPROC glad_glGenFramebuffers = NULL;
PFNGLGENQUERIESPROC glad_glGenQueries = NULL;
PFNGLGENRENDERBUFFERSPROC glad_glGenRenderbuffers = NULL;
PFNGLGENSAMPLERSPROC glad_glGenSamplers = NULL;
PFNGLGENTEXTURESPROC glad_glGenTextures = NULL;
PFNGLGENTRANSFORMFEEDBACKSPROC glad_glGenTransformFeedbacks = NULL;
PFNGLGENVERTEXARRAYSPROC glad_glGenVertexArrays = NULL;
PFNGLGENERATEMIPMAPPROC glad_glGenerateMipmap = NULL;
PFNGLGETACTIVEATTRIBPROC glad_glGetActiveAttrib = NULL;
PFNGLGETACTIVEUNIFORMPROC glad_glGetActiveUniform = NULL;
PFNGLGETACTIVEUNIFORMBLOCKNAMEPROC glad_glGetActiveUniformBlockName = NULL;
PFNGLGETACTIVEUNIFORMBLOCKIVPROC glad_glGetActiveUniformBlockiv = NULL;
PFNGLGETACTIVEUNIFORMSIVPROC glad_glGetActiveUniformsiv = NULL;
PFNGLGETATTACHEDSHADERSPROC glad_glGetAttachedShaders = NULL;
PFNGLGETATTRIBLOCATIONPROC glad_glGetAttribLocation = NULL;
PFNGLGETBOOLEANVPROC glad_glGetBooleanv = NULL;
PFNGLGETBUFFERPARAMETERI64VPROC glad_glGetBufferParameteri64v = NULL;
PFNGLGETBUFFERPARAMETERIVPROC glad_glGetBufferParameteriv = NULL;
PFNGLGETBUFFERPOINTERVPROC glad_glGetBufferPointerv = NULL;
PFNGLGETERRORPROC glad_glGetError = NULL;
PFNGLGETFLOATVPROC glad_glGetFloatv = NULL;
PFNGLGETFRAGDATALOCATIONPROC glad_glGetFragDataLocation = NULL;
PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC glad_glGetFramebufferAttachmentParameteriv = NULL;
PFNGLGETINTEGER64I_VPROC glad_glGetInteger64i_v = NULL;
PFNGLGETINTEGER64VPROC glad_glGetInteger64v = NULL;
PFNGLGETINTEGERI_VPROC glad_glGetIntegeri_v = NULL;
PFNGLGETINTEGERVPROC glad_glGetIntegerv = NULL;
PFNGLGETINTERNALFORMATIVPROC glad_glGetInternalformativ = NULL;
PFNGLGETPROGRAMBINARYPROC glad_glGetProgramBinary = NULL;
PFNGLGETPROGRAMINFOLOGPROC glad_glGetProgramInfoLog = NULL;
PFNGLGETPROGRAMIVPROC glad_glGetProgramiv = NULL;
PFNGLGETQUERYOBJECTUIVPROC glad_glGetQueryObjectuiv = NULL;
PFNGLGETQUERYIVPROC glad_glGetQueryiv = NULL;
PFNGLGETRENDERBUFFERPARAMETERIVPROC glad_glGetRenderbufferParameteriv = NULL;
PFNGLGETSAMPLERPARAMETERFVPROC glad_glGetSamplerParameterfv = NULL;
PFNGLGETSAMPLERPARAMETERIVPROC glad_glGetSamplerParameteriv = NULL;
PFNGLGETSHADERINFOLOGPROC glad_glGetShaderInfoLog = NULL;
PFNGLGETSHADERPRECISIONFORMATPROC glad_glGetShaderPrecisionFormat = NULL;
PFNGLGETSHADERSOURCEPROC glad_glGetShaderSource = NULL;
PFNGLGETSHADERIVPROC glad_glGetShaderiv = NULL;
PFNGLGETSTRINGPROC glad_glGetString = NULL;
PFNGLGETSTRINGIPROC glad_glGetStringi = NULL;
PFNGLGETSYNCIVPROC glad_glGetSynciv = NULL;
PFNGLGETTEXPARAMETERFVPROC glad_glGetTexParameterfv = NULL;
PFNGLGETTEXPARAMETERIVPROC glad_glGetTexParameteriv = NULL;
PFNGLGETTRANSFORMFEEDBACKVARYINGPROC glad_glGetTransformFeedbackVarying = NULL;
PFNGLGETUNIFORMBLOCKINDEXPROC glad_glGetUniformBlockIndex = NULL;
PFNGLGETUNIFORMINDICESPROC glad_glGetUniformIndices = NULL;
PFNGLGETUNIFORMLOCATIONPROC glad_glGetUniformLocation = NULL;
PFNGLGETUNIFORMFVPROC glad_glGetUniformfv = NULL;
PFNGLGETUNIFORMIVPROC glad_glGetUniformiv = NULL;
PFNGLGETUNIFORMUIVPROC glad_glGetUniformuiv = NULL;
PFNGLGETVERTEXATTRIBIIVPROC glad_glGetVertexAttribIiv = NULL;
PFNGLGETVERTEXATTRIBIUIVPROC glad_glGetVertexAttribIuiv = NULL;
PFNGLGETVERTEXATTRIBPOINTERVPROC glad_glGetVertexAttribPointerv = NULL;
PFNGLGETVERTEXATTRIBFVPROC glad_glGetVertexAttribfv = NULL;
PFNGLGETVERTEXATTRIBIVPROC glad_glGetVertexAttribiv = NULL;
PFNGLHINTPROC glad_glHint = NULL;
PFNGLINVALIDATEFRAMEBUFFERPROC glad_glInvalidateFramebuffer = NULL;
PFNGLINVALIDATESUBFRAMEBUFFERPROC glad_glInvalidateSubFramebuffer = NULL;
PFNGLISBUFFERPROC glad_glIsBuffer = NULL;
PFNGLISENABLEDPROC glad_glIsEnabled = NULL;
PFNGLISFRAMEBUFFERPROC glad_glIsFramebuffer = NULL;
PFNGLISPROGRAMPROC glad_glIsProgram = NULL;
PFNGLISQUERYPROC glad_glIsQuery = NULL;
PFNGLISRENDERBUFFERPROC glad_glIsRenderbuffer = NULL;
PFNGLISSAMPLERPROC glad_glIsSampler = NULL;
PFNGLISSHADERPROC glad_glIsShader = NULL;
PFNGLISSYNCPROC glad_glIsSync = NULL;
PFNGLISTEXTUREPROC glad_glIsTexture = NULL;
PFNGLISTRANSFORMFEEDBACKPROC glad_glIsTransformFeedback = NULL;
PFNGLISVERTEXARRAYPROC glad_glIsVertexArray = NULL;
PFNGLLINEWIDTHPROC glad_glLineWidth = NULL;
PFNGLLINKPROGRAMPROC glad_glLinkProgram = NULL;
PFNGLMAPBUFFERRANGEPROC glad_glMapBufferRange = NULL;
PFNGLPAUSETRANSFORMFEEDBACKPROC glad_glPauseTransformFeedback = NULL;
PFNGLPIXELSTOREIPROC glad_glPixelStorei = NULL;
PFNGLPOLYGONOFFSETPROC glad_glPolygonOffset = NULL;
PFNGLPROGRAMBINARYPROC glad_glProgramBinary = NULL;
PFNGLPROGRAMPARAMETERIPROC glad_glProgramParameteri = NULL;
PFNGLREADBUFFERPROC glad_glReadBuffer = NULL;
PFNGLREADPIXELSPROC glad_glReadPixels = NULL;
PFNGLRELEASESHADERCOMPILERPROC glad_glReleaseShaderCompiler = NULL;
PFNGLRENDERBUFFERSTORAGEPROC glad_glRenderbufferStorage = NULL;
PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC glad_glRenderbufferStorageMultisample = NULL;
PFNGLRESUMETRANSFORMFEEDBACKPROC glad_glResumeTransformFeedback = NULL;
PFNGLSAMPLECOVERAGEPROC glad_glSampleCoverage = NULL;
PFNGLSAMPLERPARAMETERFPROC glad_glSamplerParameterf = NULL;
PFNGLSAMPLERPARAMETERFVPROC glad_glSamplerParameterfv = NULL;
PFNGLSAMPLERPARAMETERIPROC glad_glSamplerParameteri = NULL;
PFNGLSAMPLERPARAMETERIVPROC glad_glSamplerParameteriv = NULL;
PFNGLSCISSORPROC glad_glScissor = NULL;
PFNGLSHADERBINARYPROC glad_glShaderBinary = NULL;
PFNGLSHADERSOURCEPROC glad_glShaderSource = NULL;
PFNGLSTENCILFUNCPROC glad_glStencilFunc = NULL;
PFNGLSTENCILFUNCSEPARATEPROC glad_glStencilFuncSeparate = NULL;
PFNGLSTENCILMASKPROC glad_glStencilMask = NULL;
PFNGLSTENCILMASKSEPARATEPROC glad_glStencilMaskSeparate = NULL;
PFNGLSTENCILOPPROC glad_glStencilOp = NULL;
PFNGLSTENCILOPSEPARATEPROC glad_glStencilOpSeparate = NULL;
PFNGLTEXIMAGE2DPROC glad_glTexImage2D = NULL;
PFNGLTEXIMAGE3DPROC glad_glTexImage3D = NULL;
PFNGLTEXPARAMETERFPROC glad_glTexParameterf = NULL;
PFNGLTEXPARAMETERFVPROC glad_glTexParameterfv = NULL;
PFNGLTEXPARAMETERIPROC glad_glTexParameteri = NULL;
PFNGLTEXPARAMETERIVPROC glad_glTexParameteriv = NULL;
PFNGLTEXSTORAGE2DPROC glad_glTexStorage2D = NULL;
PFNGLTEXSTORAGE3DPROC glad_glTexStorage3D = NULL;
PFNGLTEXSUBIMAGE2DPROC glad_glTexSubImage2D = NULL;
PFNGLTEXSUBIMAGE3DPROC glad_glTexSubImage3D = NULL;
PFNGLTRANSFORMFEEDBACKVARYINGSPROC glad_glTransformFeedbackVaryings = NULL;
PFNGLUNIFORM1FPROC glad_glUniform1f = NULL;
PFNGLUNIFORM1FVPROC glad_glUniform1fv = NULL;
PFNGLUNIFORM1IPROC glad_glUniform1i = NULL;
PFNGLUNIFORM1IVPROC glad_glUniform1iv = NULL;
PFNGLUNIFORM1UIPROC glad_glUniform1ui = NULL;
PFNGLUNIFORM1UIVPROC glad_glUniform1uiv = NULL;
PFNGLUNIFORM2FPROC glad_glUniform2f = NULL;
PFNGLUNIFORM2FVPROC glad_glUniform2fv = NULL;
PFNGLUNIFORM2IPROC glad_glUniform2i = NULL;
PFNGLUNIFORM2IVPROC glad_glUniform2iv = NULL;
PFNGLUNIFORM2UIPROC glad_glUniform2ui = NULL;
PFNGLUNIFORM2UIVPROC glad_glUniform2uiv = NULL;
PFNGLUNIFORM3FPROC glad_glUniform3f = NULL;
PFNGLUNIFORM3FVPROC glad_glUniform3fv = NULL;
PFNGLUNIFORM3IPROC glad_glUniform3i = NULL;
PFNGLUNIFORM3IVPROC glad_glUniform3iv = NULL;
PFNGLUNIFORM3UIPROC glad_glUniform3ui = NULL;
PFNGLUNIFORM3UIVPROC glad_glUniform3uiv = NULL;
PFNGLUNIFORM4FPROC glad_glUniform4f = NULL;
PFNGLUNIFORM4FVPROC glad_glUniform4fv = NULL;
PFNGLUNIFORM4IPROC glad_glUniform4i = NULL;
PFNGLUNIFORM4IVPROC glad_glUniform4iv = NULL;
PFNGLUNIFORM4UIPROC glad_glUniform4ui = NULL;
PFNGLUNIFORM4UIVPROC glad_glUniform4uiv = NULL;
PFNGLUNIFORMBLOCKBINDINGPROC glad_glUniformBlockBinding = NULL;
PFNGLUNIFORMMATRIX2FVPROC glad_glUniformMatrix2fv = NULL;
PFNGLUNIFORMMATRIX2X3FVPROC glad_glUniformMatrix2x3fv = NULL;
PFNGLUNIFORMMATRIX2X4FVPROC glad_glUniformMatrix2x4fv = NULL;
PFNGLUNIFORMMATRIX3FVPROC glad_glUniformMatrix3fv = NULL;
PFNGLUNIFORMMATRIX3X2FVPROC glad_glUniformMatrix3x2fv = NULL;
PFNGLUNIFORMMATRIX3X4FVPROC glad_glUniformMatrix3x4fv = NULL;
PFNGLUNIFORMMATRIX4FVPROC glad_glUniformMatrix4fv = NULL;
PFNGLUNIFORMMATRIX4X2FVPROC glad_glUniformMatrix4x2fv = NULL;
PFNGLUNIFORMMATRIX4X3FVPROC glad_glUniformMatrix4x3fv = NULL;
PFNGLUNMAPBUFFERPROC glad_glUnmapBuffer = NULL;
PFNGLUSEPROGRAMPROC glad_glUseProgram = NULL;
PFNGLVALIDATEPROGRAMPROC glad_glValidateProgram = NULL;
PFNGLVERTEXATTRIB1FPROC glad_glVertexAttrib1f = NULL;
PFNGLVERTEXATTRIB1FVPROC glad_glVertexAttrib1fv = NULL;
PFNGLVERTEXATTRIB2FPROC glad_glVertexAttrib2f = NULL;
PFNGLVERTEXATTRIB2FVPROC glad_glVertexAttrib2fv = NULL;
PFNGLVERTEXATTRIB3FPROC glad_glVertexAttrib3f = NULL;
PFNGLVERTEXATTRIB3FVPROC glad_glVertexAttrib3fv = NULL;
PFNGLVERTEXATTRIB4FPROC glad_glVertexAttrib4f = NULL;
PFNGLVERTEXATTRIB4FVPROC glad_glVertexAttrib4fv = NULL;
PFNGLVERTEXATTRIBDIVISORPROC glad_glVertexAttribDivisor = NULL;
PFNGLVERTEXATTRIBI4IPROC glad_glVertexAttribI4i = NULL;
PFNGLVERTEXATTRIBI4IVPROC glad_glVertexAttribI4iv = NULL;
PFNGLVERTEXATTRIBI4UIPROC glad_glVertexAttribI4ui = NULL;
PFNGLVERTEXATTRIBI4UIVPROC glad_glVertexAttribI4uiv = NULL;
PFNGLVERTEXATTRIBIPOINTERPROC glad_glVertexAttribIPointer = NULL;
PFNGLVERTEXATTRIBPOINTERPROC glad_glVertexAttribPointer = NULL;
PFNGLVIEWPORTPROC glad_glViewport = NULL;
PFNGLWAITSYNCPROC glad_glWaitSync = NULL;
static void glad_gl_load_GL_ES_VERSION_2_0( GLADuserptrloadfunc load, void* userptr) {
if(!GLAD_GL_ES_VERSION_2_0) return;
glad_glActiveTexture = (PFNGLACTIVETEXTUREPROC) load(userptr, "glActiveTexture");
glad_glAttachShader = (PFNGLATTACHSHADERPROC) load(userptr, "glAttachShader");
glad_glBindAttribLocation = (PFNGLBINDATTRIBLOCATIONPROC) load(userptr, "glBindAttribLocation");
glad_glBindBuffer = (PFNGLBINDBUFFERPROC) load(userptr, "glBindBuffer");
glad_glBindFramebuffer = (PFNGLBINDFRAMEBUFFERPROC) load(userptr, "glBindFramebuffer");
glad_glBindRenderbuffer = (PFNGLBINDRENDERBUFFERPROC) load(userptr, "glBindRenderbuffer");
glad_glBindTexture = (PFNGLBINDTEXTUREPROC) load(userptr, "glBindTexture");
glad_glBlendColor = (PFNGLBLENDCOLORPROC) load(userptr, "glBlendColor");
glad_glBlendEquation = (PFNGLBLENDEQUATIONPROC) load(userptr, "glBlendEquation");
glad_glBlendEquationSeparate = (PFNGLBLENDEQUATIONSEPARATEPROC) load(userptr, "glBlendEquationSeparate");
glad_glBlendFunc = (PFNGLBLENDFUNCPROC) load(userptr, "glBlendFunc");
glad_glBlendFuncSeparate = (PFNGLBLENDFUNCSEPARATEPROC) load(userptr, "glBlendFuncSeparate");
glad_glBufferData = (PFNGLBUFFERDATAPROC) load(userptr, "glBufferData");
glad_glBufferSubData = (PFNGLBUFFERSUBDATAPROC) load(userptr, "glBufferSubData");
glad_glCheckFramebufferStatus = (PFNGLCHECKFRAMEBUFFERSTATUSPROC) load(userptr, "glCheckFramebufferStatus");
glad_glClear = (PFNGLCLEARPROC) load(userptr, "glClear");
glad_glClearColor = (PFNGLCLEARCOLORPROC) load(userptr, "glClearColor");
glad_glClearDepthf = (PFNGLCLEARDEPTHFPROC) load(userptr, "glClearDepthf");
glad_glClearStencil = (PFNGLCLEARSTENCILPROC) load(userptr, "glClearStencil");
glad_glColorMask = (PFNGLCOLORMASKPROC) load(userptr, "glColorMask");
glad_glCompileShader = (PFNGLCOMPILESHADERPROC) load(userptr, "glCompileShader");
glad_glCompressedTexImage2D = (PFNGLCOMPRESSEDTEXIMAGE2DPROC) load(userptr, "glCompressedTexImage2D");
glad_glCompressedTexSubImage2D = (PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC) load(userptr, "glCompressedTexSubImage2D");
glad_glCopyTexImage2D = (PFNGLCOPYTEXIMAGE2DPROC) load(userptr, "glCopyTexImage2D");
glad_glCopyTexSubImage2D = (PFNGLCOPYTEXSUBIMAGE2DPROC) load(userptr, "glCopyTexSubImage2D");
glad_glCreateProgram = (PFNGLCREATEPROGRAMPROC) load(userptr, "glCreateProgram");
glad_glCreateShader = (PFNGLCREATESHADERPROC) load(userptr, "glCreateShader");
glad_glCullFace = (PFNGLCULLFACEPROC) load(userptr, "glCullFace");
glad_glDeleteBuffers = (PFNGLDELETEBUFFERSPROC) load(userptr, "glDeleteBuffers");
glad_glDeleteFramebuffers = (PFNGLDELETEFRAMEBUFFERSPROC) load(userptr, "glDeleteFramebuffers");
glad_glDeleteProgram = (PFNGLDELETEPROGRAMPROC) load(userptr, "glDeleteProgram");
glad_glDeleteRenderbuffers = (PFNGLDELETERENDERBUFFERSPROC) load(userptr, "glDeleteRenderbuffers");
glad_glDeleteShader = (PFNGLDELETESHADERPROC) load(userptr, "glDeleteShader");
glad_glDeleteTextures = (PFNGLDELETETEXTURESPROC) load(userptr, "glDeleteTextures");
glad_glDepthFunc = (PFNGLDEPTHFUNCPROC) load(userptr, "glDepthFunc");
glad_glDepthMask = (PFNGLDEPTHMASKPROC) load(userptr, "glDepthMask");
glad_glDepthRangef = (PFNGLDEPTHRANGEFPROC) load(userptr, "glDepthRangef");
glad_glDetachShader = (PFNGLDETACHSHADERPROC) load(userptr, "glDetachShader");
glad_glDisable = (PFNGLDISABLEPROC) load(userptr, "glDisable");
glad_glDisableVertexAttribArray = (PFNGLDISABLEVERTEXATTRIBARRAYPROC) load(userptr, "glDisableVertexAttribArray");
glad_glDrawArrays = (PFNGLDRAWARRAYSPROC) load(userptr, "glDrawArrays");
glad_glDrawElements = (PFNGLDRAWELEMENTSPROC) load(userptr, "glDrawElements");
glad_glEnable = (PFNGLENABLEPROC) load(userptr, "glEnable");
glad_glEnableVertexAttribArray = (PFNGLENABLEVERTEXATTRIBARRAYPROC) load(userptr, "glEnableVertexAttribArray");
glad_glFinish = (PFNGLFINISHPROC) load(userptr, "glFinish");
glad_glFlush = (PFNGLFLUSHPROC) load(userptr, "glFlush");
glad_glFramebufferRenderbuffer = (PFNGLFRAMEBUFFERRENDERBUFFERPROC) load(userptr, "glFramebufferRenderbuffer");
glad_glFramebufferTexture2D = (PFNGLFRAMEBUFFERTEXTURE2DPROC) load(userptr, "glFramebufferTexture2D");
glad_glFrontFace = (PFNGLFRONTFACEPROC) load(userptr, "glFrontFace");
glad_glGenBuffers = (PFNGLGENBUFFERSPROC) load(userptr, "glGenBuffers");
glad_glGenFramebuffers = (PFNGLGENFRAMEBUFFERSPROC) load(userptr, "glGenFramebuffers");
glad_glGenRenderbuffers = (PFNGLGENRENDERBUFFERSPROC) load(userptr, "glGenRenderbuffers");
glad_glGenTextures = (PFNGLGENTEXTURESPROC) load(userptr, "glGenTextures");
glad_glGenerateMipmap = (PFNGLGENERATEMIPMAPPROC) load(userptr, "glGenerateMipmap");
glad_glGetActiveAttrib = (PFNGLGETACTIVEATTRIBPROC) load(userptr, "glGetActiveAttrib");
glad_glGetActiveUniform = (PFNGLGETACTIVEUNIFORMPROC) load(userptr, "glGetActiveUniform");
glad_glGetAttachedShaders = (PFNGLGETATTACHEDSHADERSPROC) load(userptr, "glGetAttachedShaders");
glad_glGetAttribLocation = (PFNGLGETATTRIBLOCATIONPROC) load(userptr, "glGetAttribLocation");
glad_glGetBooleanv = (PFNGLGETBOOLEANVPROC) load(userptr, "glGetBooleanv");
glad_glGetBufferParameteriv = (PFNGLGETBUFFERPARAMETERIVPROC) load(userptr, "glGetBufferParameteriv");
glad_glGetError = (PFNGLGETERRORPROC) load(userptr, "glGetError");
glad_glGetFloatv = (PFNGLGETFLOATVPROC) load(userptr, "glGetFloatv");
glad_glGetFramebufferAttachmentParameteriv = (PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC) load(userptr, "glGetFramebufferAttachmentParameteriv");
glad_glGetIntegerv = (PFNGLGETINTEGERVPROC) load(userptr, "glGetIntegerv");
glad_glGetProgramInfoLog = (PFNGLGETPROGRAMINFOLOGPROC) load(userptr, "glGetProgramInfoLog");
glad_glGetProgramiv = (PFNGLGETPROGRAMIVPROC) load(userptr, "glGetProgramiv");
glad_glGetRenderbufferParameteriv = (PFNGLGETRENDERBUFFERPARAMETERIVPROC) load(userptr, "glGetRenderbufferParameteriv");
glad_glGetShaderInfoLog = (PFNGLGETSHADERINFOLOGPROC) load(userptr, "glGetShaderInfoLog");
glad_glGetShaderPrecisionFormat = (PFNGLGETSHADERPRECISIONFORMATPROC) load(userptr, "glGetShaderPrecisionFormat");
glad_glGetShaderSource = (PFNGLGETSHADERSOURCEPROC) load(userptr, "glGetShaderSource");
glad_glGetShaderiv = (PFNGLGETSHADERIVPROC) load(userptr, "glGetShaderiv");
glad_glGetString = (PFNGLGETSTRINGPROC) load(userptr, "glGetString");
glad_glGetTexParameterfv = (PFNGLGETTEXPARAMETERFVPROC) load(userptr, "glGetTexParameterfv");
glad_glGetTexParameteriv = (PFNGLGETTEXPARAMETERIVPROC) load(userptr, "glGetTexParameteriv");
glad_glGetUniformLocation = (PFNGLGETUNIFORMLOCATIONPROC) load(userptr, "glGetUniformLocation");
glad_glGetUniformfv = (PFNGLGETUNIFORMFVPROC) load(userptr, "glGetUniformfv");
glad_glGetUniformiv = (PFNGLGETUNIFORMIVPROC) load(userptr, "glGetUniformiv");
glad_glGetVertexAttribPointerv = (PFNGLGETVERTEXATTRIBPOINTERVPROC) load(userptr, "glGetVertexAttribPointerv");
glad_glGetVertexAttribfv = (PFNGLGETVERTEXATTRIBFVPROC) load(userptr, "glGetVertexAttribfv");
glad_glGetVertexAttribiv = (PFNGLGETVERTEXATTRIBIVPROC) load(userptr, "glGetVertexAttribiv");
glad_glHint = (PFNGLHINTPROC) load(userptr, "glHint");
glad_glIsBuffer = (PFNGLISBUFFERPROC) load(userptr, "glIsBuffer");
glad_glIsEnabled = (PFNGLISENABLEDPROC) load(userptr, "glIsEnabled");
glad_glIsFramebuffer = (PFNGLISFRAMEBUFFERPROC) load(userptr, "glIsFramebuffer");
glad_glIsProgram = (PFNGLISPROGRAMPROC) load(userptr, "glIsProgram");
glad_glIsRenderbuffer = (PFNGLISRENDERBUFFERPROC) load(userptr, "glIsRenderbuffer");
glad_glIsShader = (PFNGLISSHADERPROC) load(userptr, "glIsShader");
glad_glIsTexture = (PFNGLISTEXTUREPROC) load(userptr, "glIsTexture");
glad_glLineWidth = (PFNGLLINEWIDTHPROC) load(userptr, "glLineWidth");
glad_glLinkProgram = (PFNGLLINKPROGRAMPROC) load(userptr, "glLinkProgram");
glad_glPixelStorei = (PFNGLPIXELSTOREIPROC) load(userptr, "glPixelStorei");
glad_glPolygonOffset = (PFNGLPOLYGONOFFSETPROC) load(userptr, "glPolygonOffset");
glad_glReadPixels = (PFNGLREADPIXELSPROC) load(userptr, "glReadPixels");
glad_glReleaseShaderCompiler = (PFNGLRELEASESHADERCOMPILERPROC) load(userptr, "glReleaseShaderCompiler");
glad_glRenderbufferStorage = (PFNGLRENDERBUFFERSTORAGEPROC) load(userptr, "glRenderbufferStorage");
glad_glSampleCoverage = (PFNGLSAMPLECOVERAGEPROC) load(userptr, "glSampleCoverage");
glad_glScissor = (PFNGLSCISSORPROC) load(userptr, "glScissor");
glad_glShaderBinary = (PFNGLSHADERBINARYPROC) load(userptr, "glShaderBinary");
glad_glShaderSource = (PFNGLSHADERSOURCEPROC) load(userptr, "glShaderSource");
glad_glStencilFunc = (PFNGLSTENCILFUNCPROC) load(userptr, "glStencilFunc");
glad_glStencilFuncSeparate = (PFNGLSTENCILFUNCSEPARATEPROC) load(userptr, "glStencilFuncSeparate");
glad_glStencilMask = (PFNGLSTENCILMASKPROC) load(userptr, "glStencilMask");
glad_glStencilMaskSeparate = (PFNGLSTENCILMASKSEPARATEPROC) load(userptr, "glStencilMaskSeparate");
glad_glStencilOp = (PFNGLSTENCILOPPROC) load(userptr, "glStencilOp");
glad_glStencilOpSeparate = (PFNGLSTENCILOPSEPARATEPROC) load(userptr, "glStencilOpSeparate");
glad_glTexImage2D = (PFNGLTEXIMAGE2DPROC) load(userptr, "glTexImage2D");
glad_glTexParameterf = (PFNGLTEXPARAMETERFPROC) load(userptr, "glTexParameterf");
glad_glTexParameterfv = (PFNGLTEXPARAMETERFVPROC) load(userptr, "glTexParameterfv");
glad_glTexParameteri = (PFNGLTEXPARAMETERIPROC) load(userptr, "glTexParameteri");
glad_glTexParameteriv = (PFNGLTEXPARAMETERIVPROC) load(userptr, "glTexParameteriv");
glad_glTexSubImage2D = (PFNGLTEXSUBIMAGE2DPROC) load(userptr, "glTexSubImage2D");
glad_glUniform1f = (PFNGLUNIFORM1FPROC) load(userptr, "glUniform1f");
glad_glUniform1fv = (PFNGLUNIFORM1FVPROC) load(userptr, "glUniform1fv");
glad_glUniform1i = (PFNGLUNIFORM1IPROC) load(userptr, "glUniform1i");
glad_glUniform1iv = (PFNGLUNIFORM1IVPROC) load(userptr, "glUniform1iv");
glad_glUniform2f = (PFNGLUNIFORM2FPROC) load(userptr, "glUniform2f");
glad_glUniform2fv = (PFNGLUNIFORM2FVPROC) load(userptr, "glUniform2fv");
glad_glUniform2i = (PFNGLUNIFORM2IPROC) load(userptr, "glUniform2i");
glad_glUniform2iv = (PFNGLUNIFORM2IVPROC) load(userptr, "glUniform2iv");
glad_glUniform3f = (PFNGLUNIFORM3FPROC) load(userptr, "glUniform3f");
glad_glUniform3fv = (PFNGLUNIFORM3FVPROC) load(userptr, "glUniform3fv");
glad_glUniform3i = (PFNGLUNIFORM3IPROC) load(userptr, "glUniform3i");
glad_glUniform3iv = (PFNGLUNIFORM3IVPROC) load(userptr, "glUniform3iv");
glad_glUniform4f = (PFNGLUNIFORM4FPROC) load(userptr, "glUniform4f");
glad_glUniform4fv = (PFNGLUNIFORM4FVPROC) load(userptr, "glUniform4fv");
glad_glUniform4i = (PFNGLUNIFORM4IPROC) load(userptr, "glUniform4i");
glad_glUniform4iv = (PFNGLUNIFORM4IVPROC) load(userptr, "glUniform4iv");
glad_glUniformMatrix2fv = (PFNGLUNIFORMMATRIX2FVPROC) load(userptr, "glUniformMatrix2fv");
glad_glUniformMatrix3fv = (PFNGLUNIFORMMATRIX3FVPROC) load(userptr, "glUniformMatrix3fv");
glad_glUniformMatrix4fv = (PFNGLUNIFORMMATRIX4FVPROC) load(userptr, "glUniformMatrix4fv");
glad_glUseProgram = (PFNGLUSEPROGRAMPROC) load(userptr, "glUseProgram");
glad_glValidateProgram = (PFNGLVALIDATEPROGRAMPROC) load(userptr, "glValidateProgram");
glad_glVertexAttrib1f = (PFNGLVERTEXATTRIB1FPROC) load(userptr, "glVertexAttrib1f");
glad_glVertexAttrib1fv = (PFNGLVERTEXATTRIB1FVPROC) load(userptr, "glVertexAttrib1fv");
glad_glVertexAttrib2f = (PFNGLVERTEXATTRIB2FPROC) load(userptr, "glVertexAttrib2f");
glad_glVertexAttrib2fv = (PFNGLVERTEXATTRIB2FVPROC) load(userptr, "glVertexAttrib2fv");
glad_glVertexAttrib3f = (PFNGLVERTEXATTRIB3FPROC) load(userptr, "glVertexAttrib3f");
glad_glVertexAttrib3fv = (PFNGLVERTEXATTRIB3FVPROC) load(userptr, "glVertexAttrib3fv");
glad_glVertexAttrib4f = (PFNGLVERTEXATTRIB4FPROC) load(userptr, "glVertexAttrib4f");
glad_glVertexAttrib4fv = (PFNGLVERTEXATTRIB4FVPROC) load(userptr, "glVertexAttrib4fv");
glad_glVertexAttribPointer = (PFNGLVERTEXATTRIBPOINTERPROC) load(userptr, "glVertexAttribPointer");
glad_glViewport = (PFNGLVIEWPORTPROC) load(userptr, "glViewport");
}
static void glad_gl_load_GL_ES_VERSION_3_0( GLADuserptrloadfunc load, void* userptr) {
if(!GLAD_GL_ES_VERSION_3_0) return;
glad_glBeginQuery = (PFNGLBEGINQUERYPROC) load(userptr, "glBeginQuery");
glad_glBeginTransformFeedback = (PFNGLBEGINTRANSFORMFEEDBACKPROC) load(userptr, "glBeginTransformFeedback");
glad_glBindBufferBase = (PFNGLBINDBUFFERBASEPROC) load(userptr, "glBindBufferBase");
glad_glBindBufferRange = (PFNGLBINDBUFFERRANGEPROC) load(userptr, "glBindBufferRange");
glad_glBindSampler = (PFNGLBINDSAMPLERPROC) load(userptr, "glBindSampler");
glad_glBindTransformFeedback = (PFNGLBINDTRANSFORMFEEDBACKPROC) load(userptr, "glBindTransformFeedback");
glad_glBindVertexArray = (PFNGLBINDVERTEXARRAYPROC) load(userptr, "glBindVertexArray");
glad_glBlitFramebuffer = (PFNGLBLITFRAMEBUFFERPROC) load(userptr, "glBlitFramebuffer");
glad_glClearBufferfi = (PFNGLCLEARBUFFERFIPROC) load(userptr, "glClearBufferfi");
glad_glClearBufferfv = (PFNGLCLEARBUFFERFVPROC) load(userptr, "glClearBufferfv");
glad_glClearBufferiv = (PFNGLCLEARBUFFERIVPROC) load(userptr, "glClearBufferiv");
glad_glClearBufferuiv = (PFNGLCLEARBUFFERUIVPROC) load(userptr, "glClearBufferuiv");
glad_glClientWaitSync = (PFNGLCLIENTWAITSYNCPROC) load(userptr, "glClientWaitSync");
glad_glCompressedTexImage3D = (PFNGLCOMPRESSEDTEXIMAGE3DPROC) load(userptr, "glCompressedTexImage3D");
glad_glCompressedTexSubImage3D = (PFNGLCOMPRESSEDTEXSUBIMAGE3DPROC) load(userptr, "glCompressedTexSubImage3D");
glad_glCopyBufferSubData = (PFNGLCOPYBUFFERSUBDATAPROC) load(userptr, "glCopyBufferSubData");
glad_glCopyTexSubImage3D = (PFNGLCOPYTEXSUBIMAGE3DPROC) load(userptr, "glCopyTexSubImage3D");
glad_glDeleteQueries = (PFNGLDELETEQUERIESPROC) load(userptr, "glDeleteQueries");
glad_glDeleteSamplers = (PFNGLDELETESAMPLERSPROC) load(userptr, "glDeleteSamplers");
glad_glDeleteSync = (PFNGLDELETESYNCPROC) load(userptr, "glDeleteSync");
glad_glDeleteTransformFeedbacks = (PFNGLDELETETRANSFORMFEEDBACKSPROC) load(userptr, "glDeleteTransformFeedbacks");
glad_glDeleteVertexArrays = (PFNGLDELETEVERTEXARRAYSPROC) load(userptr, "glDeleteVertexArrays");
glad_glDrawArraysInstanced = (PFNGLDRAWARRAYSINSTANCEDPROC) load(userptr, "glDrawArraysInstanced");
glad_glDrawBuffers = (PFNGLDRAWBUFFERSPROC) load(userptr, "glDrawBuffers");
glad_glDrawElementsInstanced = (PFNGLDRAWELEMENTSINSTANCEDPROC) load(userptr, "glDrawElementsInstanced");
glad_glDrawRangeElements = (PFNGLDRAWRANGEELEMENTSPROC) load(userptr, "glDrawRangeElements");
glad_glEndQuery = (PFNGLENDQUERYPROC) load(userptr, "glEndQuery");
glad_glEndTransformFeedback = (PFNGLENDTRANSFORMFEEDBACKPROC) load(userptr, "glEndTransformFeedback");
glad_glFenceSync = (PFNGLFENCESYNCPROC) load(userptr, "glFenceSync");
glad_glFlushMappedBufferRange = (PFNGLFLUSHMAPPEDBUFFERRANGEPROC) load(userptr, "glFlushMappedBufferRange");
glad_glFramebufferTextureLayer = (PFNGLFRAMEBUFFERTEXTURELAYERPROC) load(userptr, "glFramebufferTextureLayer");
glad_glGenQueries = (PFNGLGENQUERIESPROC) load(userptr, "glGenQueries");
glad_glGenSamplers = (PFNGLGENSAMPLERSPROC) load(userptr, "glGenSamplers");
glad_glGenTransformFeedbacks = (PFNGLGENTRANSFORMFEEDBACKSPROC) load(userptr, "glGenTransformFeedbacks");
glad_glGenVertexArrays = (PFNGLGENVERTEXARRAYSPROC) load(userptr, "glGenVertexArrays");
glad_glGetActiveUniformBlockName = (PFNGLGETACTIVEUNIFORMBLOCKNAMEPROC) load(userptr, "glGetActiveUniformBlockName");
glad_glGetActiveUniformBlockiv = (PFNGLGETACTIVEUNIFORMBLOCKIVPROC) load(userptr, "glGetActiveUniformBlockiv");
glad_glGetActiveUniformsiv = (PFNGLGETACTIVEUNIFORMSIVPROC) load(userptr, "glGetActiveUniformsiv");
glad_glGetBufferParameteri64v = (PFNGLGETBUFFERPARAMETERI64VPROC) load(userptr, "glGetBufferParameteri64v");
glad_glGetBufferPointerv = (PFNGLGETBUFFERPOINTERVPROC) load(userptr, "glGetBufferPointerv");
glad_glGetFragDataLocation = (PFNGLGETFRAGDATALOCATIONPROC) load(userptr, "glGetFragDataLocation");
glad_glGetInteger64i_v = (PFNGLGETINTEGER64I_VPROC) load(userptr, "glGetInteger64i_v");
glad_glGetInteger64v = (PFNGLGETINTEGER64VPROC) load(userptr, "glGetInteger64v");
glad_glGetIntegeri_v = (PFNGLGETINTEGERI_VPROC) load(userptr, "glGetIntegeri_v");
glad_glGetInternalformativ = (PFNGLGETINTERNALFORMATIVPROC) load(userptr, "glGetInternalformativ");
glad_glGetProgramBinary = (PFNGLGETPROGRAMBINARYPROC) load(userptr, "glGetProgramBinary");
glad_glGetQueryObjectuiv = (PFNGLGETQUERYOBJECTUIVPROC) load(userptr, "glGetQueryObjectuiv");
glad_glGetQueryiv = (PFNGLGETQUERYIVPROC) load(userptr, "glGetQueryiv");
glad_glGetSamplerParameterfv = (PFNGLGETSAMPLERPARAMETERFVPROC) load(userptr, "glGetSamplerParameterfv");
glad_glGetSamplerParameteriv = (PFNGLGETSAMPLERPARAMETERIVPROC) load(userptr, "glGetSamplerParameteriv");
glad_glGetStringi = (PFNGLGETSTRINGIPROC) load(userptr, "glGetStringi");
glad_glGetSynciv = (PFNGLGETSYNCIVPROC) load(userptr, "glGetSynciv");
glad_glGetTransformFeedbackVarying = (PFNGLGETTRANSFORMFEEDBACKVARYINGPROC) load(userptr, "glGetTransformFeedbackVarying");
glad_glGetUniformBlockIndex = (PFNGLGETUNIFORMBLOCKINDEXPROC) load(userptr, "glGetUniformBlockIndex");
glad_glGetUniformIndices = (PFNGLGETUNIFORMINDICESPROC) load(userptr, "glGetUniformIndices");
glad_glGetUniformuiv = (PFNGLGETUNIFORMUIVPROC) load(userptr, "glGetUniformuiv");
glad_glGetVertexAttribIiv = (PFNGLGETVERTEXATTRIBIIVPROC) load(userptr, "glGetVertexAttribIiv");
glad_glGetVertexAttribIuiv = (PFNGLGETVERTEXATTRIBIUIVPROC) load(userptr, "glGetVertexAttribIuiv");
glad_glInvalidateFramebuffer = (PFNGLINVALIDATEFRAMEBUFFERPROC) load(userptr, "glInvalidateFramebuffer");
glad_glInvalidateSubFramebuffer = (PFNGLINVALIDATESUBFRAMEBUFFERPROC) load(userptr, "glInvalidateSubFramebuffer");
glad_glIsQuery = (PFNGLISQUERYPROC) load(userptr, "glIsQuery");
glad_glIsSampler = (PFNGLISSAMPLERPROC) load(userptr, "glIsSampler");
glad_glIsSync = (PFNGLISSYNCPROC) load(userptr, "glIsSync");
glad_glIsTransformFeedback = (PFNGLISTRANSFORMFEEDBACKPROC) load(userptr, "glIsTransformFeedback");
glad_glIsVertexArray = (PFNGLISVERTEXARRAYPROC) load(userptr, "glIsVertexArray");
glad_glMapBufferRange = (PFNGLMAPBUFFERRANGEPROC) load(userptr, "glMapBufferRange");
glad_glPauseTransformFeedback = (PFNGLPAUSETRANSFORMFEEDBACKPROC) load(userptr, "glPauseTransformFeedback");
glad_glProgramBinary = (PFNGLPROGRAMBINARYPROC) load(userptr, "glProgramBinary");
glad_glProgramParameteri = (PFNGLPROGRAMPARAMETERIPROC) load(userptr, "glProgramParameteri");
glad_glReadBuffer = (PFNGLREADBUFFERPROC) load(userptr, "glReadBuffer");
glad_glRenderbufferStorageMultisample = (PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC) load(userptr, "glRenderbufferStorageMultisample");
glad_glResumeTransformFeedback = (PFNGLRESUMETRANSFORMFEEDBACKPROC) load(userptr, "glResumeTransformFeedback");
glad_glSamplerParameterf = (PFNGLSAMPLERPARAMETERFPROC) load(userptr, "glSamplerParameterf");
glad_glSamplerParameterfv = (PFNGLSAMPLERPARAMETERFVPROC) load(userptr, "glSamplerParameterfv");
glad_glSamplerParameteri = (PFNGLSAMPLERPARAMETERIPROC) load(userptr, "glSamplerParameteri");
glad_glSamplerParameteriv = (PFNGLSAMPLERPARAMETERIVPROC) load(userptr, "glSamplerParameteriv");
glad_glTexImage3D = (PFNGLTEXIMAGE3DPROC) load(userptr, "glTexImage3D");
glad_glTexStorage2D = (PFNGLTEXSTORAGE2DPROC) load(userptr, "glTexStorage2D");
glad_glTexStorage3D = (PFNGLTEXSTORAGE3DPROC) load(userptr, "glTexStorage3D");
glad_glTexSubImage3D = (PFNGLTEXSUBIMAGE3DPROC) load(userptr, "glTexSubImage3D");
glad_glTransformFeedbackVaryings = (PFNGLTRANSFORMFEEDBACKVARYINGSPROC) load(userptr, "glTransformFeedbackVaryings");
glad_glUniform1ui = (PFNGLUNIFORM1UIPROC) load(userptr, "glUniform1ui");
glad_glUniform1uiv = (PFNGLUNIFORM1UIVPROC) load(userptr, "glUniform1uiv");
glad_glUniform2ui = (PFNGLUNIFORM2UIPROC) load(userptr, "glUniform2ui");
glad_glUniform2uiv = (PFNGLUNIFORM2UIVPROC) load(userptr, "glUniform2uiv");
glad_glUniform3ui = (PFNGLUNIFORM3UIPROC) load(userptr, "glUniform3ui");
glad_glUniform3uiv = (PFNGLUNIFORM3UIVPROC) load(userptr, "glUniform3uiv");
glad_glUniform4ui = (PFNGLUNIFORM4UIPROC) load(userptr, "glUniform4ui");
glad_glUniform4uiv = (PFNGLUNIFORM4UIVPROC) load(userptr, "glUniform4uiv");
glad_glUniformBlockBinding = (PFNGLUNIFORMBLOCKBINDINGPROC) load(userptr, "glUniformBlockBinding");
glad_glUniformMatrix2x3fv = (PFNGLUNIFORMMATRIX2X3FVPROC) load(userptr, "glUniformMatrix2x3fv");
glad_glUniformMatrix2x4fv = (PFNGLUNIFORMMATRIX2X4FVPROC) load(userptr, "glUniformMatrix2x4fv");
glad_glUniformMatrix3x2fv = (PFNGLUNIFORMMATRIX3X2FVPROC) load(userptr, "glUniformMatrix3x2fv");
glad_glUniformMatrix3x4fv = (PFNGLUNIFORMMATRIX3X4FVPROC) load(userptr, "glUniformMatrix3x4fv");
glad_glUniformMatrix4x2fv = (PFNGLUNIFORMMATRIX4X2FVPROC) load(userptr, "glUniformMatrix4x2fv");
glad_glUniformMatrix4x3fv = (PFNGLUNIFORMMATRIX4X3FVPROC) load(userptr, "glUniformMatrix4x3fv");
glad_glUnmapBuffer = (PFNGLUNMAPBUFFERPROC) load(userptr, "glUnmapBuffer");
glad_glVertexAttribDivisor = (PFNGLVERTEXATTRIBDIVISORPROC) load(userptr, "glVertexAttribDivisor");
glad_glVertexAttribI4i = (PFNGLVERTEXATTRIBI4IPROC) load(userptr, "glVertexAttribI4i");
glad_glVertexAttribI4iv = (PFNGLVERTEXATTRIBI4IVPROC) load(userptr, "glVertexAttribI4iv");
glad_glVertexAttribI4ui = (PFNGLVERTEXATTRIBI4UIPROC) load(userptr, "glVertexAttribI4ui");
glad_glVertexAttribI4uiv = (PFNGLVERTEXATTRIBI4UIVPROC) load(userptr, "glVertexAttribI4uiv");
glad_glVertexAttribIPointer = (PFNGLVERTEXATTRIBIPOINTERPROC) load(userptr, "glVertexAttribIPointer");
glad_glWaitSync = (PFNGLWAITSYNCPROC) load(userptr, "glWaitSync");
}
static void glad_gl_free_extensions(char **exts_i) {
if (exts_i != NULL) {
unsigned int index;
for(index = 0; exts_i[index]; index++) {
free((void *) (exts_i[index]));
}
free((void *)exts_i);
exts_i = NULL;
}
}
static int glad_gl_get_extensions( const char **out_exts, char ***out_exts_i) {
#if defined(GL_ES_VERSION_3_0) || defined(GL_VERSION_3_0)
if (glad_glGetStringi != NULL && glad_glGetIntegerv != NULL) {
unsigned int index = 0;
unsigned int num_exts_i = 0;
char **exts_i = NULL;
glad_glGetIntegerv(GL_NUM_EXTENSIONS, (int*) &num_exts_i);
exts_i = (char **) malloc((num_exts_i + 1) * (sizeof *exts_i));
if (exts_i == NULL) {
return 0;
}
for(index = 0; index < num_exts_i; index++) {
const char *gl_str_tmp = (const char*) glad_glGetStringi(GL_EXTENSIONS, index);
size_t len = strlen(gl_str_tmp) + 1;
char *local_str = (char*) malloc(len * sizeof(char));
if(local_str == NULL) {
exts_i[index] = NULL;
glad_gl_free_extensions(exts_i);
return 0;
}
memcpy(local_str, gl_str_tmp, len * sizeof(char));
exts_i[index] = local_str;
}
exts_i[index] = NULL;
*out_exts_i = exts_i;
return 1;
}
#else
GLAD_UNUSED(out_exts_i);
#endif
if (glad_glGetString == NULL) {
return 0;
}
*out_exts = (const char *)glad_glGetString(GL_EXTENSIONS);
return 1;
}
static int glad_gl_has_extension(const char *exts, char **exts_i, const char *ext) {
if(exts_i) {
unsigned int index;
for(index = 0; exts_i[index]; index++) {
const char *e = exts_i[index];
if(strcmp(e, ext) == 0) {
return 1;
}
}
} else {
const char *extensions;
const char *loc;
const char *terminator;
extensions = exts;
if(extensions == NULL || ext == NULL) {
return 0;
}
while(1) {
loc = strstr(extensions, ext);
if(loc == NULL) {
return 0;
}
terminator = loc + strlen(ext);
if((loc == extensions || *(loc - 1) == ' ') &&
(*terminator == ' ' || *terminator == '\0')) {
return 1;
}
extensions = terminator;
}
}
return 0;
}
static GLADapiproc glad_gl_get_proc_from_userptr(void *userptr, const char* name) {
return (GLAD_GNUC_EXTENSION (GLADapiproc (*)(const char *name)) userptr)(name);
}
static int glad_gl_find_extensions_gles2(void) {
const char *exts = NULL;
char **exts_i = NULL;
if (!glad_gl_get_extensions(&exts, &exts_i)) return 0;
GLAD_UNUSED(glad_gl_has_extension);
glad_gl_free_extensions(exts_i);
return 1;
}
static int glad_gl_find_core_gles2(void) {
int i;
const char* version;
const char* prefixes[] = {
"OpenGL ES-CM ",
"OpenGL ES-CL ",
"OpenGL ES ",
"OpenGL SC ",
NULL
};
int major = 0;
int minor = 0;
version = (const char*) glad_glGetString(GL_VERSION);
if (!version) return 0;
for (i = 0; prefixes[i]; i++) {
const size_t length = strlen(prefixes[i]);
if (strncmp(version, prefixes[i], length) == 0) {
version += length;
break;
}
}
GLAD_IMPL_UTIL_SSCANF(version, "%d.%d", &major, &minor);
GLAD_GL_ES_VERSION_2_0 = (major == 2 && minor >= 0) || major > 2;
GLAD_GL_ES_VERSION_3_0 = (major == 3 && minor >= 0) || major > 3;
return GLAD_MAKE_VERSION(major, minor);
}
int gladLoadGLES2UserPtr( GLADuserptrloadfunc load, void *userptr) {
int version;
glad_glGetString = (PFNGLGETSTRINGPROC) load(userptr, "glGetString");
if(glad_glGetString == NULL) return 0;
version = glad_gl_find_core_gles2();
glad_gl_load_GL_ES_VERSION_2_0(load, userptr);
glad_gl_load_GL_ES_VERSION_3_0(load, userptr);
if (!glad_gl_find_extensions_gles2()) return 0;
return version;
}
int gladLoadGLES2( GLADloadfunc load) {
return gladLoadGLES2UserPtr( glad_gl_get_proc_from_userptr, GLAD_GNUC_EXTENSION (void*) load);
}
#ifdef GLAD_GLES2
#ifndef GLAD_LOADER_LIBRARY_C_
#define GLAD_LOADER_LIBRARY_C_
#include <stddef.h>
#include <stdlib.h>
#if GLAD_PLATFORM_WIN32
#include <windows.h>
#else
#include <dlfcn.h>
#endif
static void* glad_get_dlopen_handle(const char *lib_names[], int length) {
void *handle = NULL;
int i;
for (i = 0; i < length; ++i) {
#if GLAD_PLATFORM_WIN32
#if GLAD_PLATFORM_UWP
size_t buffer_size = (strlen(lib_names[i]) + 1) * sizeof(WCHAR);
LPWSTR buffer = (LPWSTR) malloc(buffer_size);
if (buffer != NULL) {
int ret = MultiByteToWideChar(CP_ACP, 0, lib_names[i], -1, buffer, buffer_size);
if (ret != 0) {
handle = (void*) LoadPackagedLibrary(buffer, 0);
}
free((void*) buffer);
}
#else
handle = (void*) LoadLibraryA(lib_names[i]);
#endif
#else
handle = dlopen(lib_names[i], RTLD_LAZY | RTLD_LOCAL);
#endif
if (handle != NULL) {
return handle;
}
}
return NULL;
}
static void glad_close_dlopen_handle(void* handle) {
if (handle != NULL) {
#if GLAD_PLATFORM_WIN32
FreeLibrary((HMODULE) handle);
#else
dlclose(handle);
#endif
}
}
static GLADapiproc glad_dlsym_handle(void* handle, const char *name) {
if (handle == NULL) {
return NULL;
}
#if GLAD_PLATFORM_WIN32
return (GLADapiproc) GetProcAddress((HMODULE) handle, name);
#else
return GLAD_GNUC_EXTENSION (GLADapiproc) dlsym(handle, name);
#endif
}
#endif /* GLAD_LOADER_LIBRARY_C_ */
#if GLAD_PLATFORM_EMSCRIPTEN
#ifndef GLAD_EGL_H_
typedef void (*__eglMustCastToProperFunctionPointerType)(void);
typedef __eglMustCastToProperFunctionPointerType (GLAD_API_PTR *PFNEGLGETPROCADDRESSPROC)(const char *name);
#endif
extern __eglMustCastToProperFunctionPointerType emscripten_GetProcAddress(const char *name);
#elif GLAD_GLES2_USE_SYSTEM_EGL
#include <EGL/egl.h>
typedef __eglMustCastToProperFunctionPointerType (GLAD_API_PTR *PFNEGLGETPROCADDRESSPROC)(const char *name);
#else
#include <glad/egl.h>
#endif
struct _glad_gles2_userptr {
void *handle;
PFNEGLGETPROCADDRESSPROC get_proc_address_ptr;
};
static GLADapiproc glad_gles2_get_proc(void *vuserptr, const char* name) {
struct _glad_gles2_userptr userptr = *(struct _glad_gles2_userptr*) vuserptr;
GLADapiproc result = NULL;
#if GLAD_PLATFORM_EMSCRIPTEN
GLAD_UNUSED(glad_dlsym_handle);
#else
result = glad_dlsym_handle(userptr.handle, name);
#endif
if (result == NULL) {
result = userptr.get_proc_address_ptr(name);
}
return result;
}
static void* _glad_GLES2_loader_handle = NULL;
static void* glad_gles2_dlopen_handle(void) {
#if GLAD_PLATFORM_EMSCRIPTEN
#elif GLAD_PLATFORM_APPLE
static const char *NAMES[] = {"libGLESv2.dylib"};
#elif GLAD_PLATFORM_WIN32
static const char *NAMES[] = {"GLESv2.dll", "libGLESv2.dll"};
#else
static const char *NAMES[] = {"libGLESv2.so.2", "libGLESv2.so"};
#endif
#if GLAD_PLATFORM_EMSCRIPTEN
GLAD_UNUSED(glad_get_dlopen_handle);
return NULL;
#else
if (_glad_GLES2_loader_handle == NULL) {
_glad_GLES2_loader_handle = glad_get_dlopen_handle(NAMES, sizeof(NAMES) / sizeof(NAMES[0]));
}
return _glad_GLES2_loader_handle;
#endif
}
static struct _glad_gles2_userptr glad_gles2_build_userptr(void *handle) {
struct _glad_gles2_userptr userptr;
#if GLAD_PLATFORM_EMSCRIPTEN
GLAD_UNUSED(handle);
userptr.get_proc_address_ptr = emscripten_GetProcAddress;
#else
userptr.handle = handle;
userptr.get_proc_address_ptr = eglGetProcAddress;
#endif
return userptr;
}
int gladLoaderLoadGLES2(void) {
int version = 0;
void *handle = NULL;
int did_load = 0;
struct _glad_gles2_userptr userptr;
#if GLAD_PLATFORM_EMSCRIPTEN
GLAD_UNUSED(handle);
GLAD_UNUSED(did_load);
GLAD_UNUSED(glad_gles2_dlopen_handle);
GLAD_UNUSED(glad_gles2_build_userptr);
userptr.get_proc_address_ptr = emscripten_GetProcAddress;
version = gladLoadGLES2UserPtr(glad_gles2_get_proc, &userptr);
#else
if (eglGetProcAddress == NULL) {
return 0;
}
did_load = _glad_GLES2_loader_handle == NULL;
handle = glad_gles2_dlopen_handle();
if (handle != NULL) {
userptr = glad_gles2_build_userptr(handle);
version = gladLoadGLES2UserPtr(glad_gles2_get_proc, &userptr);
if (!version && did_load) {
gladLoaderUnloadGLES2();
}
}
#endif
return version;
}
void gladLoaderUnloadGLES2(void) {
if (_glad_GLES2_loader_handle != NULL) {
glad_close_dlopen_handle(_glad_GLES2_loader_handle);
_glad_GLES2_loader_handle = NULL;
}
}
#endif /* GLAD_GLES2 */
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,22 @@
///|/ Copyright (c) Prusa Research 2023 Enrico Turri @enricoturri1966, Pavel Mikuš @Godrak
///|/
///|/ libvgcode is released under the terms of the AGPLv3 or higher
///|/
#ifndef VGCODE_COLORPRINT_HPP
#define VGCODE_COLORPRINT_HPP
#include "../include/Types.hpp"
namespace libvgcode {
struct ColorPrint
{
uint8_t extruder_id{ 0 };
uint8_t color_id{ 0 };
uint32_t layer_id{ 0 };
std::array<float, TIME_MODES_COUNT> times{ 0.0f, 0.0f };
};
} // namespace libvgcode
#endif // VGCODE_COLORPRINT_HPP

View File

@@ -0,0 +1,107 @@
///|/ Copyright (c) Prusa Research 2023 Enrico Turri @enricoturri1966, Pavel Mikuš @Godrak
///|/
///|/ libvgcode is released under the terms of the AGPLv3 or higher
///|/
#ifndef VGCODE_COLORRANGE_HPP
#define VGCODE_COLORRANGE_HPP
#include "../include/Types.hpp"
#include <cfloat>
namespace libvgcode {
static const Palette DEFAULT_RANGES_COLORS{ {
{ 11, 44, 122 }, // bluish
{ 19, 89, 133 },
{ 28, 136, 145 },
{ 4, 214, 15 },
{ 170, 242, 0 },
{ 252, 249, 3 },
{ 245, 206, 10 },
{ 227, 136, 32 },
{ 209, 104, 48 },
{ 194, 82, 60 },
{ 148, 38, 22 } // reddish
} };
class ColorRange
{
public:
//
// Constructor
//
explicit ColorRange(EColorRangeType type = EColorRangeType::Linear);
//
// Return the type of this ColorRange.
//
EColorRangeType get_type() const;
//
// Return the palette used by this ColorRange.
// Default is DEFAULT_RANGES_COLORS
//
const Palette& get_palette() const;
//
// Set the palette to be used by this ColorRange.
// The given palette must contain at least two colors.
//
void set_palette(const Palette& palette);
//
// Return the interpolated color at the given value.
// Value is clamped to [get_range()[0]..get_range()[1]].
//
Color get_color_at(float value) const;
//
// Return the range of this ColorRange.
// The range is detected during the call to Viewer::load().
// [0] -> min
// [1] -> max
//
const std::array<float, 2>& get_range() const;
//
// Return the values corresponding to the detected color bins of this ColorRange.
// The size of the returned vector can be:
// 1 - If only one value was detected while setting up this ColorRange.
// 2 - If only two values were detected while setting up this ColorRange.
// get_palette().size() - If more than two distinct values were detected while setting up this ColorRange.
//
std::vector<float> get_values() const;
//
// Return the size of the palette, in bytes
//
std::size_t size_in_bytes_cpu() const;
static const ColorRange DUMMY_COLOR_RANGE;
private:
EColorRangeType m_type{ EColorRangeType::Linear };
//
// The palette used by this ColorRange
//
Palette m_palette;
//
// [0] = min
// [1] = max
//
std::array<float, 2> m_range{ FLT_MAX, -FLT_MAX };
//
// Count of different values passed to update()
//
std::size_t m_count{ 0 };
//
// Use the passed value to update the range.
//
void update(float value);
//
// Reset the range
// Call this method before reuse an instance of ColorRange.
//
void reset();
friend class ViewerImpl;
};
} // namespace libvgcode
#endif // VGCODE_COLORRANGE_HPP

View File

@@ -0,0 +1,36 @@
///|/ Copyright (c) Prusa Research 2023 Enrico Turri @enricoturri1966
///|/
///|/ libvgcode is released under the terms of the AGPLv3 or higher
///|/
#ifndef VGCODE_GCODEINPUTDATA_HPP
#define VGCODE_GCODEINPUTDATA_HPP
#include "PathVertex.hpp"
namespace libvgcode {
struct GCodeInputData
{
//
// Whether or not the gcode was generated with spiral vase mode enabled.
// Required to properly detect fictitious layer changes when spiral vase mode is enabled.
//
bool spiral_vase_mode{ false };
//
// List of path vertices (gcode moves)
// See: PathVertex
//
std::vector<PathVertex> vertices;
//
// Palette for extruders colors
//
Palette tools_colors;
//
// Palette for color print colors
//
Palette color_print_colors;
};
} // namespace libvgcode
#endif // VGCODE_BITSET_HPP

View File

@@ -0,0 +1,121 @@
///|/ Copyright (c) Prusa Research 2023 Enrico Turri @enricoturri1966, Pavel Mikuš @Godrak
///|/
///|/ libvgcode is released under the terms of the AGPLv3 or higher
///|/
#ifndef VGCODE_PATHVERTEX_HPP
#define VGCODE_PATHVERTEX_HPP
#include "Types.hpp"
#include <cfloat>
namespace libvgcode {
//
// Struct representating a gcode move (toolpath segment)
//
struct PathVertex
{
//
// Segment end position
//
Vec3 position{ FLT_MAX, FLT_MAX, FLT_MAX };
//
// Segment height
//
float height{ 0.0f };
//
// Segment width
//
float width{ 0.0f };
//
// Segment speed
//
float feedrate{ 0.0f };
//
// Segment actual speed
//
float actual_feedrate{ 0.0f };
//
// Segment mm3_per_mm
//
float mm3_per_mm{ 0.0f };
//
// Segment fan speed
//
float fan_speed{ 0.0f };
//
// Segment temperature
//
float temperature{ 0.0f };
#if VGCODE_ENABLE_COG_AND_TOOL_MARKERS
//
// Segment weight
//
float weight{ 0.0f };
#endif // VGCODE_ENABLE_COG_AND_TOOL_MARKERS
//
// Segment extrusion role
//
EGCodeExtrusionRole role{ EGCodeExtrusionRole::None };
//
// Segment move type
//
EMoveType type{ EMoveType::Noop };
//
// Segment gcode line id
//
uint32_t gcode_id{ 0 };
//
// Segment layer id
//
uint32_t layer_id{ 0 };
//
// Segment extruder id
//
uint8_t extruder_id{ 0 };
//
// Segment color id
//
uint8_t color_id{ 0 };
//
// Segment estimated times
//
std::array<float, TIME_MODES_COUNT> times{ 0.0f, 0.0f };
//
// Return true if the segment is an extrusion move
//
bool is_extrusion() const;
//
// Return true if the segment is an travel move
//
bool is_travel() const;
//
// Return true if the segment is an option
// See: EOptionType
//
bool is_option() const;
//
// Return true if the segment is a wipe move
//
bool is_wipe() const;
//
// Return true if the segment was generated by custom gcode
//
bool is_custom_gcode() const;
//
// Return the volumetric flow rate of the segment
//
float volumetric_rate() const { return feedrate * mm3_per_mm; }
//
// Return the acutal volumetric flow rate of the segment
//
float actual_volumetric_rate() const { return actual_feedrate * mm3_per_mm; }
static const PathVertex DUMMY_PATH_VERTEX;
};
} // namespace libvgcode
#endif // VGCODE_PATHVERTEX_HPP

View File

@@ -0,0 +1,218 @@
///|/ Copyright (c) Prusa Research 2023 Enrico Turri @enricoturri1966, Pavel Mikuš @Godrak
///|/
///|/ libvgcode is released under the terms of the AGPLv3 or higher
///|/
#ifndef VGCODE_TYPES_HPP
#define VGCODE_TYPES_HPP
#define VGCODE_ENABLE_COG_AND_TOOL_MARKERS 0
#include <array>
#include <vector>
#include <cstdint>
namespace libvgcode {
static constexpr float PI = 3.141592f;
//
// Predefined values for the radius, in mm, of the cylinders used to render the travel moves.
//
static constexpr float DEFAULT_TRAVELS_RADIUS_MM = 0.1f;
static constexpr float MIN_TRAVELS_RADIUS_MM = 0.05f;
static constexpr float MAX_TRAVELS_RADIUS_MM = 1.0f;
//
// Predefined values for the radius, in mm, of the cylinders used to render the wipe moves.
//
static constexpr float DEFAULT_WIPES_RADIUS_MM = 0.1f;
static constexpr float MIN_WIPES_RADIUS_MM = 0.05f;
static constexpr float MAX_WIPES_RADIUS_MM = 1.0f;
//
// Vector in 3 dimensions
// [0] -> x
// [1] -> y
// [2] -> z
// Used for positions, displacements and so on.
//
using Vec3 = std::array<float, 3>;
//
// 4x4 square matrix with elements in column-major order:
// | a[0] a[4] a[8] a[12] |
// | a[1] a[5] a[9] a[13] |
// | a[2] a[6] a[10] a[14] |
// | a[3] a[7] a[11] a[15] |
//
using Mat4x4 = std::array<float, 16>;
//
// RGB color
// [0] -> red
// [1] -> green
// [2] -> blue
//
using Color = std::array<uint8_t, 3>;
//
// Color palette
//
using Palette = std::vector<Color>;
//
// Axis aligned box in 3 dimensions
// [0] -> { min_x, min_y, min_z }
// [1] -> { max_x, max_y, max_z }
//
using AABox = std::array<Vec3, 2>;
//
// One dimensional natural numbers interval
// [0] -> min
// [1] -> max
//
using Interval = std::array<std::size_t, 2>;
//
// View types
//
enum class EViewType : uint8_t
{
FeatureType,
Height,
Width,
Speed,
ActualSpeed,
FanSpeed,
Temperature,
VolumetricFlowRate,
ActualVolumetricFlowRate,
LayerTimeLinear,
LayerTimeLogarithmic,
Tool,
ColorPrint,
COUNT
};
static constexpr std::size_t VIEW_TYPES_COUNT = static_cast<std::size_t>(EViewType::COUNT);
//
// Move types
//
enum class EMoveType : uint8_t
{
Noop,
Retract,
Unretract,
Seam,
ToolChange,
ColorChange,
PausePrint,
CustomGCode,
Travel,
Wipe,
Extrude,
COUNT
};
static constexpr std::size_t MOVE_TYPES_COUNT = static_cast<std::size_t>(EMoveType::COUNT);
//
// Extrusion roles
//
enum class EGCodeExtrusionRole : uint8_t
{
// This enum is used as in index into extrusion_roles_visibility.
// Better only add things to the end.
None,
Perimeter,
ExternalPerimeter,
OverhangPerimeter,
InternalInfill,
SolidInfill,
TopSolidInfill,
Ironing,
BridgeInfill,
GapFill,
Skirt,
SupportMaterial,
SupportMaterialInterface,
WipeTower,
Custom,
COUNT
};
static constexpr std::size_t GCODE_EXTRUSION_ROLES_COUNT = static_cast<std::size_t>(EGCodeExtrusionRole::COUNT);
//
// Option types
//
enum class EOptionType : uint8_t
{
// This enum is used as in index into options_visibility.
// Better only add things to the end.
Travels,
Wipes,
Retractions,
Unretractions,
Seams,
ToolChanges,
ColorChanges,
PausePrints,
CustomGCodes,
#if VGCODE_ENABLE_COG_AND_TOOL_MARKERS
CenterOfGravity,
ToolMarker,
#endif // VGCODE_ENABLE_COG_AND_TOOL_MARKERS
COUNT
};
static constexpr std::size_t OPTION_TYPES_COUNT = static_cast<std::size_t>(EOptionType::COUNT);
//
// Time modes
//
enum class ETimeMode : uint8_t
{
Normal,
Stealth,
COUNT
};
static constexpr std::size_t TIME_MODES_COUNT = static_cast<std::size_t>(ETimeMode::COUNT);
//
// Color range types
//
enum class EColorRangeType : uint8_t
{
Linear,
Logarithmic,
COUNT
};
static constexpr std::size_t COLOR_RANGE_TYPES_COUNT = static_cast<std::size_t>(EColorRangeType::COUNT);
//
// Predefined colors
//
static const Color DUMMY_COLOR{ 64, 64, 64 };
//
// Mapping from EMoveType to EOptionType
// Returns EOptionType::COUNT if the given move type does not correspond
// to any option type.
//
extern EOptionType move_type_to_option(EMoveType type);
//
// Returns the linear interpolation between the two given colors
// at the given t.
// t is clamped in the range [0..1]
//
extern Color lerp(const Color& c1, const Color& c2, float t);
} // namespace libvgcode
#endif // VGCODE_TYPES_HPP

View File

@@ -0,0 +1,419 @@
///|/ Copyright (c) Prusa Research 2023 Enrico Turri @enricoturri1966, Pavel Mikuš @Godrak
///|/
///|/ libvgcode is released under the terms of the AGPLv3 or higher
///|/
#ifndef VGCODE_VIEWER_HPP
#define VGCODE_VIEWER_HPP
#include "Types.hpp"
#include <string>
namespace libvgcode {
class ViewerImpl;
struct GCodeInputData;
struct PathVertex;
class ColorRange;
struct ColorPrint;
class Viewer
{
public:
Viewer();
~Viewer();
Viewer(const Viewer& other) = delete;
Viewer(Viewer&& other) = delete;
Viewer& operator = (const Viewer& other) = delete;
Viewer& operator = (Viewer&& other) = delete;
//
// Initialize the viewer.
// Param opengl_context_version must be the string returned by glGetString(GL_VERSION).
// This method must be called after a valid OpenGL context has been already created
// and before calling any other method of the viewer.
// Throws an std::runtime_error exception if:
// * the method is called before creating an OpenGL context
// * the created OpenGL context does not support OpenGL 3.2 or greater
// * when using OpenGL ES, the created OpenGL ES context does not support OpenGL ES 2.0 or greater
// * any of the shaders fails to compile
//
void init(const std::string& opengl_context_version);
//
// Release the resources used by the viewer.
// This method must be called before releasing the OpenGL context if the viewer
// goes out of scope after releasing it.
//
void shutdown();
//
// Reset the contents of the viewer.
// Automatically called by load() method.
//
void reset();
//
// Setup the viewer content from the given data.
// See: GCodeInputData
//
void load(GCodeInputData&& gcode_data);
//
// Render the toolpaths according to the current settings and
// using the given camera matrices.
//
void render(const Mat4x4& view_matrix, const Mat4x4& projection_matrix);
//
// ************************************************************************
// Settings
// The following methods can be used to query/customize the parameters
// used to render the toolpaths.
// ************************************************************************
//
//
// View type
// See: EViewType
//
EViewType get_view_type() const;
void set_view_type(EViewType type);
//
// Time mode
// See: ETimeMode
//
ETimeMode get_time_mode() const;
void set_time_mode(ETimeMode mode);
//
// Top layer only
// Whether or not the visible range is limited to the current top layer only.
//
bool is_top_layer_only_view_range() const;
//
// Toggle the top layer only state.
//
void toggle_top_layer_only_view_range();
//
// Returns true if the given option is visible.
//
bool is_option_visible(EOptionType type) const;
//
// Toggle the visibility state of the given option.
//
void toggle_option_visibility(EOptionType type);
//
// Returns true if the given extrusion role is visible.
//
bool is_extrusion_role_visible(EGCodeExtrusionRole role) const;
//
// Toggle the visibility state of the given extrusion role.
//
void toggle_extrusion_role_visibility(EGCodeExtrusionRole role);
//
// Return the color used to render the given extrusion rols.
//
const Color& get_extrusion_role_color(EGCodeExtrusionRole role) const;
//
// Set the color used to render the given extrusion role.
//
void set_extrusion_role_color(EGCodeExtrusionRole role, const Color& color);
//
// Reset the colors used to render the extrusion roles to the default value.
//
void reset_default_extrusion_roles_colors();
//
// Return the color used to render the given option.
//
const Color& get_option_color(EOptionType type) const;
//
// Set the color used to render the given option.
//
void set_option_color(EOptionType type, const Color& color);
//
// Reset the colors used to render the options to the default value.
//
void reset_default_options_colors();
//
// Return the count of colors in the palette used to render
// the toolpaths when the view type is EViewType::Tool.
//
size_t get_tool_colors_count() const;
//
// Return the palette used to render the toolpaths when
// the view type is EViewType::Tool.
//
const Palette& get_tool_colors() const;
//
// Set the palette used to render the toolpaths when
// the view type is EViewType::Tool with the given one.
//
void set_tool_colors(const Palette& colors);
//
// Return the count of colors in the palette used to render
// the toolpaths when the view type is EViewType::ColorPrint.
//
size_t get_color_print_colors_count() const;
//
// Return the palette used to render the toolpaths when
// the view type is EViewType::ColorPrint.
//
const Palette& get_color_print_colors() const;
//
// Set the palette used to render the toolpaths when
// the view type is EViewType::ColorPrint with the given one.
//
void set_color_print_colors(const Palette& colors);
//
// Get the color range for the given view type.
// Valid view types are:
// EViewType::Height
// EViewType::Width
// EViewType::Speed
// EViewType::ActualSpeed
// EViewType::FanSpeed
// EViewType::Temperature
// EViewType::VolumetricFlowRate
// EViewType::ActualVolumetricFlowRate
// EViewType::LayerTimeLinear
// EViewType::LayerTimeLogarithmic
//
const ColorRange& get_color_range(EViewType type) const;
//
// Set the palette for the color range corresponding to the given view type
// with the given value.
// Valid view types are:
// EViewType::Height
// EViewType::Width
// EViewType::Speed
// EViewType::ActualSpeed
// EViewType::FanSpeed
// EViewType::Temperature
// EViewType::VolumetricFlowRate
// EViewType::ActualVolumetricFlowRate
// EViewType::LayerTimeLinear
// EViewType::LayerTimeLogarithmic
//
void set_color_range_palette(EViewType type, const Palette& palette);
//
// Get the radius, in mm, of the cylinders used to render the travel moves.
//
float get_travels_radius() const;
//
// Set the radius, in mm, of the cylinders used to render the travel moves.
// Radius is clamped to [MIN_TRAVELS_RADIUS_MM..MAX_TRAVELS_RADIUS_MM]
//
void set_travels_radius(float radius);
//
// Get the radius, in mm, of the cylinders used to render the wipe moves.
//
float get_wipes_radius() const;
//
// Set the radius, in mm, of the cylinders used to render the wipe moves.
// Radius is clamped to [MIN_WIPES_RADIUS_MM..MAX_WIPES_RADIUS_MM]
//
void set_wipes_radius(float radius);
//
// Return the count of detected layers.
//
size_t get_layers_count() const;
//
// Return the current visible layers range.
//
const Interval& get_layers_view_range() const;
//
// Set the current visible layers range with the given interval.
// Values are clamped to [0..get_layers_count() - 1].
//
void set_layers_view_range(const Interval& range);
//
// Set the current visible layers range with the given min and max values.
// Values are clamped to [0..get_layers_count() - 1].
//
void set_layers_view_range(Interval::value_type min, Interval::value_type max);
//
// Return the current visible range.
// Three ranges are defined: full, enabled and visible.
// For all of them the range endpoints represent:
// [0] -> min vertex id
// [1] -> max vertex id
// Full is the range of vertices that could potentially be visualized accordingly to the current settings.
// Enabled is the part of the full range that is selected for visualization accordingly to the current settings.
// Visible is the part of the enabled range that is actually visualized accordingly to the current settings.
//
const Interval& get_view_visible_range() const;
//
// Set the current visible range.
// Values are clamped to the current view enabled range;
//
void set_view_visible_range(Interval::value_type min, Interval::value_type max);
//
// Return the current full range.
//
const Interval& get_view_full_range() const;
//
// Return the current enabled range.
//
const Interval& get_view_enabled_range() const;
//
// ************************************************************************
// Property getters
// The following methods can be used to query detected properties.
// ************************************************************************
//
//
// Spiral vase mode
// Whether or not the gcode was generated with spiral vase mode enabled.
// See: GCodeInputData
//
bool is_spiral_vase_mode() const;
//
// Return the z of the layer with the given id
// or 0.0f if the id does not belong to [0..get_layers_count() - 1].
//
float get_layer_z(size_t layer_id) const;
//
// Return the list of zs of the detected layers.
//
std::vector<float> get_layers_zs() const;
//
// Return the id of the layer closest to the given z.
//
size_t get_layer_id_at(float z) const;
//
// Return the count of detected used extruders.
//
size_t get_used_extruders_count() const;
//
// Return the list of ids of the detected used extruders.
//
std::vector<uint8_t> get_used_extruders_ids() const;
//
// Return the list of detected time modes.
//
std::vector<ETimeMode> get_time_modes() const;
//
// Return the count of vertices used to render the toolpaths
//
size_t get_vertices_count() const;
//
// Return the vertex pointed by the max value of the view visible range
//
const PathVertex& get_current_vertex() const;
//
// Return the index of vertex pointed by the max value of the view visible range
//
size_t get_current_vertex_id() const;
//
// Return the vertex at the given index
//
const PathVertex& get_vertex_at(size_t id) const;
//
// Return the total estimated time, in seconds, using the current time mode.
//
float get_estimated_time() const;
//
// Return the estimated time, in seconds, at the vertex with the given index
// using the current time mode.
//
float get_estimated_time_at(size_t id) const;
//
// Return the color used to render the given vertex with the current settings.
//
Color get_vertex_color(const PathVertex& vertex) const;
//
// Return the count of detected extrusion roles
//
size_t get_extrusion_roles_count() const;
//
// Return the list of detected extrusion roles
//
std::vector<EGCodeExtrusionRole> get_extrusion_roles() const;
//
// Return the count of detected options.
//
size_t get_options_count() const;
//
// Return the list of detected options.
//
const std::vector<EOptionType>& get_options() const;
//
// Return the count of detected color prints.
//
size_t get_color_prints_count(uint8_t extruder_id) const;
//
// Return the list of detected color prints.
//
std::vector<ColorPrint> get_color_prints(uint8_t extruder_id) const;
//
// Return the estimated time for the given role and the current time mode.
//
float get_extrusion_role_estimated_time(EGCodeExtrusionRole role) const;
//
// Return the estimated time for the travel moves and the current time mode.
//
float get_travels_estimated_time() const;
//
// Return the list of layers time for the current time mode.
//
std::vector<float> get_layers_estimated_times() const;
//
// Return the axes aligned bounding box containing all the given types.
//
AABox get_bounding_box(const std::vector<EMoveType>& types = {
EMoveType::Retract, EMoveType::Unretract, EMoveType::Seam, EMoveType::ToolChange,
EMoveType::ColorChange, EMoveType::PausePrint, EMoveType::CustomGCode, EMoveType::Travel,
EMoveType::Wipe, EMoveType::Extrude }) const;
//
// Return the axes aligned bounding box containing all the extrusions with the given roles.
//
AABox get_extrusion_bounding_box(const std::vector<EGCodeExtrusionRole>& roles = {
EGCodeExtrusionRole::Perimeter, EGCodeExtrusionRole::ExternalPerimeter, EGCodeExtrusionRole::OverhangPerimeter,
EGCodeExtrusionRole::InternalInfill, EGCodeExtrusionRole::SolidInfill, EGCodeExtrusionRole::TopSolidInfill,
EGCodeExtrusionRole::Ironing, EGCodeExtrusionRole::BridgeInfill, EGCodeExtrusionRole::GapFill,
EGCodeExtrusionRole::Skirt, EGCodeExtrusionRole::SupportMaterial, EGCodeExtrusionRole::SupportMaterialInterface,
EGCodeExtrusionRole::WipeTower, EGCodeExtrusionRole::Custom }) const;
//
// Return the size of the used cpu memory, in bytes
//
size_t get_used_cpu_memory() const;
//
// Return the size of the used gpu memory, in bytes
//
size_t get_used_gpu_memory() const;
#if VGCODE_ENABLE_COG_AND_TOOL_MARKERS
//
// Returns the position of the center of gravity of the toolpaths.
// It does not take in account extrusions of type:
// Skirt
// Support Material
// Support Material Interface
// WipeTower
// Custom
//
Vec3 get_cog_position() const;
float get_cog_marker_scale_factor() const;
void set_cog_marker_scale_factor(float factor);
const Vec3& get_tool_marker_position() const;
float get_tool_marker_offset_z() const;
void set_tool_marker_offset_z(float offset_z);
float get_tool_marker_scale_factor() const;
void set_tool_marker_scale_factor(float factor);
const Color& get_tool_marker_color() const;
void set_tool_marker_color(const Color& color);
float get_tool_marker_alpha() const;
void set_tool_marker_alpha(float alpha);
#endif // VGCODE_ENABLE_COG_AND_TOOL_MARKERS
private:
ViewerImpl* m_impl{ nullptr };
};
} // namespace libvgcode
#endif // VGCODE_VIEWER_HPP

View File

@@ -0,0 +1,8 @@
///|/ Copyright (c) Prusa Research 2023 Enrico Turri @enricoturri1966, Pavel Mikuš @Godrak
///|/
///|/ libvgcode is released under the terms of the AGPLv3 or higher
///|/
#include "Bitset.hpp"
namespace libvgcode {
} // namespace libvgcode

View File

@@ -0,0 +1,103 @@
///|/ Copyright (c) Prusa Research 2023 Enrico Turri @enricoturri1966, Pavel Mikuš @Godrak
///|/
///|/ libvgcode is released under the terms of the AGPLv3 or higher
///|/
#ifndef VGCODE_BITSET_HPP
#define VGCODE_BITSET_HPP
#include <atomic>
#include <vector>
namespace libvgcode {
// By default, types are not atomic,
template<typename T> auto constexpr is_atomic = false;
// but std::atomic<T> types are,
template<typename T> auto constexpr is_atomic<std::atomic<T>> = true;
template<typename T = unsigned long long>
struct BitSet
{
BitSet() = default;
BitSet(std::size_t size) : size(size), blocks(1 + (size / (sizeof(T) * 8))) { clear(); }
void clear() {
for (std::size_t i = 0; i < blocks.size(); ++i) {
blocks[i] &= T(0);
}
}
void setAll() {
for (std::size_t i = 0; i < blocks.size(); ++i) {
blocks[i] |= ~T(0);
}
}
//return true if bit changed
bool set(std::size_t index) {
const auto [block_idx, bit_idx] = get_coords(index);
const T mask = (T(1) << bit_idx);
bool flip = mask ^ blocks[block_idx];
blocks[block_idx] |= mask;
return flip;
}
//return true if bit changed
bool reset(std::size_t index) {
const auto [block_idx, bit_idx] = get_coords(index);
const T mask = (T(1) << bit_idx);
const bool flip = mask ^ blocks[block_idx];
blocks[block_idx] &= (~mask);
return flip;
}
bool operator [] (std::size_t index) const {
const auto [block_idx, bit_idx] = get_coords(index);
return ((blocks[block_idx] >> bit_idx) & 1) != 0;
}
template<typename U>
BitSet& operator &= (const BitSet<U>& other) {
static_assert(sizeof(T) == sizeof(U), "Type1 and Type2 must be of the same size.");
for (std::size_t i = 0; i < blocks.size(); ++i) {
blocks[i] &= other.blocks[i];
}
return *this;
}
// Atomic set operation (enabled only for atomic types), return true if bit changed
template<typename U = T>
inline typename std::enable_if<is_atomic<U>, bool>::type set_atomic(std::size_t index) {
const auto [block_idx, bit_idx] = get_coords(index);
const T mask = static_cast<T>(1) << bit_idx;
const T oldval = blocks[block_idx].fetch_or(mask, std::memory_order_relaxed);
return oldval ^ (oldval or mask);
}
// Atomic reset operation (enabled only for atomic types), return true if bit changed
template<typename U = T>
inline typename std::enable_if<is_atomic<U>, bool>::type reset_atomic(std::size_t index) {
const auto [block_idx, bit_idx] = get_coords(index);
const T mask = ~(static_cast<T>(1) << bit_idx);
const T oldval = blocks[block_idx].fetch_and(mask, std::memory_order_relaxed);
return oldval ^ (oldval and mask);
}
std::pair<std::size_t, std::size_t> get_coords(std::size_t index) const {
const std::size_t block_idx = index / (sizeof(T) * 8);
const std::size_t bit_idx = index % (sizeof(T) * 8);
return { block_idx, bit_idx };
}
std::size_t size_in_bytes_cpu() const {
return blocks.size() * sizeof(T);
}
std::size_t size{ 0 };
std::vector<T> blocks{ 0 };
};
} // namespace libvgcode
#endif // VGCODE_BITSET_HPP

View File

@@ -0,0 +1,173 @@
///|/ Copyright (c) Prusa Research 2023 Enrico Turri @enricoturri1966
///|/
///|/ libvgcode is released under the terms of the AGPLv3 or higher
///|/
// needed for tech VGCODE_ENABLE_COG_AND_TOOL_MARKERS
#include "../include/Types.hpp"
#include "CogMarker.hpp"
#include "OpenGLUtils.hpp"
#include "Utils.hpp"
#include <cmath>
#include <assert.h>
#include <algorithm>
#if VGCODE_ENABLE_COG_AND_TOOL_MARKERS
namespace libvgcode {
// Geometry:
// sphere with 'resolution' sides, centered at (0.0, 0.0, 0.0) and radius equal to 'radius'
void CogMarker::init(uint8_t resolution, float radius)
{
if (m_vao_id != 0)
return;
// ensure vertices count does not exceed 65536
resolution = std::clamp<uint8_t>(resolution, 4, 105);
const uint16_t sector_count = (uint16_t)resolution;
const uint16_t stack_count = (uint16_t)resolution;
const float sector_step = 2.0f * PI / float(sector_count);
const float stack_step = PI / float(stack_count);
std::vector<float> vertices;
const uint16_t vertices_count = (stack_count - 1) * sector_count + 2;
vertices.reserve(6 * vertices_count);
m_indices_count = 3 * (2 * (stack_count - 1) * sector_count);
std::vector<uint16_t> indices;
indices.reserve(m_indices_count);
// vertices
for (uint16_t i = 0; i <= stack_count; ++i) {
// from pi/2 to -pi/2
const float stack_angle = 0.5f * PI - stack_step * float(i);
const float xy = radius * std::cos(stack_angle);
const float z = radius * std::sin(stack_angle);
if (i == 0 || i == stack_count) {
const Vec3 pos = { xy, 0.0f, z };
const Vec3 norm = normalize(pos);
add_vertex(pos, norm, vertices);
}
else {
for (uint16_t j = 0; j < sector_count; ++j) {
// from 0 to 2pi
const float sector_angle = sector_step * float(j);
const Vec3 pos = { xy * std::cos(sector_angle), xy * std::sin(sector_angle), z };
const Vec3 norm = normalize(pos);
add_vertex(pos, norm, vertices);
}
}
}
// indices
for (uint16_t i = 0; i < stack_count; ++i) {
// Beginning of current stack.
uint16_t k1 = (i == 0) ? 0 : (1 + (i - 1) * sector_count);
const uint16_t k1_first = k1;
// Beginning of next stack.
uint16_t k2 = (i == 0) ? 1 : (k1 + sector_count);
const uint16_t k2_first = k2;
for (uint16_t j = 0; j < sector_count; ++j) {
// 2 triangles per sector excluding first and last stacks
uint16_t k1_next = k1;
uint16_t k2_next = k2;
if (i != 0) {
k1_next = (j + 1 == sector_count) ? k1_first : (k1 + 1);
add_triangle(k1, k2, k1_next, indices);
}
if (i + 1 != stack_count) {
k2_next = (j + 1 == sector_count) ? k2_first : (k2 + 1);
add_triangle(k1_next, k2, k2_next, indices);
}
k1 = k1_next;
k2 = k2_next;
}
}
m_size_in_bytes_gpu += vertices.size() * sizeof(float);
m_size_in_bytes_gpu += indices.size() * sizeof(uint16_t);
const size_t vertex_stride = 6 * sizeof(float);
const size_t position_offset = 0;
const size_t normal_offset = 3 * sizeof(float);
int curr_vertex_array;
glsafe(glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &curr_vertex_array));
int curr_array_buffer;
glsafe(glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &curr_array_buffer));
glsafe(glGenVertexArrays(1, &m_vao_id));
glsafe(glBindVertexArray(m_vao_id));
glsafe(glGenBuffers(1, &m_vbo_id));
glsafe(glBindBuffer(GL_ARRAY_BUFFER, m_vbo_id));
glsafe(glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(float), vertices.data(), GL_STATIC_DRAW));
glsafe(glEnableVertexAttribArray(0));
glsafe(glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, vertex_stride, (const void*)position_offset));
glsafe(glEnableVertexAttribArray(1));
glsafe(glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, vertex_stride, (const void*)normal_offset));
glsafe(glGenBuffers(1, &m_ibo_id));
glsafe(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_ibo_id));
glsafe(glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size() * sizeof(uint16_t), indices.data(), GL_STATIC_DRAW));
glsafe(glBindBuffer(GL_ARRAY_BUFFER, curr_array_buffer));
glsafe(glBindVertexArray(curr_vertex_array));
}
void CogMarker::shutdown()
{
if (m_ibo_id != 0) {
glsafe(glDeleteBuffers(1, &m_ibo_id));
m_ibo_id = 0;
}
if (m_vbo_id != 0) {
glsafe(glDeleteBuffers(1, &m_vbo_id));
m_vbo_id = 0;
}
if (m_vao_id != 0) {
glsafe(glDeleteVertexArrays(1, &m_vao_id));
m_vao_id = 0;
}
m_size_in_bytes_gpu = 0;
}
void CogMarker::render()
{
if (m_vao_id == 0 || m_vbo_id == 0 || m_ibo_id == 0 || m_indices_count == 0)
return;
int curr_vertex_array;
glsafe(glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &curr_vertex_array));
glcheck();
glsafe(glBindVertexArray(m_vao_id));
glsafe(glDrawElements(GL_TRIANGLES, m_indices_count, GL_UNSIGNED_SHORT, (const void*)0));
glsafe(glBindVertexArray(curr_vertex_array));
}
void CogMarker::update(const Vec3& position, float mass)
{
m_total_position = m_total_position + mass * position;
m_total_mass += mass;
}
void CogMarker::reset()
{
m_total_position = { 0.0f, 0.0f, 0.0f };
m_total_mass = 0.0f;
}
Vec3 CogMarker::get_position() const
{
assert(m_total_mass > 0.0f);
const float inv_total_mass = 1.0f / m_total_mass;
return inv_total_mass * m_total_position;
}
} // namespace libvgcode
#endif // VGCODE_ENABLE_COG_AND_TOOL_MARKERS

View File

@@ -0,0 +1,77 @@
///|/ Copyright (c) Prusa Research 2023 Enrico Turri @enricoturri1966
///|/
///|/ libvgcode is released under the terms of the AGPLv3 or higher
///|/
#ifndef VGCODE_COGMARKER_HPP
#define VGCODE_COGMARKER_HPP
#if VGCODE_ENABLE_COG_AND_TOOL_MARKERS
namespace libvgcode {
class CogMarker
{
public:
CogMarker() = default;
~CogMarker() { shutdown(); }
CogMarker(const CogMarker& other) = delete;
CogMarker(CogMarker&& other) = delete;
CogMarker& operator = (const CogMarker& other) = delete;
CogMarker& operator = (CogMarker&& other) = delete;
//
// Initialize gpu buffers
//
void init(uint8_t resolution, float radius);
//
// Release gpu buffers
//
void shutdown();
//
// Render the marker
//
void render();
//
// Update values used to calculate the center of gravity
//
void update(const Vec3& position, float mass);
//
// Reset values used to calculate the center of gravity
//
void reset();
//
// Return the calculated center of gravity position
//
Vec3 get_position() const;
//
// Return the size of the data sent to gpu, in bytes.
//
size_t size_in_bytes_gpu() const { return m_size_in_bytes_gpu; }
private:
//
// Values used to calculate the center of gravity
//
float m_total_mass{ 0.0f };
Vec3 m_total_position{ 0.0f, 0.0f, 0.0f };
//
// The count of indices stored into the ibo buffer.
//
uint16_t m_indices_count{ 0 };
//
// gpu buffers ids.
//
unsigned int m_vao_id{ 0 };
unsigned int m_vbo_id{ 0 };
unsigned int m_ibo_id{ 0 };
//
// Size of the data sent to gpu, in bytes.
//
size_t m_size_in_bytes_gpu{ 0 };
};
} // namespace libvgcode
#endif // VGCODE_ENABLE_COG_AND_TOOL_MARKERS
#endif // VGCODE_COGMARKER_HPP

View File

@@ -0,0 +1,8 @@
///|/ Copyright (c) Prusa Research 2023 Enrico Turri @enricoturri1966, Pavel Mikuš @Godrak
///|/
///|/ libvgcode is released under the terms of the AGPLv3 or higher
///|/
#include "../include/ColorPrint.hpp"
namespace libvgcode {
} // namespace libvgcode

View File

@@ -0,0 +1,139 @@
///|/ Copyright (c) Prusa Research 2023 Enrico Turri @enricoturri1966, Pavel Mikuš @Godrak
///|/
///|/ libvgcode is released under the terms of the AGPLv3 or higher
///|/
#include "../include/ColorRange.hpp"
#include "Utils.hpp"
#include <algorithm>
#include <assert.h>
#include <cmath>
namespace libvgcode {
const ColorRange ColorRange::DUMMY_COLOR_RANGE = ColorRange();
static float get_step_size(const ColorRange& color_range)
{
const std::array<float, 2>& range = color_range.get_range();
const Palette& palette = color_range.get_palette();
switch (color_range.get_type())
{
default:
case EColorRangeType::Linear:
{
return (range[1] - range[0]) / (static_cast<float>(palette.size()) - 1.0f);
}
case EColorRangeType::Logarithmic:
{
return (range[0] != 0.0f) ? std::log(range[1] / range[0]) / (static_cast<float>(palette.size()) - 1.0f) : 0.0f;
}
}
}
ColorRange::ColorRange(EColorRangeType type)
: m_type(type)
, m_palette(DEFAULT_RANGES_COLORS)
{
}
EColorRangeType ColorRange::get_type() const
{
return m_type;
}
const Palette& ColorRange::get_palette() const
{
return m_palette;
}
void ColorRange::set_palette(const Palette& palette)
{
if (palette.size() > 1)
m_palette = palette;
}
Color ColorRange::get_color_at(float value) const
{
// Input value scaled to the colors range
float global_t = 0.0f;
value = std::clamp(value, m_range[0], m_range[1]);
const float step = get_step_size(*this);
if (step > 0.0f) {
if (m_type == EColorRangeType::Logarithmic) {
if (m_range[0] != 0.0f)
global_t = std::log(value / m_range[0]) / step;
}
else
global_t = (value - m_range[0]) / step;
}
const size_t color_max_idx = m_palette.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);
// Interpolate between the low and high colors to find exactly which color the input value should get
return lerp(m_palette[color_low_idx], m_palette[color_high_idx], global_t - static_cast<float>(color_low_idx));
}
const std::array<float, 2>& ColorRange::get_range() const
{
return m_range;
}
std::vector<float> ColorRange::get_values() const
{
std::vector<float> ret;
if (m_count == 1) {
// single item use case
ret.emplace_back(m_range[0]);
}
else if (m_count == 2) {
// two items use case
ret.emplace_back(m_range[0]);
ret.emplace_back(m_range[1]);
}
else {
const float step_size = get_step_size(*this);
for (size_t i = 0; i < m_palette.size(); ++i) {
float value = 0.0f;
switch (m_type)
{
default:
case EColorRangeType::Linear: { value = m_range[0] + static_cast<float>(i) * step_size; break; }
case EColorRangeType::Logarithmic: { value = ::exp(::log(m_range[0]) + static_cast<float>(i) * step_size); break; }
}
ret.emplace_back(value);
}
}
return ret;
}
size_t ColorRange::size_in_bytes_cpu() const
{
size_t ret = STDVEC_MEMSIZE(m_palette, Color);
return ret;
}
void ColorRange::update(float value)
{
if (value != m_range[0] && value != m_range[1])
++m_count;
m_range[0] = std::min(m_range[0], value);
m_range[1] = std::max(m_range[1], value);
}
void ColorRange::reset()
{
m_range = { FLT_MAX, -FLT_MAX };
m_count = 0;
}
} // namespace libvgcode

View File

@@ -0,0 +1,39 @@
///|/ Copyright (c) Prusa Research 2023 Enrico Turri @enricoturri1966
///|/
///|/ libvgcode is released under the terms of the AGPLv3 or higher
///|/
#include "ExtrusionRoles.hpp"
namespace libvgcode {
void ExtrusionRoles::add(EGCodeExtrusionRole role, const std::array<float, TIME_MODES_COUNT>& times)
{
auto role_it = m_items.find(role);
if (role_it == m_items.end())
role_it = m_items.insert(std::make_pair(role, Item())).first;
for (std::size_t i = 0; i < TIME_MODES_COUNT; ++i) {
role_it->second.times[i] += times[i];
}
}
std::vector<EGCodeExtrusionRole> ExtrusionRoles::get_roles() const
{
std::vector<EGCodeExtrusionRole> ret;
ret.reserve(m_items.size());
for (const auto& [role, item] : m_items) {
ret.emplace_back(role);
}
return ret;
}
float ExtrusionRoles::get_time(EGCodeExtrusionRole role, ETimeMode mode) const
{
const auto role_it = m_items.find(role);
if (role_it == m_items.end())
return 0.0f;
return (mode < ETimeMode::COUNT) ? role_it->second.times[static_cast<std::size_t>(mode)] : 0.0f;
}
} // namespace libvgcode

View File

@@ -0,0 +1,36 @@
///|/ Copyright (c) Prusa Research 2023 Enrico Turri @enricoturri1966
///|/
///|/ libvgcode is released under the terms of the AGPLv3 or higher
///|/
#ifndef VGCODE_EXTRUSION_ROLES_HPP
#define VGCODE_EXTRUSION_ROLES_HPP
#include "../include/Types.hpp"
#include <map>
namespace libvgcode {
class ExtrusionRoles
{
public:
struct Item
{
std::array<float, TIME_MODES_COUNT> times;
};
void add(EGCodeExtrusionRole role, const std::array<float, TIME_MODES_COUNT>& times);
std::size_t get_roles_count() const { return m_items.size(); }
std::vector<EGCodeExtrusionRole> get_roles() const;
float get_time(EGCodeExtrusionRole role, ETimeMode mode) const;
void reset() { m_items.clear(); }
private:
std::map<EGCodeExtrusionRole, Item> m_items;
};
} // namespace libvgcode
#endif // VGCODE_EXTRUSION_ROLES_HPP

View File

@@ -0,0 +1,8 @@
///|/ Copyright (c) Prusa Research 2023 Enrico Turri @enricoturri1966
///|/
///|/ libvgcode is released under the terms of the AGPLv3 or higher
///|/
#include "../include/GCodeInputData.hpp"
namespace libvgcode {
} // namespace libvgcode

View File

@@ -0,0 +1,83 @@
///|/ Copyright (c) Prusa Research 2023 Enrico Turri @enricoturri1966, Pavel Mikuš @Godrak
///|/
///|/ libvgcode is released under the terms of the AGPLv3 or higher
///|/
#include "Layers.hpp"
#include "../include/PathVertex.hpp"
#include "Utils.hpp"
#include <assert.h>
#include <algorithm>
namespace libvgcode {
static bool is_colorprint_option(const PathVertex& v)
{
return v.type == EMoveType::PausePrint || v.type == EMoveType::CustomGCode;
}
void Layers::update(const PathVertex& vertex, uint32_t vertex_id)
{
if (m_items.empty() || vertex.layer_id == m_items.size()) {
// this code assumes that gcode paths are sent sequentially, one layer after the other
assert(vertex.layer_id == static_cast<uint32_t>(m_items.size()));
Item& item = m_items.emplace_back(Item());
if (vertex.type == EMoveType::Extrude && vertex.role != EGCodeExtrusionRole::Custom)
item.z = vertex.position[2];
item.range.set(vertex_id, vertex_id);
item.times = vertex.times;
item.contains_colorprint_options |= is_colorprint_option(vertex);
}
else {
Item& item = m_items.back();
if (vertex.type == EMoveType::Extrude && vertex.role != EGCodeExtrusionRole::Custom && item.z != vertex.position[2])
item.z = vertex.position[2];
item.range.set_max(vertex_id);
for (size_t i = 0; i < TIME_MODES_COUNT; ++i) {
item.times[i] += vertex.times[i];
}
item.contains_colorprint_options |= is_colorprint_option(vertex);
}
}
void Layers::reset()
{
m_items.clear();
m_view_range.reset();
}
std::vector<float> Layers::get_times(ETimeMode mode) const
{
std::vector<float> ret;
if (mode < ETimeMode::COUNT) {
for (const Item& item : m_items) {
ret.emplace_back(item.times[static_cast<size_t>(mode)]);
}
}
return ret;
}
std::vector<float> Layers::get_zs() const
{
std::vector<float> ret;
ret.reserve(m_items.size());
for (const Item& item : m_items) {
ret.emplace_back(item.z);
}
return ret;
}
size_t Layers::get_layer_id_at(float z) const
{
auto iter = std::upper_bound(m_items.begin(), m_items.end(), z, [](float z, const Item& item) { return item.z < z; });
return std::distance(m_items.begin(), iter);
}
size_t Layers::size_in_bytes_cpu() const
{
size_t ret = STDVEC_MEMSIZE(m_items, Item);
return ret;
}
} // namespace libvgcode

View File

@@ -0,0 +1,60 @@
///|/ Copyright (c) Prusa Research 2023 Enrico Turri @enricoturri1966, Pavel Mikuš @Godrak
///|/
///|/ libvgcode is released under the terms of the AGPLv3 or higher
///|/
#ifndef VGCODE_LAYERS_HPP
#define VGCODE_LAYERS_HPP
#include "Range.hpp"
namespace libvgcode {
struct PathVertex;
class Layers
{
public:
void update(const PathVertex& vertex, uint32_t vertex_id);
void reset();
bool empty() const { return m_items.empty(); }
std::size_t count() const { return m_items.size(); }
std::vector<float> get_times(ETimeMode mode) const;
std::vector<float> get_zs() const;
float get_layer_time(ETimeMode mode, std::size_t layer_id) const {
return (mode < ETimeMode::COUNT&& layer_id < m_items.size()) ?
m_items[layer_id].times[static_cast<std::size_t>(mode)] : 0.0f;
}
float get_layer_z(std::size_t layer_id) const {
return (layer_id < m_items.size()) ? m_items[layer_id].z : 0.0f;
}
std::size_t get_layer_id_at(float z) const;
const Interval& get_view_range() const { return m_view_range.get(); }
void set_view_range(const Interval& range) { set_view_range(range[0], range[1]); }
void set_view_range(Interval::value_type min, Interval::value_type max) { m_view_range.set(min, max); }
bool layer_contains_colorprint_options(std::size_t layer_id) const {
return (layer_id < m_items.size()) ? m_items[layer_id].contains_colorprint_options : false;
}
std::size_t size_in_bytes_cpu() const;
private:
struct Item
{
float z{ 0.0f };
Range range;
std::array<float, TIME_MODES_COUNT> times{ 0.0f, 0.0f };
bool contains_colorprint_options{ false };
};
std::vector<Item> m_items;
Range m_view_range;
};
} // namespace libvgcode
#endif // VGCODE_LAYERS_HPP

View File

@@ -0,0 +1,98 @@
///|/ Copyright (c) Prusa Research 2023 Enrico Turri @enricoturri1966, Pavel Mikuš @Godrak, Vojtěch Bubník @bubnikv
///|/
///|/ libvgcode is released under the terms of the AGPLv3 or higher
///|/
#include "OpenGLUtils.hpp"
#include <iostream>
#include <assert.h>
#include <cctype>
#include <stdio.h>
#include <cstring>
namespace libvgcode {
#ifdef HAS_GLSAFE
void glAssertRecentCallImpl(const char* file_name, unsigned int line, const char* function_name)
{
const GLenum err = glGetError();
if (err == GL_NO_ERROR)
return;
const char* sErr = 0;
switch (err) {
case GL_INVALID_ENUM: { sErr = "Invalid Enum"; break; }
case GL_INVALID_VALUE: { sErr = "Invalid Value"; break; }
// be aware that GL_INVALID_OPERATION is generated if glGetError is executed between the execution of glBegin / glEnd
case GL_INVALID_OPERATION: { sErr = "Invalid Operation"; break; }
case GL_OUT_OF_MEMORY: { sErr = "Out Of Memory"; break; }
case GL_INVALID_FRAMEBUFFER_OPERATION: { sErr = "Invalid framebuffer operation"; break; }
#if !defined(ENABLE_OPENGL_ES)
case GL_STACK_OVERFLOW: { sErr = "Stack Overflow"; break; }
case GL_STACK_UNDERFLOW: { sErr = "Stack Underflow"; break; }
#endif // ENABLE_OPENGL_ES
default: { sErr = "Unknown"; break; }
}
std::cout << "OpenGL error in " << file_name << ":" << line << ", function " << function_name << "() : " << (int)err << " - " << sErr << "\n";
assert(false);
}
#endif // HAS_GLSAFE
static const char* OPENGL_ES_PREFIXES[] = { "OpenGL ES-CM ", "OpenGL ES-CL ", "OpenGL ES ", nullptr };
bool OpenGLWrapper::s_valid_context = false;
#ifdef ENABLE_OPENGL_ES
int OpenGLWrapper::s_max_texture_size = 0;
#endif // ENABLE_OPENGL_ES
bool OpenGLWrapper::load_opengl(const std::string& context_version)
{
s_valid_context = false;
const char* version = context_version.c_str();
for (int i = 0; OPENGL_ES_PREFIXES[i] != nullptr; ++i) {
const size_t length = strlen(OPENGL_ES_PREFIXES[i]);
if (strncmp(version, OPENGL_ES_PREFIXES[i], length) == 0) {
version += length;
break;
}
}
GLint major = 0;
GLint minor = 0;
#ifdef _MSC_VER
const int res = sscanf_s(version, "%d.%d", &major, &minor);
#else
const int res = sscanf(version, "%d.%d", &major, &minor);
#endif // _MSC_VER
if (res != 2)
return false;
#ifdef ENABLE_OPENGL_ES
s_valid_context = major > 3 || (major == 3 && minor >= 0);
const int glad_res = gladLoaderLoadGLES2();
#else
s_valid_context = major > 3 || (major == 3 && minor >= 2);
const int glad_res = gladLoaderLoadGL();
#endif // ENABLE_OPENGL_ES
if (glad_res == 0)
return false;
#ifdef ENABLE_OPENGL_ES
glsafe(glGetIntegerv(GL_MAX_TEXTURE_SIZE, &s_max_texture_size));
#endif // ENABLE_OPENGL_ES
return s_valid_context;
}
void OpenGLWrapper::unload_opengl()
{
#ifdef ENABLE_OPENGL_ES
gladLoaderUnloadGLES2();
#else
gladLoaderUnloadGL();
#endif // ENABLE_OPENGL_ES
}
} // namespace libvgcode

View File

@@ -0,0 +1,52 @@
///|/ Copyright (c) Prusa Research 2023 Enrico Turri @enricoturri1966, Pavel Mikuš @Godrak, Vojtěch Bubník @bubnikv
///|/
///|/ libvgcode is released under the terms of the AGPLv3 or higher
///|/
#ifndef VGCODE_OPENGLUTILS_HPP
#define VGCODE_OPENGLUTILS_HPP
// OpenGL loader
#ifdef ENABLE_OPENGL_ES
#include "../glad/include/glad/gles2.h"
#else
#include "../glad/include/glad/gl.h"
#endif // ENABLE_OPENGL_ES
#include <string>
namespace libvgcode {
#ifndef NDEBUG
#define HAS_GLSAFE
#endif // NDEBUG
#ifdef HAS_GLSAFE
extern void glAssertRecentCallImpl(const char* file_name, unsigned int line, const char* function_name);
inline void glAssertRecentCall() { glAssertRecentCallImpl(__FILE__, __LINE__, __FUNCTION__); }
#define glsafe(cmd) do { cmd; glAssertRecentCallImpl(__FILE__, __LINE__, __FUNCTION__); } while (false)
#define glcheck() do { glAssertRecentCallImpl(__FILE__, __LINE__, __FUNCTION__); } while (false)
#else
inline void glAssertRecentCall() { }
#define glsafe(cmd) cmd
#define glcheck()
#endif // HAS_GLSAFE
class OpenGLWrapper
{
public:
static bool load_opengl(const std::string& context_version);
static void unload_opengl();
static bool is_valid_context() { return s_valid_context; }
#ifdef ENABLE_OPENGL_ES
static size_t max_texture_size() { return static_cast<size_t>(s_max_texture_size); }
#endif // ENABLE_OPENGL_ES
private:
static bool s_valid_context;
#ifdef ENABLE_OPENGL_ES
static int s_max_texture_size;
#endif // ENABLE_OPENGL_ES
};
} // namespace libvgcode
#endif // VGCODE_OPENGLUTILS_HPP

View File

@@ -0,0 +1,126 @@
///|/ Copyright (c) Prusa Research 2023 Enrico Turri @enricoturri1966
///|/
///|/ libvgcode is released under the terms of the AGPLv3 or higher
///|/
#include "OptionTemplate.hpp"
#include "OpenGLUtils.hpp"
#include "Utils.hpp"
#include <vector>
#include <algorithm>
#include <cmath>
namespace libvgcode {
// Geometry:
// diamond with 'resolution' sides, centered at (0.0, 0.0, 0.0)
// height and width of the diamond are equal to 1.0
void OptionTemplate::init(uint8_t resolution)
{
if (m_top_vao_id != 0)
return;
m_resolution = std::max<uint8_t>(resolution, 3);
m_vertices_count = 2 + resolution;
const float step = 2.0f * PI / float(m_resolution);
//
// top fan
//
std::vector<float> top_vertices;
top_vertices.reserve(6 * m_vertices_count);
add_vertex({ 0.0f, 0.0f, 0.5f }, { 0.0f, 0.0f, 1.0f }, top_vertices);
for (uint8_t i = 0; i <= m_resolution; ++i) {
const float ii = float(i) * step;
const Vec3 pos = { 0.5f * std::cos(ii), 0.5f * std::sin(ii), 0.0f };
const Vec3 norm = normalize(pos);
add_vertex(pos, norm, top_vertices);
}
//
// bottom fan
//
std::vector<float> bottom_vertices;
bottom_vertices.reserve(6 * m_vertices_count);
add_vertex({ 0.0f, 0.0f, -0.5f }, { 0.0f, 0.0f, -1.0f }, bottom_vertices);
for (uint8_t i = 0; i <= m_resolution; ++i) {
const float ii = -float(i) * step;
const Vec3 pos = { 0.5f * std::cos(ii), 0.5f * std::sin(ii), 0.0f };
const Vec3 norm = normalize(pos);
add_vertex(pos, norm, bottom_vertices);
}
m_size_in_bytes_gpu += top_vertices.size() * sizeof(float);
m_size_in_bytes_gpu += bottom_vertices.size() * sizeof(float);
const size_t vertex_stride = 6 * sizeof(float);
const size_t position_offset = 0;
const size_t normal_offset = 3 * sizeof(float);
int curr_vertex_array;
glsafe(glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &curr_vertex_array));
int curr_array_buffer;
glsafe(glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &curr_array_buffer));
glsafe(glGenVertexArrays(1, &m_top_vao_id));
glsafe(glBindVertexArray(m_top_vao_id));
glsafe(glGenBuffers(1, &m_top_vbo_id));
glsafe(glBindBuffer(GL_ARRAY_BUFFER, m_top_vbo_id));
glsafe(glBufferData(GL_ARRAY_BUFFER, top_vertices.size() * sizeof(float), top_vertices.data(), GL_STATIC_DRAW));
glsafe(glEnableVertexAttribArray(0));
glsafe(glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, vertex_stride, (const void*)position_offset));
glsafe(glEnableVertexAttribArray(1));
glsafe(glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, vertex_stride, (const void*)normal_offset));
glsafe(glGenVertexArrays(1, &m_bottom_vao_id));
glsafe(glBindVertexArray(m_bottom_vao_id));
glsafe(glGenBuffers(1, &m_bottom_vbo_id));
glsafe(glBindBuffer(GL_ARRAY_BUFFER, m_bottom_vbo_id));
glsafe(glBufferData(GL_ARRAY_BUFFER, bottom_vertices.size() * sizeof(float), bottom_vertices.data(), GL_STATIC_DRAW));
glsafe(glEnableVertexAttribArray(0));
glsafe(glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, vertex_stride, (const void*)position_offset));
glsafe(glEnableVertexAttribArray(1));
glsafe(glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, vertex_stride, (const void*)normal_offset));
glsafe(glBindBuffer(GL_ARRAY_BUFFER, curr_array_buffer));
glsafe(glBindVertexArray(curr_vertex_array));
}
void OptionTemplate::shutdown()
{
if (m_bottom_vbo_id != 0) {
glsafe(glDeleteBuffers(1, &m_bottom_vbo_id));
m_bottom_vbo_id = 0;
}
if (m_bottom_vao_id != 0) {
glsafe(glDeleteVertexArrays(1, &m_bottom_vao_id));
m_bottom_vao_id = 0;
}
if (m_top_vbo_id != 0) {
glsafe(glDeleteBuffers(1, &m_top_vbo_id));
m_top_vbo_id = 0;
}
if (m_top_vao_id != 0) {
glsafe(glDeleteVertexArrays(1, &m_top_vao_id));
m_top_vao_id = 0;
}
m_size_in_bytes_gpu = 0;
}
void OptionTemplate::render(size_t count)
{
if (m_top_vao_id == 0 || m_top_vbo_id == 0 || m_bottom_vao_id == 0 || m_bottom_vbo_id == 0 || count == 0)
return;
int curr_vertex_array;
glsafe(glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &curr_vertex_array));
glsafe(glBindVertexArray(m_top_vao_id));
glsafe(glDrawArraysInstanced(GL_TRIANGLE_FAN, 0, static_cast<GLsizei>(m_vertices_count), static_cast<GLsizei>(count)));
glsafe(glBindVertexArray(m_bottom_vao_id));
glsafe(glDrawArraysInstanced(GL_TRIANGLE_FAN, 0, static_cast<GLsizei>(m_vertices_count), static_cast<GLsizei>(count)));
glsafe(glBindVertexArray(curr_vertex_array));
}
} // namespace libvgcode

View File

@@ -0,0 +1,56 @@
///|/ Copyright (c) Prusa Research 2023 Enrico Turri @enricoturri1966
///|/
///|/ libvgcode is released under the terms of the AGPLv3 or higher
///|/
#ifndef VGCODE_OPTIONTEMPLATE_HPP
#define VGCODE_OPTIONTEMPLATE_HPP
#include <cstdint>
#include <cstddef>
namespace libvgcode {
class OptionTemplate
{
public:
OptionTemplate() = default;
~OptionTemplate() { shutdown(); }
OptionTemplate(const OptionTemplate& other) = delete;
OptionTemplate(OptionTemplate&& other) = delete;
OptionTemplate& operator = (const OptionTemplate& other) = delete;
OptionTemplate& operator = (OptionTemplate&& other) = delete;
//
// Initialize gpu buffers.
//
void init(uint8_t resolution);
//
// Release gpu buffers.
//
void shutdown();
void render(size_t count);
//
// Return the size of the data sent to gpu, in bytes.
//
size_t size_in_bytes_gpu() const { return m_size_in_bytes_gpu; }
private:
uint8_t m_resolution{ 0 };
uint8_t m_vertices_count{ 0 };
//
// gpu buffers ids.
//
unsigned int m_top_vao_id{ 0 };
unsigned int m_top_vbo_id{ 0 };
unsigned int m_bottom_vao_id{ 0 };
unsigned int m_bottom_vbo_id{ 0 };
//
// Size of the data sent to gpu, in bytes.
//
size_t m_size_in_bytes_gpu{ 0 };
};
} // namespace libvgcode
#endif // VGCODE_OPTIONTEMPLATE_HPP

View File

@@ -0,0 +1,52 @@
///|/ Copyright (c) Prusa Research 2023 Enrico Turri @enricoturri1966, Pavel Mikuš @Godrak
///|/
///|/ libvgcode is released under the terms of the AGPLv3 or higher
///|/
#include "../include/PathVertex.hpp"
namespace libvgcode {
const PathVertex PathVertex::DUMMY_PATH_VERTEX = PathVertex();
bool PathVertex::is_extrusion() const
{
return type == EMoveType::Extrude;
}
bool PathVertex::is_travel() const
{
return type == EMoveType::Travel;
}
bool PathVertex::is_wipe() const
{
return type == EMoveType::Wipe;
}
bool PathVertex::is_option() const
{
switch (type)
{
case EMoveType::Retract:
case EMoveType::Unretract:
case EMoveType::Seam:
case EMoveType::ToolChange:
case EMoveType::ColorChange:
case EMoveType::PausePrint:
case EMoveType::CustomGCode:
{
return true;
}
default:
{
return false;
}
}
}
bool PathVertex::is_custom_gcode() const
{
return type == EMoveType::Extrude && role == EGCodeExtrusionRole::Custom;
}
} // namespace libvgcode

View File

@@ -0,0 +1,25 @@
///|/ Copyright (c) Prusa Research 2023 Enrico Turri @enricoturri1966, Pavel Mikuš @Godrak
///|/
///|/ libvgcode is released under the terms of the AGPLv3 or higher
///|/
#include "Range.hpp"
#include <algorithm>
namespace libvgcode {
void Range::set(Interval::value_type min, Interval::value_type max)
{
if (max < min)
std::swap(min, max);
m_range[0] = min;
m_range[1] = max;
}
void Range::clamp(Range& other)
{
other.m_range[0] = std::clamp(other.m_range[0], m_range[0], m_range[1]);
other.m_range[1] = std::clamp(other.m_range[1], m_range[0], m_range[1]);
}
} // namespace libvgcode

View File

@@ -0,0 +1,39 @@
///|/ Copyright (c) Prusa Research 2023 Enrico Turri @enricoturri1966, Pavel Mikuš @Godrak
///|/
///|/ libvgcode is released under the terms of the AGPLv3 or higher
///|/
#ifndef VGCODE_RANGE_HPP
#define VGCODE_RANGE_HPP
#include "../include/Types.hpp"
namespace libvgcode {
class Range
{
public:
const Interval& get() const { return m_range; }
void set(const Range& other) { m_range = other.m_range; }
void set(const Interval& range) { set(range[0], range[1]); }
void set(Interval::value_type min, Interval::value_type max);
Interval::value_type get_min() const { return m_range[0]; }
void set_min(Interval::value_type min) { set(min, m_range[1]); }
Interval::value_type get_max() const { return m_range[1]; }
void set_max(Interval::value_type max) { set(m_range[0], max); }
// clamp the given range to stay inside this range
void clamp(Range& other);
void reset() { m_range = { 0, 0 }; }
bool operator == (const Range& other) const { return m_range == other.m_range; }
bool operator != (const Range& other) const { return m_range != other.m_range; }
private:
Interval m_range{ 0, 0 };
};
} // namespace libvgcode
#endif // VGCODE_RANGE_HPP

View File

@@ -0,0 +1,85 @@
///|/ Copyright (c) Prusa Research 2023 Enrico Turri @enricoturri1966, Pavel Mikuš @Godrak
///|/
///|/ libvgcode is released under the terms of the AGPLv3 or higher
///|/
#include "SegmentTemplate.hpp"
#include "OpenGLUtils.hpp"
#include <cstdint>
#include <array>
namespace libvgcode {
//| /1-------6\ |
//| / | | \ |
//| 2--0-------5--7 |
//| \ | | / |
//| 3-------4 |
static constexpr const std::array<uint8_t, 24> VERTEX_DATA = {
0, 1, 2, // front spike
0, 2, 3, // front spike
0, 3, 4, // right/bottom body
0, 4, 5, // right/bottom body
0, 5, 6, // left/top body
0, 6, 1, // left/top body
5, 4, 7, // back spike
5, 7, 6, // back spike
};
void SegmentTemplate::init()
{
if (m_vao_id != 0)
return;
m_size_in_bytes_gpu += VERTEX_DATA.size() * sizeof(uint8_t);
int curr_vertex_array;
glsafe(glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &curr_vertex_array));
int curr_array_buffer;
glsafe(glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &curr_array_buffer));
glsafe(glGenVertexArrays(1, &m_vao_id));
glsafe(glBindVertexArray(m_vao_id));
glsafe(glGenBuffers(1, &m_vbo_id));
glsafe(glBindBuffer(GL_ARRAY_BUFFER, m_vbo_id));
glsafe(glBufferData(GL_ARRAY_BUFFER, VERTEX_DATA.size() * sizeof(uint8_t), VERTEX_DATA.data(), GL_STATIC_DRAW));
glsafe(glEnableVertexAttribArray(0));
#ifdef ENABLE_OPENGL_ES
glsafe(glVertexAttribPointer(0, 1, GL_UNSIGNED_BYTE, GL_FALSE, 0, (const void*)0));
#else
glsafe(glVertexAttribIPointer(0, 1, GL_UNSIGNED_BYTE, 0, (const void*)0));
#endif // ENABLE_OPENGL_ES
glsafe(glBindBuffer(GL_ARRAY_BUFFER, curr_array_buffer));
glsafe(glBindVertexArray(curr_vertex_array));
}
void SegmentTemplate::shutdown()
{
if (m_vbo_id != 0) {
glsafe(glDeleteBuffers(1, &m_vbo_id));
m_vbo_id = 0;
}
if (m_vao_id != 0) {
glsafe(glDeleteVertexArrays(1, &m_vao_id));
m_vao_id = 0;
}
m_size_in_bytes_gpu = 0;
}
void SegmentTemplate::render(size_t count)
{
if (m_vao_id == 0 || m_vbo_id == 0 || count == 0)
return;
int curr_vertex_array;
glsafe(glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &curr_vertex_array));
glsafe(glBindVertexArray(m_vao_id));
glsafe(glDrawArraysInstanced(GL_TRIANGLES, 0, static_cast<GLsizei>(VERTEX_DATA.size()), static_cast<GLsizei>(count)));
glsafe(glBindVertexArray(curr_vertex_array));
}
} // namespace libvgcode

View File

@@ -0,0 +1,51 @@
///|/ Copyright (c) Prusa Research 2023 Enrico Turri @enricoturri1966, Pavel Mikuš @Godrak
///|/
///|/ libvgcode is released under the terms of the AGPLv3 or higher
///|/
#ifndef VGCODE_SEGMENTTEMPLATE_HPP
#define VGCODE_SEGMENTTEMPLATE_HPP
#include <cstddef>
namespace libvgcode {
class SegmentTemplate
{
public:
SegmentTemplate() = default;
~SegmentTemplate() { shutdown(); }
SegmentTemplate(const SegmentTemplate& other) = delete;
SegmentTemplate(SegmentTemplate&& other) = delete;
SegmentTemplate& operator = (const SegmentTemplate& other) = delete;
SegmentTemplate& operator = (SegmentTemplate&& other) = delete;
//
// Initialize gpu buffers.
//
void init();
//
// Release gpu buffers.
//
void shutdown();
void render(size_t count);
//
// Return the size of the data sent to gpu, in bytes.
//
size_t size_in_bytes_gpu() const { return m_size_in_bytes_gpu; }
private:
//
// gpu buffers ids.
//
unsigned int m_vao_id{ 0 };
unsigned int m_vbo_id{ 0 };
//
// Size of the data sent to gpu, in bytes.
//
size_t m_size_in_bytes_gpu{ 0 };
};
} // namespace libvgcode
#endif // VGCODE_SEGMENTTEMPLATE_HPP

View File

@@ -0,0 +1,9 @@
///|/ Copyright (c) Prusa Research 2023 Enrico Turri @enricoturri1966, Pavel Mikuš @Godrak
///|/
///|/ libvgcode is released under the terms of the AGPLv3 or higher
///|/
#include "Settings.hpp"
namespace libvgcode {
} // namespace libvgcode

View File

@@ -0,0 +1,70 @@
///|/ Copyright (c) Prusa Research 2023 Enrico Turri @enricoturri1966, Pavel Mikuš @Godrak
///|/
///|/ libvgcode is released under the terms of the AGPLv3 or higher
///|/
#ifndef VGCODE_SETTINGS_HPP
#define VGCODE_SETTINGS_HPP
#include "../include/Types.hpp"
#include <map>
namespace libvgcode {
struct Settings
{
//
// Visualization parameters
//
EViewType view_type{ EViewType::FeatureType };
ETimeMode time_mode{ ETimeMode::Normal };
bool top_layer_only_view_range{ false };
bool spiral_vase_mode{ false };
//
// Required update flags
//
bool update_view_full_range{ true };
bool update_enabled_entities{ true };
bool update_colors{ true };
//
// Visibility maps
//
std::array<bool, std::size_t(EOptionType::COUNT)> options_visibility{
false, // Travels
false, // Wipes
false, // Retractions
false, // Unretractions
false, // Seams
false, // ToolChanges
false, // ColorChanges
false, // PausePrints
false, // CustomGCodes
#if VGCODE_ENABLE_COG_AND_TOOL_MARKERS
false, // CenterOfGravity
true // ToolMarker
#endif // VGCODE_ENABLE_COG_AND_TOOL_MARKERS
};
std::array<bool, std::size_t(EGCodeExtrusionRole::COUNT)> extrusion_roles_visibility{
true, // None
true, // Perimeter
true, // ExternalPerimeter
true, // OverhangPerimeter
true, // InternalInfill
true, // SolidInfill
true, // TopSolidInfill
true, // Ironing
true, // BridgeInfill
true, // GapFill
true, // Skirt
true, // SupportMaterial
true, // SupportMaterialInterface
true, // WipeTower
true // Custom
};
};
} // namespace libvgcode
#endif // VGCODE_SETTINGS_HPP

View File

@@ -0,0 +1,299 @@
///|/ Copyright (c) Prusa Research 2023 Enrico Turri @enricoturri1966, Pavel Mikuš @Godrak
///|/
///|/ libvgcode is released under the terms of the AGPLv3 or higher
///|/
#ifndef VGCODE_SHADERS_HPP
#define VGCODE_SHADERS_HPP
// needed for tech VGCODE_ENABLE_COG_AND_TOOL_MARKERS
#include "../include/Types.hpp"
namespace libvgcode {
static const char* Segments_Vertex_Shader =
"#version 150\n"
"#define POINTY_CAPS\n"
"#define FIX_TWISTING\n"
"const vec3 light_top_dir = vec3(-0.4574957, 0.4574957, 0.7624929);\n"
"const float light_top_diffuse = 0.6 * 0.8;\n"
"const float light_top_specular = 0.6 * 0.125;\n"
"const float light_top_shininess = 20.0;\n"
"const vec3 light_front_dir = vec3(0.6985074, 0.1397015, 0.6985074);\n"
"const float light_front_diffuse = 0.6 * 0.3;\n"
"const float ambient = 0.3;\n"
"const float emission = 0.15;\n"
"const vec3 UP = vec3(0, 0, 1);\n"
"uniform mat4 view_matrix;\n"
"uniform mat4 projection_matrix;\n"
"uniform vec3 camera_position;\n"
"uniform samplerBuffer position_tex;\n"
"uniform samplerBuffer height_width_angle_tex;\n"
"uniform samplerBuffer color_tex;\n"
"uniform usamplerBuffer segment_index_tex;\n"
"in int vertex_id;\n"
"out vec3 color;\n"
"vec3 decode_color(float color) {\n"
" int c = int(round(color));\n"
" int r = (c >> 16) & 0xFF;\n"
" int g = (c >> 8) & 0xFF;\n"
" int b = (c >> 0) & 0xFF;\n"
" float f = 1.0 / 255.0f;\n"
" return f * vec3(r, g, b);\n"
"}\n"
"float lighting(vec3 eye_position, vec3 eye_normal) {\n"
" float top_diffuse = light_top_diffuse * max(dot(eye_normal, light_top_dir), 0.0);\n"
" float front_diffuse = light_front_diffuse * max(dot(eye_normal, light_front_dir), 0.0);\n"
" float top_specular = light_top_specular * pow(max(dot(-normalize(eye_position), reflect(-light_top_dir, eye_normal)), 0.0), light_top_shininess);\n"
" return ambient + top_diffuse + front_diffuse + top_specular + emission;\n"
"}\n"
"void main() {\n"
" int id_a = int(texelFetch(segment_index_tex, gl_InstanceID).r);\n"
" int id_b = id_a + 1;\n"
" vec3 pos_a = texelFetch(position_tex, id_a).xyz;\n"
" vec3 pos_b = texelFetch(position_tex, id_b).xyz;\n"
" vec3 line = pos_b - pos_a;\n"
" // directions of the line box in world space\n"
" float line_len = length(line);\n"
" vec3 line_dir;\n"
" if (line_len < 1e-4)\n"
" line_dir = vec3(1.0, 0.0, 0.0);\n"
" else\n"
" line_dir = line / line_len;\n"
" vec3 line_right_dir;\n"
" if (abs(dot(line_dir, UP)) > 0.9) {\n"
" // For vertical lines, the width and height should be same, there is no concept of up and down.\n"
" // For simplicity, the code will expand width in the x axis, and height in the y axis\n"
" line_right_dir = normalize(cross(vec3(1, 0, 0), line_dir));\n"
" }\n"
" else\n"
" line_right_dir = normalize(cross(line_dir, UP));\n"
" vec3 line_up_dir = normalize(cross(line_right_dir, line_dir));\n"
" const vec2 horizontal_vertical_view_signs_array[16] = vec2[](\n"
" //horizontal view (from right)\n"
" vec2(1.0, 0.0),\n"
" vec2(0.0, 1.0),\n"
" vec2(0.0, 0.0),\n"
" vec2(0.0, -1.0),\n"
" vec2(0.0, -1.0),\n"
" vec2(1.0, 0.0),\n"
" vec2(0.0, 1.0),\n"
" vec2(0.0, 0.0),\n"
" // vertical view (from top)\n"
" vec2(0.0, 1.0),\n"
" vec2(-1.0, 0.0),\n"
" vec2(0.0, 0.0),\n"
" vec2(1.0, 0.0),\n"
" vec2(1.0, 0.0),\n"
" vec2(0.0, 1.0),\n"
" vec2(-1.0, 0.0),\n"
" vec2(0.0, 0.0)\n"
" );\n"
" int id = vertex_id < 4 ? id_a : id_b;\n"
" vec3 endpoint_pos = vertex_id < 4 ? pos_a : pos_b;\n"
" vec3 height_width_angle = texelFetch(height_width_angle_tex, id).xyz;\n"
"#ifdef FIX_TWISTING\n"
" int closer_id = (dot(camera_position - pos_a, camera_position - pos_a) < dot(camera_position - pos_b, camera_position - pos_b)) ? id_a : id_b;\n"
" vec3 closer_pos = (closer_id == id_a) ? pos_a : pos_b;\n"
" vec3 camera_view_dir = normalize(closer_pos - camera_position);\n"
" vec3 closer_height_width_angle = texelFetch(height_width_angle_tex, closer_id).xyz;\n"
" vec3 diagonal_dir_border = normalize(closer_height_width_angle.x * line_up_dir + closer_height_width_angle.y * line_right_dir);\n"
"#else\n"
" vec3 camera_view_dir = normalize(endpoint_pos - camera_position);\n"
" vec3 diagonal_dir_border = normalize(height_width_angle.x * line_up_dir + height_width_angle.y * line_right_dir);\n"
"#endif\n"
" bool is_vertical_view = abs(dot(camera_view_dir, line_up_dir)) / abs(dot(diagonal_dir_border, line_up_dir)) >\n"
" abs(dot(camera_view_dir, line_right_dir)) / abs(dot(diagonal_dir_border, line_right_dir));\n"
" vec2 signs = horizontal_vertical_view_signs_array[vertex_id + 8 * int(is_vertical_view)];\n"
"#ifndef POINTY_CAPS\n"
" if (vertex_id == 2 || vertex_id == 7) signs = -horizontal_vertical_view_signs_array[(vertex_id - 2) + 8 * int(is_vertical_view)];\n"
"#endif\n"
" float view_right_sign = sign(dot(-camera_view_dir, line_right_dir));\n"
" float view_top_sign = sign(dot(-camera_view_dir, line_up_dir));\n"
" float half_height = 0.5 * height_width_angle.x;\n"
" float half_width = 0.5 * height_width_angle.y;\n"
" vec3 horizontal_dir = half_width * line_right_dir;\n"
" vec3 vertical_dir = half_height * line_up_dir;\n"
" float horizontal_sign = signs.x * view_right_sign;\n"
" float vertical_sign = signs.y * view_top_sign;\n"
" vec3 pos = endpoint_pos + horizontal_sign * horizontal_dir + vertical_sign * vertical_dir;\n"
" if (vertex_id == 2 || vertex_id == 7) {\n"
" float line_dir_sign = (vertex_id == 2) ? -1.0 : 1.0;\n"
" if (height_width_angle.z == 0) {\n"
"#ifdef POINTY_CAPS\n"
" // There I add a cap to lines that do not have a following line\n"
" // (or they have one, but perfectly aligned, so the cap is hidden inside the next line).\n"
" pos += line_dir_sign * line_dir * half_width;\n"
"#endif\n"
" }\n"
" else {\n"
" pos += line_dir_sign * line_dir * half_width * sin(abs(height_width_angle.z) * 0.5);\n"
" pos += sign(height_width_angle.z) * horizontal_dir * cos(abs(height_width_angle.z) * 0.5);\n"
" }\n"
" }\n"
" vec3 eye_position = (view_matrix * vec4(pos, 1.0)).xyz;\n"
" vec3 eye_normal = (view_matrix * vec4(normalize(pos - endpoint_pos), 0.0)).xyz;\n"
" vec3 color_base = decode_color(texelFetch(color_tex, id).r);\n"
" color = color_base * lighting(eye_position, eye_normal);\n"
" gl_Position = projection_matrix * vec4(eye_position, 1.0);\n"
"}\n";
static const char* Segments_Fragment_Shader =
"#version 150\n"
"in vec3 color;\n"
"out vec4 fragment_color;\n"
"void main() {\n"
" fragment_color = vec4(color, 1.0);\n"
"}\n";
static const char* Options_Vertex_Shader =
"#version 150\n"
"const vec3 light_top_dir = vec3(-0.4574957, 0.4574957, 0.7624929);\n"
"const float light_top_diffuse = 0.6 * 0.8;\n"
"const float light_top_specular = 0.6 * 0.125;\n"
"const float light_top_shininess = 20.0;\n"
"const vec3 light_front_dir = vec3(0.6985074, 0.1397015, 0.6985074);\n"
"const float light_front_diffuse = 0.6 * 0.3;\n"
"const float ambient = 0.3;\n"
"const float emission = 0.25;\n"
"const float scaling_factor = 1.5;\n"
"uniform mat4 view_matrix;\n"
"uniform mat4 projection_matrix;\n"
"uniform samplerBuffer position_tex;\n"
"uniform samplerBuffer height_width_angle_tex;\n"
"uniform samplerBuffer color_tex;\n"
"uniform usamplerBuffer segment_index_tex;\n"
"in vec3 in_position;\n"
"in vec3 in_normal;\n"
"out vec3 color;\n"
"vec3 decode_color(float color) {\n"
" int c = int(round(color));\n"
" int r = (c >> 16) & 0xFF;\n"
" int g = (c >> 8) & 0xFF;\n"
" int b = (c >> 0) & 0xFF;\n"
" float f = 1.0 / 255.0f;\n"
" return f * vec3(r, g, b);\n"
"}\n"
"float lighting(vec3 eye_position, vec3 eye_normal) {\n"
" float top_diffuse = light_top_diffuse * max(dot(eye_normal, light_top_dir), 0.0);\n"
" float front_diffuse = light_front_diffuse * max(dot(eye_normal, light_front_dir), 0.0);\n"
" float top_specular = light_top_specular * pow(max(dot(-normalize(eye_position), reflect(-light_top_dir, eye_normal)), 0.0), light_top_shininess);\n"
" return ambient + top_diffuse + front_diffuse + top_specular + emission;\n"
"}\n"
"void main() {\n"
" int id = int(texelFetch(segment_index_tex, gl_InstanceID).r);\n"
" vec2 height_width = texelFetch(height_width_angle_tex, id).xy;\n"
" vec3 offset = texelFetch(position_tex, id).xyz - vec3(0.0, 0.0, 0.5 * height_width.x);\n"
" height_width *= scaling_factor;\n"
" mat3 scale_matrix = mat3(\n"
" height_width.y, 0.0, 0.0,\n"
" 0.0, height_width.y, 0.0,\n"
" 0.0, 0.0, height_width.x);\n"
" vec3 eye_position = (view_matrix * vec4(scale_matrix * in_position + offset, 1.0)).xyz;\n"
" vec3 eye_normal = (view_matrix * vec4(in_normal, 0.0)).xyz;\n"
" vec3 color_base = decode_color(texelFetch(color_tex, id).r);\n"
" color = color_base * lighting(eye_position, eye_normal);\n"
" gl_Position = projection_matrix * vec4(eye_position, 1.0);\n"
"}\n";
static const char* Options_Fragment_Shader =
"#version 150\n"
"in vec3 color;\n"
"out vec4 fragment_color;\n"
"void main() {\n"
" fragment_color = vec4(color, 1.0);\n"
"}\n";
#if VGCODE_ENABLE_COG_AND_TOOL_MARKERS
static const char* Cog_Marker_Vertex_Shader =
"#version 150\n"
"const vec3 light_top_dir = vec3(-0.4574957, 0.4574957, 0.7624929);\n"
"const float light_top_diffuse = 0.6 * 0.8;\n"
"const float light_top_specular = 0.6 * 0.125;\n"
"const float light_top_shininess = 20.0;\n"
"const vec3 light_front_dir = vec3(0.6985074, 0.1397015, 0.6985074);\n"
"const float light_front_diffuse = 0.6 * 0.3;\n"
"const float ambient = 0.3;\n"
"const float emission = 0.25;\n"
"uniform vec3 world_center_position;\n"
"uniform float scale_factor;\n"
"uniform mat4 view_matrix;\n"
"uniform mat4 projection_matrix;\n"
"in vec3 in_position;\n"
"in vec3 in_normal;\n"
"out float intensity;\n"
"out vec3 world_position;\n"
"float lighting(vec3 eye_position, vec3 eye_normal) {\n"
" float top_diffuse = light_top_diffuse * max(dot(eye_normal, light_top_dir), 0.0);\n"
" float front_diffuse = light_front_diffuse * max(dot(eye_normal, light_front_dir), 0.0);\n"
" float top_specular = light_top_specular * pow(max(dot(-normalize(eye_position), reflect(-light_top_dir, eye_normal)), 0.0), light_top_shininess);\n"
" return ambient + top_diffuse + front_diffuse + top_specular + emission;\n"
"}\n"
"void main() {\n"
" world_position = scale_factor * in_position + world_center_position;\n"
" vec3 eye_position = (view_matrix * vec4(world_position, 1.0)).xyz;\n"
" vec3 eye_normal = (view_matrix * vec4(in_normal, 0.0)).xyz;\n"
" intensity = lighting(eye_position, eye_normal);\n"
" gl_Position = projection_matrix * vec4(eye_position, 1.0);\n"
"}\n";
static const char* Cog_Marker_Fragment_Shader =
"#version 150\n"
"const vec3 BLACK = vec3(0.05);\n"
"const vec3 WHITE = vec3(0.95);\n"
"uniform vec3 world_center_position;\n"
"in float intensity;\n"
"in vec3 world_position;\n"
"out vec4 out_color;\n"
"void main()\n"
"{\n"
" vec3 delta = world_position - world_center_position;\n"
" vec3 color = delta.x * delta.y * delta.z > 0.0 ? BLACK : WHITE;\n"
" out_color = intensity * vec4(color, 1.0);\n"
"}\n";
static const char* Tool_Marker_Vertex_Shader =
"#version 150\n"
"const vec3 light_top_dir = vec3(-0.4574957, 0.4574957, 0.7624929);\n"
"const float light_top_diffuse = 0.6 * 0.8;\n"
"const float light_top_specular = 0.6 * 0.125;\n"
"const float light_top_shininess = 20.0;\n"
"const vec3 light_front_dir = vec3(0.6985074, 0.1397015, 0.6985074);\n"
"const float light_front_diffuse = 0.6 * 0.3;\n"
"const float ambient = 0.3;\n"
"const float emission = 0.25;\n"
"uniform vec3 world_origin;\n"
"uniform float scale_factor;\n"
"uniform mat4 view_matrix;\n"
"uniform mat4 projection_matrix;\n"
"uniform vec4 color_base;\n"
"in vec3 in_position;\n"
"in vec3 in_normal;\n"
"out vec4 color;\n"
"float lighting(vec3 eye_position, vec3 eye_normal) {\n"
" float top_diffuse = light_top_diffuse * max(dot(eye_normal, light_top_dir), 0.0);\n"
" float front_diffuse = light_front_diffuse * max(dot(eye_normal, light_front_dir), 0.0);\n"
" float top_specular = light_top_specular * pow(max(dot(-normalize(eye_position), reflect(-light_top_dir, eye_normal)), 0.0), light_top_shininess);\n"
" return ambient + top_diffuse + front_diffuse + top_specular + emission;\n"
"}\n"
"void main() {\n"
" vec3 world_position = scale_factor * in_position + world_origin;\n"
" vec3 eye_position = (view_matrix * vec4(world_position, 1.0)).xyz;\n"
" // no need of normal matrix as the scaling is uniform\n"
" vec3 eye_normal = (view_matrix * vec4(in_normal, 0.0)).xyz;\n"
" color = vec4(color_base.rgb * lighting(eye_position, eye_normal), color_base.a);\n"
" gl_Position = projection_matrix * vec4(eye_position, 1.0);\n"
"}\n";
static const char* Tool_Marker_Fragment_Shader =
"#version 150\n"
"in vec4 color;\n"
"out vec4 fragment_color;\n"
"void main() {\n"
" fragment_color = color;\n"
"}\n";
#endif // VGCODE_ENABLE_COG_AND_TOOL_MARKERS
} // namespace libvgcode
#endif // VGCODE_SHADERS_HPP

View File

@@ -0,0 +1,322 @@
///|/ Copyright (c) Prusa Research 2023 Enrico Turri @enricoturri1966, Pavel Mikuš @Godrak
///|/
///|/ libvgcode is released under the terms of the AGPLv3 or higher
///|/
#ifndef VGCODE_SHADERSES_HPP
#define VGCODE_SHADERSES_HPP
// needed for tech VGCODE_ENABLE_COG_AND_TOOL_MARKERS
#include "../include/Types.hpp"
namespace libvgcode {
static const char* Segments_Vertex_Shader_ES =
"#version 300 es\n"
"precision lowp usampler2D;\n"
"#define POINTY_CAPS\n"
"#define FIX_TWISTING\n"
"const vec3 light_top_dir = vec3(-0.4574957, 0.4574957, 0.7624929);\n"
"const float light_top_diffuse = 0.6 * 0.8;\n"
"const float light_top_specular = 0.6 * 0.125;\n"
"const float light_top_shininess = 20.0;\n"
"const vec3 light_front_dir = vec3(0.6985074, 0.1397015, 0.6985074);\n"
"const float light_front_diffuse = 0.6 * 0.3;\n"
"const float ambient = 0.3;\n"
"const float emission = 0.15;\n"
"const vec3 UP = vec3(0, 0, 1);\n"
"uniform mat4 view_matrix;\n"
"uniform mat4 projection_matrix;\n"
"uniform vec3 camera_position;\n"
"uniform sampler2D position_tex;\n"
"uniform sampler2D height_width_angle_tex;\n"
"uniform sampler2D color_tex;\n"
"uniform usampler2D segment_index_tex;\n"
"in float vertex_id_float;\n"
"out vec3 color;\n"
"vec3 decode_color(float color) {\n"
" int c = int(round(color));\n"
" int r = (c >> 16) & 0xFF;\n"
" int g = (c >> 8) & 0xFF;\n"
" int b = (c >> 0) & 0xFF;\n"
" float f = 1.0 / 255.0f;\n"
" return f * vec3(r, g, b);\n"
"}\n"
"float lighting(vec3 eye_position, vec3 eye_normal) {\n"
" float top_diffuse = light_top_diffuse * max(dot(eye_normal, light_top_dir), 0.0);\n"
" float front_diffuse = light_front_diffuse * max(dot(eye_normal, light_front_dir), 0.0);\n"
" float top_specular = light_top_specular * pow(max(dot(-normalize(eye_position), reflect(-light_top_dir, eye_normal)), 0.0), light_top_shininess);\n"
" return ambient + top_diffuse + front_diffuse + top_specular + emission;\n"
"}\n"
"ivec2 tex_coord(sampler2D sampler, int id) {\n"
" ivec2 tex_size = textureSize(sampler, 0);\n"
" return (tex_size.y == 1) ? ivec2(id, 0) : ivec2(id % tex_size.x, id / tex_size.x);\n"
"}\n"
"ivec2 tex_coord_u(usampler2D sampler, int id) {\n"
" ivec2 tex_size = textureSize(sampler, 0);\n"
" return (tex_size.y == 1) ? ivec2(id, 0) : ivec2(id % tex_size.x, id / tex_size.x);\n"
"}\n"
"void main() {\n"
" int vertex_id = int(vertex_id_float);\n"
" int id_a = int(texelFetch(segment_index_tex, tex_coord_u(segment_index_tex, gl_InstanceID), 0).r);\n"
" int id_b = id_a + 1;\n"
" vec3 pos_a = texelFetch(position_tex, tex_coord(position_tex, id_a), 0).xyz;\n"
" vec3 pos_b = texelFetch(position_tex, tex_coord(position_tex, id_b), 0).xyz;\n"
" vec3 line = pos_b - pos_a;\n"
" // directions of the line box in world space\n"
" float line_len = length(line);\n"
" vec3 line_dir;\n"
" if (line_len < 1e-4)\n"
" line_dir = vec3(1.0, 0.0, 0.0);\n"
" else\n"
" line_dir = line / line_len;\n"
" vec3 line_right_dir;\n"
" if (abs(dot(line_dir, UP)) > 0.9) {\n"
" // For vertical lines, the width and height should be same, there is no concept of up and down.\n"
" // For simplicity, the code will expand width in the x axis, and height in the y axis\n"
" line_right_dir = normalize(cross(vec3(1, 0, 0), line_dir));\n"
" }\n"
" else\n"
" line_right_dir = normalize(cross(line_dir, UP));\n"
" vec3 line_up_dir = normalize(cross(line_right_dir, line_dir));\n"
" const vec2 horizontal_vertical_view_signs_array[16] = vec2[](\n"
" //horizontal view (from right)\n"
" vec2(1.0, 0.0),\n"
" vec2(0.0, 1.0),\n"
" vec2(0.0, 0.0),\n"
" vec2(0.0, -1.0),\n"
" vec2(0.0, -1.0),\n"
" vec2(1.0, 0.0),\n"
" vec2(0.0, 1.0),\n"
" vec2(0.0, 0.0),\n"
" // vertical view (from top)\n"
" vec2(0.0, 1.0),\n"
" vec2(-1.0, 0.0),\n"
" vec2(0.0, 0.0),\n"
" vec2(1.0, 0.0),\n"
" vec2(1.0, 0.0),\n"
" vec2(0.0, 1.0),\n"
" vec2(-1.0, 0.0),\n"
" vec2(0.0, 0.0)\n"
" );\n"
" int id = vertex_id < 4 ? id_a : id_b;\n"
" vec3 endpoint_pos = vertex_id < 4 ? pos_a : pos_b;\n"
" vec3 height_width_angle = texelFetch(height_width_angle_tex, tex_coord(height_width_angle_tex, id), 0).xyz;\n"
"#ifdef FIX_TWISTING\n"
" int closer_id = (dot(camera_position - pos_a, camera_position - pos_a) < dot(camera_position - pos_b, camera_position - pos_b)) ? id_a : id_b;\n"
" vec3 closer_pos = (closer_id == id_a) ? pos_a : pos_b;\n"
" vec3 camera_view_dir = normalize(closer_pos - camera_position);\n"
" vec3 closer_height_width_angle = texelFetch(height_width_angle_tex, tex_coord(height_width_angle_tex, closer_id), 0).xyz;\n"
" vec3 diagonal_dir_border = normalize(closer_height_width_angle.x * line_up_dir + closer_height_width_angle.y * line_right_dir);\n"
"#else\n"
" vec3 camera_view_dir = normalize(endpoint_pos - camera_position);\n"
" vec3 diagonal_dir_border = normalize(height_width_angle.x * line_up_dir + height_width_angle.y * line_right_dir);\n"
"#endif\n"
" bool is_vertical_view = abs(dot(camera_view_dir, line_up_dir)) / abs(dot(diagonal_dir_border, line_up_dir)) >\n"
" abs(dot(camera_view_dir, line_right_dir)) / abs(dot(diagonal_dir_border, line_right_dir));\n"
" vec2 signs = horizontal_vertical_view_signs_array[vertex_id + 8 * int(is_vertical_view)];\n"
"#ifndef POINTY_CAPS\n"
" if (vertex_id == 2 || vertex_id == 7) signs = -horizontal_vertical_view_signs_array[(vertex_id - 2) + 8 * int(is_vertical_view)];\n"
"#endif\n"
" float view_right_sign = sign(dot(-camera_view_dir, line_right_dir));\n"
" float view_top_sign = sign(dot(-camera_view_dir, line_up_dir));\n"
" float half_height = 0.5 * height_width_angle.x;\n"
" float half_width = 0.5 * height_width_angle.y;\n"
" vec3 horizontal_dir = half_width * line_right_dir;\n"
" vec3 vertical_dir = half_height * line_up_dir;\n"
" float horizontal_sign = signs.x * view_right_sign;\n"
" float vertical_sign = signs.y * view_top_sign;\n"
" vec3 pos = endpoint_pos + horizontal_sign * horizontal_dir + vertical_sign * vertical_dir;\n"
" if (vertex_id == 2 || vertex_id == 7) {\n"
" float line_dir_sign = (vertex_id == 2) ? -1.0 : 1.0;\n"
" if (height_width_angle.z == 0.0) {\n"
"#ifdef POINTY_CAPS\n"
" // There I add a cap to lines that do not have a following line\n"
" // (or they have one, but perfectly aligned, so the cap is hidden inside the next line).\n"
" pos += line_dir_sign * line_dir * half_width;\n"
"#endif\n"
" }\n"
" else {\n"
" pos += line_dir_sign * line_dir * half_width * sin(abs(height_width_angle.z) * 0.5);\n"
" pos += sign(height_width_angle.z) * horizontal_dir * cos(abs(height_width_angle.z) * 0.5);\n"
" }\n"
" }\n"
" vec3 eye_position = (view_matrix * vec4(pos, 1.0)).xyz;\n"
" vec3 eye_normal = (view_matrix * vec4(normalize(pos - endpoint_pos), 0.0)).xyz;\n"
" vec3 color_base = decode_color(texelFetch(color_tex, tex_coord(color_tex, id), 0).r);\n"
" color = color_base * lighting(eye_position, eye_normal);\n"
" gl_Position = projection_matrix * vec4(eye_position, 1.0);\n"
"}\n";
static const char* Segments_Fragment_Shader_ES =
"#version 300 es\n"
"precision highp float;\n"
"in vec3 color;\n"
"out vec4 fragment_color;\n"
"void main() {\n"
" fragment_color = vec4(color, 1.0);\n"
"}\n";
static const char* Options_Vertex_Shader_ES =
"#version 300 es\n"
"precision lowp usampler2D;\n"
"const vec3 light_top_dir = vec3(-0.4574957, 0.4574957, 0.7624929);\n"
"const float light_top_diffuse = 0.6 * 0.8;\n"
"const float light_top_specular = 0.6 * 0.125;\n"
"const float light_top_shininess = 20.0;\n"
"const vec3 light_front_dir = vec3(0.6985074, 0.1397015, 0.6985074);\n"
"const float light_front_diffuse = 0.6 * 0.3;\n"
"const float ambient = 0.3;\n"
"const float emission = 0.25;\n"
"const float scaling_factor = 1.5;\n"
"uniform mat4 view_matrix;\n"
"uniform mat4 projection_matrix;\n"
"uniform sampler2D position_tex;\n"
"uniform sampler2D height_width_angle_tex;\n"
"uniform sampler2D color_tex;\n"
"uniform usampler2D segment_index_tex;\n"
"in vec3 in_position;\n"
"in vec3 in_normal;\n"
"out vec3 color;\n"
"vec3 decode_color(float color) {\n"
" int c = int(round(color));\n"
" int r = (c >> 16) & 0xFF;\n"
" int g = (c >> 8) & 0xFF;\n"
" int b = (c >> 0) & 0xFF;\n"
" float f = 1.0 / 255.0f;\n"
" return f * vec3(r, g, b);\n"
"}\n"
"float lighting(vec3 eye_position, vec3 eye_normal) {\n"
" float top_diffuse = light_top_diffuse * max(dot(eye_normal, light_top_dir), 0.0);\n"
" float front_diffuse = light_front_diffuse * max(dot(eye_normal, light_front_dir), 0.0);\n"
" float top_specular = light_top_specular * pow(max(dot(-normalize(eye_position), reflect(-light_top_dir, eye_normal)), 0.0), light_top_shininess);\n"
" return ambient + top_diffuse + front_diffuse + top_specular + emission;\n"
"}\n"
"ivec2 tex_coord(sampler2D sampler, int id) {\n"
" ivec2 tex_size = textureSize(sampler, 0);\n"
" return (tex_size.y == 1) ? ivec2(id, 0) : ivec2(id % tex_size.x, id / tex_size.x);\n"
"}\n"
"ivec2 tex_coord_u(usampler2D sampler, int id) {\n"
" ivec2 tex_size = textureSize(sampler, 0);\n"
" return (tex_size.y == 1) ? ivec2(id, 0) : ivec2(id % tex_size.x, id / tex_size.x);\n"
"}\n"
"void main() {\n"
" int id = int(texelFetch(segment_index_tex, tex_coord_u(segment_index_tex, gl_InstanceID), 0).r);\n"
" vec2 height_width = texelFetch(height_width_angle_tex, tex_coord(height_width_angle_tex, id), 0).xy;\n"
" vec3 offset = texelFetch(position_tex, tex_coord(position_tex, id), 0).xyz - vec3(0.0, 0.0, 0.5 * height_width.x);\n"
" height_width *= scaling_factor;\n"
" mat3 scale_matrix = mat3(\n"
" height_width.y, 0.0, 0.0,\n"
" 0.0, height_width.y, 0.0,\n"
" 0.0, 0.0, height_width.x);\n"
" vec3 eye_position = (view_matrix * vec4(scale_matrix * in_position + offset, 1.0)).xyz;\n"
" vec3 eye_normal = (view_matrix * vec4(in_normal, 0.0)).xyz;\n"
" vec3 color_base = decode_color(texelFetch(color_tex, tex_coord(color_tex, id), 0).r);\n"
" color = color_base * lighting(eye_position, eye_normal);\n"
" gl_Position = projection_matrix * vec4(eye_position, 1.0);\n"
"}\n";
static const char* Options_Fragment_Shader_ES =
"#version 300 es\n"
"precision highp float;\n"
"in vec3 color;\n"
"out vec4 fragment_color;\n"
"void main() {\n"
" fragment_color = vec4(color, 1.0);\n"
"}\n";
#if VGCODE_ENABLE_COG_AND_TOOL_MARKERS
static const char* Cog_Marker_Vertex_Shader_ES =
"#version 300 es\n"
"const vec3 light_top_dir = vec3(-0.4574957, 0.4574957, 0.7624929);\n"
"const float light_top_diffuse = 0.6 * 0.8;\n"
"const float light_top_specular = 0.6 * 0.125;\n"
"const float light_top_shininess = 20.0;\n"
"const vec3 light_front_dir = vec3(0.6985074, 0.1397015, 0.6985074);\n"
"const float light_front_diffuse = 0.6 * 0.3;\n"
"const float ambient = 0.3;\n"
"const float emission = 0.25;\n"
"uniform vec3 world_center_position;\n"
"uniform float scale_factor;\n"
"uniform mat4 view_matrix;\n"
"uniform mat4 projection_matrix;\n"
"in vec3 in_position;\n"
"in vec3 in_normal;\n"
"out float intensity;\n"
"out vec3 world_position;\n"
"float lighting(vec3 eye_position, vec3 eye_normal) {\n"
" float top_diffuse = light_top_diffuse * max(dot(eye_normal, light_top_dir), 0.0);\n"
" float front_diffuse = light_front_diffuse * max(dot(eye_normal, light_front_dir), 0.0);\n"
" float top_specular = light_top_specular * pow(max(dot(-normalize(eye_position), reflect(-light_top_dir, eye_normal)), 0.0), light_top_shininess);\n"
" return ambient + top_diffuse + front_diffuse + top_specular + emission;\n"
"}\n"
"void main() {\n"
" world_position = scale_factor * in_position + world_center_position;\n"
" vec3 eye_position = (view_matrix * vec4(world_position, 1.0)).xyz;\n"
" vec3 eye_normal = (view_matrix * vec4(in_normal, 0.0)).xyz;\n"
" intensity = lighting(eye_position, eye_normal);\n"
" gl_Position = projection_matrix * vec4(eye_position, 1.0);\n"
"}\n";
static const char* Cog_Marker_Fragment_Shader_ES =
"#version 300 es\n"
"precision highp float;\n"
"const vec3 BLACK = vec3(0.05);\n"
"const vec3 WHITE = vec3(0.95);\n"
"uniform vec3 world_center_position;\n"
"in float intensity;\n"
"in vec3 world_position;\n"
"out vec4 out_color;\n"
"void main()\n"
"{\n"
" vec3 delta = world_position - world_center_position;\n"
" vec3 color = delta.x * delta.y * delta.z > 0.0 ? BLACK : WHITE;\n"
" out_color = intensity * vec4(color, 1.0);\n"
"}\n";
static const char* Tool_Marker_Vertex_Shader_ES =
"#version 300 es\n"
"const vec3 light_top_dir = vec3(-0.4574957, 0.4574957, 0.7624929);\n"
"const float light_top_diffuse = 0.6 * 0.8;\n"
"const float light_top_specular = 0.6 * 0.125;\n"
"const float light_top_shininess = 20.0;\n"
"const vec3 light_front_dir = vec3(0.6985074, 0.1397015, 0.6985074);\n"
"const float light_front_diffuse = 0.6 * 0.3;\n"
"const float ambient = 0.3;\n"
"const float emission = 0.25;\n"
"uniform vec3 world_origin;\n"
"uniform float scale_factor;\n"
"uniform mat4 view_matrix;\n"
"uniform mat4 projection_matrix;\n"
"uniform vec4 color_base;\n"
"in vec3 in_position;\n"
"in vec3 in_normal;\n"
"out vec4 color;\n"
"float lighting(vec3 eye_position, vec3 eye_normal) {\n"
" float top_diffuse = light_top_diffuse * max(dot(eye_normal, light_top_dir), 0.0);\n"
" float front_diffuse = light_front_diffuse * max(dot(eye_normal, light_front_dir), 0.0);\n"
" float top_specular = light_top_specular * pow(max(dot(-normalize(eye_position), reflect(-light_top_dir, eye_normal)), 0.0), light_top_shininess);\n"
" return ambient + top_diffuse + front_diffuse + top_specular + emission;\n"
"}\n"
"void main() {\n"
" vec3 world_position = scale_factor * in_position + world_origin;\n"
" vec3 eye_position = (view_matrix * vec4(world_position, 1.0)).xyz;\n"
" // no need of normal matrix as the scaling is uniform\n"
" vec3 eye_normal = (view_matrix * vec4(in_normal, 0.0)).xyz;\n"
" color = vec4(color_base.rgb * lighting(eye_position, eye_normal), color_base.a);\n"
" gl_Position = projection_matrix * vec4(eye_position, 1.0);\n"
"}\n";
static const char* Tool_Marker_Fragment_Shader_ES =
"#version 300 es\n"
"precision highp float;\n"
"in vec4 color;\n"
"out vec4 fragment_color;\n"
"void main() {\n"
" fragment_color = color;\n"
"}\n";
#endif // VGCODE_ENABLE_COG_AND_TOOL_MARKERS
} // namespace libvgcode
#endif // VGCODE_SHADERSES_HPP

View File

@@ -0,0 +1,172 @@
///|/ Copyright (c) Prusa Research 2023 Enrico Turri @enricoturri1966
///|/
///|/ libvgcode is released under the terms of the AGPLv3 or higher
///|/
#include "ToolMarker.hpp"
#include "OpenGLUtils.hpp"
#include "Utils.hpp"
#include <cmath>
#if VGCODE_ENABLE_COG_AND_TOOL_MARKERS
namespace libvgcode {
// Geometry:
// Arrow with cylindrical stem and conical tip, with the given dimensions and resolution
// The origin of the arrow is at the tip of the conical section
// The axis of symmetry is along the Z axis
// The arrow is pointing downward
void ToolMarker::init(uint16_t resolution, float tip_radius, float tip_height, float stem_radius, float stem_height)
{
if (m_vao_id != 0)
return;
// ensure vertices count does not exceed 65536
resolution = std::clamp<uint16_t>(resolution, 4, 10922);
std::vector<float> vertices;
const uint16_t vertices_count = 6 * resolution + 2;
vertices.reserve(6 * vertices_count);
m_indices_count = 6 * resolution * 3;
std::vector<uint16_t> indices;
indices.reserve(m_indices_count);
const float angle_step = 2.0f * PI / float(resolution);
std::vector<float> cosines(resolution);
std::vector<float> sines(resolution);
for (uint16_t i = 0; i < resolution; ++i) {
const float angle = angle_step * float(i);
cosines[i] = std::cos(angle);
sines[i] = -std::sin(angle);
}
const float total_height = tip_height + stem_height;
// tip vertices
add_vertex({ 0.0f, 0.0f, 0.0f }, { 0.0f, 0.0f, -1.0f }, vertices);
for (uint16_t i = 0; i < resolution; ++i) {
add_vertex({ tip_radius * sines[i], tip_radius * cosines[i], tip_height }, { sines[i], cosines[i], 0.0f }, vertices);
}
// tip triangles
for (uint16_t i = 0; i < resolution; ++i) {
const uint16_t v3 = (i < resolution - 1) ? i + 2 : 1;
add_triangle(0, i + 1, v3, indices);
}
// tip cap outer perimeter vertices
for (uint16_t i = 0; i < resolution; ++i) {
add_vertex({ tip_radius * sines[i], tip_radius * cosines[i], tip_height }, { 0.0f, 0.0f, 1.0f }, vertices);
}
// tip cap inner perimeter vertices
for (uint16_t i = 0; i < resolution; ++i) {
add_vertex({ stem_radius * sines[i], stem_radius * cosines[i], tip_height }, { 0.0f, 0.0f, 1.0f }, vertices);
}
// tip cap triangles
for (uint16_t i = 0; i < resolution; ++i) {
const uint16_t v2 = (i < resolution - 1) ? i + resolution + 2 : resolution + 1;
const uint16_t v3 = (i < resolution - 1) ? i + 2 * resolution + 2 : 2 * resolution + 1;
add_triangle(i + resolution + 1, v3, v2, indices);
add_triangle(i + resolution + 1, i + 2 * resolution + 1, v3, indices);
}
// stem bottom vertices
for (uint16_t i = 0; i < resolution; ++i) {
add_vertex({ stem_radius * sines[i], stem_radius * cosines[i], tip_height }, { sines[i], cosines[i], 0.0f }, vertices);
}
// stem top vertices
for (uint16_t i = 0; i < resolution; ++i) {
add_vertex({ stem_radius * sines[i], stem_radius * cosines[i], total_height }, { sines[i], cosines[i], 0.0f }, vertices);
}
// stem triangles
for (uint16_t i = 0; i < resolution; ++i) {
const uint16_t v2 = (i < resolution - 1) ? i + 3 * resolution + 2 : 3 * resolution + 1;
const uint16_t v3 = (i < resolution - 1) ? i + 4 * resolution + 2 : 4 * resolution + 1;
add_triangle(i + 3 * resolution + 1, v3, v2, indices);
add_triangle(i + 3 * resolution + 1, i + 4 * resolution + 1, v3, indices);
}
// stem cap vertices
add_vertex({ 0.0f, 0.0f, total_height }, { 0.0f, 0.0f, 1.0f }, vertices);
for (uint16_t i = 0; i < resolution; ++i) {
add_vertex({ stem_radius * sines[i], stem_radius * cosines[i], total_height }, { 0.0f, 0.0f, 1.0f }, vertices);
}
// stem cap triangles
for (uint16_t i = 0; i < resolution; ++i) {
const uint16_t v3 = (i < resolution - 1) ? i + 5 * resolution + 3 : 5 * resolution + 2;
add_triangle(5 * resolution + 1, v3, i + 5 * resolution + 2, indices);
}
m_size_in_bytes_gpu += vertices.size() * sizeof(float);
m_size_in_bytes_gpu += indices.size() * sizeof(uint16_t);
const size_t vertex_stride = 6 * sizeof(float);
const size_t position_offset = 0;
const size_t normal_offset = 3 * sizeof(float);
int curr_vertex_array;
glsafe(glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &curr_vertex_array));
int curr_array_buffer;
glsafe(glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &curr_array_buffer));
glsafe(glGenVertexArrays(1, &m_vao_id));
glsafe(glBindVertexArray(m_vao_id));
glsafe(glGenBuffers(1, &m_vbo_id));
glsafe(glBindBuffer(GL_ARRAY_BUFFER, m_vbo_id));
glsafe(glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(float), vertices.data(), GL_STATIC_DRAW));
glsafe(glEnableVertexAttribArray(0));
glsafe(glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, vertex_stride, (const void*)position_offset));
glsafe(glEnableVertexAttribArray(1));
glsafe(glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, vertex_stride, (const void*)normal_offset));
glsafe(glGenBuffers(1, &m_ibo_id));
glsafe(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_ibo_id));
glsafe(glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size() * sizeof(uint16_t), indices.data(), GL_STATIC_DRAW));
glsafe(glBindBuffer(GL_ARRAY_BUFFER, curr_array_buffer));
glsafe(glBindVertexArray(curr_vertex_array));
}
void ToolMarker::shutdown()
{
if (m_ibo_id != 0) {
glsafe(glDeleteBuffers(1, &m_ibo_id));
m_ibo_id = 0;
}
if (m_vbo_id != 0) {
glsafe(glDeleteBuffers(1, &m_vbo_id));
m_vbo_id = 0;
}
if (m_vao_id != 0) {
glsafe(glDeleteVertexArrays(1, &m_vao_id));
m_vao_id = 0;
}
m_size_in_bytes_gpu = 0;
}
void ToolMarker::render()
{
if (m_vao_id == 0 || m_vbo_id == 0 || m_ibo_id == 0)
return;
int curr_vertex_array;
glsafe(glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &curr_vertex_array));
glcheck();
glsafe(glBindVertexArray(m_vao_id));
glsafe(glDrawElements(GL_TRIANGLES, m_indices_count, GL_UNSIGNED_SHORT, (const void*)0));
glsafe(glBindVertexArray(curr_vertex_array));
}
} // namespace libvgcode
#endif // VGCODE_ENABLE_COG_AND_TOOL_MARKERS

View File

@@ -0,0 +1,75 @@
///|/ Copyright (c) Prusa Research 2023 Enrico Turri @enricoturri1966
///|/
///|/ libvgcode is released under the terms of the AGPLv3 or higher
///|/
#ifndef VGCODE_TOOLMARKER_HPP
#define VGCODE_TOOLMARKER_HPP
#include "../include/Types.hpp"
#if VGCODE_ENABLE_COG_AND_TOOL_MARKERS
#include <algorithm>
namespace libvgcode {
class ToolMarker
{
public:
ToolMarker() = default;
~ToolMarker() { shutdown(); }
ToolMarker(const ToolMarker& other) = delete;
ToolMarker(ToolMarker&& other) = delete;
ToolMarker& operator = (const ToolMarker& other) = delete;
ToolMarker& operator = (ToolMarker&& other) = delete;
//
// Initialize gpu buffers.
//
void init(uint16_t resolution, float tip_radius, float tip_height, float stem_radius, float stem_height);
//
// Release gpu buffers.
//
void shutdown();
void render();
const Vec3& get_position() const { return m_position; }
void set_position(const Vec3& position) { m_position = position; }
float get_offset_z() const { return m_offset_z; }
void set_offset_z(float offset_z) { m_offset_z = std::max(offset_z, 0.0f); }
const Color& get_color() const { return m_color; }
void set_color(const Color& color) { m_color = color; }
float get_alpha() const { return m_alpha; }
void set_alpha(float alpha) { m_alpha = std::clamp(alpha, 0.25f, 0.75f); }
//
// Return the size of the data sent to gpu, in bytes.
//
size_t size_in_bytes_gpu() const { return m_size_in_bytes_gpu; }
private:
Vec3 m_position{ 0.0f, 0.0f, 0.0f };
float m_offset_z{ 0.5f };
Color m_color{ 255, 255, 255 };
float m_alpha{ 0.5f };
uint16_t m_indices_count{ 0 };
//
// gpu buffers ids.
//
unsigned int m_vao_id{ 0 };
unsigned int m_vbo_id{ 0 };
unsigned int m_ibo_id{ 0 };
//
// Size of the data sent to gpu, in bytes.
//
size_t m_size_in_bytes_gpu{ 0 };
};
} // namespace libvgcode
#endif // VGCODE_ENABLE_COG_AND_TOOL_MARKERS
#endif // VGCODE_TOOLMARKER_HPP

View File

@@ -0,0 +1,42 @@
///|/ Copyright (c) Prusa Research 2023 Enrico Turri @enricoturri1966, Pavel Mikuš @Godrak
///|/
///|/ libvgcode is released under the terms of the AGPLv3 or higher
///|/
#include "../include/Types.hpp"
#include <algorithm>
namespace libvgcode {
// mapping from EMoveType to EOptionType
EOptionType move_type_to_option(EMoveType type)
{
switch (type)
{
case EMoveType::Travel: { return EOptionType::Travels; }
case EMoveType::Wipe: { return EOptionType::Wipes; }
case EMoveType::Retract: { return EOptionType::Retractions; }
case EMoveType::Unretract: { return EOptionType::Unretractions; }
case EMoveType::Seam: { return EOptionType::Seams; }
case EMoveType::ToolChange: { return EOptionType::ToolChanges; }
case EMoveType::ColorChange: { return EOptionType::ColorChanges; }
case EMoveType::PausePrint: { return EOptionType::PausePrints; }
case EMoveType::CustomGCode: { return EOptionType::CustomGCodes; }
default: { return EOptionType::COUNT; }
}
}
static uint8_t lerp(uint8_t f1, uint8_t f2, float t)
{
const float one_minus_t = 1.0f - t;
return static_cast<uint8_t>(one_minus_t * static_cast<float>(f1) + t * static_cast<float>(f2));
}
// It will be possible to replace this with std::lerp when using c++20
Color lerp(const Color& c1, const Color& c2, float t)
{
t = std::clamp(t, 0.0f, 1.0f);
return { lerp(c1[0], c2[0], t), lerp(c1[1], c2[1], t), lerp(c1[2], c2[2], t) };
}
} // namespace libvgcode

View File

@@ -0,0 +1,68 @@
///|/ Copyright (c) Prusa Research 2023 Enrico Turri @enricoturri1966
///|/
///|/ libvgcode is released under the terms of the AGPLv3 or higher
///|/
#include "Utils.hpp"
#include <assert.h>
#include <cmath>
namespace libvgcode {
void add_vertex(const Vec3& position, const Vec3& normal, std::vector<float>& vertices)
{
vertices.emplace_back(position[0]);
vertices.emplace_back(position[1]);
vertices.emplace_back(position[2]);
vertices.emplace_back(normal[0]);
vertices.emplace_back(normal[1]);
vertices.emplace_back(normal[2]);
}
void add_triangle(uint16_t v1, uint16_t v2, uint16_t v3, std::vector<uint16_t>& indices)
{
indices.emplace_back(v1);
indices.emplace_back(v2);
indices.emplace_back(v3);
}
Vec3 normalize(const Vec3& v)
{
const float length = std::sqrt(dot(v, v));
assert(length > 0.0f);
const float inv_length = 1.0f / length;
return { v[0] * inv_length, v[1] * inv_length, v[2] * inv_length };
}
float dot(const Vec3& v1, const Vec3& v2)
{
return v1[0] * v2[0] + v1[1] * v2[1] + v1[2] * v2[2];
}
float length(const Vec3& v)
{
return std::sqrt(dot(v, v));
}
bool operator == (const Vec3& v1, const Vec3& v2) {
return v1[0] == v2[0] && v1[1] == v2[1] && v1[2] == v2[2];
}
bool operator != (const Vec3& v1, const Vec3& v2) {
return v1[0] != v2[0] || v1[1] != v2[1] || v1[2] != v2[2];
}
Vec3 operator + (const Vec3& v1, const Vec3& v2) {
return { v1[0] + v2[0], v1[1] + v2[1], v1[2] + v2[2] };
}
Vec3 operator - (const Vec3& v1, const Vec3& v2) {
return { v1[0] - v2[0], v1[1] - v2[1], v1[2] - v2[2] };
}
Vec3 operator * (float f, const Vec3& v) {
return { f * v[0], f * v[1], f * v[2] };
}
} // namespace libvgcode

View File

@@ -0,0 +1,31 @@
///|/ Copyright (c) Prusa Research 2023 Enrico Turri @enricoturri1966
///|/
///|/ libvgcode is released under the terms of the AGPLv3 or higher
///|/
#ifndef VGCODE_UTILS_HPP
#define VGCODE_UTILS_HPP
#include "../include/Types.hpp"
#ifdef _WIN32
#define STDVEC_MEMSIZE(NAME, TYPE) NAME.capacity() * ((sizeof(TYPE) + __alignof(TYPE) - 1) / __alignof(TYPE)) * __alignof(TYPE)
#else
#define STDVEC_MEMSIZE(NAME, TYPE) NAME.capacity() * ((sizeof(TYPE) + alignof(TYPE) - 1) / alignof(TYPE)) * alignof(TYPE)
#endif // _WIN32
namespace libvgcode {
extern void add_vertex(const Vec3& position, const Vec3& normal, std::vector<float>& vertices);
extern void add_triangle(uint16_t v1, uint16_t v2, uint16_t v3, std::vector<uint16_t>& indices);
extern Vec3 normalize(const Vec3& v);
extern float dot(const Vec3& v1, const Vec3& v2);
extern float length(const Vec3& v);
extern bool operator == (const Vec3& v1, const Vec3& v2);
extern bool operator != (const Vec3& v1, const Vec3& v2);
extern Vec3 operator + (const Vec3& v1, const Vec3& v2);
extern Vec3 operator - (const Vec3& v1, const Vec3& v2);
extern Vec3 operator * (float f, const Vec3& v);
} // namespace libvgcode
#endif // VGCODE_UTILS_HPP

View File

@@ -0,0 +1,39 @@
///|/ Copyright (c) Prusa Research 2023 Enrico Turri @enricoturri1966, Pavel Mikuš @Godrak
///|/
///|/ libvgcode is released under the terms of the AGPLv3 or higher
///|/
#include "ViewRange.hpp"
namespace libvgcode {
void ViewRange::set_full(Interval::value_type min, Interval::value_type max)
{
m_full.set(min, max);
// force the enabled range to stay inside the modified full range
m_full.clamp(m_enabled);
// force the visible range to stay inside the modified enabled range
m_enabled.clamp(m_visible);
}
void ViewRange::set_enabled(Interval::value_type min, Interval::value_type max)
{
m_enabled.set(min, max);
// force the visible range to stay inside the modified enabled range
m_enabled.clamp(m_visible);
}
void ViewRange::set_visible(Interval::value_type min, Interval::value_type max)
{
m_visible.set(min, max);
// force the visible range to stay inside the enabled range
m_enabled.clamp(m_visible);
}
void ViewRange::reset()
{
m_full.reset();
m_enabled.reset();
m_visible.reset();
}
} // namespace libvgcode

View File

@@ -0,0 +1,56 @@
///|/ Copyright (c) Prusa Research 2023 Enrico Turri @enricoturri1966, Pavel Mikuš @Godrak
///|/
///|/ libvgcode is released under the terms of the AGPLv3 or higher
///|/
#ifndef VGCODE_VIEWRANGE_HPP
#define VGCODE_VIEWRANGE_HPP
#include "Range.hpp"
namespace libvgcode {
class ViewRange
{
public:
const Interval& get_full() const { return m_full.get(); }
void set_full(const Range& other) { set_full(other.get()); }
void set_full(const Interval& range) { set_full(range[0], range[1]); }
void set_full(Interval::value_type min, Interval::value_type max);
const Interval& get_enabled() const { return m_enabled.get(); }
void set_enabled(const Range& other) { set_enabled(other.get()); }
void set_enabled(const Interval& range) { set_enabled(range[0], range[1]); }
void set_enabled(Interval::value_type min, Interval::value_type max);
const Interval& get_visible() const { return m_visible.get(); }
void set_visible(const Range& other) { set_visible(other.get()); }
void set_visible(const Interval& range) { set_visible(range[0], range[1]); }
void set_visible(Interval::value_type min, Interval::value_type max);
void reset();
private:
//
// Full range
// The range of moves that could potentially be visible.
// It is usually equal to the enabled range, unless Settings::top_layer_only_view_range is set to true.
//
Range m_full;
//
// Enabled range
// The range of moves that are enabled for visualization.
// It is usually equal to the full range, unless Settings::top_layer_only_view_range is set to true.
//
Range m_enabled;
//
// Visible range
// The range of moves that are currently rendered.
//
Range m_visible;
};
} // namespace libvgcode
#endif // VGCODE_VIEWRANGE_HPP

View File

@@ -0,0 +1,422 @@
///|/ Copyright (c) Prusa Research 2023 Enrico Turri @enricoturri1966, Pavel Mikuš @Godrak
///|/
///|/ libvgcode is released under the terms of the AGPLv3 or higher
///|/
#include "../include/Viewer.hpp"
#include "ViewerImpl.hpp"
namespace libvgcode {
Viewer::Viewer()
{
m_impl = new ViewerImpl();
}
Viewer::~Viewer()
{
delete m_impl;
}
void Viewer::init(const std::string& opengl_context_version)
{
m_impl->init(opengl_context_version);
}
void Viewer::shutdown()
{
m_impl->shutdown();
}
void Viewer::reset()
{
m_impl->reset();
}
void Viewer::load(GCodeInputData&& gcode_data)
{
m_impl->load(std::move(gcode_data));
}
void Viewer::render(const Mat4x4& view_matrix, const Mat4x4& projection_matrix)
{
m_impl->render(view_matrix, projection_matrix);
}
EViewType Viewer::get_view_type() const
{
return m_impl->get_view_type();
}
void Viewer::set_view_type(EViewType type)
{
m_impl->set_view_type(type);
}
ETimeMode Viewer::get_time_mode() const
{
return m_impl->get_time_mode();
}
void Viewer::set_time_mode(ETimeMode mode)
{
m_impl->set_time_mode(mode);
}
bool Viewer::is_top_layer_only_view_range() const
{
return m_impl->is_top_layer_only_view_range();
}
void Viewer::toggle_top_layer_only_view_range()
{
m_impl->toggle_top_layer_only_view_range();
}
bool Viewer::is_option_visible(EOptionType type) const
{
return m_impl->is_option_visible(type);
}
void Viewer::toggle_option_visibility(EOptionType type)
{
m_impl->toggle_option_visibility(type);
}
bool Viewer::is_extrusion_role_visible(EGCodeExtrusionRole role) const
{
return m_impl->is_extrusion_role_visible(role);
}
void Viewer::toggle_extrusion_role_visibility(EGCodeExtrusionRole role)
{
m_impl->toggle_extrusion_role_visibility(role);
}
const Color& Viewer::get_extrusion_role_color(EGCodeExtrusionRole role) const
{
return m_impl->get_extrusion_role_color(role);
}
void Viewer::set_extrusion_role_color(EGCodeExtrusionRole role, const Color& color)
{
m_impl->set_extrusion_role_color(role, color);
}
void Viewer::reset_default_extrusion_roles_colors()
{
m_impl->reset_default_extrusion_roles_colors();
}
const Color& Viewer::get_option_color(EOptionType type) const
{
return m_impl->get_option_color(type);
}
void Viewer::set_option_color(EOptionType type, const Color& color)
{
m_impl->set_option_color(type, color);
}
void Viewer::reset_default_options_colors()
{
m_impl->reset_default_options_colors();
}
size_t Viewer::get_tool_colors_count() const
{
return m_impl->get_tool_colors_count();
}
const Palette& Viewer::get_tool_colors() const
{
return m_impl->get_tool_colors();
}
void Viewer::set_tool_colors(const Palette& colors)
{
m_impl->set_tool_colors(colors);
}
size_t Viewer::get_color_print_colors_count() const
{
return m_impl->get_color_print_colors_count();
}
const Palette& Viewer::get_color_print_colors() const
{
return m_impl->get_color_print_colors();
}
void Viewer::set_color_print_colors(const Palette& colors)
{
m_impl->set_color_print_colors(colors);
}
const ColorRange& Viewer::get_color_range(EViewType type) const
{
return m_impl->get_color_range(type);
}
void Viewer::set_color_range_palette(EViewType type, const Palette& palette)
{
m_impl->set_color_range_palette(type, palette);
}
float Viewer::get_travels_radius() const
{
return m_impl->get_travels_radius();
}
void Viewer::set_travels_radius(float radius)
{
m_impl->set_travels_radius(radius);
}
float Viewer::get_wipes_radius() const
{
return m_impl->get_wipes_radius();
}
void Viewer::set_wipes_radius(float radius)
{
m_impl->set_wipes_radius(radius);
}
size_t Viewer::get_layers_count() const
{
return m_impl->get_layers_count();
}
const Interval& Viewer::get_layers_view_range() const
{
return m_impl->get_layers_view_range();
}
void Viewer::set_layers_view_range(const Interval& range)
{
m_impl->set_layers_view_range(range);
}
void Viewer::set_layers_view_range(Interval::value_type min, Interval::value_type max)
{
m_impl->set_layers_view_range(min, max);
}
const Interval& Viewer::get_view_visible_range() const
{
return m_impl->get_view_visible_range();
}
void Viewer::set_view_visible_range(Interval::value_type min, Interval::value_type max)
{
m_impl->set_view_visible_range(min, max);
}
const Interval& Viewer::get_view_full_range() const
{
return m_impl->get_view_full_range();
}
const Interval& Viewer::get_view_enabled_range() const
{
return m_impl->get_view_enabled_range();
}
bool Viewer::is_spiral_vase_mode() const
{
return m_impl->is_spiral_vase_mode();
}
float Viewer::get_layer_z(size_t layer_id) const
{
return m_impl->get_layer_z(layer_id);
}
std::vector<float> Viewer::get_layers_zs() const
{
return m_impl->get_layers_zs();
}
size_t Viewer::get_layer_id_at(float z) const
{
return m_impl->get_layer_id_at(z);
}
size_t Viewer::get_used_extruders_count() const
{
return m_impl->get_used_extruders_count();
}
std::vector<uint8_t> Viewer::get_used_extruders_ids() const
{
return m_impl->get_used_extruders_ids();
}
std::vector<ETimeMode> Viewer::get_time_modes() const
{
return m_impl->get_time_modes();
}
size_t Viewer::get_vertices_count() const
{
return m_impl->get_vertices_count();
}
const PathVertex& Viewer::get_current_vertex() const
{
return m_impl->get_current_vertex();
}
size_t Viewer::get_current_vertex_id() const
{
return m_impl->get_current_vertex_id();
}
const PathVertex& Viewer::get_vertex_at(size_t id) const
{
return m_impl->get_vertex_at(id);
}
float Viewer::get_estimated_time() const
{
return m_impl->get_estimated_time();
}
float Viewer::get_estimated_time_at(size_t id) const
{
return m_impl->get_estimated_time_at(id);
}
Color Viewer::get_vertex_color(const PathVertex& vertex) const
{
return m_impl->get_vertex_color(vertex);
}
size_t Viewer::get_extrusion_roles_count() const
{
return m_impl->get_extrusion_roles_count();
}
std::vector<EGCodeExtrusionRole> Viewer::get_extrusion_roles() const
{
return m_impl->get_extrusion_roles();
}
size_t Viewer::get_options_count() const
{
return m_impl->get_options_count();
}
const std::vector<EOptionType>& Viewer::get_options() const
{
return m_impl->get_options();
}
size_t Viewer::get_color_prints_count(uint8_t extruder_id) const
{
return m_impl->get_color_prints_count(extruder_id);
}
std::vector<ColorPrint> Viewer::get_color_prints(uint8_t extruder_id) const
{
return m_impl->get_color_prints(extruder_id);
}
float Viewer::get_extrusion_role_estimated_time(EGCodeExtrusionRole role) const
{
return m_impl->get_extrusion_role_estimated_time(role);
}
float Viewer::get_travels_estimated_time() const
{
return m_impl->get_travels_estimated_time();
}
std::vector<float> Viewer::get_layers_estimated_times() const
{
return m_impl->get_layers_estimated_times();
}
AABox Viewer::get_bounding_box(const std::vector<EMoveType>& types) const
{
return m_impl->get_bounding_box(types);
}
AABox Viewer::get_extrusion_bounding_box(const std::vector<EGCodeExtrusionRole>& roles) const
{
return m_impl->get_extrusion_bounding_box(roles);
}
size_t Viewer::get_used_cpu_memory() const
{
return m_impl->get_used_cpu_memory();
}
size_t Viewer::get_used_gpu_memory() const
{
return m_impl->get_used_gpu_memory();
}
#if VGCODE_ENABLE_COG_AND_TOOL_MARKERS
Vec3 Viewer::get_cog_position() const
{
return m_impl->get_cog_marker_position();
}
float Viewer::get_cog_marker_scale_factor() const
{
return m_impl->get_cog_marker_scale_factor();
}
void Viewer::set_cog_marker_scale_factor(float factor)
{
m_impl->set_cog_marker_scale_factor(factor);
}
const Vec3& Viewer::get_tool_marker_position() const
{
return m_impl->get_tool_marker_position();
}
float Viewer::get_tool_marker_offset_z() const
{
return m_impl->get_tool_marker_offset_z();
}
void Viewer::set_tool_marker_offset_z(float offset_z)
{
m_impl->set_tool_marker_offset_z(offset_z);
}
float Viewer::get_tool_marker_scale_factor() const
{
return m_impl->get_tool_marker_scale_factor();
}
void Viewer::set_tool_marker_scale_factor(float factor)
{
m_impl->set_tool_marker_scale_factor(factor);
}
const Color& Viewer::get_tool_marker_color() const
{
return m_impl->get_tool_marker_color();
}
void Viewer::set_tool_marker_color(const Color& color)
{
m_impl->set_tool_marker_color(color);
}
float Viewer::get_tool_marker_alpha() const
{
return m_impl->get_tool_marker_alpha();
}
void Viewer::set_tool_marker_alpha(float alpha)
{
m_impl->set_tool_marker_alpha(alpha);
}
#endif // VGCODE_ENABLE_COG_AND_TOOL_MARKERS
} // namespace libvgcode

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,466 @@
///|/ Copyright (c) Prusa Research 2023 Enrico Turri @enricoturri1966, Pavel Mikuš @Godrak
///|/
///|/ libvgcode is released under the terms of the AGPLv3 or higher
///|/
#ifndef VGCODE_VIEWERIMPL_HPP
#define VGCODE_VIEWERIMPL_HPP
#include "Settings.hpp"
#include "SegmentTemplate.hpp"
#include "OptionTemplate.hpp"
#if VGCODE_ENABLE_COG_AND_TOOL_MARKERS
#include "CogMarker.hpp"
#include "ToolMarker.hpp"
#endif // VGCODE_ENABLE_COG_AND_TOOL_MARKERS
#include "../include/PathVertex.hpp"
#include "../include/ColorRange.hpp"
#include "../include/ColorPrint.hpp"
#include "Bitset.hpp"
#include "ViewRange.hpp"
#include "Layers.hpp"
#include "ExtrusionRoles.hpp"
#include <string>
#include <optional>
namespace libvgcode {
struct GCodeInputData;
class ViewerImpl
{
public:
ViewerImpl();
~ViewerImpl() { shutdown(); }
ViewerImpl(const ViewerImpl& other) = delete;
ViewerImpl(ViewerImpl&& other) = delete;
ViewerImpl& operator = (const ViewerImpl& other) = delete;
ViewerImpl& operator = (ViewerImpl&& other) = delete;
//
// Initialize shaders, uniform indices and segment geometry.
//
void init(const std::string& opengl_context_version);
//
// Release the resources used by the viewer.
//
void shutdown();
//
// Reset all caches and free gpu memory.
//
void reset();
//
// Setup all the variables used for visualization of the toolpaths
// from the given gcode data.
//
void load(GCodeInputData&& gcode_data);
//
// Update the visibility property of toolpaths in dependence
// of the current settings
//
void update_enabled_entities();
//
// Update the color of toolpaths in dependence of the current
// view type and settings
//
void update_colors();
void update_colors_texture();
//
// Render the toolpaths
//
void render(const Mat4x4& view_matrix, const Mat4x4& projection_matrix);
EViewType get_view_type() const { return m_settings.view_type; }
void set_view_type(EViewType type);
ETimeMode get_time_mode() const { return m_settings.time_mode; }
void set_time_mode(ETimeMode mode);
const Interval& get_layers_view_range() const { return m_layers.get_view_range(); }
void set_layers_view_range(const Interval& range) { set_layers_view_range(range[0], range[1]); }
void set_layers_view_range(Interval::value_type min, Interval::value_type max);
bool is_top_layer_only_view_range() const { return m_settings.top_layer_only_view_range; }
void toggle_top_layer_only_view_range();
bool is_spiral_vase_mode() const { return m_settings.spiral_vase_mode; }
std::vector<ETimeMode> get_time_modes() const;
size_t get_layers_count() const { return m_layers.count(); }
float get_layer_z(size_t layer_id) const { return m_layers.get_layer_z(layer_id); }
std::vector<float> get_layers_zs() const { return m_layers.get_zs(); }
size_t get_layer_id_at(float z) const { return m_layers.get_layer_id_at(z); }
size_t get_used_extruders_count() const { return m_used_extruders.size(); }
std::vector<uint8_t> get_used_extruders_ids() const;
size_t get_color_prints_count(uint8_t extruder_id) const;
std::vector<ColorPrint> get_color_prints(uint8_t extruder_id) const;
AABox get_bounding_box(const std::vector<EMoveType>& types = {
EMoveType::Retract, EMoveType::Unretract, EMoveType::Seam, EMoveType::ToolChange,
EMoveType::ColorChange, EMoveType::PausePrint, EMoveType::CustomGCode, EMoveType::Travel,
EMoveType::Wipe, EMoveType::Extrude }) const;
AABox get_extrusion_bounding_box(const std::vector<EGCodeExtrusionRole>& roles = {
EGCodeExtrusionRole::Perimeter, EGCodeExtrusionRole::ExternalPerimeter, EGCodeExtrusionRole::OverhangPerimeter,
EGCodeExtrusionRole::InternalInfill, EGCodeExtrusionRole::SolidInfill, EGCodeExtrusionRole::TopSolidInfill,
EGCodeExtrusionRole::Ironing, EGCodeExtrusionRole::BridgeInfill, EGCodeExtrusionRole::GapFill,
EGCodeExtrusionRole::Skirt, EGCodeExtrusionRole::SupportMaterial, EGCodeExtrusionRole::SupportMaterialInterface,
EGCodeExtrusionRole::WipeTower, EGCodeExtrusionRole::Custom }) const;
bool is_option_visible(EOptionType type) const;
void toggle_option_visibility(EOptionType type);
bool is_extrusion_role_visible(EGCodeExtrusionRole role) const;
void toggle_extrusion_role_visibility(EGCodeExtrusionRole role);
const Interval& get_view_full_range() const { return m_view_range.get_full(); }
const Interval& get_view_enabled_range() const { return m_view_range.get_enabled(); }
const Interval& get_view_visible_range() const { return m_view_range.get_visible(); }
void set_view_visible_range(Interval::value_type min, Interval::value_type max);
size_t get_vertices_count() const { return m_vertices.size(); }
const PathVertex& get_current_vertex() const { return get_vertex_at(get_current_vertex_id()); }
size_t get_current_vertex_id() const { return static_cast<size_t>(m_view_range.get_visible()[1]); }
const PathVertex& get_vertex_at(size_t id) const {
return (id < m_vertices.size()) ? m_vertices[id] : PathVertex::DUMMY_PATH_VERTEX;
}
float get_estimated_time() const { return m_total_time[static_cast<size_t>(m_settings.time_mode)]; }
float get_estimated_time_at(size_t id) const;
Color get_vertex_color(const PathVertex& vertex) const;
size_t get_extrusion_roles_count() const { return m_extrusion_roles.get_roles_count(); }
std::vector<EGCodeExtrusionRole> get_extrusion_roles() const { return m_extrusion_roles.get_roles(); }
float get_extrusion_role_estimated_time(EGCodeExtrusionRole role) const { return m_extrusion_roles.get_time(role, m_settings.time_mode); }
size_t get_options_count() const { return m_options.size(); }
const std::vector<EOptionType>& get_options() const { return m_options; }
float get_travels_estimated_time() const { return m_travels_time[static_cast<size_t>(m_settings.time_mode)]; }
std::vector<float> get_layers_estimated_times() const { return m_layers.get_times(m_settings.time_mode); }
size_t get_tool_colors_count() const { return m_tool_colors.size(); }
const Palette& get_tool_colors() const { return m_tool_colors; }
void set_tool_colors(const Palette& colors);
size_t get_color_print_colors_count() const { return m_color_print_colors.size(); }
const Palette& get_color_print_colors() const { return m_color_print_colors; }
void set_color_print_colors(const Palette& colors);
const Color& get_extrusion_role_color(EGCodeExtrusionRole role) const;
void set_extrusion_role_color(EGCodeExtrusionRole role, const Color& color);
void reset_default_extrusion_roles_colors();
const Color& get_option_color(EOptionType type) const;
void set_option_color(EOptionType type, const Color& color);
void reset_default_options_colors();
const ColorRange& get_color_range(EViewType type) const;
void set_color_range_palette(EViewType type, const Palette& palette);
float get_travels_radius() const { return m_travels_radius; }
void set_travels_radius(float radius);
float get_wipes_radius() const { return m_wipes_radius; }
void set_wipes_radius(float radius);
size_t get_used_cpu_memory() const;
size_t get_used_gpu_memory() const;
#if VGCODE_ENABLE_COG_AND_TOOL_MARKERS
Vec3 get_cog_marker_position() const { return m_cog_marker.get_position(); }
float get_cog_marker_scale_factor() const { return m_cog_marker_scale_factor; }
void set_cog_marker_scale_factor(float factor) { m_cog_marker_scale_factor = std::max(factor, 0.001f); }
const Vec3& get_tool_marker_position() const { return m_tool_marker.get_position(); }
float get_tool_marker_offset_z() const { return m_tool_marker.get_offset_z(); }
void set_tool_marker_offset_z(float offset_z) { m_tool_marker.set_offset_z(offset_z); }
float get_tool_marker_scale_factor() const { return m_tool_marker_scale_factor; }
void set_tool_marker_scale_factor(float factor) { m_tool_marker_scale_factor = std::max(factor, 0.001f); }
const Color& get_tool_marker_color() const { return m_tool_marker.get_color(); }
void set_tool_marker_color(const Color& color) { m_tool_marker.set_color(color); }
float get_tool_marker_alpha() const { return m_tool_marker.get_alpha(); }
void set_tool_marker_alpha(float alpha) { m_tool_marker.set_alpha(alpha); }
#endif // VGCODE_ENABLE_COG_AND_TOOL_MARKERS
private:
//
// Settings used to render the toolpaths
//
Settings m_settings;
//
// Detected layers
//
Layers m_layers;
//
// Detected extrusion roles
//
ExtrusionRoles m_extrusion_roles;
//
// Detected options
//
std::vector<EOptionType> m_options;
//
// Detected used extruders ids
//
std::map<uint8_t, std::vector<ColorPrint>> m_used_extruders;
//
// Vertices ranges for visualization
//
ViewRange m_view_range;
//
// Detected total moves times
//
std::array<float, TIME_MODES_COUNT> m_total_time{ 0.0f, 0.0f };
//
// Detected travel moves times
//
std::array<float, TIME_MODES_COUNT> m_travels_time{ 0.0f, 0.0f };
//
// Radius of cylinders used to render travel moves segments
//
float m_travels_radius{ DEFAULT_TRAVELS_RADIUS_MM };
//
// Radius of cylinders used to render wipe moves segments
//
float m_wipes_radius{ DEFAULT_WIPES_RADIUS_MM };
//
// Palette used to render extrusion roles
//
std::array<Color, size_t(EGCodeExtrusionRole::COUNT)> m_extrusion_roles_colors;
//
// Palette used to render options
//
std::array<Color, size_t(EOptionType::COUNT)> m_options_colors;
bool m_initialized{ false };
//
// The OpenGL element used to represent all toolpath segments
//
SegmentTemplate m_segment_template;
//
// The OpenGL element used to represent all option markers
//
OptionTemplate m_option_template;
#if VGCODE_ENABLE_COG_AND_TOOL_MARKERS
//
// The OpenGL element used to represent the center of gravity
//
CogMarker m_cog_marker;
float m_cog_marker_scale_factor{ 1.0f };
//
// The OpenGL element used to represent the tool nozzle
//
ToolMarker m_tool_marker;
float m_tool_marker_scale_factor{ 1.0f };
#endif // VGCODE_ENABLE_COG_AND_TOOL_MARKERS
//
// cpu buffer to store vertices
//
std::vector<PathVertex> m_vertices;
// Cache for the colors to reduce the need to recalculate colors of all the vertices.
std::vector<float> m_vertices_colors;
//
// Variables used for toolpaths visibiliity
//
BitSet<> m_valid_lines_bitset;
//
// Variables used for toolpaths coloring
//
std::optional<Settings> m_settings_used_for_ranges;
ColorRange m_height_range;
ColorRange m_width_range;
ColorRange m_speed_range;
ColorRange m_actual_speed_range;
ColorRange m_fan_speed_range;
ColorRange m_temperature_range;
ColorRange m_volumetric_rate_range;
ColorRange m_actual_volumetric_rate_range;
std::array<ColorRange, COLOR_RANGE_TYPES_COUNT> m_layer_time_range{
ColorRange(EColorRangeType::Linear), ColorRange(EColorRangeType::Logarithmic)
};
Palette m_tool_colors;
Palette m_color_print_colors;
//
// OpenGL shaders ids
//
unsigned int m_segments_shader_id{ 0 };
unsigned int m_options_shader_id{ 0 };
#if VGCODE_ENABLE_COG_AND_TOOL_MARKERS
unsigned int m_cog_marker_shader_id{ 0 };
unsigned int m_tool_marker_shader_id{ 0 };
#endif // VGCODE_ENABLE_COG_AND_TOOL_MARKERS
//
// Caches for OpenGL uniforms id for segments shader
//
int m_uni_segments_view_matrix_id{ -1 };
int m_uni_segments_projection_matrix_id{ -1 };
int m_uni_segments_camera_position_id{ -1 };
int m_uni_segments_positions_tex_id{ -1 };
int m_uni_segments_height_width_angle_tex_id{ -1 };
int m_uni_segments_colors_tex_id{ -1 };
int m_uni_segments_segment_index_tex_id{ -1 };
//
// Caches for OpenGL uniforms id for options shader
//
int m_uni_options_view_matrix_id{ -1 };
int m_uni_options_projection_matrix_id{ -1 };
int m_uni_options_positions_tex_id{ -1 };
int m_uni_options_height_width_angle_tex_id{ -1 };
int m_uni_options_colors_tex_id{ -1 };
int m_uni_options_segment_index_tex_id{ -1 };
#if VGCODE_ENABLE_COG_AND_TOOL_MARKERS
//
// Caches for OpenGL uniforms id for cog marker shader
//
int m_uni_cog_marker_world_center_position{ -1 };
int m_uni_cog_marker_scale_factor{ -1 };
int m_uni_cog_marker_view_matrix{ -1 };
int m_uni_cog_marker_projection_matrix{ -1 };
//
// Caches for OpenGL uniforms id for tool marker shader
//
int m_uni_tool_marker_world_origin{ -1 };
int m_uni_tool_marker_scale_factor{ -1 };
int m_uni_tool_marker_view_matrix{ -1 };
int m_uni_tool_marker_projection_matrix{ -1 };
int m_uni_tool_marker_color_base{ -1 };
#endif // VGCODE_ENABLE_COG_AND_TOOL_MARKERS
#ifdef ENABLE_OPENGL_ES
class TextureData
{
public:
void init(size_t vertices_count);
void set_positions(const std::vector<Vec3>& positions);
void set_heights_widths_angles(const std::vector<Vec3>& heights_widths_angles);
void set_colors(const std::vector<float>& colors);
void set_enabled_segments(const std::vector<uint32_t>& enabled_segments);
void set_enabled_options(const std::vector<uint32_t>& enabled_options);
void reset();
size_t get_count() const { return m_count; }
std::pair<unsigned int, size_t> get_positions_tex_id(size_t id) const;
std::pair<unsigned int, size_t> get_heights_widths_angles_tex_id(size_t id) const;
std::pair<unsigned int, size_t> get_colors_tex_id(size_t id) const;
std::pair<unsigned int, size_t> get_enabled_segments_tex_id(size_t id) const;
std::pair<unsigned int, size_t> get_enabled_options_tex_id(size_t id) const;
size_t get_enabled_segments_count() const;
size_t get_enabled_options_count() const;
size_t max_texture_capacity() const { return m_width * m_height; }
size_t get_used_gpu_memory() const;
private:
//
// Texture width
//
size_t m_width{ 0 };
//
// Texture height
//
size_t m_height{ 0 };
//
// Count of textures
//
size_t m_count{ 0 };
//
// Caches for size of data sent to gpu, in bytes
//
size_t m_positions_size{ 0 };
size_t m_height_width_angle_size{ 0 };
size_t m_colors_size{ 0 };
size_t m_enabled_segments_size{ 0 };
size_t m_enabled_options_size{ 0 };
struct TexIds
{
//
// OpenGL texture to store positions
//
std::pair<unsigned int, size_t> positions{ 0, 0 };
//
// OpenGL texture to store heights, widths and angles
//
std::pair<unsigned int, size_t> heights_widths_angles{ 0, 0 };
//
// OpenGL texture to store colors
//
std::pair<unsigned int, size_t> colors{ 0, 0 };
//
// OpenGL texture to store enabled segments
//
std::pair<unsigned int, size_t> enabled_segments{ 0, 0 };
//
// OpenGL texture to store enabled options
//
std::pair<unsigned int, size_t> enabled_options{ 0, 0 };
};
std::vector<TexIds> m_tex_ids;
};
TextureData m_texture_data;
#else
//
// OpenGL buffers to store positions
//
unsigned int m_positions_buf_id{ 0 };
unsigned int m_positions_tex_id{ 0 };
//
// OpenGL buffers to store heights, widths and angles
//
unsigned int m_heights_widths_angles_buf_id{ 0 };
unsigned int m_heights_widths_angles_tex_id{ 0 };
//
// OpenGL buffers to store colors
//
unsigned int m_colors_buf_id{ 0 };
unsigned int m_colors_tex_id{ 0 };
//
// OpenGL buffers to store enabled segments
//
unsigned int m_enabled_segments_buf_id{ 0 };
unsigned int m_enabled_segments_tex_id{ 0 };
size_t m_enabled_segments_count{ 0 };
//
// OpenGL buffers to store enabled options
//
unsigned int m_enabled_options_buf_id{ 0 };
unsigned int m_enabled_options_tex_id{ 0 };
size_t m_enabled_options_count{ 0 };
//
// Caches for size of data sent to gpu, in bytes
//
size_t m_positions_tex_size{ 0 };
size_t m_height_width_angle_tex_size{ 0 };
size_t m_colors_tex_size{ 0 };
size_t m_enabled_segments_tex_size{ 0 };
size_t m_enabled_options_tex_size{ 0 };
#endif // ENABLE_OPENGL_ES
void update_view_full_range();
void update_color_ranges();
void update_heights_widths();
void render_segments(const Mat4x4& view_matrix, const Mat4x4& projection_matrix, const Vec3& camera_position);
void render_options(const Mat4x4& view_matrix, const Mat4x4& projection_matrix);
#if VGCODE_ENABLE_COG_AND_TOOL_MARKERS
void render_cog_marker(const Mat4x4& view_matrix, const Mat4x4& projection_matrix);
void render_tool_marker(const Mat4x4& view_matrix, const Mat4x4& projection_matrix);
#endif // VGCODE_ENABLE_COG_AND_TOOL_MARKERS
};
} // namespace libvgcode
#endif // VGCODE_VIEWERIMPL_HPP

View File

@@ -267,6 +267,8 @@ set(SLIC3R_GUI_SOURCES
GUI/Jobs/Worker.hpp
GUI/KBShortcutsDialog.cpp
GUI/KBShortcutsDialog.hpp
GUI/LibVGCode/LibVGCodeWrapper.hpp
GUI/LibVGCode/LibVGCodeWrapper.cpp
GUI/MainFrame.cpp
GUI/MainFrame.hpp
GUI/MarkdownTip.cpp
@@ -627,7 +629,7 @@ source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR} FILES ${SLIC3R_GUI_SOURCES})
encoding_check(libslic3r_gui)
find_package(libnoise REQUIRED)
target_link_libraries(libslic3r_gui libslic3r cereal::cereal imgui imguizmo minilzo GLEW::GLEW OpenGL::GL hidapi ${wxWidgets_LIBRARIES} glfw libcurl OpenSSL::SSL OpenSSL::Crypto noise::noise)
target_link_libraries(libslic3r_gui libslic3r cereal::cereal imgui imguizmo minilzo libvgcode GLEW::GLEW OpenGL::GL hidapi ${wxWidgets_LIBRARIES} glfw libcurl OpenSSL::SSL OpenSSL::Crypto noise::noise)
if (MSVC)
target_link_libraries(libslic3r_gui Setupapi.lib)

View File

@@ -912,7 +912,11 @@ void GLVolumeCollection::render(GLVolumeCollection::ERenderType type,
return;
GLShaderProgram* sink_shader = GUI::wxGetApp().get_shader("flat");
GLShaderProgram* edges_shader = GUI::wxGetApp().get_shader("flat");
#if SLIC3R_OPENGL_ES
GLShaderProgram* edges_shader = GUI::wxGetApp().get_shader("dashed_lines");
#else
GLShaderProgram* edges_shader = GUI::OpenGLManager::get_gl_info().is_core_profile() ? GUI::wxGetApp().get_shader("dashed_thick_lines") : GUI::wxGetApp().get_shader("flat");
#endif // SLIC3R_OPENGL_ES
if (type == ERenderType::Transparent) {
glsafe(::glEnable(GL_BLEND));

File diff suppressed because it is too large Load Diff

View File

@@ -10,6 +10,10 @@
#include <boost/iostreams/device/mapped_file.hpp>
#include "LibVGCode/LibVGCodeWrapper.hpp"
// needed for tech VGCODE_ENABLE_COG_AND_TOOL_MARKERS
#include <libvgcode/include/Types.hpp>
#include <cstdint>
#include <float.h>
#include <set>
@@ -33,350 +37,6 @@ static const float SLIDER_RIGHT_MARGIN = 124.0f;
static const float SLIDER_BOTTOM_MARGIN = 64.0f;
class GCodeViewer
{
using IBufferType = unsigned short;
using VertexBuffer = std::vector<float>;
using MultiVertexBuffer = std::vector<VertexBuffer>;
using IndexBuffer = std::vector<IBufferType>;
using MultiIndexBuffer = std::vector<IndexBuffer>;
using InstanceBuffer = std::vector<float>;
using InstanceIdBuffer = std::vector<size_t>;
using InstancesOffsets = std::vector<Vec3f>;
static const std::vector<ColorRGBA> Extrusion_Role_Colors;
static const std::vector<ColorRGBA> Options_Colors;
static const std::vector<ColorRGBA> Travel_Colors;
static const std::vector<ColorRGBA> Range_Colors;
static const ColorRGBA Wipe_Color;
static const ColorRGBA Neutral_Color;
enum class EOptionsColors : unsigned char
{
Retractions,
Unretractions,
Seams,
ToolChanges,
ColorChanges,
PausePrints,
CustomGCodes
};
// vbo buffer containing vertices data used to render a specific toolpath type
struct VBuffer
{
enum class EFormat : unsigned char
{
// vertex format: 3 floats -> position.x|position.y|position.z
Position,
// vertex format: 4 floats -> position.x|position.y|position.z|normal.x
PositionNormal1,
// vertex format: 6 floats -> position.x|position.y|position.z|normal.x|normal.y|normal.z
PositionNormal3
};
EFormat format{ EFormat::Position };
// vbos id
std::vector<unsigned int> vbos;
// sizes of the buffers, in bytes, used in export to obj
std::vector<size_t> sizes;
// count of vertices, updated after data are sent to gpu
size_t count{ 0 };
size_t data_size_bytes() const { return count * vertex_size_bytes(); }
// We set 65536 as max count of vertices inside a vertex buffer to allow
// to use unsigned short in place of unsigned int for indices in the index buffer, to save memory
size_t max_size_bytes() const { return 65536 * vertex_size_bytes(); }
size_t vertex_size_floats() const { return position_size_floats() + normal_size_floats(); }
size_t vertex_size_bytes() const { return vertex_size_floats() * sizeof(float); }
size_t position_offset_floats() const { return 0; }
size_t position_offset_bytes() const { return position_offset_floats() * sizeof(float); }
size_t position_size_floats() const { return 3; }
size_t position_size_bytes() const { return position_size_floats() * sizeof(float); }
size_t normal_offset_floats() const {
assert(format == EFormat::PositionNormal1 || format == EFormat::PositionNormal3);
return position_size_floats();
}
size_t normal_offset_bytes() const { return normal_offset_floats() * sizeof(float); }
size_t normal_size_floats() const {
switch (format)
{
case EFormat::PositionNormal1: { return 1; }
case EFormat::PositionNormal3: { return 3; }
default: { return 0; }
}
}
size_t normal_size_bytes() const { return normal_size_floats() * sizeof(float); }
void reset();
};
// buffer containing instances data used to render a toolpaths using instanced or batched models
// instance record format:
// instanced models: 5 floats -> position.x|position.y|position.z|width|height (which are sent to the shader as -> vec3 (offset) + vec2 (scales) in GLModel::render_instanced())
// batched models: 3 floats -> position.x|position.y|position.z
struct InstanceVBuffer
{
// ranges used to render only subparts of the intances
struct Ranges
{
struct Range
{
// offset in bytes of the 1st instance to render
unsigned int offset;
// count of instances to render
unsigned int count;
// vbo id
unsigned int vbo{ 0 };
// Color to apply to the instances
ColorRGBA color;
};
std::vector<Range> ranges;
void reset();
};
enum class EFormat : unsigned char
{
InstancedModel,
BatchedModel
};
EFormat format;
// cpu-side buffer containing all instances data
InstanceBuffer buffer;
// indices of the moves for all instances
std::vector<size_t> s_ids;
// position offsets, used to show the correct value of the tool position
InstancesOffsets offsets;
Ranges render_ranges;
size_t data_size_bytes() const { return s_ids.size() * instance_size_bytes(); }
size_t instance_size_floats() const {
switch (format)
{
case EFormat::InstancedModel: { return 5; }
case EFormat::BatchedModel: { return 3; }
default: { return 0; }
}
}
size_t instance_size_bytes() const { return instance_size_floats() * sizeof(float); }
void reset();
};
// ibo buffer containing indices data (for lines/triangles) used to render a specific toolpath type
struct IBuffer
{
// id of the associated vertex buffer
unsigned int vbo{ 0 };
// ibo id
unsigned int ibo{ 0 };
// count of indices, updated after data are sent to gpu
size_t count{ 0 };
void reset();
};
// Used to identify different toolpath sub-types inside a IBuffer
struct Path
{
struct Endpoint
{
// index of the buffer in the multibuffer vector
// the buffer type may change:
// it is the vertex buffer while extracting vertices data,
// the index buffer while extracting indices data
unsigned int b_id{ 0 };
// index into the buffer
size_t i_id{ 0 };
// move id
size_t s_id{ 0 };
Vec3f position{ Vec3f::Zero() };
};
struct Sub_Path
{
Endpoint first;
Endpoint last;
bool contains(size_t s_id) const {
return first.s_id <= s_id && s_id <= last.s_id;
}
};
EMoveType type{ EMoveType::Noop };
ExtrusionRole role{ erNone };
float delta_extruder{ 0.0f };
float height{ 0.0f };
float width{ 0.0f };
float feedrate{ 0.0f };
float fan_speed{ 0.0f };
float temperature{ 0.0f };
float volumetric_rate{ 0.0f };
float layer_time{ 0.0f };
unsigned char extruder_id{ 0 };
unsigned char cp_color_id{ 0 };
std::vector<Sub_Path> sub_paths;
bool matches(const GCodeProcessorResult::MoveVertex& move) const;
size_t vertices_count() const {
return sub_paths.empty() ? 0 : sub_paths.back().last.s_id - sub_paths.front().first.s_id + 1;
}
bool contains(size_t s_id) const {
return sub_paths.empty() ? false : sub_paths.front().first.s_id <= s_id && s_id <= sub_paths.back().last.s_id;
}
int get_id_of_sub_path_containing(size_t s_id) const {
if (sub_paths.empty())
return -1;
else {
for (int i = 0; i < static_cast<int>(sub_paths.size()); ++i) {
if (sub_paths[i].contains(s_id))
return i;
}
return -1;
}
}
void add_sub_path(const GCodeProcessorResult::MoveVertex& move, unsigned int b_id, size_t i_id, size_t s_id) {
Endpoint endpoint = { b_id, i_id, s_id, move.position };
sub_paths.push_back({ endpoint , endpoint });
}
};
// Used to batch the indices needed to render the paths
struct RenderPath
{
// Index of the parent tbuffer
unsigned char tbuffer_id;
// Render path property
ColorRGBA color;
// Index of the buffer in TBuffer::indices
unsigned int ibuffer_id;
// Render path content
// Index of the path in TBuffer::paths
unsigned int path_id;
std::vector<unsigned int> sizes;
std::vector<size_t> offsets; // use size_t because we need an unsigned integer whose size matches pointer's size (used in the call glMultiDrawElements())
bool contains(size_t offset) const {
for (size_t i = 0; i < offsets.size(); ++i) {
if (offsets[i] <= offset && offset <= offsets[i] + static_cast<size_t>(sizes[i] * sizeof(IBufferType)))
return true;
}
return false;
}
};
struct RenderPathPropertyLower {
bool operator() (const RenderPath &l, const RenderPath &r) const {
if (l.tbuffer_id < r.tbuffer_id)
return true;
if (l.color < r.color)
return true;
else if (l.color > r.color)
return false;
return l.ibuffer_id < r.ibuffer_id;
}
};
struct RenderPathPropertyEqual {
bool operator() (const RenderPath &l, const RenderPath &r) const {
return l.tbuffer_id == r.tbuffer_id && l.ibuffer_id == r.ibuffer_id && l.color == r.color;
}
};
// buffer containing data for rendering a specific toolpath type
struct TBuffer
{
enum class ERenderPrimitiveType : unsigned char
{
Line,
Triangle,
InstancedModel,
BatchedModel
};
ERenderPrimitiveType render_primitive_type;
// buffers for point, line and triangle primitive types
VBuffer vertices;
std::vector<IBuffer> indices;
struct Model
{
GLModel model;
ColorRGBA color;
InstanceVBuffer instances;
GLModel::Geometry data;
void reset();
};
// contain the buffer for model primitive types
Model model;
std::string shader;
std::vector<Path> paths;
std::vector<RenderPath> render_paths;
bool visible{ false };
void reset();
// b_id index of buffer contained in this->indices
// i_id index of first index contained in this->indices[b_id]
// s_id index of first vertex contained in this->vertices
void add_path(const GCodeProcessorResult::MoveVertex& move, unsigned int b_id, size_t i_id, size_t s_id);
unsigned int max_vertices_per_segment() const {
switch (render_primitive_type)
{
case ERenderPrimitiveType::Line: { return 2; }
case ERenderPrimitiveType::Triangle: { return 8; }
default: { return 0; }
}
}
size_t max_vertices_per_segment_size_floats() const { return vertices.vertex_size_floats() * static_cast<size_t>(max_vertices_per_segment()); }
size_t max_vertices_per_segment_size_bytes() const { return max_vertices_per_segment_size_floats() * sizeof(float); }
unsigned int indices_per_segment() const {
switch (render_primitive_type)
{
case ERenderPrimitiveType::Line: { return 2; }
case ERenderPrimitiveType::Triangle: { return 30; } // 3 indices x 10 triangles
default: { return 0; }
}
}
size_t indices_per_segment_size_bytes() const { return static_cast<size_t>(indices_per_segment() * sizeof(IBufferType)); }
unsigned int max_indices_per_segment() const {
switch (render_primitive_type)
{
case ERenderPrimitiveType::Line: { return 2; }
case ERenderPrimitiveType::Triangle: { return 36; } // 3 indices x 12 triangles
default: { return 0; }
}
}
size_t max_indices_per_segment_size_bytes() const { return max_indices_per_segment() * sizeof(IBufferType); }
bool has_data() const {
switch (render_primitive_type)
{
case ERenderPrimitiveType::Line:
case ERenderPrimitiveType::Triangle: {
return !vertices.vbos.empty() && vertices.vbos.front() != 0 && !indices.empty() && indices.front().ibo != 0;
}
case ERenderPrimitiveType::InstancedModel: { return model.model.is_initialized() && !model.instances.buffer.empty(); }
case ERenderPrimitiveType::BatchedModel: {
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; }
}
}
};
// helper to render shells
struct Shells
{
@@ -388,239 +48,45 @@ class GCodeViewer
bool previewing{ false };
};
// helper to render extrusion paths
struct Extrusions
{
struct Range
{
float min;
float max;
unsigned int count;
bool log_scale;
Range() { reset(); }
void update_from(const float value) {
if (value != max && value != min)
++count;
min = std::min(min, value);
max = std::max(max, value);
}
void reset(bool log = false) { min = FLT_MAX; max = -FLT_MAX; count = 0; log_scale = log; }
float step_size() const;
ColorRGBA get_color_at(float value) const;
float get_value_at_step(int step) const;
};
struct Ranges
{
// 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;
// Color mapping by extrusion temperature.
Range temperature;
// Color mapping by layer time.
Range layer_duration;
Range layer_duration_log;
void reset() {
height.reset();
width.reset();
feedrate.reset();
fan_speed.reset();
volumetric_rate.reset();
temperature.reset();
layer_duration.reset();
layer_duration_log.reset(true);
}
};
unsigned int role_visibility_flags{ 0 };
Ranges ranges;
void reset_role_visibility_flags() {
role_visibility_flags = 0;
for (unsigned int i = 0; i < erCount; ++i) {
role_visibility_flags |= 1 << i;
}
}
void reset_ranges() { ranges.reset(); }
};
class Layers
{
public:
struct Endpoints
{
size_t first{ 0 };
size_t last{ 0 };
bool operator == (const Endpoints& other) const { return first == other.first && last == other.last; }
bool operator != (const Endpoints& other) const { return !operator==(other); }
};
private:
std::vector<double> m_zs;
std::vector<Endpoints> m_endpoints;
public:
void append(double z, Endpoints endpoints) {
m_zs.emplace_back(z);
m_endpoints.emplace_back(endpoints);
}
void reset() {
m_zs = std::vector<double>();
m_endpoints = std::vector<Endpoints>();
}
size_t size() const { return m_zs.size(); }
bool empty() const { return m_zs.empty(); }
const std::vector<double>& get_zs() const { return m_zs; }
const std::vector<Endpoints>& get_endpoints() const { return m_endpoints; }
std::vector<Endpoints>& get_endpoints() { return m_endpoints; }
double get_z_at(unsigned int id) const { return (id < m_zs.size()) ? m_zs[id] : 0.0; }
Endpoints get_endpoints_at(unsigned int id) const { return (id < m_endpoints.size()) ? m_endpoints[id] : Endpoints(); }
int get_l_at(float z) const
{
auto iter = std::upper_bound(m_zs.begin(), m_zs.end(), z);
return std::distance(m_zs.begin(), iter);
}
bool operator != (const Layers& other) const {
if (m_zs != other.m_zs)
return true;
if (m_endpoints != other.m_endpoints)
return true;
return false;
}
};
// used to render the toolpath caps of the current sequential range
// (i.e. when sliding on the horizontal slider)
struct SequentialRangeCap
{
TBuffer* buffer{ nullptr };
unsigned int ibo{ 0 };
unsigned int vbo{ 0 };
ColorRGBA color;
~SequentialRangeCap();
bool is_renderable() const { return buffer != nullptr; }
void reset();
size_t indices_count() const { return 6; }
};
#if ENABLE_GCODE_VIEWER_STATISTICS
struct Statistics
{
// time
int64_t results_time{ 0 };
int64_t load_time{ 0 };
int64_t load_vertices{ 0 };
int64_t smooth_vertices{ 0 };
int64_t load_indices{ 0 };
int64_t refresh_time{ 0 };
int64_t refresh_paths_time{ 0 };
// opengl calls
int64_t gl_multi_lines_calls_count{ 0 };
int64_t gl_multi_triangles_calls_count{ 0 };
int64_t gl_triangles_calls_count{ 0 };
int64_t gl_instanced_models_calls_count{ 0 };
int64_t gl_batched_models_calls_count{ 0 };
// memory
int64_t results_size{ 0 };
int64_t total_vertices_gpu_size{ 0 };
int64_t total_indices_gpu_size{ 0 };
int64_t total_instances_gpu_size{ 0 };
int64_t max_vbuffer_gpu_size{ 0 };
int64_t max_ibuffer_gpu_size{ 0 };
int64_t paths_size{ 0 };
int64_t render_paths_size{ 0 };
int64_t models_instances_size{ 0 };
// other
int64_t travel_segments_count{ 0 };
int64_t wipe_segments_count{ 0 };
int64_t extrude_segments_count{ 0 };
int64_t instances_count{ 0 };
int64_t batched_count{ 0 };
int64_t vbuffers_count{ 0 };
int64_t ibuffers_count{ 0 };
void reset_all() {
reset_times();
reset_opengl();
reset_sizes();
reset_others();
}
void reset_times() {
results_time = 0;
load_time = 0;
load_vertices = 0;
smooth_vertices = 0;
load_indices = 0;
refresh_time = 0;
refresh_paths_time = 0;
}
void reset_opengl() {
gl_multi_lines_calls_count = 0;
gl_multi_triangles_calls_count = 0;
gl_triangles_calls_count = 0;
gl_instanced_models_calls_count = 0;
gl_batched_models_calls_count = 0;
}
void reset_sizes() {
results_size = 0;
total_vertices_gpu_size = 0;
total_indices_gpu_size = 0;
total_instances_gpu_size = 0;
max_vbuffer_gpu_size = 0;
max_ibuffer_gpu_size = 0;
paths_size = 0;
render_paths_size = 0;
models_instances_size = 0;
}
void reset_others() {
travel_segments_count = 0;
wipe_segments_count = 0;
extrude_segments_count = 0;
instances_count = 0;
batched_count = 0;
vbuffers_count = 0;
ibuffers_count = 0;
}
};
#endif // ENABLE_GCODE_VIEWER_STATISTICS
public:
enum class EViewType : unsigned char;
struct SequentialView
{
#if ENABLE_ACTUAL_SPEED_DEBUG
struct ActualSpeedImguiWidget
{
std::pair<float, float> y_range = { 0.0f, 0.0f };
std::vector<std::pair<float, ColorRGBA>> levels;
struct Item
{
float pos{ 0.0f };
float speed{ 0.0f };
bool internal{ false };
};
std::vector<Item> data;
int plot(const char* label, const std::array<float, 2>& frame_size = { 0.0f, 0.0f });
};
#endif // ENABLE_ACTUAL_SPEED_DEBUG
class Marker
{
GLModel m_model;
Vec3f m_world_position;
Transform3f m_world_transform;
// for seams, the position of the marker is on the last endpoint of the toolpath containing it
// the offset is used to show the correct value of tool position in the "ToolPosition" window
// see implementation of render() method
Vec3f m_world_offset;
float m_z_offset{ 0.5f };
// z offset of the model
float m_model_z_offset{ 0.5f };
GCodeProcessorResult::MoveVertex m_curr_move;
bool m_visible{ true };
bool m_is_dark = false;
bool m_fixed_screen_size{ false };
float m_scale_factor{ 1.0f };
#if ENABLE_ACTUAL_SPEED_DEBUG
ActualSpeedImguiWidget m_actual_speed_imgui_widget;
#endif // ENABLE_ACTUAL_SPEED_DEBUG
public:
float m_scale = 1.0f;
@@ -629,13 +95,26 @@ public:
const BoundingBoxf3& get_bounding_box() const { return m_model.get_bounding_box(); }
void set_world_position(const Vec3f& position);
void set_world_position(const Vec3f& position) { m_world_position = position; }
void set_world_offset(const Vec3f& offset) { m_world_offset = offset; }
#if ENABLE_ACTUAL_SPEED_DEBUG
void set_actual_speed_y_range(const std::pair<float, float>& y_range) {
m_actual_speed_imgui_widget.y_range = y_range;
}
void set_actual_speed_levels(const std::vector<std::pair<float, ColorRGBA>>& levels) {
m_actual_speed_imgui_widget.levels = levels;
}
void set_actual_speed_data(const std::vector<ActualSpeedImguiWidget::Item>& data) {
m_actual_speed_imgui_widget.data = data;
}
#endif // ENABLE_ACTUAL_SPEED_DEBUG
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);
void render(int canvas_width, int canvas_height, const libvgcode::EViewType& view_type);
void render_position_window(const libvgcode::Viewer* viewer);
void on_change_color_mode(bool is_dark) { m_is_dark = is_dark; }
void update_curr_move(const GCodeProcessorResult::MoveVertex move);
@@ -682,25 +161,11 @@ public:
void stop_mapping_file();
};
struct Endpoints
{
size_t first{ 0 };
size_t last{ 0 };
};
bool skip_invisible_moves{ false };
Endpoints endpoints;
Endpoints current;
Endpoints last_current;
Endpoints global;
Vec3f current_position{ Vec3f::Zero() };
Vec3f current_offset{ Vec3f::Zero() };
Marker marker;
GCodeWindow gcode_window;
std::vector<unsigned int> gcode_ids;
float m_scale = 1.0;
bool m_show_marker = false;
void render(const bool has_render_path, float legend_height, int canvas_width, int canvas_height, int right_margin, const EViewType& view_type);
void render(const bool has_render_path, float legend_height, const libvgcode::Viewer* viewer, uint32_t gcode_id, int canvas_width, int canvas_height, int right_margin, const libvgcode::EViewType& view_type);
};
struct ETools
@@ -709,37 +174,18 @@ public:
std::vector<bool> m_tool_visibles;
};
enum class EViewType : unsigned char
{
FeatureType = 0,
Height,
Width,
Feedrate,
FanSpeed,
Temperature,
VolumetricRate,
Tool,
ColorPrint,
FilamentId,
LayerTime,
LayerTimeLog,
Count
};
//BBS
ConflictResultOpt m_conflict_result;
private:
std::vector<int> m_plater_extruder;
bool m_gl_data_initialized{ false };
unsigned int m_last_result_id{ 0 };
size_t m_moves_count{ 0 };
//BBS: save m_gcode_result as well
const GCodeProcessorResult* m_gcode_result;
//BBS: add only gcode mode
bool m_only_gcode_in_preview {false};
std::vector<size_t> m_ssid_to_moveid_map;
std::vector<TBuffer> m_buffers{ static_cast<size_t>(EMoveType::Extrude) };
// bounding box of toolpaths
BoundingBoxf3 m_paths_bounding_box;
// bounding box of toolpaths + marker tools
@@ -753,35 +199,41 @@ private:
ConfigOptionMode m_user_mode;
bool m_fold = {false};
Layers m_layers;
std::array<unsigned int, 2> m_layers_z_range;
std::vector<ExtrusionRole> m_roles;
size_t m_extruders_count;
std::vector<unsigned char> m_extruder_ids;
std::vector<float> m_filament_diameters;
std::vector<float> m_filament_densities;
Extrusions m_extrusions;
SequentialView m_sequential_view;
IMSlider* m_moves_slider;
IMSlider* m_layers_slider;
Shells m_shells;
#if VGCODE_ENABLE_COG_AND_TOOL_MARKERS
// whether or not to render the cog model with fixed screen size
bool m_cog_marker_fixed_screen_size{ true };
float m_cog_marker_size{ 1.0f };
bool m_tool_marker_fixed_screen_size{ false };
float m_tool_marker_size{ 1.0f };
#endif // VGCODE_ENABLE_COG_AND_TOOL_MARKERS
/*BBS GUI refactor, store displayed items in color scheme combobox */
std::vector<EViewType> view_type_items;
std::vector<libvgcode::EViewType> view_type_items;
std::vector<std::string> view_type_items_str;
int m_view_type_sel = 0;
EViewType m_view_type{ EViewType::FeatureType };
std::vector<EMoveType> options_items;
bool m_legend_visible{ true };
bool m_legend_enabled{ true };
struct ViewTypeCache
{
bool write{ false };
bool load{ false };
libvgcode::EViewType value{ libvgcode::EViewType::FeatureType };
};
ViewTypeCache m_view_type_cache;
float m_legend_height;
PrintEstimatedStatistics m_print_statistics;
PrintEstimatedStatistics::ETimeMode m_time_estimate_mode{ PrintEstimatedStatistics::ETimeMode::Normal };
#if ENABLE_GCODE_VIEWER_STATISTICS
Statistics m_statistics;
#endif // ENABLE_GCODE_VIEWER_STATISTICS
std::array<float, 2> m_detected_point_sizes = { 0.0f, 0.0f };
GCodeProcessorResult::SettingsIds m_settings_ids;
std::array<SequentialRangeCap, 2> m_sequential_range_caps;
std::vector<CustomGCode::Item> m_custom_gcode_per_print_z;
@@ -789,6 +241,9 @@ private:
mutable bool m_no_render_path { false };
bool m_is_dark = false;
libvgcode::Viewer m_viewer;
bool m_loaded_as_preview{ false };
public:
GCodeViewer();
~GCodeViewer();
@@ -801,11 +256,10 @@ public:
// 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<BoundingBoxf3>& 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<std::string>& str_tool_colors);
void refresh_render_paths();
void load_as_gcode(const GCodeProcessorResult& gcode_result, const Print& print, const std::vector<std::string>& str_tool_colors,
const std::vector<std::string>& str_color_print_colors, const BuildVolume& build_volume,
const std::vector<BoundingBoxf3>& exclude_bounding_box, ConfigOptionMode mode, bool only_gcode = false);
void load_as_preview(libvgcode::GCodeInputData&& data);
void update_shells_color_by_extruder(const DynamicPrintConfig* config);
void set_shell_transparency(float alpha = 0.15f);
@@ -819,11 +273,11 @@ public:
//BBS: GUI refactor: add canvas width and height
void render(int canvas_width, int canvas_height, int right_margin);
//BBS
void _render_calibration_thumbnail_internal(ThumbnailData& thumbnail_data, const ThumbnailsParams& thumbnail_params, PartPlateList& partplate_list, OpenGLManager& opengl_manager);
void _render_calibration_thumbnail_framebuffer(ThumbnailData& thumbnail_data, unsigned int w, unsigned int h, const ThumbnailsParams& thumbnail_params, PartPlateList& partplate_list, OpenGLManager& opengl_manager);
void render_calibration_thumbnail(ThumbnailData& thumbnail_data, unsigned int w, unsigned int h, const ThumbnailsParams& thumbnail_params, PartPlateList& partplate_list, OpenGLManager& opengl_manager);
// void _render_calibration_thumbnail_internal(ThumbnailData& thumbnail_data, const ThumbnailsParams& thumbnail_params, PartPlateList& partplate_list, OpenGLManager& opengl_manager);
// void _render_calibration_thumbnail_framebuffer(ThumbnailData& thumbnail_data, unsigned int w, unsigned int h, const ThumbnailsParams& thumbnail_params, PartPlateList& partplate_list, OpenGLManager& opengl_manager);
// void render_calibration_thumbnail(ThumbnailData& thumbnail_data, unsigned int w, unsigned int h, const ThumbnailsParams& thumbnail_params, PartPlateList& partplate_list, OpenGLManager& opengl_manager);
bool has_data() const { return !m_viewer.get_extrusion_roles().empty(); }
bool has_data() const { return !m_roles.empty(); }
bool can_export_toolpaths() const;
std::vector<int> get_plater_extruder();
@@ -831,8 +285,15 @@ public:
const BoundingBoxf3& get_paths_bounding_box() const { return m_paths_bounding_box; }
const BoundingBoxf3& get_max_bounding_box() const { return m_max_bounding_box; }
const BoundingBoxf3& get_shell_bounding_box() const { return m_shell_bounding_box; }
const std::vector<double>& get_layers_zs() const { return m_layers.get_zs(); }
const std::array<unsigned int,2> &get_layers_z_range() const { return m_layers_z_range; }
std::vector<double> get_layers_zs() const {
const std::vector<float> zs = m_viewer.get_layers_zs();
std::vector<double> ret;
std::transform(zs.begin(), zs.end(), std::back_inserter(ret), [](float z) { return static_cast<double>(z); });
return ret;
}
std::vector<float> get_layers_times() const { return m_viewer.get_layers_estimated_times(); }
const std::array<size_t,2> &get_layers_z_range() const { return m_viewer.get_layers_view_range(); }
const SequentialView& get_sequential_view() const { return m_sequential_view; }
void update_sequential_view_current(unsigned int first, unsigned int last);
@@ -845,70 +306,69 @@ public:
void update_layers_slider_mode();
void update_marker_curr_move();
const libvgcode::Interval& get_gcode_view_full_range() const { return m_viewer.get_view_full_range(); }
const libvgcode::Interval& get_gcode_view_enabled_range() const { return m_viewer.get_view_enabled_range(); }
const libvgcode::Interval& get_gcode_view_visible_range() const { return m_viewer.get_view_visible_range(); }
const libvgcode::PathVertex& get_gcode_vertex_at(size_t id) const { return m_viewer.get_vertex_at(id); }
bool is_contained_in_bed() const { return m_contained_in_bed; }
//BBS: add only gcode mode
bool is_only_gcode_in_preview() const { return m_only_gcode_in_preview; }
EViewType get_view_type() const { return m_view_type; }
void set_view_type(EViewType type, bool reset_feature_type_visible = true) {
if (type == EViewType::Count)
type = EViewType::FeatureType;
m_view_type = (EViewType)type;
if (reset_feature_type_visible && type == EViewType::ColorPrint) {
reset_visible(EViewType::FeatureType);
}
void set_view_type(libvgcode::EViewType type) {
m_viewer.set_view_type((m_view_type_cache.load && m_view_type_cache.value != type) ? m_view_type_cache.value : type);
const libvgcode::EViewType view_type = get_view_type();
if (m_view_type_cache.write && m_view_type_cache.value != view_type)
m_view_type_cache.value = view_type;
}
void reset_visible(EViewType type) {
if (type == EViewType::FeatureType) {
for (size_t i = 0; i < m_roles.size(); ++i) {
ExtrusionRole role = m_roles[i];
m_extrusions.role_visibility_flags = m_extrusions.role_visibility_flags | (1 << role);
void reset_visible(libvgcode::EViewType type) {
if (type == libvgcode::EViewType::FeatureType) {
auto roles = m_viewer.get_extrusion_roles();
for (size_t i = 0; i < roles.size(); ++i) {
auto role = roles[i];
if (!m_viewer.is_extrusion_role_visible(role)) {
m_viewer.toggle_extrusion_role_visibility(role);
}
}
} else if (type == EViewType::ColorPrint){
} else if (type == libvgcode::EViewType::ColorPrint){
for(auto item: m_tools.m_tool_visibles) item = true;
}
}
bool is_toolpath_move_type_visible(EMoveType type) const;
void set_toolpath_move_type_visible(EMoveType type, bool visible);
unsigned int get_toolpath_role_visibility_flags() const { return m_extrusions.role_visibility_flags; }
void set_toolpath_role_visibility_flags(unsigned int flags) { m_extrusions.role_visibility_flags = flags; }
unsigned int get_options_visibility_flags() const;
void set_options_visibility_from_flags(unsigned int flags);
libvgcode::EViewType get_view_type() const { return m_viewer.get_view_type(); }
void enable_view_type_cache_load(bool enable) { m_view_type_cache.load = enable; }
void enable_view_type_cache_write(bool enable) { m_view_type_cache.write = enable; }
bool is_view_type_cache_load_enabled() const { return m_view_type_cache.load; }
bool is_view_type_cache_write_enabled() const { return m_view_type_cache.write; }
void set_layers_z_range(const std::array<unsigned int, 2>& layers_z_range);
bool is_legend_enabled() const { return m_legend_enabled; }
bool is_legend_shown() const { return m_legend_visible && m_legend_enabled; }
void show_legend(bool show) { m_legend_visible = show; }
void enable_legend(bool enable) { m_legend_enabled = enable; }
float get_legend_height() { return m_legend_height; }
void export_toolpaths_to_obj(const char* filename) const;
std::vector<CustomGCode::Item>& get_custom_gcode_per_print_z() { return m_custom_gcode_per_print_z; }
size_t get_extruders_count() { return m_extruders_count; }
void push_combo_style();
void pop_combo_style();
void invalidate_legend() { /*TODO: m_legend_resizer.reset();*/ }
#if VGCODE_ENABLE_COG_AND_TOOL_MARKERS
float get_cog_marker_scale_factor() const { return m_viewer.get_cog_marker_scale_factor(); }
void set_cog_marker_scale_factor(float factor) { return m_viewer.set_cog_marker_scale_factor(factor); }
#endif // VGCODE_ENABLE_COG_AND_TOOL_MARKERS
private:
void load_toolpaths(const GCodeProcessorResult& gcode_result, const BuildVolume& build_volume, const std::vector<BoundingBoxf3>& exclude_bounding_box);
//BBS: always load shell at preview
//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(int canvas_width, int canvas_height);
//BBS: GUI refactor: add canvas size
void render_legend(float &legend_height, int canvas_width, int canvas_height, int right_margin);
void render_slider(int canvas_width, int canvas_height);
#if ENABLE_GCODE_VIEWER_STATISTICS
void render_statistics();
#endif // ENABLE_GCODE_VIEWER_STATISTICS
bool is_visible(ExtrusionRole role) const {
return role < erCount && (m_extrusions.role_visibility_flags & (1 << role)) != 0;
}
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;
ColorRGBA option_color(EMoveType move_type) const;
};
} // namespace GUI

File diff suppressed because it is too large Load Diff

View File

@@ -285,8 +285,8 @@ class GLCanvas3D
bool is_allowed() const;
bool is_enabled() const;
void set_enabled(bool enabled);
bool is_enabled() const { return m_enabled; }
void set_enabled(bool enabled) { m_enabled = is_allowed() && enabled; }
void show_tooltip_information(const GLCanvas3D& canvas, std::map<wxString, wxString> captions_texts, float x, float y);
void render_variable_layer_height_dialog(const GLCanvas3D& canvas);
@@ -326,25 +326,20 @@ class GLCanvas3D
static const Vec3d Invalid_3D_Point;
static const int MoveThresholdPx;
Point start_position_2D;
Vec3d start_position_3D;
int move_volume_idx;
bool move_requires_threshold;
Point move_start_threshold_position_2D;
public:
Drag();
Point start_position_2D{ Invalid_2D_Point };
Vec3d start_position_3D{ Invalid_3D_Point };
int move_volume_idx{ -1 };
bool move_requires_threshold{ false };
Point move_start_threshold_position_2D{ Invalid_2D_Point };
};
bool dragging;
Vec2d position;
Vec3d scene_position;
bool dragging{ false };
Vec2d position{ DBL_MAX, DBL_MAX };
Vec3d scene_position{ DBL_MAX, DBL_MAX, DBL_MAX };
bool ignore_left_up{ false };
Drag drag;
bool ignore_left_up;
bool ignore_right_up;
Mouse();
void set_start_position_2D_as_invalid() { drag.start_position_2D = Drag::Invalid_2D_Point; }
void set_start_position_3D_as_invalid() { drag.start_position_3D = Drag::Invalid_3D_Point; }
void set_move_start_threshold_position_2D_as_invalid() { drag.move_start_threshold_position_2D = Drag::Invalid_2D_Point; }
@@ -622,6 +617,9 @@ private:
int custom_height_count = 0;
int assembly_view_count = 0;
// used to show layers times on the layers slider when pre-gcode view is active
std::vector<float> m_gcode_layers_times_cache;
public:
OrientSettings& get_orient_settings()
{
@@ -669,7 +667,7 @@ public:
struct ToolbarHighlighter
{
void set_timer_owner(wxEvtHandler* owner, int timerid = wxID_ANY);
void set_timer_owner(wxEvtHandler* owner, int timerid = wxID_ANY) { m_timer.SetOwner(owner, timerid); }
void init(GLToolbarItem* toolbar_item, GLCanvas3D* canvas);
void blink();
void invalidate();
@@ -684,7 +682,7 @@ public:
struct GizmoHighlighter
{
void set_timer_owner(wxEvtHandler* owner, int timerid = wxID_ANY);
void set_timer_owner(wxEvtHandler* owner, int timerid = wxID_ANY) { m_timer.SetOwner(owner, timerid); }
void init(GLGizmosManager* manager, GLGizmosManager::EType gizmo, GLCanvas3D* canvas);
void blink();
void invalidate();
@@ -748,22 +746,33 @@ public:
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; }
void set_as_dirty();
void set_as_dirty() { m_dirty = true; }
void requires_check_outside_state() { m_requires_check_outside_state = true; }
unsigned int get_volumes_count() const;
unsigned int get_volumes_count() const { return (unsigned int)m_volumes.volumes.size(); }
const GLVolumeCollection& get_volumes() const { return m_volumes; }
void reset_volumes();
ModelInstanceEPrintVolumeState check_volumes_outside_state() const;
ModelInstanceEPrintVolumeState check_volumes_outside_state(bool selection_only = true) const;
void check_volumes_outside_state(GLVolumeCollection& volumes) const { check_volumes_outside_state(volumes, nullptr, false); }
bool is_all_plates_selected() { return m_sel_plate_toolbar.m_all_plates_stats_item && m_sel_plate_toolbar.m_all_plates_stats_item->selected; }
const float get_scale() const;
private:
// returns true if all the volumes are completely contained in the print volume
// returns the containment state in the given out_state, if non-null
bool check_volumes_outside_state(GLVolumeCollection& volumes, ModelInstanceEPrintVolumeState* out_state, bool selection_only = true) const;
public:
//BBS
GCodeViewer& get_gcode_viewer() { return m_gcode_viewer; }
void init_gcode_viewer(ConfigOptionMode mode, Slic3r::PresetBundle* preset_bundle) { m_gcode_viewer.init(mode, preset_bundle); }
void reset_gcode_toolpaths() { m_gcode_viewer.reset(); }
const GCodeViewer::SequentialView& get_gcode_sequential_view() const { return m_gcode_viewer.get_sequential_view(); }
void update_gcode_sequential_view_current(unsigned int first, unsigned int last) { m_gcode_viewer.update_sequential_view_current(first, last); }
const libvgcode::Interval& get_gcode_view_full_range() const { return m_gcode_viewer.get_gcode_view_full_range(); }
const libvgcode::Interval& get_gcode_view_enabled_range() const { return m_gcode_viewer.get_gcode_view_enabled_range(); }
const libvgcode::Interval& get_gcode_view_visible_range() const { return m_gcode_viewer.get_gcode_view_visible_range(); }
const libvgcode::PathVertex& get_gcode_vertex_at(size_t id) const { return m_gcode_viewer.get_gcode_vertex_at(id); }
void toggle_selected_volume_visibility(bool selected_visible);
void toggle_sla_auxiliaries_visibility(bool visible, const ModelObject* mo = nullptr, int instance_idx = -1);
@@ -772,7 +781,7 @@ public:
void update_instance_printable_state_for_objects(const std::vector<size_t>& object_idxs);
void set_config(const DynamicPrintConfig* config);
void set_process(BackgroundSlicingProcess* process);
void set_process(BackgroundSlicingProcess* process) { m_process = process; }
void set_model(Model* model);
const Model* get_model() const { return m_model; }
@@ -816,22 +825,28 @@ public:
BoundingBoxf3 scene_bounding_box() const;
BoundingBoxf3 plate_scene_bounding_box(int plate_idx) const;
bool is_layers_editing_enabled() const;
bool is_layers_editing_allowed() const;
bool is_layers_editing_enabled() const { return m_layers_editing.is_enabled(); }
bool is_layers_editing_allowed() const { return m_layers_editing.is_allowed(); }
void reset_layer_height_profile();
void adaptive_layer_height_profile(float quality_factor);
void smooth_layer_height_profile(const HeightProfileSmoothingParams& smoothing_params);
bool is_reload_delayed() const;
bool is_reload_delayed() const { return m_reload_delayed; }
void enable_layers_editing(bool enable);
void enable_legend_texture(bool enable);
void enable_picking(bool enable);
void enable_moving(bool enable);
void enable_gizmos(bool enable);
void enable_selection(bool enable);
void enable_main_toolbar(bool enable);
void enable_picking(bool enable)
{
m_picking_enabled = enable;
// Orca: invalidate hover state when dragging is toggled, otherwise if we turned off dragging
// while hovering above a volume, the hovering state won't update even if mouse has moved away.
// Fixes https://github.com/SoftFever/OrcaSlicer/pull/9979#issuecomment-3065575889
m_hover_volume_idxs.clear();
}
void enable_moving(bool enable) { m_moving_enabled = enable; }
void enable_gizmos(bool enable) { m_gizmos.set_enabled(enable); }
void enable_selection(bool enable) { m_selection.set_enabled(enable); }
void enable_main_toolbar(bool enable) { m_main_toolbar.set_enabled(enable); }
//BBS: GUI refactor: GLToolbar
void _update_select_plate_toolbar_stats_item(bool force_selected = false);
void reset_select_plate_toolbar_selection();
@@ -839,10 +854,10 @@ public:
void enable_assemble_view_toolbar(bool enable);
void enable_return_toolbar(bool enable);
void enable_separator_toolbar(bool enable);
void enable_dynamic_background(bool enable);
void enable_dynamic_background(bool enable) { m_dynamic_background_enabled = enable; }
void enable_labels(bool enable) { m_labels.enable(enable); }
void enable_slope(bool enable) { m_slope.enable(enable); }
void allow_multisample(bool allow);
void allow_multisample(bool allow) { m_multisample_allowed = allow; }
void zoom_to_bed();
void zoom_to_volumes();
@@ -906,7 +921,7 @@ public:
GLShaderProgram* shader, Camera::EType camera_type, bool use_top_view = false, bool for_picking = false, bool ban_light = false);
//BBS use gcoder viewer render calibration thumbnails
void render_calibration_thumbnail(ThumbnailData& thumbnail_data, unsigned int w, unsigned int h, const ThumbnailsParams& thumbnail_params);
// void render_calibration_thumbnail(ThumbnailData& thumbnail_data, unsigned int w, unsigned int h, const ThumbnailsParams& thumbnail_params);
//BBS
void select_curr_plate_all();
@@ -918,18 +933,14 @@ public:
void deselect_all();
void exit_gizmo();
void set_selected_visible(bool visible);
void delete_selected();
void delete_selected() { m_selection.erase(); }
void ensure_on_bed(unsigned int object_idx, bool allow_negative_z);
bool is_gcode_legend_enabled() const { return m_gcode_viewer.is_legend_enabled(); }
GCodeViewer::EViewType get_gcode_view_type() const { return m_gcode_viewer.get_view_type(); }
const std::vector<double>& get_gcode_layers_zs() const;
std::vector<double> get_volumes_print_zs(bool active_only) const;
unsigned int get_gcode_options_visibility_flags() const { return m_gcode_viewer.get_options_visibility_flags(); }
void set_gcode_options_visibility_from_flags(unsigned int flags);
unsigned int get_toolpath_role_visibility_flags() const { return m_gcode_viewer.get_toolpath_role_visibility_flags(); }
void set_volumes_z_range(const std::array<double, 2>& range);
std::vector<CustomGCode::Item>& get_custom_gcode_per_print_z() { return m_gcode_viewer.get_custom_gcode_per_print_z(); }
std::vector<double> get_gcode_layers_zs() const { return m_gcode_viewer.get_layers_zs(); }
std::vector<float> get_gcode_layers_times() const { return m_gcode_viewer.get_layers_times(); }
const std::vector<float>& get_gcode_layers_times_cache() const { return m_gcode_layers_times_cache; }
void reset_gcode_layers_times_cache() { m_gcode_layers_times_cache.clear(); }
void set_volumes_z_range(const std::array<double, 2>& range) { m_volumes.set_range(range[0] - 1e-6, range[1] + 1e-6); }
size_t get_gcode_extruders_count() { return m_gcode_viewer.get_extruders_count(); }
std::vector<int> load_object(const ModelObject& model_object, int obj_idx, std::vector<int> instance_idxs);
@@ -945,16 +956,22 @@ public:
void set_shells_on_previewing(bool is_preview) { m_gcode_viewer.set_shells_on_preview(is_preview); }
//BBS: add only gcode mode
void load_gcode_preview(const GCodeProcessorResult& gcode_result, const std::vector<std::string>& str_tool_colors, bool only_gcode);
void refresh_gcode_preview_render_paths();
void set_gcode_view_preview_type(GCodeViewer::EViewType type) { return m_gcode_viewer.set_view_type(type); }
GCodeViewer::EViewType get_gcode_view_preview_type() const { return m_gcode_viewer.get_view_type(); }
void load_gcode_preview(const GCodeProcessorResult& gcode_result, const std::vector<std::string>& str_tool_colors,
const std::vector<std::string>& str_color_print_colors, bool only_gcode);
void set_gcode_view_type(libvgcode::EViewType type) { return m_gcode_viewer.set_view_type(type); }
libvgcode::EViewType get_gcode_view_type() const { return m_gcode_viewer.get_view_type(); }
void enable_gcode_view_type_cache_load(bool enable) { m_gcode_viewer.enable_view_type_cache_load(enable); }
void enable_gcode_view_type_cache_write(bool enable) { m_gcode_viewer.enable_view_type_cache_write(enable); }
bool is_gcode_view_type_cache_load_enabled() const { return m_gcode_viewer.is_view_type_cache_load_enabled(); }
bool is_gcode_view_type_cache_write_enabled() const { return m_gcode_viewer.is_view_type_cache_write_enabled(); }
void load_sla_preview();
//void load_preview(const std::vector<std::string>& str_tool_colors, const std::vector<CustomGCode::Item>& color_print_values);
// void load_preview(const std::vector<std::string>& str_tool_colors, const std::vector<std::string>& str_color_print_colors,
// const std::vector<CustomGCode::Item>& color_print_values);
void bind_event_handlers();
void unbind_event_handlers();
void on_size(wxSizeEvent& evt);
void on_size(wxSizeEvent& evt) { m_dirty = true; }
void on_idle(wxIdleEvent& evt);
void on_char(wxKeyEvent& evt);
void on_key(wxKeyEvent& evt);
@@ -1021,7 +1038,8 @@ public:
inline double rotation() const { return m_rotation; }
inline const Vec2d bb_size() const { return m_bb.size(); }
void apply_wipe_tower() const;
void apply_wipe_tower() const { apply_wipe_tower(m_pos, m_rotation); }
void apply_wipe_tower(Vec2d pos, double rot) const;
};
// BBS: add partplate logic
@@ -1043,7 +1061,7 @@ public:
Vec2f get_nearest_empty_cell(const Vec2f start_point, const Vec2f step = {10, 10});
void set_cursor(ECursorType type);
void msw_rescale();
void msw_rescale() { m_gcode_viewer.invalidate_legend(); }
void request_extra_frame() { m_extra_frame_requested = true; }
@@ -1053,8 +1071,8 @@ public:
void force_main_toolbar_left_action(int item_id) { m_main_toolbar.force_left_action(item_id, *this); }
void force_main_toolbar_right_action(int item_id) { m_main_toolbar.force_right_action(item_id, *this); }
bool has_toolpaths_to_export() const;
void export_toolpaths_to_obj(const char* filename) const;
bool has_toolpaths_to_export() const { return m_gcode_viewer.can_export_toolpaths(); }
void export_toolpaths_to_obj(const char* filename) const { m_gcode_viewer.export_toolpaths_to_obj(filename); }
void mouse_up_cleanup();
@@ -1174,7 +1192,7 @@ private:
void _render_selection();
void _render_sequential_clearance();
#if ENABLE_RENDER_SELECTION_CENTER
void _render_selection_center();
void _render_selection_center() { m_selection.render_center(m_gizmos.is_dragging()); }
#endif // ENABLE_RENDER_SELECTION_CENTER
void _check_and_update_toolbar_icon_scale();
void _render_overlays();
@@ -1199,7 +1217,7 @@ private:
void _render_camera_target();
#endif // ENABLE_SHOW_CAMERA_TARGET
void _render_sla_slices();
void _render_selection_sidebar_hints();
void _render_selection_sidebar_hints() { m_selection.render_sidebar_hints(m_sidebar_field, m_gizmos.get_uniform_scaling()); }
//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);
@@ -1212,23 +1230,12 @@ private:
// Convert the screen space coordinate to world coordinate on the bed.
Vec3d _mouse_to_bed_3d(const Point& mouse_pos);
void _start_timer();
void _stop_timer();
// Create 3D thick extrusion lines for a skirt and brim.
// Adds a new Slic3r::GUI::3DScene::Volume to volumes, updates collision with the build_volume.
void _load_print_toolpaths(const BuildVolume &build_volume);
// Create 3D thick extrusion lines for object forming extrusions.
// Adds a new Slic3r::GUI::3DScene::Volume to $self->volumes,
// one for perimeters, one for infill and one for supports, updates collision with the build_volume.
void _load_print_object_toolpaths(const PrintObject& print_object, const BuildVolume &build_volume,
const std::vector<std::string>& str_tool_colors, const std::vector<CustomGCode::Item>& color_print_values);
// Create 3D thick extrusion lines for wipe tower extrusions, updates collision with the build_volume.
void _load_wipe_tower_toolpaths(const BuildVolume &build_volume, const std::vector<std::string>& str_tool_colors);
void _start_timer() { m_timer.Start(100, wxTIMER_CONTINUOUS); }
void _stop_timer() { m_timer.Stop(); }
// Load SLA objects and support structures for objects, for which the slaposSliceSupports step has been finished.
void _load_sla_shells();
void _update_sla_shells_outside_state();
void _load_sla_shells();
void _update_sla_shells_outside_state() { check_volumes_outside_state(); }
void _set_warning_notification_if_needed(EWarning warning);
//BBS: add partplate print volume get function

View File

@@ -551,6 +551,16 @@ void GLModel::reset()
glsafe(::glDeleteBuffers(1, &m_render_data.vbo_id));
m_render_data.vbo_id = 0;
}
#if !SLIC3R_OPENGL_ES
if (OpenGLManager::get_gl_info().is_core_profile()) {
#endif // !SLIC3R_OPENGL_ES
if (m_render_data.vao_id > 0) {
glsafe(::glDeleteVertexArrays(1, &m_render_data.vao_id));
m_render_data.vao_id = 0;
}
#if !SLIC3R_OPENGL_ES
}
#endif // !SLIC3R_OPENGL_ES
m_render_data.vertices_count = 0;
m_render_data.indices_count = 0;
@@ -619,6 +629,14 @@ void GLModel::render(const std::pair<size_t, size_t>& range)
const bool normal = Geometry::has_normal(data.format);
const bool tex_coord = Geometry::has_tex_coord(data.format);
#if !SLIC3R_OPENGL_ES
if (OpenGLManager::get_gl_info().is_core_profile()) {
#endif // !SLIC3R_OPENGL_ES
glsafe(::glBindVertexArray(m_render_data.vao_id));
#if !SLIC3R_OPENGL_ES
}
#endif // !SLIC3R_OPENGL_ES
// the following binding is needed to set the vertex attributes
glsafe(::glBindBuffer(GL_ARRAY_BUFFER, m_render_data.vbo_id));
int position_id = -1;
@@ -661,6 +679,13 @@ void GLModel::render(const std::pair<size_t, size_t>& range)
glsafe(::glDisableVertexAttribArray(position_id));
glsafe(::glBindBuffer(GL_ARRAY_BUFFER, 0));
#if !SLIC3R_OPENGL_ES
if (OpenGLManager::get_gl_info().is_core_profile()) {
#endif // !SLIC3R_OPENGL_ES
glsafe(::glBindVertexArray(0));
#if !SLIC3R_OPENGL_ES
}
#endif // !SLIC3R_OPENGL_ES
}
void GLModel::render_instanced(unsigned int instances_vbo, unsigned int instances_count)
@@ -689,6 +714,14 @@ void GLModel::render_instanced(unsigned int instances_vbo, unsigned int instance
return;
}
#if !SLIC3R_OPENGL_ES
if (OpenGLManager::get_gl_info().is_core_profile()) {
#endif // !SLIC3R_OPENGL_ES
glsafe(::glBindVertexArray(m_render_data.vao_id));
#if !SLIC3R_OPENGL_ES
}
#endif // !SLIC3R_OPENGL_ES
glsafe(::glBindBuffer(GL_ARRAY_BUFFER, instances_vbo));
const size_t instance_stride = 5 * sizeof(float);
glsafe(::glVertexAttribPointer(offset_id, 3, GL_FLOAT, GL_FALSE, instance_stride, (const void*)0));
@@ -735,6 +768,13 @@ void GLModel::render_instanced(unsigned int instances_vbo, unsigned int instance
glsafe(::glDisableVertexAttribArray(offset_id));
glsafe(::glBindBuffer(GL_ARRAY_BUFFER, 0));
#if !SLIC3R_OPENGL_ES
if (OpenGLManager::get_gl_info().is_core_profile()) {
#endif // !SLIC3R_OPENGL_ES
glsafe(::glBindVertexArray(0));
#if !SLIC3R_OPENGL_ES
}
#endif // !SLIC3R_OPENGL_ES
}
bool GLModel::send_to_gpu()
@@ -750,6 +790,15 @@ bool GLModel::send_to_gpu()
return false;
}
#if !SLIC3R_OPENGL_ES
if (OpenGLManager::get_gl_info().is_core_profile()) {
#endif // !SLIC3R_OPENGL_ES
glsafe(::glGenVertexArrays(1, &m_render_data.vao_id));
glsafe(::glBindVertexArray(m_render_data.vao_id));
#if !SLIC3R_OPENGL_ES
}
#endif // !SLIC3R_OPENGL_ES
// vertices
glsafe(::glGenBuffers(1, &m_render_data.vbo_id));
glsafe(::glBindBuffer(GL_ARRAY_BUFFER, m_render_data.vbo_id));
@@ -790,6 +839,14 @@ bool GLModel::send_to_gpu()
m_render_data.indices_count = indices_count;
data.indices = std::vector<unsigned int>();
#if !SLIC3R_OPENGL_ES
if (OpenGLManager::get_gl_info().is_core_profile()) {
#endif // !SLIC3R_OPENGL_ES
glsafe(::glBindVertexArray(0));
#if !SLIC3R_OPENGL_ES
}
#endif // !SLIC3R_OPENGL_ES
return true;
}

View File

@@ -131,6 +131,7 @@ namespace GUI {
struct RenderData
{
Geometry geometry;
unsigned int vao_id{ 0 };
unsigned int vbo_id{ 0 };
unsigned int ibo_id{ 0 };
size_t vertices_count{ 0 };

View File

@@ -72,15 +72,26 @@ namespace GUI {
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));
#if !SLIC3R_OPENGL_ES
if (!OpenGLManager::get_gl_info().is_core_profile())
glsafe(::glLineWidth(1.5f));
#endif // !SLIC3R_OPENGL_ES
glsafe(::glDisable(GL_DEPTH_TEST));
glsafe(::glPushAttrib(GL_ENABLE_BIT));
glsafe(::glLineStipple(4, 0xAAAA));
glsafe(::glEnable(GL_LINE_STIPPLE));
#if !SLIC3R_OPENGL_ES
if (!OpenGLManager::get_gl_info().is_core_profile()) {
glsafe(::glPushAttrib(GL_ENABLE_BIT));
glsafe(::glLineStipple(4, 0xAAAA));
glsafe(::glEnable(GL_LINE_STIPPLE));
}
#endif // !SLIC3R_OPENGL_ES
GLShaderProgram* shader = wxGetApp().get_shader("flat");
#if SLIC3R_OPENGL_ES
GLShaderProgram* shader = wxGetApp().get_shader("dashed_lines");
#else
GLShaderProgram* shader = OpenGLManager::get_gl_info().is_core_profile() ? wxGetApp().get_shader("dashed_thick_lines") : wxGetApp().get_shader("flat");
#endif // SLIC3R_OPENGL_ES
if (shader != nullptr) {
shader->start_using();
@@ -90,34 +101,86 @@ namespace GUI {
m_rectangle.reset();
GLModel::Geometry init_data;
init_data.format = { GLModel::Geometry::EPrimitiveType::LineLoop, GLModel::Geometry::EVertexLayout::P2 };
init_data.reserve_vertices(4);
init_data.reserve_indices(4);
#if !SLIC3R_OPENGL_ES
if (OpenGLManager::get_gl_info().is_core_profile()) {
#endif // !SLIC3R_OPENGL_ES
init_data.format = { GLModel::Geometry::EPrimitiveType::Lines, GLModel::Geometry::EVertexLayout::P4 };
init_data.reserve_vertices(5);
init_data.reserve_indices(8);
#if !SLIC3R_OPENGL_ES
}
else {
init_data.format = { GLModel::Geometry::EPrimitiveType::LineLoop, GLModel::Geometry::EVertexLayout::P2 };
init_data.reserve_vertices(4);
init_data.reserve_indices(4);
}
#endif // !SLIC3R_OPENGL_ES
// 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));
#if !SLIC3R_OPENGL_ES
if (OpenGLManager::get_gl_info().is_core_profile()) {
#endif // !SLIC3R_OPENGL_ES
const float width = right - left;
const float height = top - bottom;
float perimeter = 0.0f;
// indices
init_data.add_index(0);
init_data.add_index(1);
init_data.add_index(2);
init_data.add_index(3);
init_data.add_vertex(Vec4f(left, bottom, 0.0f, perimeter));
perimeter += width;
init_data.add_vertex(Vec4f(right, bottom, 0.0f, perimeter));
perimeter += height;
init_data.add_vertex(Vec4f(right, top, 0.0f, perimeter));
perimeter += width;
init_data.add_vertex(Vec4f(left, top, 0.0f, perimeter));
perimeter += height;
init_data.add_vertex(Vec4f(left, bottom, 0.0f, perimeter));
// indices
init_data.add_line(0, 1);
init_data.add_line(1, 2);
init_data.add_line(2, 3);
init_data.add_line(3, 4);
#if !SLIC3R_OPENGL_ES
}
else {
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_index(0);
init_data.add_index(1);
init_data.add_index(2);
init_data.add_index(3);
}
#endif // !SLIC3R_OPENGL_ES
m_rectangle.init_from(std::move(init_data));
}
shader->set_uniform("view_model_matrix", Transform3d::Identity());
shader->set_uniform("projection_matrix", Transform3d::Identity());
#if !SLIC3R_OPENGL_ES
if (OpenGLManager::get_gl_info().is_core_profile()) {
#endif // !SLIC3R_OPENGL_ES
const std::array<int, 4>& viewport = wxGetApp().plater()->get_camera().get_viewport();
shader->set_uniform("viewport_size", Vec2d(double(viewport[2]), double(viewport[3])));
shader->set_uniform("width", 0.25f);
shader->set_uniform("dash_size", 0.01f);
shader->set_uniform("gap_size", 0.0075f);
#if !SLIC3R_OPENGL_ES
}
#endif // !SLIC3R_OPENGL_ES
m_rectangle.set_color(ColorRGBA::ORCA()); // ORCA: use orca color for selection rectangle
m_rectangle.render();
shader->stop_using();
}
glsafe(::glPopAttrib());
#if !SLIC3R_OPENGL_ES
if (!OpenGLManager::get_gl_info().is_core_profile())
glsafe(::glPopAttrib());
#endif // !SLIC3R_OPENGL_ES
}
} // namespace GUI

View File

@@ -33,7 +33,13 @@ std::pair<bool, std::string> GLShadersManager::init()
bool valid = true;
#if SLIC3R_OPENGL_ES
const std::string prefix = "ES/";
// used to render wireframed triangles
valid &= append_shader("wireframe", { prefix + "wireframe.vs", prefix + "wireframe.fs" });
#else
const std::string prefix = GUI::wxGetApp().is_gl_version_greater_or_equal_to(3, 1) ? "140/" : "110/";
#endif // SLIC3R_OPENGL_ES
// imgui shader
valid &= append_shader("imgui", { prefix + "imgui.vs", prefix + "imgui.fs" });
// basic shader, used to render all what was previously rendered using the immediate mode
@@ -44,6 +50,14 @@ std::pair<bool, std::string> GLShadersManager::init()
valid &= append_shader("flat_texture", { prefix + "flat_texture.vs", prefix + "flat_texture.fs" });
// used to render 3D scene background
valid &= append_shader("background", { prefix + "background.vs", prefix + "background.fs" });
#if SLIC3R_OPENGL_ES
// used to render dashed lines
valid &= append_shader("dashed_lines", { prefix + "dashed_lines.vs", prefix + "dashed_lines.fs" });
#else
if (GUI::OpenGLManager::get_gl_info().is_core_profile())
// used to render thick and/or dashed lines
valid &= append_shader("dashed_thick_lines", { prefix + "dashed_thick_lines.vs", prefix + "dashed_thick_lines.fs", prefix + "dashed_thick_lines.gs" });
#endif // SLIC3R_OPENGL_ES
// 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", { prefix + "gouraud_light.vs", prefix + "gouraud_light.fs" });
//used to render thumbnail

View File

@@ -1894,7 +1894,8 @@ std::string GUI_App::get_gl_info(bool for_github)
wxGLContext* GUI_App::init_glcontext(wxGLCanvas& canvas)
{
return m_opengl_mgr.init_glcontext(canvas);
return m_opengl_mgr.init_glcontext(canvas, init_params != nullptr ? init_params->opengl_version : std::make_pair(0, 0),
init_params != nullptr ? init_params->opengl_compatibility_profile : false, init_params != nullptr ? init_params->opengl_debug : false);
}
bool GUI_App::init_opengl()
@@ -5659,7 +5660,7 @@ void GUI_App::open_preferences(size_t open_on_tab, const std::string& highlight_
#else
if (dlg.seq_top_layer_only_changed())
#endif // ENABLE_GCODE_LINES_ID_IN_H_SLIDER
this->plater_->refresh_print();
this->plater_->reload_print();
#ifdef _WIN32
if (is_editor()) {
if (app_config->get("associate_3mf") == "true")

View File

@@ -23,6 +23,8 @@
namespace Slic3r {
namespace GUI {
const std::vector<std::pair<int, int>> OpenGLVersions::core = { {3,2}, {3,3}, {4,0}, {4,1}, {4,2}, {4,3}, {4,4}, {4,5}, {4,6} };
int GUI_Run(GUI_InitParams &params)
{
#if __APPLE__

View File

@@ -8,6 +8,11 @@ namespace Slic3r {
namespace GUI {
struct OpenGLVersions
{
static const std::vector<std::pair<int, int>> core;
};
struct GUI_InitParams
{
int argc;
@@ -20,6 +25,10 @@ struct GUI_InitParams
DynamicPrintConfig extra_config;
std::vector<std::string> input_files;
std::pair<int, int> opengl_version { 0, 0 };
bool opengl_debug { false };
bool opengl_compatibility_profile { false };
//BBS: remove start_as_gcodeviewer logic
//bool start_as_gcodeviewer;
bool input_gcode { false };

View File

@@ -5,6 +5,9 @@
#include "GUI_Preview.hpp"
#include "GUI_App.hpp"
#include "GUI.hpp"
#if ENABLE_OPENGL_AUTO_AA_SAMPLES
#include "GUI_Init.hpp"
#endif // ENABLE_OPENGL_AUTO_AA_SAMPLES
#include "I18N.hpp"
#include "3DScene.hpp"
#include "BackgroundSlicingProcess.hpp"
@@ -55,6 +58,10 @@ bool View3D::init(wxWindow* parent, Bed3D& bed, Model* model, DynamicPrintConfig
if (!Create(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0 /* disable wxTAB_TRAVERSAL */))
return false;
#if ENABLE_OPENGL_AUTO_AA_SAMPLES
const GUI_InitParams* const init_params = wxGetApp().init_params;
m_canvas_widget = OpenGLManager::create_wxglcanvas(*this, (init_params != nullptr) ? init_params->opengl_aa : false);
#else
m_canvas_widget = OpenGLManager::create_wxglcanvas(*this);
if (m_canvas_widget == nullptr)
return false;
@@ -254,6 +261,7 @@ bool Preview::init(wxWindow* parent, Bed3D& bed, Model* model)
#endif // _WIN32
m_canvas_widget = OpenGLManager::create_wxglcanvas(*this);
#endif // ENABLE_OPENGL_AUTO_AA_SAMPLES
if (m_canvas_widget == nullptr)
return false;
@@ -264,7 +272,7 @@ bool Preview::init(wxWindow* parent, Bed3D& bed, Model* model)
m_canvas->set_model(model);
m_canvas->set_process(m_process);
m_canvas->set_type(GLCanvas3D::ECanvasType::CanvasPreview);
m_canvas->enable_legend_texture(true);
m_canvas->get_gcode_viewer().enable_legend(true);
m_canvas->enable_dynamic_background(true);
//BBS: GUI refactor: GLToolbar
if (wxGetApp().is_editor()) {
@@ -332,50 +340,16 @@ void Preview::load_print(bool keep_z_range, bool only_gcode)
}
//BBS: add only gcode mode
void Preview::reload_print(bool keep_volumes, bool only_gcode)
void Preview::reload_print(bool only_gcode)
{
BOOST_LOG_TRIVIAL(debug) << __FUNCTION__ << boost::format(" %1%: enter, keep_volumes %2%")%__LINE__ %keep_volumes;
#ifdef __linux__
// We are getting mysterious crashes on Linux in gtk due to OpenGL context activation GH #1874 #1955.
// So we are applying a workaround here: a delayed release of OpenGL vertex buffers.
if (!IsShown())
{
m_volumes_cleanup_required = !keep_volumes;
return;
}
#endif /* __linux__ */
if (
#ifdef __linux__
m_volumes_cleanup_required ||
#endif /* __linux__ */
!keep_volumes)
{
m_canvas->reset_volumes();
//BBS: add m_loaded_print logic
//m_loaded = false;
m_loaded_print = nullptr;
#ifdef __linux__
m_volumes_cleanup_required = false;
#endif /* __linux__ */
}
BOOST_LOG_TRIVIAL(debug) << __FUNCTION__ << boost::format(" %1%: enter")%__LINE__;
load_print(false, only_gcode);
m_only_gcode = only_gcode;
}
//BBS: add only gcode mode
void Preview::refresh_print()
{
BOOST_LOG_TRIVIAL(debug) << __FUNCTION__ << boost::format(" %1%: enter, current m_loaded_print %2%")%__LINE__ %m_loaded_print;
//BBS: add m_loaded_print logic
//m_loaded = false;
m_loaded_print = nullptr;
if (!IsShown())
return;
load_print(true, m_only_gcode);
BOOST_LOG_TRIVIAL(debug) << __FUNCTION__ << boost::format(" %1%: exit")%__LINE__;
load_print(false, only_gcode);
m_only_gcode = only_gcode;
}
//BBS: always load shell at preview
@@ -396,7 +370,7 @@ void Preview::msw_rescale()
get_canvas3d()->msw_rescale();
// rescale legend
refresh_print();
reload_print(m_only_gcode);
}
void Preview::sys_color_changed()
@@ -580,7 +554,7 @@ void Preview::update_layers_slider(const std::vector<double>& layers_z, bool kee
ticks_info_from_curr_plate = plater->model().get_curr_plate_custom_gcodes();
else {
ticks_info_from_curr_plate.mode = CustomGCode::Mode::SingleExtruder;
ticks_info_from_curr_plate.gcodes = m_canvas->get_custom_gcode_per_print_z();
ticks_info_from_curr_plate.gcodes = m_gcode_result->custom_gcode_per_print_z;
}
check_layers_slider_values(ticks_info_from_curr_plate.gcodes, layers_z);
@@ -612,7 +586,7 @@ void Preview::update_layers_slider(const std::vector<double>& layers_z, bool kee
m_layers_slider->SetTicksValues(ticks_info_from_curr_plate);
auto print_mode_stat = m_gcode_result->print_statistics.modes.front();
m_layers_slider->SetLayersTimes(print_mode_stat.layers_times, print_mode_stat.time);
m_layers_slider->SetLayersTimes(m_canvas->get_gcode_layers_times_cache(), print_mode_stat.time);
// Suggest the auto color change, if model looks like sign
if (m_layers_slider->IsNewPrint()) {
@@ -701,28 +675,17 @@ void Preview::load_print_as_fff(bool keep_z_range, bool only_gcode)
else if (directly_preview && !has_layers)
keep_z_range = false;
GCodeViewer::EViewType gcode_view_type = m_canvas->get_gcode_view_preview_type();
bool gcode_preview_data_valid = !m_gcode_result->moves.empty();
libvgcode::EViewType gcode_view_type = m_canvas->get_gcode_view_type();
const bool gcode_preview_data_valid = !m_gcode_result->moves.empty();
const bool is_pregcode_preview = !gcode_preview_data_valid && wxGetApp().is_editor();
// Collect colors per extruder.
std::vector<std::string> colors;
std::vector<CustomGCode::Item> color_print_values = {};
// set color print values, if it si selected "ColorPrint" view type
if (gcode_view_type == GCodeViewer::EViewType::ColorPrint) {
colors = wxGetApp().plater()->get_colors_for_color_print(m_gcode_result);
if (!gcode_preview_data_valid) {
if (wxGetApp().is_editor())
//BBS
color_print_values = wxGetApp().plater()->model().get_curr_plate_custom_gcodes().gcodes;
else
color_print_values = m_canvas->get_custom_gcode_per_print_z();
colors.push_back("#808080"); // gray color for pause print or custom G-code
}
}
else if (gcode_preview_data_valid || gcode_view_type == GCodeViewer::EViewType::Tool) {
colors = wxGetApp().plater()->get_extruder_colors_from_plater_config(m_gcode_result);
color_print_values.clear();
const std::vector<std::string> tool_colors = wxGetApp().plater()->get_extruder_colors_from_plater_config(m_gcode_result);
const std::vector<CustomGCode::Item>& color_print_values = wxGetApp().is_editor() ?
wxGetApp().plater()->model().get_curr_plate_custom_gcodes().gcodes : m_gcode_result->custom_gcode_per_print_z;
std::vector<std::string> color_print_colors;
if (!color_print_values.empty()) {
color_print_colors = wxGetApp().plater()->get_colors_for_color_print(m_gcode_result);
color_print_colors.push_back("#808080"); // gray color for pause print or custom G-code
}
std::vector<double> zs;
@@ -735,7 +698,9 @@ void Preview::load_print_as_fff(bool keep_z_range, bool only_gcode)
//BBS: add more log
BOOST_LOG_TRIVIAL(debug) << __FUNCTION__ << boost::format(": will load gcode_preview from result, moves count %1%") % m_gcode_result->moves.size();
//BBS: add only gcode mode
m_canvas->load_gcode_preview(*m_gcode_result, colors, only_gcode);
m_canvas->load_gcode_preview(*m_gcode_result, tool_colors, color_print_colors, only_gcode);
// the view type may have been changed by the call m_canvas->load_gcode_preview()
gcode_view_type = m_canvas->get_gcode_view_type();
//BBS show sliders
show_moves_sliders();
@@ -748,7 +713,7 @@ void Preview::load_print_as_fff(bool keep_z_range, bool only_gcode)
//m_loaded = true;
m_loaded_print = print;
}
else if (wxGetApp().is_editor()) {
else if (is_pregcode_preview) {
// Load the initial preview based on slices, not the final G-code.
//BBS: only display shell before slicing result out
//m_canvas->load_preview(colors, color_print_values);
@@ -764,7 +729,7 @@ void Preview::load_print_as_fff(bool keep_z_range, bool only_gcode)
std::vector<CustomGCode::Item> gcodes = wxGetApp().is_editor() ?
//BBS
wxGetApp().plater()->model().get_curr_plate_custom_gcodes().gcodes :
m_canvas->get_custom_gcode_per_print_z();
m_gcode_result->custom_gcode_per_print_z;
const wxString choice = !gcodes.empty() ?
_L("Multicolor Print") :
(number_extruders > 1) ? _L("Filaments") : _L("Line Type");
@@ -775,7 +740,8 @@ void Preview::load_print_as_fff(bool keep_z_range, bool only_gcode)
//BBS
show_layers_sliders(false);
m_canvas_widget->Refresh();
} else
}
else
update_layers_slider(zs, keep_z_range);
}
}
@@ -798,7 +764,12 @@ bool AssembleView::init(wxWindow* parent, Bed3D& bed, Model* model, DynamicPrint
if (!Create(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0 /* disable wxTAB_TRAVERSAL */))
return false;
#if ENABLE_OPENGL_AUTO_AA_SAMPLES
const GUI_InitParams* const init_params = wxGetApp().init_params;
m_canvas_widget = OpenGLManager::create_wxglcanvas(*this, (init_params != nullptr) ? init_params->opengl_aa : false);
#else
m_canvas_widget = OpenGLManager::create_wxglcanvas(*this);
#endif // ENABLE_OPENGL_AUTO_AA_SAMPLES
if (m_canvas_widget == nullptr)
return false;

View File

@@ -92,12 +92,6 @@ class Preview : public wxPanel
BackgroundSlicingProcess* m_process;
GCodeProcessorResult* m_gcode_result;
#ifdef __linux__
// We are getting mysterious crashes on Linux in gtk due to OpenGL context activation GH #1874 #1955.
// So we are applying a workaround here.
bool m_volumes_cleanup_required { false };
#endif /* __linux__ */
// Calling this function object forces Plater::schedule_background_process.
std::function<void()> m_schedule_background_process;
@@ -146,8 +140,7 @@ public:
//BBS: add only gcode mode
void load_print(bool keep_z_range = false, bool only_gcode = false);
void reload_print(bool keep_volumes = false, bool only_gcode = false);
void refresh_print();
void reload_print(bool only_gcode = false);
//BBS: always load shell at preview
void load_shells(const Print& print, bool force_previewing = false);
void reset_shells();

View File

@@ -1184,24 +1184,30 @@ void GLGizmoMeasure::render_dimensioning()
const Transform3d ss_to_ndc_matrix = TransformHelper::ndc_to_ss_matrix_inverse(viewport);
#if ENABLE_GL_CORE_PROFILE
#if !SLIC3R_OPENGL_ES
if (OpenGLManager::get_gl_info().is_core_profile()) {
#endif // !SLIC3R_OPENGL_ES
shader->stop_using();
shader = wxGetApp().get_shader("dashed_thick_lines");
#if SLIC3R_OPENGL_ES
shader = wxGetApp().get_shader("dashed_lines");
#else
shader = wxGetApp().get_shader("dashed_thick_lines");
#endif // SLIC3R_OPENGL_ES
if (shader == nullptr)
return;
shader->start_using();
shader->set_uniform("projection_matrix", Transform3d::Identity());
const std::array<int, 4>& 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);
#if !SLIC3R_OPENGL_ES
}
else
#endif // ENABLE_GL_CORE_PROFILE
glsafe(::glLineWidth(2.0f));
glsafe(::glLineWidth(2.0f));
#endif // !SLIC3R_OPENGL_ES
// 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 }) :
@@ -1209,8 +1215,9 @@ void GLGizmoMeasure::render_dimensioning()
m_dimensioning.line.set_color(color);
m_dimensioning.line.render();
#if ENABLE_GL_CORE_PROFILE
#if !SLIC3R_OPENGL_ES
if (OpenGLManager::get_gl_info().is_core_profile()) {
#endif // !SLIC3R_OPENGL_ES
shader->stop_using();
shader = wxGetApp().get_shader("flat");
@@ -1218,10 +1225,11 @@ void GLGizmoMeasure::render_dimensioning()
return;
shader->start_using();
#if !SLIC3R_OPENGL_ES
}
else
#endif // ENABLE_GL_CORE_PROFILE
glsafe(::glLineWidth(1.0f));
#endif // !SLIC3R_OPENGL_ES
// arrow 1
if (show_first_tri) {
@@ -1441,11 +1449,16 @@ void GLGizmoMeasure::render_dimensioning()
}
const Camera& camera = wxGetApp().plater()->get_camera();
#if ENABLE_GL_CORE_PROFILE
#if !SLIC3R_OPENGL_ES
if (OpenGLManager::get_gl_info().is_core_profile()) {
#endif // !SLIC3R_OPENGL_ES
shader->stop_using();
#if SLIC3R_OPENGL_ES
shader = wxGetApp().get_shader("dashed_lines");
#else
shader = wxGetApp().get_shader("dashed_thick_lines");
#endif // SLIC3R_OPENGL_ES
if (shader == nullptr)
return;
@@ -1455,18 +1468,20 @@ void GLGizmoMeasure::render_dimensioning()
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);
#if !SLIC3R_OPENGL_ES
}
else
#endif // ENABLE_GL_CORE_PROFILE
glsafe(::glLineWidth(2.0f));
glsafe(::glLineWidth(2.0f));
#endif // !SLIC3R_OPENGL_ES
// 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 !SLIC3R_OPENGL_ES
if (OpenGLManager::get_gl_info().is_core_profile()) {
#endif // !SLIC3R_OPENGL_ES
shader->stop_using();
shader = wxGetApp().get_shader("flat");
@@ -1474,10 +1489,11 @@ void GLGizmoMeasure::render_dimensioning()
return;
shader->start_using();
#if !SLIC3R_OPENGL_ES
}
else
#endif // ENABLE_GL_CORE_PROFILE
glsafe(::glLineWidth(1.0f));
glsafe(::glLineWidth(1.0f));
#endif // !SLIC3R_OPENGL_ES
// arrows
auto render_arrow = [this, shader, &camera, &normal, &center, &e1_unit, draw_radius, step, resolution](unsigned int endpoint_id) {

View File

@@ -896,6 +896,16 @@ void GLMmSegmentationGizmo3DScene::release_geometry() {
glsafe(::glDeleteBuffers(1, &triangle_indices_VBO_id));
triangle_indices_VBO_id = 0;
}
#if !SLIC3R_OPENGL_ES
if (OpenGLManager::get_gl_info().is_core_profile()) {
#endif // !SLIC3R_OPENGL_ES
if (this->vertices_VAO_id > 0) {
glsafe(::glDeleteVertexArrays(1, &this->vertices_VAO_id));
this->vertices_VAO_id = 0;
}
#if !SLIC3R_OPENGL_ES
}
#endif // !SLIC3R_OPENGL_ES
this->clear();
}
@@ -904,6 +914,13 @@ 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());
#if !SLIC3R_OPENGL_ES
if (OpenGLManager::get_gl_info().is_core_profile()) {
#endif // !SLIC3R_OPENGL_ES
assert(this->vertices_VAO_id != 0);
#if !SLIC3R_OPENGL_ES
}
#endif // !SLIC3R_OPENGL_ES
assert(this->vertices_VBO_id != 0);
assert(this->triangle_indices_VBO_ids[triangle_indices_idx] != 0);
@@ -911,6 +928,13 @@ void GLMmSegmentationGizmo3DScene::render(size_t triangle_indices_idx) const
if (shader == nullptr)
return;
#if !SLIC3R_OPENGL_ES
if (OpenGLManager::get_gl_info().is_core_profile()) {
#endif // !SLIC3R_OPENGL_ES
glsafe(::glBindVertexArray(this->vertices_VAO_id));
#if !SLIC3R_OPENGL_ES
}
#endif // !SLIC3R_OPENGL_ES
// 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");
@@ -931,17 +955,48 @@ void GLMmSegmentationGizmo3DScene::render(size_t triangle_indices_idx) const
glsafe(::glDisableVertexAttribArray(position_id));
glsafe(::glBindBuffer(GL_ARRAY_BUFFER, 0));
#if !SLIC3R_OPENGL_ES
if (OpenGLManager::get_gl_info().is_core_profile()) {
#endif // !SLIC3R_OPENGL_ES
glsafe(::glBindVertexArray(0));
#if !SLIC3R_OPENGL_ES
}
#endif // !SLIC3R_OPENGL_ES
}
void GLMmSegmentationGizmo3DScene::finalize_vertices()
{
#if !SLIC3R_OPENGL_ES
if (OpenGLManager::get_gl_info().is_core_profile()) {
#endif // !SLIC3R_OPENGL_ES
assert(this->vertices_VAO_id == 0);
#if !SLIC3R_OPENGL_ES
}
#endif // !SLIC3R_OPENGL_ES
assert(this->vertices_VBO_id == 0);
if (!this->vertices.empty()) {
#if !SLIC3R_OPENGL_ES
if (OpenGLManager::get_gl_info().is_core_profile()) {
#endif // !SLIC3R_OPENGL_ES
glsafe(::glGenVertexArrays(1, &this->vertices_VAO_id));
glsafe(::glBindVertexArray(this->vertices_VAO_id));
#if !SLIC3R_OPENGL_ES
}
#endif // !SLIC3R_OPENGL_ES
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();
#if !SLIC3R_OPENGL_ES
if (OpenGLManager::get_gl_info().is_core_profile()) {
#endif // !SLIC3R_OPENGL_ES
glsafe(::glBindVertexArray(0));
#if !SLIC3R_OPENGL_ES
}
#endif // !SLIC3R_OPENGL_ES
}
}

View File

@@ -57,6 +57,7 @@ public:
// 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<unsigned int> triangle_indices_VBO_ids;
};

View File

@@ -160,7 +160,11 @@ void GLGizmoMove3D::on_render()
m_grabbers[i].color = AXES_COLOR[i];
m_grabbers[i].hover_color = AXES_HOVER_COLOR[i];
}
glsafe(::glLineWidth((m_hover_id != -1) ? 2.0f : 1.5f));
#if !SLIC3R_OPENGL_ES
if (!OpenGLManager::get_gl_info().is_core_profile())
glsafe(::glLineWidth((m_hover_id != -1) ? 2.0f : 1.5f));
#endif // !SLIC3R_OPENGL_ES
auto render_grabber_connection = [this, &zero](unsigned int id) {
if (m_grabbers[id].enabled) {
@@ -191,12 +195,26 @@ void GLGizmoMove3D::on_render()
}
};
GLShaderProgram* shader = wxGetApp().get_shader("flat");
#if SLIC3R_OPENGL_ES
GLShaderProgram* shader = wxGetApp().get_shader("dashed_lines");
#else
GLShaderProgram* shader = OpenGLManager::get_gl_info().is_core_profile() ? wxGetApp().get_shader("dashed_thick_lines") : wxGetApp().get_shader("flat");
#endif // SLIC3R_OPENGL_ES
if (shader != nullptr) {
shader->start_using();
const Camera& camera = wxGetApp().plater()->get_camera();
shader->set_uniform("view_model_matrix", camera.get_view_matrix() * base_matrix);
shader->set_uniform("projection_matrix", camera.get_projection_matrix());
#if !SLIC3R_OPENGL_ES
if (OpenGLManager::get_gl_info().is_core_profile()) {
#endif // !SLIC3R_OPENGL_ES
const std::array<int, 4>& viewport = camera.get_viewport();
shader->set_uniform("viewport_size", Vec2d(double(viewport[2]), double(viewport[3])));
shader->set_uniform("width", 0.25f);
shader->set_uniform("gap_size", 0.0f);
#if !SLIC3R_OPENGL_ES
}
#endif // !SLIC3R_OPENGL_ES
// draw axes
for (unsigned int i = 0; i < 3; ++i) {
@@ -210,7 +228,11 @@ void GLGizmoMove3D::on_render()
render_grabbers(box);
if (m_object_manipulation->is_instance_coordinates()) {
shader = wxGetApp().get_shader("flat");
#if SLIC3R_OPENGL_ES
GLShaderProgram* shader = wxGetApp().get_shader("dashed_lines");
#else
GLShaderProgram* shader = OpenGLManager::get_gl_info().is_core_profile() ? wxGetApp().get_shader("dashed_thick_lines") : wxGetApp().get_shader("flat");
#endif // SLIC3R_OPENGL_ES
if (shader != nullptr) {
shader->start_using();
const Camera& camera = wxGetApp().plater()->get_camera();
@@ -224,6 +246,16 @@ void GLGizmoMove3D::on_render()
shader->set_uniform("view_model_matrix", camera.get_view_matrix() * cur_tran.get_matrix());
shader->set_uniform("projection_matrix", camera.get_projection_matrix());
#if !SLIC3R_OPENGL_ES
if (OpenGLManager::get_gl_info().is_core_profile()) {
#endif /// !SLIC3R_OPENGL_ES
const std::array<int, 4>& viewport = camera.get_viewport();
shader->set_uniform("viewport_size", Vec2d(double(viewport[2]), double(viewport[3])));
shader->set_uniform("width", 0.5f);
shader->set_uniform("gap_size", 0.0f);
#if !SLIC3R_OPENGL_ES
}
#endif // !SLIC3R_OPENGL_ES
render_cross_mark(Vec3f::Zero(), true);

View File

@@ -181,14 +181,23 @@ void GLGizmoPainterBase::render_cursor_circle()
const float cnv_inv_height = 1.0f / cnv_height;
const Vec2d center = m_parent.get_local_mouse_position();
const float zoom = float(wxGetApp().plater()->get_camera().get_zoom());
const float radius = m_cursor_radius * float(wxGetApp().plater()->get_camera().get_zoom());
glsafe(::glLineWidth(1.5f));
#if !SLIC3R_OPENGL_ES
if (!OpenGLManager::get_gl_info().is_core_profile())
glsafe(::glLineWidth(1.5f));
#endif // !SLIC3R_OPENGL_ES
glsafe(::glDisable(GL_DEPTH_TEST));
glsafe(::glPushAttrib(GL_ENABLE_BIT));
glsafe(::glLineStipple(4, 0xAAAA));
glsafe(::glEnable(GL_LINE_STIPPLE));
#if !SLIC3R_OPENGL_ES
if (!OpenGLManager::get_gl_info().is_core_profile()) {
glsafe(::glPushAttrib(GL_ENABLE_BIT));
glsafe(::glLineStipple(4, 0xAAAA));
glsafe(::glEnable(GL_LINE_STIPPLE));
}
#endif // !SLIC3R_OPENGL_ES
if (!m_circle.is_initialized() || !m_old_center.isApprox(center) || std::abs(m_old_cursor_radius - radius) > EPSILON) {
m_old_cursor_radius = radius;
@@ -196,19 +205,49 @@ void GLGizmoPainterBase::render_cursor_circle()
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 };
unsigned int steps_count = 0;
#if !SLIC3R_OPENGL_ES
if (OpenGLManager::get_gl_info().is_core_profile()) {
#endif // !SLIC3R_OPENGL_ES
steps_count = (unsigned int)(2 * (4 + int(252 * (zoom - 1.0f) / (250.0f - 1.0f))));
init_data.format = { GLModel::Geometry::EPrimitiveType::Lines, GLModel::Geometry::EVertexLayout::P2 };
#if !SLIC3R_OPENGL_ES
}
else {
steps_count = 32;
init_data.format = { GLModel::Geometry::EPrimitiveType::LineLoop, GLModel::Geometry::EVertexLayout::P2 };
}
#endif // !SLIC3R_OPENGL_ES
const float step_size = 2.0f * float(PI) / float(steps_count);
init_data.color = { 0.0f, 1.0f, 0.3f, 1.0f };
init_data.reserve_vertices(StepsCount);
init_data.reserve_indices(StepsCount);
init_data.reserve_vertices(steps_count);
init_data.reserve_indices(steps_count);
// vertices + indices
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)));
init_data.add_index(i);
for (unsigned int i = 0; i < steps_count; ++i) {
#if !SLIC3R_OPENGL_ES
if (OpenGLManager::get_gl_info().is_core_profile()) {
#endif // !SLIC3R_OPENGL_ES
if (i % 2 != 0) continue;
const float angle_i = float(i) * step_size;
const unsigned int j = (i + 1) % steps_count;
const float angle_j = float(j) * step_size;
const Vec2d v_i(::cos(angle_i), ::sin(angle_i));
const Vec2d v_j(::cos(angle_j), ::sin(angle_j));
init_data.add_vertex(Vec2f(v_i.x(), v_i.y()));
init_data.add_vertex(Vec2f(v_j.x(), v_j.y()));
const size_t vcount = init_data.vertices_count();
init_data.add_line(vcount - 2, vcount - 1);
#if !SLIC3R_OPENGL_ES
}
else {
const float angle = float(i) * step_size;
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);
}
#endif // !SLIC3R_OPENGL_ES
}
m_circle.init_from(std::move(init_data));
@@ -223,16 +262,43 @@ void GLGizmoPainterBase::render_cursor_circle()
m_circle.set_color(render_color);
GLShaderProgram* shader = GUI::wxGetApp().get_shader("flat");
#if SLIC3R_OPENGL_ES
GLShaderProgram* shader = wxGetApp().get_shader("dashed_lines");
#else
GLShaderProgram* shader = OpenGLManager::get_gl_info().is_core_profile() ? wxGetApp().get_shader("dashed_thick_lines") : wxGetApp().get_shader("flat");
#endif // SLIC3R_OPENGL_ES
if (shader != nullptr) {
shader->start_using();
shader->set_uniform("view_model_matrix", Transform3d::Identity());
#if !SLIC3R_OPENGL_ES
if (OpenGLManager::get_gl_info().is_core_profile()) {
#endif // !SLIC3R_OPENGL_ES
const Transform3d view_model_matrix = Geometry::translation_transform(Vec3d(2.0f * (center.x() * cnv_inv_width - 0.5f), -2.0f * (center.y() * cnv_inv_height - 0.5f), 0.0)) *
Geometry::scale_transform(Vec3d(2.0f * radius * cnv_inv_width, 2.0f * radius * cnv_inv_height, 1.0f));
shader->set_uniform("view_model_matrix", view_model_matrix);
#if !SLIC3R_OPENGL_ES
}
else
shader->set_uniform("view_model_matrix", Transform3d::Identity());
#endif // !SLIC3R_OPENGL_ES
shader->set_uniform("projection_matrix", Transform3d::Identity());
#if !SLIC3R_OPENGL_ES
if (OpenGLManager::get_gl_info().is_core_profile()) {
#endif // !SLIC3R_OPENGL_ES
const std::array<int, 4>& viewport = wxGetApp().plater()->get_camera().get_viewport();
shader->set_uniform("viewport_size", Vec2d(double(viewport[2]), double(viewport[3])));
shader->set_uniform("width", 0.25f);
shader->set_uniform("gap_size", 0.0f);
#if !SLIC3R_OPENGL_ES
}
#endif // !SLIC3R_OPENGL_ES
m_circle.render();
shader->stop_using();
}
glsafe(::glPopAttrib());
#if !SLIC3R_OPENGL_ES
if (!OpenGLManager::get_gl_info().is_core_profile())
glsafe(::glPopAttrib());
#endif // !SLIC3R_OPENGL_ES
glsafe(::glEnable(GL_DEPTH_TEST));
}
@@ -1528,6 +1594,13 @@ void TriangleSelectorPatch::render(int triangle_indices_idx, bool show_wireframe
{
assert(triangle_indices_idx < this->m_triangle_indices_VBO_ids.size());
assert(this->m_triangle_patches.size() == this->m_triangle_indices_VBO_ids.size());
#if !SLIC3R_OPENGL_ES
if (OpenGLManager::get_gl_info().is_core_profile()) {
#endif // !SLIC3R_OPENGL_ES
assert(this->m_vertices_VAO_id != 0);
#if !SLIC3R_OPENGL_ES
}
#endif // !SLIC3R_OPENGL_ES
//assert(this->m_vertices_VBO_id != 0);
assert(this->m_triangle_patches.size() == this->m_vertices_VBO_ids.size());
assert(this->m_vertices_VBO_ids[triangle_indices_idx] != 0);
@@ -1537,6 +1610,13 @@ void TriangleSelectorPatch::render(int triangle_indices_idx, bool show_wireframe
if (shader == nullptr)
return;
#if !SLIC3R_OPENGL_ES
if (OpenGLManager::get_gl_info().is_core_profile()) {
#endif // !SLIC3R_OPENGL_ES
glsafe(::glBindVertexArray(this->m_vertices_VAO_id));
#if !SLIC3R_OPENGL_ES
}
#endif // !SLIC3R_OPENGL_ES
// 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");
@@ -1580,6 +1660,16 @@ void TriangleSelectorPatch::release_geometry()
glsafe(::glDeleteBuffers(1, &m_vertices_VBO_id));
m_vertices_VBO_id = 0;
}*/
#if !SLIC3R_OPENGL_ES
if (OpenGLManager::get_gl_info().is_core_profile()) {
#endif // !SLIC3R_OPENGL_ES
if (this->m_vertices_VAO_id > 0) {
glsafe(::glDeleteVertexArrays(1, &this->m_vertices_VAO_id));
this->m_vertices_VAO_id = 0;
}
#if !SLIC3R_OPENGL_ES
}
#endif // !SLIC3R_OPENGL_ES
for (auto& vertice_VBO_id : m_vertices_VBO_ids) {
glsafe(::glDeleteBuffers(1, &vertice_VBO_id));
vertice_VBO_id = 0;
@@ -1607,6 +1697,13 @@ void TriangleSelectorPatch::finalize_vertices()
void TriangleSelectorPatch::finalize_triangle_indices()
{
#if !SLIC3R_OPENGL_ES
if (OpenGLManager::get_gl_info().is_core_profile()) {
#endif // !SLIC3R_OPENGL_ES
assert(this->m_vertices_VAO_id == 0);
#if !SLIC3R_OPENGL_ES
}
#endif // !SLIC3R_OPENGL_ES
m_vertices_VBO_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());
@@ -1634,6 +1731,15 @@ void TriangleSelectorPatch::finalize_triangle_indices()
triangle_indices.clear();
}
}
#if !SLIC3R_OPENGL_ES
if (OpenGLManager::get_gl_info().is_core_profile()) {
#endif // !SLIC3R_OPENGL_ES
glsafe(::glGenVertexArrays(1, &this->m_vertices_VAO_id));
glsafe(::glBindVertexArray(this->m_vertices_VAO_id));
#if !SLIC3R_OPENGL_ES
}
#endif // !SLIC3R_OPENGL_ES
}
#ifdef PRUSASLICER_TRIANGLE_SELECTOR_DEBUG

View File

@@ -162,6 +162,7 @@ protected:
// 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_VAO_id{ 0 };
//unsigned int m_vertices_VBO_id{ 0 };
std::vector<unsigned int> m_vertices_VBO_ids;
std::vector<unsigned int> m_triangle_indices_VBO_ids;

View File

@@ -149,8 +149,16 @@ 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");
#if !SLIC3R_OPENGL_ES
if (!OpenGLManager::get_gl_info().is_core_profile())
glsafe(::glLineWidth((m_hover_id != -1) ? 2.0f : 1.5f));
#endif // !SLIC3R_OPENGL_ES
#if SLIC3R_OPENGL_ES
GLShaderProgram* shader = wxGetApp().get_shader("dashed_lines");
#else
GLShaderProgram* shader = OpenGLManager::get_gl_info().is_core_profile() ? wxGetApp().get_shader("dashed_thick_lines") : wxGetApp().get_shader("flat");
#endif // SLIC3R_OPENGL_ES
if (shader != nullptr) {
shader->start_using();
@@ -158,6 +166,16 @@ void GLGizmoRotate::on_render()
const 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());
#if !SLIC3R_OPENGL_ES
if (OpenGLManager::get_gl_info().is_core_profile()) {
#endif // !SLIC3R_OPENGL_ES
const std::array<int, 4>& viewport = camera.get_viewport();
shader->set_uniform("viewport_size", Vec2d(double(viewport[2]), double(viewport[3])));
shader->set_uniform("width", 0.25f);
shader->set_uniform("gap_size", 0.0f);
#if !SLIC3R_OPENGL_ES
}
#endif // !SLIC3R_OPENGL_ES
const bool radius_changed = std::abs(m_old_radius - m_radius) > EPSILON;
m_old_radius = m_radius;

View File

@@ -293,12 +293,19 @@ void GLGizmoScale3D::on_render()
update_grabbers_data();
glsafe(::glLineWidth((m_hover_id != -1) ? 2.0f : 1.5f));
#if !SLIC3R_OPENGL_ES
if (!OpenGLManager::get_gl_info().is_core_profile())
glsafe(::glLineWidth((m_hover_id != -1) ? 2.0f : 1.5f));
#endif // !SLIC3R_OPENGL_ES
const float grabber_mean_size = (float)((m_bounding_box.size().x() + m_bounding_box.size().y() + m_bounding_box.size().z()) / 3.0);
//draw connections
GLShaderProgram* shader = wxGetApp().get_shader("flat");
#if SLIC3R_OPENGL_ES
GLShaderProgram* shader = wxGetApp().get_shader("dashed_lines");
#else
GLShaderProgram* shader = OpenGLManager::get_gl_info().is_core_profile() ? wxGetApp().get_shader("dashed_thick_lines") : wxGetApp().get_shader("flat");
#endif // SLIC3R_OPENGL_ES
if (shader != nullptr) {
shader->start_using();
// BBS: when select multiple objects, uniform scale can be deselected, display the connection(4,5)
@@ -306,6 +313,16 @@ void GLGizmoScale3D::on_render()
const Camera& camera = wxGetApp().plater()->get_camera();
shader->set_uniform("view_model_matrix", camera.get_view_matrix() * m_grabbers_tran.get_matrix());
shader->set_uniform("projection_matrix", camera.get_projection_matrix());
#if !SLIC3R_OPENGL_ES
if (OpenGLManager::get_gl_info().is_core_profile()) {
#endif // !SLIC3R_OPENGL_ES
const std::array<int, 4>& viewport = camera.get_viewport();
shader->set_uniform("viewport_size", Vec2d(double(viewport[2]), double(viewport[3])));
shader->set_uniform("width", 0.25f);
shader->set_uniform("gap_size", 0.0f);
#if !SLIC3R_OPENGL_ES
}
#endif // !SLIC3R_OPENGL_ES
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);

View File

@@ -643,7 +643,7 @@ void GLGizmoSimplify::on_render()
const Transform3d trafo_matrix = selected_volume->world_matrix();
auto* gouraud_shader = wxGetApp().get_shader("gouraud_light");
glsafe(::glPushAttrib(GL_DEPTH_TEST));
glsafe(::glPushAttrib(GL_DEPTH_TEST)); // TODO: delete this line?
glsafe(::glEnable(GL_DEPTH_TEST));
gouraud_shader->start_using();
const Camera& camera = wxGetApp().plater()->get_camera();
@@ -657,20 +657,29 @@ void GLGizmoSimplify::on_render()
gouraud_shader->stop_using();
if (m_show_wireframe) {
auto* contour_shader = wxGetApp().get_shader("mm_contour");
#if SLIC3R_OPENGL_ES
auto* contour_shader = wxGetApp().get_shader("wireframe");
#else
auto *contour_shader = wxGetApp().get_shader("mm_contour");
#endif // SLIC3R_OPENGL_ES
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();
m_glmodel.set_color(ColorRGBA::WHITE());
glsafe(::glLineWidth(1.0f));
#if !SLIC3R_OPENGL_ES
if (!OpenGLManager::get_gl_info().is_core_profile())
glsafe(::glLineWidth(1.0f));
glsafe(::glPolygonMode(GL_FRONT_AND_BACK, GL_LINE));
#endif // !SLIC3R_OPENGL_ES
//ScopeGuard offset_fill_guard([]() { glsafe(::glDisable(GL_POLYGON_OFFSET_FILL)); });
//glsafe(::glEnable(GL_POLYGON_OFFSET_FILL));
//glsafe(::glPolygonOffset(5.0, 5.0));
m_glmodel.render();
#if !SLIC3R_OPENGL_ES
glsafe(::glPolygonMode(GL_FRONT_AND_BACK, GL_FILL));
#endif // !SLIC3R_OPENGL_ES
m_glmodel.set_color(color);
contour_shader->stop_using();
}

View File

@@ -99,6 +99,9 @@ static const std::map<const wchar_t, std::string> font_icons = {
{ImGui::CollapseBtn , "collapse_btn" },
{ImGui::RevertBtn , "revert_btn" },
{ImGui::HorizontalHide , "horizontal_hide" },
{ImGui::HorizontalShow , "horizontal_show" },
{ImGui::CloseBlockNotifButton , "block_notification_close" },
{ImGui::CloseBlockNotifHoverButton , "block_notification_close_hover" },
@@ -2975,22 +2978,39 @@ void ImGuiWrapper::render_draw_data(ImDrawData *draw_data)
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.
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));
// Backup GL state
GLenum last_active_texture; glsafe(::glGetIntegerv(GL_ACTIVE_TEXTURE, (GLint*)&last_active_texture));
GLuint last_program; glsafe(::glGetIntegerv(GL_CURRENT_PROGRAM, (GLint*)&last_program));
GLuint last_texture; glsafe(::glGetIntegerv(GL_TEXTURE_BINDING_2D, (GLint*)&last_texture));
GLuint last_array_buffer; glsafe(::glGetIntegerv(GL_ARRAY_BUFFER_BINDING, (GLint*)&last_array_buffer));
GLuint last_vertex_array_object = 0;
#if !SLIC3R_OPENGL_ES
if (OpenGLManager::get_gl_info().is_core_profile())
#endif // !SLIC3R_OPENGL_ES
glsafe(::glGetIntegerv(GL_VERTEX_ARRAY_BINDING, (GLint*)&last_vertex_array_object));
GLint last_viewport[4]; glsafe(::glGetIntegerv(GL_VIEWPORT, last_viewport));
GLint last_scissor_box[4]; glsafe(::glGetIntegerv(GL_SCISSOR_BOX, last_scissor_box));
GLenum last_blend_src_rgb; glsafe(::glGetIntegerv(GL_BLEND_SRC_RGB, (GLint*)&last_blend_src_rgb));
GLenum last_blend_dst_rgb; glsafe(::glGetIntegerv(GL_BLEND_DST_RGB, (GLint*)&last_blend_dst_rgb));
GLenum last_blend_src_alpha; glsafe(::glGetIntegerv(GL_BLEND_SRC_ALPHA, (GLint*)&last_blend_src_alpha));
GLenum last_blend_dst_alpha; glsafe(::glGetIntegerv(GL_BLEND_DST_ALPHA, (GLint*)&last_blend_dst_alpha));
GLenum last_blend_equation_rgb; glsafe(::glGetIntegerv(GL_BLEND_EQUATION_RGB, (GLint*)&last_blend_equation_rgb));
GLenum last_blend_equation_alpha; glsafe(::glGetIntegerv(GL_BLEND_EQUATION_ALPHA, (GLint*)&last_blend_equation_alpha));
GLboolean last_enable_blend = ::glIsEnabled(GL_BLEND);
GLboolean last_enable_cull_face = ::glIsEnabled(GL_CULL_FACE);
GLboolean last_enable_depth_test = ::glIsEnabled(GL_DEPTH_TEST);
GLboolean last_enable_stencil_test = ::glIsEnabled(GL_STENCIL_TEST);
GLboolean last_enable_scissor_test = ::glIsEnabled(GL_SCISSOR_TEST);
// set new GL state
glsafe(::glActiveTexture(GL_TEXTURE0));
glsafe(::glEnable(GL_BLEND));
glsafe(::glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA));
glsafe(::glBlendEquation(GL_FUNC_ADD));
glsafe(::glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA));
glsafe(::glDisable(GL_CULL_FACE));
glsafe(::glDisable(GL_DEPTH_TEST));
glsafe(::glDisable(GL_STENCIL_TEST));
glsafe(::glEnable(GL_SCISSOR_TEST));
glsafe(::glEnable(GL_TEXTURE_2D));
glsafe(::glPolygonMode(GL_FRONT_AND_BACK, GL_FILL));
glsafe(::glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE));
// Setup viewport, orthographic projection matrix
// 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.
@@ -3022,6 +3042,16 @@ void ImGuiWrapper::render_draw_data(ImDrawData *draw_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);
GLuint vao_id = 0;
#if !SLIC3R_OPENGL_ES
if (OpenGLManager::get_gl_info().is_core_profile()) {
#endif // !SLIC3R_OPENGL_ES
glsafe(::glGenVertexArrays(1, &vao_id));
glsafe(::glBindVertexArray(vao_id));
#if !SLIC3R_OPENGL_ES
}
#endif // !SLIC3R_OPENGL_ES
GLuint vbo_id;
glsafe(::glGenBuffers(1, &vbo_id));
glsafe(::glBindBuffer(GL_ARRAY_BUFFER, vbo_id));
@@ -3081,14 +3111,31 @@ void ImGuiWrapper::render_draw_data(ImDrawData *draw_data)
glsafe(::glDeleteBuffers(1, &ibo_id));
glsafe(::glDeleteBuffers(1, &vbo_id));
#if !SLIC3R_OPENGL_ES
if (OpenGLManager::get_gl_info().is_core_profile()) {
#endif // !SLIC3R_OPENGL_ES
if (vao_id > 0)
glsafe(::glDeleteVertexArrays(1, &vao_id));
#if !SLIC3R_OPENGL_ES
}
#endif // !SLIC3R_OPENGL_ES
}
// Restore modified state
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]);
glsafe(::glPolygonMode(GL_BACK, (GLenum)last_polygon_mode[1])));
// Restore modified GL state
glsafe(::glBindTexture(GL_TEXTURE_2D, last_texture));
glsafe(::glActiveTexture(last_active_texture));
#if !SLIC3R_OPENGL_ES
if (OpenGLManager::get_gl_info().is_core_profile())
#endif // !SLIC3R_OPENGL_ES
glsafe(::glBindVertexArray(last_vertex_array_object));
glsafe(::glBindBuffer(GL_ARRAY_BUFFER, last_array_buffer));
glsafe(::glBlendEquationSeparate(last_blend_equation_rgb, last_blend_equation_alpha));
glsafe(::glBlendFuncSeparate(last_blend_src_rgb, last_blend_dst_rgb, last_blend_src_alpha, last_blend_dst_alpha));
if (last_enable_blend) glsafe(::glEnable(GL_BLEND)); else glsafe(::glDisable(GL_BLEND));
if (last_enable_cull_face) glsafe(::glEnable(GL_CULL_FACE)); else glsafe(::glDisable(GL_CULL_FACE));
if (last_enable_depth_test) glsafe(::glEnable(GL_DEPTH_TEST)); else glsafe(::glDisable(GL_DEPTH_TEST));
if (last_enable_stencil_test) glsafe(::glEnable(GL_STENCIL_TEST)); else glsafe(::glDisable(GL_STENCIL_TEST));
if (last_enable_scissor_test) glsafe(::glEnable(GL_SCISSOR_TEST)); else glsafe(::glDisable(GL_SCISSOR_TEST));
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]));

View File

@@ -0,0 +1,800 @@
///|/ Copyright (c) Prusa Research 2020 - 2023 Enrico Turri @enricoturri1966
///|/
///|/ PrusaSlicer is released under the terms of the AGPLv3 or higher
///|/
#include <algorithm>
#include <cmath>
#include <cstring>
#include <iterator>
#include <cassert>
#include <cinttypes>
#include "libslic3r/libslic3r.h"
#include "LibVGCodeWrapper.hpp"
#include "libslic3r/Print.hpp"
#include "libslic3r/Color.hpp"
#include "libslic3r/CustomGCode.hpp"
#include "libslic3r/Exception.hpp"
#include "libslic3r/ExtrusionEntity.hpp"
#include "libslic3r/ExtrusionEntityCollection.hpp"
#include "libslic3r/GCode/WipeTower.hpp"
#include "libslic3r/Layer.hpp"
#include "libslic3r/Line.hpp"
#include "libslic3r/Polyline.hpp"
#include "libslic3r/PrintConfig.hpp"
#include "../../src/libvgcode/include/GCodeInputData.hpp"
#include "../../src/libvgcode/include/PathVertex.hpp"
#include "libvgcode/include/Types.hpp"
namespace libvgcode {
class Viewer;
Vec3 convert(const Slic3r::Vec3f& v)
{
return { v.x(), v.y(), v.z() };
}
Slic3r::Vec3f convert(const Vec3& v)
{
return { v[0], v[1], v[2] };
}
Mat4x4 convert(const Slic3r::Matrix4f& m)
{
Mat4x4 ret;
std::memcpy(ret.data(), m.data(), 16 * sizeof(float));
return ret;
}
Slic3r::ColorRGBA convert(const Color& c)
{
static const float inv_255 = 1.0f / 255.0f;
return { c[0] * inv_255, c[1] * inv_255, c[2] * inv_255, 1.0f };
}
Color convert(const Slic3r::ColorRGBA& c)
{
return { static_cast<uint8_t>(c.r() * 255.0f), static_cast<uint8_t>(c.g() * 255.0f), static_cast<uint8_t>(c.b() * 255.0f) };
}
Color convert(const std::string& color_str)
{
Slic3r::ColorRGBA color_rgba;
return decode_color(color_str, color_rgba) ? convert(color_rgba) : DUMMY_COLOR;
}
Slic3r::ExtrusionRole convert(EGCodeExtrusionRole role)
{
switch (role)
{
case EGCodeExtrusionRole::None: { return Slic3r::ExtrusionRole::erNone; }
case EGCodeExtrusionRole::Perimeter: { return Slic3r::ExtrusionRole::erPerimeter; }
case EGCodeExtrusionRole::ExternalPerimeter: { return Slic3r::ExtrusionRole::erExternalPerimeter; }
case EGCodeExtrusionRole::OverhangPerimeter: { return Slic3r::ExtrusionRole::erOverhangPerimeter; }
case EGCodeExtrusionRole::InternalInfill: { return Slic3r::ExtrusionRole::erInternalInfill; }
case EGCodeExtrusionRole::SolidInfill: { return Slic3r::ExtrusionRole::erSolidInfill; }
case EGCodeExtrusionRole::TopSolidInfill: { return Slic3r::ExtrusionRole::erTopSolidInfill; }
case EGCodeExtrusionRole::Ironing: { return Slic3r::ExtrusionRole::erIroning; }
case EGCodeExtrusionRole::BridgeInfill: { return Slic3r::ExtrusionRole::erBridgeInfill; }
case EGCodeExtrusionRole::GapFill: { return Slic3r::ExtrusionRole::erGapFill; }
case EGCodeExtrusionRole::Skirt: { return Slic3r::ExtrusionRole::erSkirt; }
case EGCodeExtrusionRole::SupportMaterial: { return Slic3r::ExtrusionRole::erSupportMaterial; }
case EGCodeExtrusionRole::SupportMaterialInterface: { return Slic3r::ExtrusionRole::erSupportMaterialInterface; }
case EGCodeExtrusionRole::WipeTower: { return Slic3r::ExtrusionRole::erWipeTower; }
case EGCodeExtrusionRole::Custom: { return Slic3r::ExtrusionRole::erCustom; }
default: { return Slic3r::ExtrusionRole::erNone; }
}
}
EGCodeExtrusionRole convert(Slic3r::ExtrusionRole role)
{
switch (role)
{
case Slic3r::ExtrusionRole::erNone: { return EGCodeExtrusionRole::None; }
case Slic3r::ExtrusionRole::erPerimeter: { return EGCodeExtrusionRole::Perimeter; }
case Slic3r::ExtrusionRole::erExternalPerimeter: { return EGCodeExtrusionRole::ExternalPerimeter; }
case Slic3r::ExtrusionRole::erOverhangPerimeter: { return EGCodeExtrusionRole::OverhangPerimeter; }
case Slic3r::ExtrusionRole::erInternalInfill: { return EGCodeExtrusionRole::InternalInfill; }
case Slic3r::ExtrusionRole::erSolidInfill: { return EGCodeExtrusionRole::SolidInfill; }
case Slic3r::ExtrusionRole::erTopSolidInfill: { return EGCodeExtrusionRole::TopSolidInfill; }
case Slic3r::ExtrusionRole::erIroning: { return EGCodeExtrusionRole::Ironing; }
case Slic3r::ExtrusionRole::erBridgeInfill: { return EGCodeExtrusionRole::BridgeInfill; }
case Slic3r::ExtrusionRole::erGapFill: { return EGCodeExtrusionRole::GapFill; }
case Slic3r::ExtrusionRole::erSkirt: { return EGCodeExtrusionRole::Skirt; }
case Slic3r::ExtrusionRole::erSupportMaterial: { return EGCodeExtrusionRole::SupportMaterial; }
case Slic3r::ExtrusionRole::erSupportMaterialInterface: { return EGCodeExtrusionRole::SupportMaterialInterface; }
case Slic3r::ExtrusionRole::erWipeTower: { return EGCodeExtrusionRole::WipeTower; }
case Slic3r::ExtrusionRole::erCustom: { return EGCodeExtrusionRole::Custom; }
default: { return EGCodeExtrusionRole::None; }
}
}
EMoveType convert(Slic3r::EMoveType type)
{
switch (type)
{
case Slic3r::EMoveType::Noop: { return EMoveType::Noop; }
case Slic3r::EMoveType::Retract: { return EMoveType::Retract; }
case Slic3r::EMoveType::Unretract: { return EMoveType::Unretract; }
case Slic3r::EMoveType::Seam: { return EMoveType::Seam; }
case Slic3r::EMoveType::Tool_change: { return EMoveType::ToolChange; }
case Slic3r::EMoveType::Color_change: { return EMoveType::ColorChange; }
case Slic3r::EMoveType::Pause_Print: { return EMoveType::PausePrint; }
case Slic3r::EMoveType::Custom_GCode: { return EMoveType::CustomGCode; }
case Slic3r::EMoveType::Travel: { return EMoveType::Travel; }
case Slic3r::EMoveType::Wipe: { return EMoveType::Wipe; }
case Slic3r::EMoveType::Extrude: { return EMoveType::Extrude; }
default: { return EMoveType::COUNT; }
}
}
// EOptionType convert(const Slic3r::GUI::Preview::OptionType& type)
// {
// switch (type)
// {
// case Slic3r::GUI::Preview::OptionType::Travel: { return EOptionType::Travels; }
// case Slic3r::GUI::Preview::OptionType::Wipe: { return EOptionType::Wipes; }
// case Slic3r::GUI::Preview::OptionType::Retractions: { return EOptionType::Retractions; }
// case Slic3r::GUI::Preview::OptionType::Unretractions: { return EOptionType::Unretractions; }
// case Slic3r::GUI::Preview::OptionType::Seams: { return EOptionType::Seams; }
// case Slic3r::GUI::Preview::OptionType::ToolChanges: { return EOptionType::ToolChanges; }
// case Slic3r::GUI::Preview::OptionType::ColorChanges: { return EOptionType::ColorChanges; }
// case Slic3r::GUI::Preview::OptionType::PausePrints: { return EOptionType::PausePrints; }
// case Slic3r::GUI::Preview::OptionType::CustomGCodes: { return EOptionType::CustomGCodes; }
// #if VGCODE_ENABLE_COG_AND_TOOL_MARKERS
// case Slic3r::GUI::Preview::OptionType::CenterOfGravity: { return EOptionType::CenterOfGravity; }
// case Slic3r::GUI::Preview::OptionType::ToolMarker: { return EOptionType::ToolMarker; }
// #else
// // case Slic3r::GUI::Preview::OptionType::CenterOfGravity: { return EOptionType::COUNT; }
// case Slic3r::GUI::Preview::OptionType::ToolMarker: { return EOptionType::COUNT; }
// #endif // VGCODE_ENABLE_COG_AND_TOOL_MARKERS
// default: { return EOptionType::COUNT; }
// }
// }
ETimeMode convert(const Slic3r::PrintEstimatedStatistics::ETimeMode& mode)
{
switch (mode)
{
case Slic3r::PrintEstimatedStatistics::ETimeMode::Normal: { return ETimeMode::Normal; }
case Slic3r::PrintEstimatedStatistics::ETimeMode::Stealth: { return ETimeMode::Stealth; }
default: { return ETimeMode::COUNT; }
}
}
Slic3r::PrintEstimatedStatistics::ETimeMode convert(const ETimeMode& mode)
{
switch (mode)
{
case ETimeMode::Normal: { return Slic3r::PrintEstimatedStatistics::ETimeMode::Normal; }
case ETimeMode::Stealth: { return Slic3r::PrintEstimatedStatistics::ETimeMode::Stealth; }
default: { return Slic3r::PrintEstimatedStatistics::ETimeMode::Count; }
}
}
GCodeInputData convert(const Slic3r::GCodeProcessorResult& result, const std::vector<std::string>& str_tool_colors,
const std::vector<std::string>& str_color_print_colors, const Viewer& viewer)
{
GCodeInputData ret;
// collect tool colors
ret.tools_colors.reserve(str_tool_colors.size());
for (const std::string& color : str_tool_colors) {
ret.tools_colors.emplace_back(convert(color));
}
// collect color print colors
const std::vector<std::string>& str_colors = str_color_print_colors.empty() ? str_tool_colors : str_color_print_colors;
ret.color_print_colors.reserve(str_colors.size());
for (const std::string& color : str_colors) {
ret.color_print_colors.emplace_back(convert(color));
}
const std::vector<Slic3r::GCodeProcessorResult::MoveVertex>& moves = result.moves;
ret.vertices.reserve(2 * moves.size());
for (size_t i = 1; i < moves.size(); ++i) {
const Slic3r::GCodeProcessorResult::MoveVertex& curr = moves[i];
const Slic3r::GCodeProcessorResult::MoveVertex& prev = moves[i - 1];
const EMoveType curr_type = convert(curr.type);
const EOptionType option_type = move_type_to_option(curr_type);
if (option_type == EOptionType::COUNT || option_type == EOptionType::Travels || option_type == EOptionType::Wipes) {
if (ret.vertices.empty() || prev.type != curr.type || prev.extrusion_role != curr.extrusion_role) {
// to allow libvgcode to properly detect the start/end of a path we need to add a 'phantom' vertex
// equal to the current one with the exception of the position, which should match the previous move position,
// and the times, which are set to zero
#if VGCODE_ENABLE_COG_AND_TOOL_MARKERS
const libvgcode::PathVertex vertex = { convert(prev.position), curr.height, curr.width, curr.feedrate, prev.actual_feedrate,
curr.mm3_per_mm, curr.fan_speed, curr.temperature, 0.0f, convert(curr.extrusion_role), curr_type,
static_cast<uint32_t>(curr.gcode_id), static_cast<uint32_t>(curr.layer_id),
static_cast<uint8_t>(curr.extruder_id), static_cast<uint8_t>(curr.cp_color_id), { 0.0f, 0.0f } };
#else
const libvgcode::PathVertex vertex = { convert(prev.position), curr.height, curr.width, curr.feedrate, prev.actual_feedrate,
curr.mm3_per_mm, curr.fan_speed, curr.temperature, convert(curr.extrusion_role), curr_type,
static_cast<uint32_t>(curr.gcode_id), static_cast<uint32_t>(curr.layer_id),
static_cast<uint8_t>(curr.extruder_id), static_cast<uint8_t>(curr.cp_color_id), { 0.0f, 0.0f } };
#endif // VGCODE_ENABLE_COG_AND_TOOL_MARKERS
ret.vertices.emplace_back(vertex);
}
}
#if VGCODE_ENABLE_COG_AND_TOOL_MARKERS
const libvgcode::PathVertex vertex = { convert(curr.position), curr.height, curr.width, curr.feedrate, curr.actual_feedrate,
curr.mm3_per_mm, curr.fan_speed, curr.temperature,
result.filament_densities[curr.extruder_id] * curr.mm3_per_mm * (curr.position - prev.position).norm(),
convert(curr.extrusion_role), curr_type, static_cast<uint32_t>(curr.gcode_id), static_cast<uint32_t>(curr.layer_id),
static_cast<uint8_t>(curr.extruder_id), static_cast<uint8_t>(curr.cp_color_id), curr.time };
#else
const libvgcode::PathVertex vertex = { convert(curr.position), curr.height, curr.width, curr.feedrate, curr.actual_feedrate,
curr.mm3_per_mm, curr.fan_speed, curr.temperature, convert(curr.extrusion_role), curr_type,
static_cast<uint32_t>(curr.gcode_id), static_cast<uint32_t>(curr.layer_id),
static_cast<uint8_t>(curr.extruder_id), static_cast<uint8_t>(curr.cp_color_id), curr.time };
#endif // VGCODE_ENABLE_COG_AND_TOOL_MARKERS
ret.vertices.emplace_back(vertex);
}
ret.vertices.shrink_to_fit();
ret.spiral_vase_mode = result.spiral_vase_mode;
return ret;
}
static void convert_lines_to_vertices(const Slic3r::Lines& lines, const std::vector<float>& widths, const std::vector<float>& heights,
float top_z, size_t layer_id, size_t extruder_id, size_t color_id, EGCodeExtrusionRole extrusion_role, bool closed, std::vector<PathVertex>& vertices)
{
if (lines.empty())
return;
// loop once more in case of closed loops
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 Slic3r::Line& line = lines[i];
// first segment of the polyline
if (ii == 0) {
// add a dummy vertex at the start, to separate the current line from the others
const Slic3r::Vec2f a = unscale(line.a).cast<float>();
#if VGCODE_ENABLE_COG_AND_TOOL_MARKERS
libvgcode::PathVertex vertex = { convert(Slic3r::Vec3f(a.x(), a.y(), top_z)), heights[i], widths[i], 0.0f, 0.0f,
0.0f, 0.0f, 0.0f, 0.0f, extrusion_role, EMoveType::Noop, 0, static_cast<uint32_t>(layer_id),
static_cast<uint8_t>(extruder_id), static_cast<uint8_t>(color_id), { 0.0f, 0.0f } };
#else
libvgcode::PathVertex vertex = { convert(Slic3r::Vec3f(a.x(), a.y(), top_z)), heights[i], widths[i], 0.0f, 0.0f,
0.0f, 0.0f, 0.0f, extrusion_role, EMoveType::Noop, 0, static_cast<uint32_t>(layer_id),
static_cast<uint8_t>(extruder_id), static_cast<uint8_t>(color_id), { 0.0f, 0.0f } };
#endif // VGCODE_ENABLE_COG_AND_TOOL_MARKERS
vertices.emplace_back(vertex);
// add the starting vertex of the segment
vertex.type = EMoveType::Extrude;
vertices.emplace_back(vertex);
}
// add the ending vertex of the segment
const Slic3r::Vec2f b = unscale(line.b).cast<float>();
#if VGCODE_ENABLE_COG_AND_TOOL_MARKERS
const libvgcode::PathVertex vertex = { convert(Slic3r::Vec3f(b.x(), b.y(), top_z)), heights[i], widths[i], 0.0f, 0.0f,
0.0f, 0.0f, 0.0f, 0.0f, extrusion_role, EMoveType::Extrude, 0, static_cast<uint32_t>(layer_id),
static_cast<uint8_t>(extruder_id), static_cast<uint8_t>(color_id), { 0.0f, 0.0f } };
#else
const libvgcode::PathVertex vertex = { convert(Slic3r::Vec3f(b.x(), b.y(), top_z)), heights[i], widths[i], 0.0f, 0.0f,
0.0f, 0.0f, 0.0f, extrusion_role, EMoveType::Extrude, 0, static_cast<uint32_t>(layer_id),
static_cast<uint8_t>(extruder_id), static_cast<uint8_t>(color_id), { 0.0f, 0.0f } };
#endif // VGCODE_ENABLE_COG_AND_TOOL_MARKERS
vertices.emplace_back(vertex);
}
}
static void convert_to_vertices(const Slic3r::ExtrusionPath& extrusion_path, float print_z, size_t layer_id, size_t extruder_id, size_t color_id,
EGCodeExtrusionRole extrusion_role, const Slic3r::Point& shift, std::vector<PathVertex>& vertices)
{
Slic3r::Polyline polyline = extrusion_path.polyline;
polyline.remove_duplicate_points();
polyline.translate(shift);
const Slic3r::Lines lines = polyline.lines();
std::vector<float> widths(lines.size(), extrusion_path.width);
std::vector<float> heights(lines.size(), extrusion_path.height);
convert_lines_to_vertices(lines, widths, heights, print_z, layer_id, extruder_id, color_id, extrusion_role, false, vertices);
}
static void convert_to_vertices(const Slic3r::ExtrusionMultiPath& extrusion_multi_path, float print_z, size_t layer_id, size_t extruder_id,
size_t color_id, EGCodeExtrusionRole extrusion_role, const Slic3r::Point& shift, std::vector<PathVertex>& vertices)
{
Slic3r::Lines lines;
std::vector<float> widths;
std::vector<float> heights;
for (const Slic3r::ExtrusionPath& extrusion_path : extrusion_multi_path.paths) {
Slic3r::Polyline polyline = extrusion_path.polyline;
polyline.remove_duplicate_points();
polyline.translate(shift);
const Slic3r::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);
}
convert_lines_to_vertices(lines, widths, heights, print_z, layer_id, extruder_id, color_id, extrusion_role, false, vertices);
}
static void convert_to_vertices(const Slic3r::ExtrusionLoop& extrusion_loop, float print_z, size_t layer_id, size_t extruder_id, size_t color_id,
EGCodeExtrusionRole extrusion_role, const Slic3r::Point& shift, std::vector<PathVertex>& vertices)
{
Slic3r::Lines lines;
std::vector<float> widths;
std::vector<float> heights;
for (const Slic3r::ExtrusionPath& extrusion_path : extrusion_loop.paths) {
Slic3r::Polyline polyline = extrusion_path.polyline;
polyline.remove_duplicate_points();
polyline.translate(shift);
const Slic3r::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);
}
convert_lines_to_vertices(lines, widths, heights, print_z, layer_id, extruder_id, color_id, extrusion_role, true, vertices);
}
// forward declaration
static void convert_to_vertices(const Slic3r::ExtrusionEntityCollection& extrusion_entity_collection, float print_z, size_t layer_id,
size_t extruder_id, size_t color_id, EGCodeExtrusionRole extrusion_role, const Slic3r::Point& shift, std::vector<PathVertex>& vertices);
static void convert_to_vertices(const Slic3r::ExtrusionEntity& extrusion_entity, float print_z, size_t layer_id, size_t extruder_id, size_t color_id,
EGCodeExtrusionRole extrusion_role, const Slic3r::Point& shift, std::vector<PathVertex>& vertices)
{
auto* extrusion_path = dynamic_cast<const Slic3r::ExtrusionPath*>(&extrusion_entity);
if (extrusion_path != nullptr)
convert_to_vertices(*extrusion_path, print_z, layer_id, extruder_id, color_id, extrusion_role, shift, vertices);
else {
auto* extrusion_loop = dynamic_cast<const Slic3r::ExtrusionLoop*>(&extrusion_entity);
if (extrusion_loop != nullptr)
convert_to_vertices(*extrusion_loop, print_z, layer_id, extruder_id, color_id, extrusion_role, shift, vertices);
else {
auto* extrusion_multi_path = dynamic_cast<const Slic3r::ExtrusionMultiPath*>(&extrusion_entity);
if (extrusion_multi_path != nullptr)
convert_to_vertices(*extrusion_multi_path, print_z, layer_id, extruder_id, color_id, extrusion_role, shift, vertices);
else {
auto* extrusion_entity_collection = dynamic_cast<const Slic3r::ExtrusionEntityCollection*>(&extrusion_entity);
if (extrusion_entity_collection != nullptr)
convert_to_vertices(*extrusion_entity_collection, print_z, layer_id, extruder_id, color_id, extrusion_role, shift, vertices);
else
throw Slic3r::RuntimeError("Found unexpected extrusion_entity type");
}
}
}
}
static void convert_to_vertices(const Slic3r::ExtrusionEntityCollection& extrusion_entity_collection, float print_z, size_t layer_id,
size_t extruder_id, size_t color_id, EGCodeExtrusionRole extrusion_role, const Slic3r::Point& shift, std::vector<PathVertex>& vertices)
{
for (const Slic3r::ExtrusionEntity* extrusion_entity : extrusion_entity_collection.entities) {
if (extrusion_entity != nullptr)
convert_to_vertices(*extrusion_entity, print_z, layer_id, extruder_id, color_id, extrusion_role, shift, vertices);
}
}
struct VerticesData
{
std::vector<PathVertex> vertices;
std::vector<float> layers_zs;
};
static void convert_brim_skirt_to_vertices(const Slic3r::Print& print, std::vector<VerticesData>& vertices_data)
{
vertices_data.emplace_back(VerticesData());
VerticesData& data = vertices_data.back();
// number of skirt layers
size_t total_layer_count = 0;
for (const Slic3r::PrintObject* print_object : print.objects()) {
total_layer_count = std::max(total_layer_count, print_object->total_layer_count());
}
size_t skirt_height = print.has_infinite_skirt() ? total_layer_count : std::min<size_t>(print.config().skirt_height.value, total_layer_count);
if (skirt_height == 0 && print.has_brim())
skirt_height = 1;
// Get first skirt_height layers.
//FIXME This code is fishy. It may not work for multiple objects with different layering due to variable layer height feature.
// This is not critical as this is just an initial preview.
const Slic3r::PrintObject* highest_object = *std::max_element(print.objects().begin(), print.objects().end(),
[](auto l, auto r) { return l->layers().size() < r->layers().size(); });
data.layers_zs.reserve(skirt_height * 2);
for (size_t i = 0; i < std::min(skirt_height, highest_object->layers().size()); ++i) {
data.layers_zs.emplace_back(float(highest_object->layers()[i]->print_z));
}
// Only add skirt for the raft layers.
for (size_t i = 0; i < std::min(skirt_height, std::min(highest_object->slicing_parameters().raft_layers(), highest_object->support_layers().size())); ++i) {
data.layers_zs.emplace_back(float(highest_object->support_layers()[i]->print_z));
}
Slic3r::sort_remove_duplicates(data.layers_zs);
skirt_height = std::min(skirt_height, data.layers_zs.size());
data.layers_zs.erase(data.layers_zs.begin() + skirt_height, data.layers_zs.end());
for (size_t i = 0; i < skirt_height; ++i) {
// TODO - brim map?
// if (i == 0)
// convert_to_vertices(print.brim(), data.layers_zs[i], i, 0, 0, EGCodeExtrusionRole::Skirt, Slic3r::Point(0, 0), data.vertices);
convert_to_vertices(print.skirt(), data.layers_zs[i], i, 0, 0, EGCodeExtrusionRole::Skirt, Slic3r::Point(0, 0), data.vertices);
}
}
class WipeTowerHelper
{
public:
WipeTowerHelper(const Slic3r::Print& print) : m_print(print) {
const Slic3r::PrintConfig& config = m_print.config();
const Slic3r::WipeTowerData& wipe_tower_data = m_print.wipe_tower_data();
if (wipe_tower_data.priming && config.single_extruder_multi_material_priming) {
for (size_t i = 0; i < wipe_tower_data.priming.get()->size(); ++i) {
m_priming.emplace_back(wipe_tower_data.priming.get()->at(i));
}
}
if (wipe_tower_data.final_purge)
m_final.emplace_back(*wipe_tower_data.final_purge.get());
m_angle = print.model().wipe_tower.rotation / 180.0f * PI;
// ORCA/BBS: plate index
m_position = print.model().wipe_tower.positions[print.get_plate_index()].cast<float>();
m_layers_count = wipe_tower_data.tool_changes.size() + (m_priming.empty() ? 0 : 1);
}
const std::vector<Slic3r::WipeTower::ToolChangeResult>& tool_change(size_t idx) {
const auto& tool_changes = m_print.wipe_tower_data().tool_changes;
return m_priming.empty() ?
((idx == tool_changes.size()) ? m_final : tool_changes[idx]) :
((idx == 0) ? m_priming : (idx == tool_changes.size() + 1) ? m_final : tool_changes[idx - 1]);
}
float get_angle() const { return m_angle; }
const Slic3r::Vec2f& get_position() const { return m_position; }
size_t get_layers_count() { return m_layers_count; }
private:
const Slic3r::Print& m_print;
std::vector<Slic3r::WipeTower::ToolChangeResult> m_priming;
std::vector<Slic3r::WipeTower::ToolChangeResult> m_final;
Slic3r::Vec2f m_position{ Slic3r::Vec2f::Zero() };
float m_angle{ 0.0f };
size_t m_layers_count{ 0 };
};
static void convert_wipe_tower_to_vertices(const Slic3r::Print& print, const std::vector<std::string>& str_tool_colors,
std::vector<VerticesData>& vertices_data)
{
vertices_data.emplace_back(VerticesData());
VerticesData& data = vertices_data.back();
WipeTowerHelper wipe_tower_helper(print);
const float angle = wipe_tower_helper.get_angle();
const Slic3r::Vec2f& position = wipe_tower_helper.get_position();
for (size_t item = 0; item < wipe_tower_helper.get_layers_count(); ++item) {
const std::vector<Slic3r::WipeTower::ToolChangeResult>& layer = wipe_tower_helper.tool_change(item);
for (const Slic3r::WipeTower::ToolChangeResult& extrusions : layer) {
data.layers_zs.emplace_back(extrusions.print_z);
for (size_t i = 1; i < extrusions.extrusions.size(); /*no increment*/) {
const Slic3r::WipeTower::Extrusion& e = extrusions.extrusions[i];
if (e.width == 0.0f) {
++i;
continue;
}
size_t j = i + 1;
if (str_tool_colors.empty())
for (; j < extrusions.extrusions.size() && extrusions.extrusions[j].width > 0.0f; ++j);
else
for (; j < extrusions.extrusions.size() && extrusions.extrusions[j].tool == e.tool && extrusions.extrusions[j].width > 0.0f; ++j);
const size_t n_lines = j - i;
Slic3r::Lines lines;
std::vector<float> widths;
std::vector<float> heights;
lines.reserve(n_lines);
widths.reserve(n_lines);
heights.assign(n_lines, extrusions.layer_height);
Slic3r::WipeTower::Extrusion e_prev = extrusions.extrusions[i - 1];
if (!extrusions.priming) { // wipe tower extrusions describe the wipe tower at the origin with no rotation
e_prev.pos = Eigen::Rotation2Df(angle) * e_prev.pos;
e_prev.pos += position;
}
for (; i < j; ++i) {
Slic3r::WipeTower::Extrusion ee = extrusions.extrusions[i];
assert(ee.width > 0.0f);
if (!extrusions.priming) {
ee.pos = Eigen::Rotation2Df(angle) * ee.pos;
ee.pos += position;
}
lines.emplace_back(Slic3r::Point::new_scale(e_prev.pos.x(), e_prev.pos.y()), Slic3r::Point::new_scale(ee.pos.x(), ee.pos.y()));
widths.emplace_back(ee.width);
e_prev = ee;
}
convert_lines_to_vertices(lines, widths, heights, extrusions.print_z, item, static_cast<size_t>(e.tool), 0,
EGCodeExtrusionRole::WipeTower, lines.front().a == lines.back().b, data.vertices);
}
}
}
Slic3r::sort_remove_duplicates(data.layers_zs);
}
class ObjectHelper
{
public:
ObjectHelper(const std::vector<Slic3r::CustomGCode::Item>& color_print_values, size_t tool_colors_count, size_t color_print_colors_count, size_t extruders_count)
: m_color_print_values(color_print_values)
, m_tool_colors_count(tool_colors_count)
, m_color_print_colors_count(color_print_colors_count)
, m_extruders_count(extruders_count) {
}
uint8_t color_id(float print_z, size_t extruder_id) const {
if (!m_color_print_values.empty())
return color_print_color_id(double(print_z), extruder_id);
else {
if (m_tool_colors_count > 0)
return std::min<uint8_t>(m_tool_colors_count - 1, static_cast<uint8_t>(extruder_id));
else
return 0;
}
}
private:
const std::vector<Slic3r::CustomGCode::Item>& m_color_print_values;
size_t m_tool_colors_count{ 0 };
size_t m_color_print_colors_count{ 0 };
size_t m_extruders_count{ 0 };
uint8_t color_print_color_id(double print_z, size_t extruder_id) const {
auto it = std::find_if(m_color_print_values.begin(), m_color_print_values.end(),
[print_z](const Slic3r::CustomGCode::Item& code) {
return std::fabs(code.print_z - print_z) < EPSILON;
});
if (it != m_color_print_values.end()) {
Slic3r::CustomGCode::Type type = it->type;
// pause print or custom Gcode
if (type == Slic3r::CustomGCode::PausePrint || (type != Slic3r::CustomGCode::ColorChange && type != Slic3r::CustomGCode::Template))
return static_cast<uint8_t>(m_color_print_colors_count - 1); // last color item is a gray color for pause print or custom G-code
switch (it->type) {
// change color for current extruder
case Slic3r::CustomGCode::ColorChange: {
const int c = color_change_color_id(it, extruder_id);
if (c >= 0)
return static_cast<uint8_t>(c);
break;
}
// change tool (extruder)
case Slic3r::CustomGCode::ToolChange: { return tool_change_color_id(it, extruder_id); }
default: { break; }
}
}
const Slic3r::CustomGCode::Item value{ print_z + EPSILON, Slic3r::CustomGCode::Custom, 0, "" };
it = std::lower_bound(m_color_print_values.begin(), m_color_print_values.end(), value);
while (it != m_color_print_values.begin()) {
--it;
switch (it->type) {
// change color for current extruder
case Slic3r::CustomGCode::ColorChange: {
const int c = color_change_color_id(it, extruder_id);
if (c >= 0)
return static_cast<uint8_t>(c);
break;
}
// change tool (extruder)
case Slic3r::CustomGCode::ToolChange: { return tool_change_color_id(it, extruder_id); }
default: { break; }
}
}
return std::min<uint8_t>(m_extruders_count - 1, static_cast<uint8_t>(extruder_id));
}
int color_change_color_id(std::vector<Slic3r::CustomGCode::Item>::const_iterator it, size_t extruder_id) const {
if (m_extruders_count == 1)
return m600_color_id(it);
auto it_n = it;
bool is_tool_change = false;
while (it_n != m_color_print_values.begin()) {
--it_n;
if (it_n->type == Slic3r::CustomGCode::ToolChange) {
is_tool_change = true;
if (it_n->extruder == it->extruder || (it_n->extruder == 0 && it->extruder == static_cast<int>(extruder_id + 1)))
return m600_color_id(it);
break;
}
}
if (!is_tool_change && it->extruder == static_cast<int>(extruder_id + 1))
return m600_color_id(it);
return -1;
}
uint8_t tool_change_color_id(std::vector<Slic3r::CustomGCode::Item>::const_iterator it, size_t extruder_id) const {
const int current_extruder = it->extruder == 0 ? static_cast<int>(extruder_id + 1) : it->extruder;
if (m_tool_colors_count == m_extruders_count + 1) // there is no one "M600"
return std::min<uint8_t>(m_extruders_count - 1, std::max<uint8_t>(current_extruder - 1, 0));
auto it_n = it;
while (it_n != m_color_print_values.begin()) {
--it_n;
if (it_n->type == Slic3r::CustomGCode::ColorChange && it_n->extruder == current_extruder)
return m600_color_id(it_n);
}
return std::min<uint8_t>(m_extruders_count - 1, std::max<uint8_t>(current_extruder - 1, 0));
}
int m600_color_id(std::vector<Slic3r::CustomGCode::Item>::const_iterator it) const {
int shift = 0;
while (it != m_color_print_values.begin()) {
--it;
if (it->type == Slic3r::CustomGCode::ColorChange)
++shift;
}
return static_cast<int>(m_extruders_count) + shift;
}
};
static void convert_object_to_vertices(const Slic3r::PrintObject& object, const std::vector<std::string>& str_tool_colors,
const std::vector<std::string>& str_color_print_colors, const std::vector<Slic3r::CustomGCode::Item>& color_print_values,
size_t extruders_count, VerticesData& data)
{
const bool has_perimeters = object.is_step_done(Slic3r::posPerimeters);
const bool has_infill = object.is_step_done(Slic3r::posInfill);
const bool has_support = object.is_step_done(Slic3r::posSupportMaterial);
// order layers by print_z
std::vector<const Slic3r::Layer*> layers;
if (has_perimeters || has_infill) {
layers.reserve(layers.size() + object.layers().size());
std::copy(object.layers().begin(), object.layers().end(), std::back_inserter(layers));
}
if (has_support) {
layers.reserve(layers.size() + object.support_layers().size());
std::copy(object.support_layers().begin(), object.support_layers().end(), std::back_inserter(layers));
}
std::sort(layers.begin(), layers.end(), [](const Slic3r::Layer* l1, const Slic3r::Layer* l2) { return l1->print_z < l2->print_z; });
ObjectHelper object_helper(color_print_values, str_tool_colors.size(), str_color_print_colors.size(), extruders_count);
data.layers_zs.reserve(layers.size());
for (const Slic3r::Layer* layer : layers) {
data.layers_zs.emplace_back(static_cast<float>(layer->print_z));
}
Slic3r::sort_remove_duplicates(data.layers_zs);
for (const Slic3r::Layer* layer : layers) {
const size_t old_vertices_count = data.vertices.size();
const float layer_z = static_cast<float>(layer->print_z);
const auto it = std::find(data.layers_zs.begin(), data.layers_zs.end(), layer_z);
assert(it != data.layers_zs.end());
const size_t layer_id = (it != data.layers_zs.end()) ? std::distance(data.layers_zs.begin(), it) : 0;
for (const Slic3r::PrintInstance& instance : object.instances()) {
const Slic3r::Point& copy = instance.shift;
for (const Slic3r::LayerRegion* layerm : layer->regions()) {
if (layerm->slices.empty())
continue;
const Slic3r::PrintRegionConfig& cfg = layerm->region().config();
if (has_perimeters) {
const size_t extruder_id = static_cast<size_t>(std::max(cfg.wall_filament.value - 1, 0));
convert_to_vertices(layerm->perimeters, layer_z, layer_id, extruder_id,
object_helper.color_id(layer_z, extruder_id), EGCodeExtrusionRole::ExternalPerimeter,
copy, data.vertices);
}
if (has_infill) {
for (const Slic3r::ExtrusionEntity* ee : layerm->fills) {
// fill represents infill extrusions of a single island.
const auto& fill = *dynamic_cast<const Slic3r::ExtrusionEntityCollection*>(ee);
if (!fill.entities.empty()) {
const bool is_solid_infill = Slic3r::is_solid_infill(fill.entities.front()->role());
const size_t extruder_id = is_solid_infill ?
static_cast<size_t>(std::max(cfg.solid_infill_filament.value - 1, 0)) :
static_cast<size_t>(std::max(cfg.sparse_infill_filament.value - 1, 0));
convert_to_vertices(fill, layer_z, layer_id, extruder_id,
object_helper.color_id(layer_z, extruder_id),
is_solid_infill ? EGCodeExtrusionRole::SolidInfill : EGCodeExtrusionRole::InternalInfill,
copy, data.vertices);
}
}
}
}
if (has_support) {
const Slic3r::SupportLayer* support_layer = dynamic_cast<const Slic3r::SupportLayer*>(layer);
if (support_layer == nullptr)
continue;
const Slic3r::PrintObjectConfig& cfg = support_layer->object()->config();
for (const Slic3r::ExtrusionEntity* extrusion_entity : support_layer->support_fills.entities) {
const bool is_support_material = extrusion_entity->role() == Slic3r::ExtrusionRole::erSupportMaterial;
const size_t extruder_id = is_support_material ?
static_cast<size_t>(std::max(cfg.support_filament.value - 1, 0)) :
static_cast<size_t>(std::max(cfg.support_interface_filament.value - 1, 0));
convert_to_vertices(*extrusion_entity, layer_z, layer_id,
extruder_id, object_helper.color_id(layer_z, extruder_id),
is_support_material ? EGCodeExtrusionRole::SupportMaterial : EGCodeExtrusionRole::SupportMaterialInterface,
copy, data.vertices);
}
}
}
// filter out empty layers
const size_t new_vertices_count = data.vertices.size();
if (new_vertices_count == old_vertices_count)
data.layers_zs.erase(data.layers_zs.begin() + layer_id);
}
}
static void convert_objects_to_vertices(const Slic3r::ConstPrintObjectPtrsAdaptor& objects, const std::vector<std::string>& str_tool_colors,
const std::vector<std::string>& str_color_print_colors, const std::vector<Slic3r::CustomGCode::Item>& color_print_values, size_t extruders_count,
std::vector<VerticesData>& data)
{
// extract vertices and layers zs object by object
data.reserve(data.size() + objects.size());
for (size_t i = 0; i < objects.size(); ++i) {
data.emplace_back(VerticesData());
convert_object_to_vertices(*objects[i], str_tool_colors, str_color_print_colors, color_print_values, extruders_count, data.back());
}
}
// mapping from Slic3r::Print to libvgcode::GCodeInputData
GCodeInputData convert(const Slic3r::Print& print, const std::vector<std::string>& str_tool_colors,
const std::vector<std::string>& str_color_print_colors, const std::vector<Slic3r::CustomGCode::Item>& color_print_values,
size_t extruders_count)
{
GCodeInputData ret;
std::vector<VerticesData> data;
if (print.is_step_done(Slic3r::psSkirtBrim) && (print.has_skirt() || print.has_brim()))
// extract vertices and layers zs from skirt/brim
convert_brim_skirt_to_vertices(print, data);
if (!print.wipe_tower_data().tool_changes.empty() && print.is_step_done(Slic3r::psWipeTower))
// extract vertices and layers zs from wipe tower
convert_wipe_tower_to_vertices(print, str_tool_colors, data);
// extract vertices and layers zs from objects
convert_objects_to_vertices(print.objects(), str_tool_colors, str_color_print_colors, color_print_values, extruders_count, data);
// collect layers zs
std::vector<float> layers;
for (const VerticesData& d : data) {
layers.reserve(layers.size() + d.layers_zs.size());
std::copy(d.layers_zs.begin(), d.layers_zs.end(), std::back_inserter(layers));
}
Slic3r::sort_remove_duplicates(layers);
// Now we need to copy the vertices into ret.vertices to be consumed by the preliminary G-code preview.
// We need to collect vertices in the first layer for all objects, push them into the output vector
// and then do the same for all the layers. The algorithm relies on the fact that the vertices from
// lower layers are always placed after vertices from the higher layer.
std::vector<size_t> vert_indices(data.size(), 0);
for (size_t layer_id = 0; layer_id < layers.size(); ++layer_id) {
const float layer_z = layers[layer_id];
for (size_t obj_idx = 0; obj_idx < data.size(); ++obj_idx) {
// d contains PathVertices for one object. Let's stuff everything below this layer_z into ret.vertices.
const size_t start_idx = vert_indices[obj_idx];
size_t idx = start_idx;
while (idx < data[obj_idx].vertices.size() && data[obj_idx].vertices[idx].position[2] <= layer_z)
++idx;
// We have found a vertex above current layer_z. Let's copy the vertices into the output
// and remember where to start when we process another layer.
ret.vertices.insert(ret.vertices.end(),
data[obj_idx].vertices.begin() + start_idx,
data[obj_idx].vertices.begin() + idx);
vert_indices[obj_idx] = idx;
}
}
// collect tool colors
ret.tools_colors.reserve(str_tool_colors.size());
for (const std::string& color : str_tool_colors) {
ret.tools_colors.emplace_back(convert(color));
}
// collect color print colors
const std::vector<std::string>& str_colors = str_color_print_colors.empty() ? str_tool_colors : str_color_print_colors;
ret.color_print_colors.reserve(str_colors.size());
for (const std::string& color : str_colors) {
ret.color_print_colors.emplace_back(convert(color));
}
return ret;
}
} // namespace libvgcode

View File

@@ -0,0 +1,83 @@
///|/ Copyright (c) Prusa Research 2020 - 2023 Enrico Turri @enricoturri1966
///|/
///|/ PrusaSlicer is released under the terms of the AGPLv3 or higher
///|/
#ifndef slic3r_LibVGCodeWrapper_hpp_
#define slic3r_LibVGCodeWrapper_hpp_
#include <../../src/libvgcode/include/Viewer.hpp>
#include <../../src/libvgcode/include/PathVertex.hpp>
#include <../../src/libvgcode/include/GCodeInputData.hpp>
#include <../../src/libvgcode/include/ColorRange.hpp>
#include <stddef.h>
#include <string>
#include <vector>
#include <cstddef>
#include "../../src/libvgcode/include/Types.hpp"
#include "libslic3r/Color.hpp"
#include "libslic3r/GCode/GCodeProcessor.hpp"
#include "slic3r/GUI/GUI_Preview.hpp"
#include "libslic3r/ExtrusionEntity.hpp"
#include "libslic3r/Point.hpp"
namespace Slic3r {
class Print;
namespace CustomGCode {
struct Item;
} // namespace CustomGCode
} // namespace Slic3r
namespace libvgcode {
class Viewer;
// mapping from Slic3r::Vec3f to libvgcode::Vec3
extern Vec3 convert(const Slic3r::Vec3f& v);
// mapping from libvgcode::Vec3 to Slic3r::Vec3f
extern Slic3r::Vec3f convert(const Vec3& v);
// mapping from Slic3r::Matrix4f to libvgcode::Mat4x4
extern Mat4x4 convert(const Slic3r::Matrix4f& m);
// mapping from libvgcode::Color to Slic3r::ColorRGBA
extern Slic3r::ColorRGBA convert(const Color& c);
// mapping from Slic3r::ColorRGBA to libvgcode::Color
extern Color convert(const Slic3r::ColorRGBA& c);
// mapping from encoded color to libvgcode::Color
extern Color convert(const std::string& color_str);
// mapping from libvgcode::EGCodeExtrusionRole to Slic3r::ExtrusionRole
extern Slic3r::ExtrusionRole convert(EGCodeExtrusionRole role);
// mapping from Slic3r::ExtrusionRole to libvgcode::EGCodeExtrusionRole
extern EGCodeExtrusionRole convert(Slic3r::ExtrusionRole role);
// mapping from Slic3r::EMoveType to libvgcode::EMoveType
extern EMoveType convert(Slic3r::EMoveType type);
// mapping from Slic3r::GUI::Preview::OptionType to libvgcode::EOptionType
// extern EOptionType convert(const Slic3r::GUI::Preview::OptionType& type);
// mapping from Slic3r::PrintEstimatedStatistics::ETimeMode to libvgcode::ETimeMode
extern ETimeMode convert(const Slic3r::PrintEstimatedStatistics::ETimeMode& mode);
// mapping from libvgcode::ETimeMode to Slic3r::PrintEstimatedStatistics::ETimeMode
extern Slic3r::PrintEstimatedStatistics::ETimeMode convert(const ETimeMode& mode);
// mapping from Slic3r::GCodeProcessorResult to libvgcode::GCodeInputData
extern GCodeInputData convert(const Slic3r::GCodeProcessorResult& result, const std::vector<std::string>& str_tool_colors,
const std::vector<std::string>& str_color_print_colors, const Viewer& viewer);
// mapping from Slic3r::Print to libvgcode::GCodeInputData
extern GCodeInputData convert(const Slic3r::Print& print, const std::vector<std::string>& str_tool_colors,
const std::vector<std::string>& str_color_print_colors, const std::vector<Slic3r::CustomGCode::Item>& color_print_values,
size_t extruders_count);
} // namespace libvgcode
#endif // slic3r_LibVGCodeWrapper_hpp_

View File

@@ -2870,7 +2870,7 @@ void MainFrame::init_menubar_as_editor()
#else
if (dlg.seq_top_layer_only_changed())
#endif
plater()->refresh_print();
plater()->reload_print();
},
"", nullptr, []() { return true; }, this, 1);
//parent_menu->Insert(1, preference_item);

Some files were not shown because too many files have changed in this diff Show More