Port libvgcode/improved G-code viewer from PrusaSlicer 2.8.0 (#10735)
Some checks are pending
Build all / Build Linux (push) Waiting to run
Build all / Build Non-Linux (push) Waiting to run
Build all / Unit Tests (push) Blocked by required conditions
Build all / Flatpak (push) Waiting to run

# Description

Fixes #6813 
Fixes #7782 
Fixes #6367

This is a port of libvgcode, OpenGL Core Profile (libvgcode requires OpenGL 3.2+), and probably other stuff I forgot from PrusaSlicer. libvgcode is also known as "Improved G-code Viewer" which was introduced in [PrusaSlicer 2.8.0](https://github.com/prusa3d/PrusaSlicer/releases/tag/version_2.8.0-alpha5). It significantly improves performance of the G-code preview and allows displaying the actual speed and volumetric flow rate.

## TODO

- [x] Make the sliders work properly again
- [x] Make view type selection work
- [x] Fix toggling of feature type visibility
- [x] Expose actual speed/actual flow view types
- [x] Fix display of G2/G3 arcs
- [x] Wire up actual speed graph widgets
- [x] Fix painter gizmos
- [x] Fix crash when selecting filament view type on Windows
- [ ] Figure out display color management (#10827)
- [x] Fix incorrect rendering of small area flow compensation (or any extrusions with varying flow)
- [ ] Localization
- [ ] Testing
- [ ] Code cleanup, performance optimization

## Removed functionality

Some functionality is not supported by libvgcode:

- Toggling visibility of tools
- Toggling visibility of colors in color print view
- Support for systems with OpenGL <3.2
- Bambu's implementation of G2/G3 arcs was replaced with PrusaSlicer's implementation

# Screenshots/Recordings/Graphs

https://github.com/user-attachments/assets/c1413a82-3058-4541-b96c-3d5f7cdef174

<details>
<summary>Outdated Stuff</summary>

https://github.com/user-attachments/assets/ca172ef4-0828-4d21-8768-b08a4132c9ab

<img width="1611" height="1145" alt="image" src="https://github.com/user-attachments/assets/5e0d04ff-8046-4636-a08a-cdedc60303bc" />
</details>

## Tests

- [x] Normally sliced G-code
- [ ] G-code viewer mode
- [x] Arc fitting enabled
- [x] Spiral Z-hops
- [x] Multi-extruder/multi-color
- [x] Vase mode
- [x] Skirt/brim
- [x] Supports
- [ ] Support transition (whatever this is)
- [x] Painter gizmos
- [x] Measurement gizmo
- [x] Move/rotate/scale gizmos
- [x] H2D/H2S support (oh no)
- [ ] Windows
- [x] macOS
- [ ] Linux
This commit is contained in:
SoftFever 2026-01-06 23:15:16 +08:00 committed by GitHub
commit ba5f0e707d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
117 changed files with 19332 additions and 6172 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="#009688"
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="#009688"
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

@ -0,0 +1,46 @@
#version 140
const vec3 ZERO = vec3(0.0, 0.0, 0.0);
const vec3 WHITE = vec3(1.0, 1.0, 1.0);
struct PrintVolumeDetection
{
// 0 = rectangle, 1 = circle, 2 = custom, 3 = invalid
int type;
// type = 0 (rectangle):
// x = min.x, y = min.y, z = max.x, w = max.y
// type = 1 (circle):
// x = center.x, y = center.y, z = radius
vec4 xy_data;
// x = min z, y = max z
vec2 z_data;
};
uniform vec4 uniform_color;
uniform float emission_factor;
uniform PrintVolumeDetection print_volume;
// x = diffuse, y = specular;
in vec2 intensity;
in vec4 world_pos;
out vec4 out_color;
void main()
{
vec3 color = uniform_color.rgb;
float alpha = uniform_color.a;
// if the fragment is outside the print volume -> use darker color
vec3 pv_check_min = ZERO;
vec3 pv_check_max = ZERO;
if (print_volume.type == 0) {// rectangle
pv_check_min = world_pos.xyz - vec3(print_volume.xy_data.x, print_volume.xy_data.y, print_volume.z_data.x);
pv_check_max = world_pos.xyz - vec3(print_volume.xy_data.z, print_volume.xy_data.w, print_volume.z_data.y);
}
else if (print_volume.type == 1) {// circle
float delta_radius = print_volume.xy_data.z - distance(world_pos.xy, print_volume.xy_data.xy);
pv_check_min = vec3(delta_radius, 0.0, world_pos.z - print_volume.z_data.x);
pv_check_max = vec3(0.0, 0.0, world_pos.z - print_volume.z_data.y);
}
color = (any(lessThan(pv_check_min, ZERO)) || any(greaterThan(pv_check_max, ZERO))) ? mix(color, WHITE, 0.3333) : color;
//out_color = vec4(vec3(intensity.y) + color * intensity.x, alpha);
out_color = vec4(vec3(intensity.y) + color * (intensity.x + emission_factor), alpha);
}

View file

@ -0,0 +1,47 @@
#version 140
#define INTENSITY_CORRECTION 0.6
// normalized values for (-0.6/1.31, 0.6/1.31, 1./1.31)
const vec3 LIGHT_TOP_DIR = vec3(-0.4574957, 0.4574957, 0.7624929);
#define LIGHT_TOP_DIFFUSE (0.8 * INTENSITY_CORRECTION)
#define LIGHT_TOP_SPECULAR (0.125 * INTENSITY_CORRECTION)
#define LIGHT_TOP_SHININESS 20.0
// normalized values for (1./1.43, 0.2/1.43, 1./1.43)
const vec3 LIGHT_FRONT_DIR = vec3(0.6985074, 0.1397015, 0.6985074);
#define LIGHT_FRONT_DIFFUSE (0.3 * INTENSITY_CORRECTION)
#define INTENSITY_AMBIENT 0.3
uniform mat4 view_model_matrix;
uniform mat4 projection_matrix;
uniform mat3 view_normal_matrix;
uniform mat4 volume_world_matrix;
in vec3 v_position;
in vec3 v_normal;
// x = tainted, y = specular;
out vec2 intensity;
out vec4 world_pos;
void main()
{
// First transform the normal into camera space and normalize the result.
vec3 normal = normalize(view_normal_matrix * v_normal);
// Compute the cos of the angle between the normal and lights direction. The light is directional so the direction is constant for every vertex.
// Since these two are normalized the cosine is the dot product. We also need to clamp the result to the [0,1] range.
float NdotL = max(dot(normal, LIGHT_TOP_DIR), 0.0);
intensity.x = INTENSITY_AMBIENT + NdotL * LIGHT_TOP_DIFFUSE;
world_pos = volume_world_matrix * vec4(v_position, 1.0);
vec4 position = view_model_matrix * vec4(v_position, 1.0);
intensity.y = LIGHT_TOP_SPECULAR * pow(max(dot(-normalize(position.xyz), reflect(-LIGHT_TOP_DIR, normal)), 0.0), LIGHT_TOP_SHININESS);
// Perform the same lighting calculation for the 2nd light source (no specular applied).
NdotL = max(dot(normal, LIGHT_FRONT_DIR), 0.0);
intensity.x += NdotL * LIGHT_FRONT_DIFFUSE;
gl_Position = projection_matrix * position;
}

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

@ -15,6 +15,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

@ -190,6 +190,9 @@ void AppConfig::set_defaults()
#endif // _WIN32
}
if (get("seq_top_layer_only").empty())
set("seq_top_layer_only", "1");
if (get("use_perspective_camera").empty())
set_bool("use_perspective_camera", true);

View file

@ -565,40 +565,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

@ -118,8 +118,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;
int get_extruder_area_count() const { return m_extruder_volumes.size(); }
const BuildExtruderVolume& get_extruder_area_volume(int index) const;

View file

@ -251,6 +251,8 @@ set(lisbslic3r_sources
GCode/WipeTower.hpp
GCodeWriter.cpp
GCodeWriter.hpp
Geometry/ArcWelder.hpp
Geometry/ArcWelder.cpp
Geometry/Bicubic.hpp
Geometry/Circle.cpp
Geometry/Circle.hpp

View file

@ -2006,6 +2006,7 @@ namespace DoExport {
silent_time_estimator_enabled = (config.gcode_flavor == gcfMarlinLegacy || config.gcode_flavor == gcfMarlinFirmware)
&& config.silent_mode;
processor.reset();
processor.initialize_result_moves();
processor.apply_config(config);
processor.enable_stealth_time_estimator(silent_time_estimator_enabled);
}
@ -2241,9 +2242,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();
@ -6335,14 +6333,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

@ -572,9 +572,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)

File diff suppressed because it is too large Load diff

View file

@ -57,21 +57,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();
}
};
@ -125,7 +116,7 @@ class Print;
struct GCodeCheckResult
{
int error_code = 0; // 0 means succeed, 0b 0001 multi extruder printable area error, 0b 0010 multi extruder printable height error,
int error_code = 0; // 0 means succeed, 0b 0001 multi extruder printable area error, 0b 0010 multi extruder printable height error,
// 0b 0100 plate printable area error, 0b 1000 plate printable height error, 0b 10000 wrapping detection area error
std::map<int, std::vector<std::pair<int, int>>> print_area_error_infos; // printable_area extruder_id to <filament_id - object_label_id> which cannot printed in this extruder
std::map<int, std::vector<std::pair<int, int>>> print_height_error_infos; // printable_height extruder_id to <filament_id - object_label_id> which cannot printed in this extruder
@ -186,31 +177,23 @@ 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
float layer_duration{ 0.0f }; // s (layer id before finalize)
std::array<float, static_cast<size_t>(PrintEstimatedStatistics::ETimeMode::Count)> time{ 0.0f, 0.0f }; // s
unsigned int layer_id{ 0 };
bool internal_only{ false };
//BBS: arc move related data
EMovePathType move_path_type{ EMovePathType::Noop_move };
Vec3f arc_center_position{ Vec3f::Zero() }; // mm
std::vector<Vec3f> interpolation_points; // interpolation points of arc for drawing
//BBS
int object_label_id{-1};
float print_z{0.0f};
float volumetric_rate() const { return 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();
}
bool is_arc_move() const {
return move_path_type == EMovePathType::Arc_move_ccw || move_path_type == EMovePathType::Arc_move_cw;
}
float actual_volumetric_rate() const { return actual_feedrate * mm3_per_mm; }
};
struct SliceWarning {
@ -240,6 +223,7 @@ class Print;
int timelapse_warning_code {0};
bool support_traditional_timelapse{true};
float printable_height;
float z_offset;
SettingsIds settings_ids;
size_t filaments_count;
bool backtrace_enabled;
@ -253,7 +237,7 @@ class Print;
std::vector<int> limit_filament_maps;
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;
@ -264,9 +248,6 @@ class Print;
std::map<std::pair<int,int>, int > filament_change_count_map;
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
@ -293,7 +274,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;
gcode_check_result = other.gcode_check_result;
@ -378,10 +359,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>;
@ -430,9 +407,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
@ -446,6 +426,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 };
@ -460,7 +441,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);
}
};
@ -477,7 +461,7 @@ class Print;
AxisCoords axis_feedrate; // mm/s
AxisCoords abs_axis_feedrate; // mm/s
//BBS: unit vector of enter speed and exit speed in x-y-z space.
//BBS: unit vector of enter speed and exit speed in x-y-z space.
//For line move, there are same. For arc move, there are different.
Vec3f enter_direction;
Vec3f exit_direction;
@ -501,6 +485,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.
@ -512,7 +510,9 @@ class Print;
// hard limit for the travel acceleration, to which the firmware will clamp.
float max_travel_acceleration; // mm/s^2
float extrude_factor_override_percentage;
float time; // s
// We accumulate total print time in doubles to reduce the loss of precision
// while adding big floating numbers with small float numbers.
double time; // s
struct StopTime
{
unsigned int g1_line_id;
@ -526,17 +526,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 UsedFilaments // filaments per ColorChange
@ -765,10 +762,6 @@ class Print;
//BBS: x, y offset for gcode generated
double m_x_offset{ 0 };
double m_y_offset{ 0 };
//BBS: arc move related data
EMovePathType m_move_path_type{ EMovePathType::Noop_move };
Vec3f m_arc_center{ Vec3f::Zero() }; // mm
std::vector<Vec3f> m_interpolation_points;
unsigned int m_line_id;
unsigned int m_last_line_id;
@ -807,9 +800,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
{
@ -836,12 +826,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();
void init_filament_maps_and_nozzle_type_when_import_only_gcode();
@ -876,6 +860,11 @@ class Print;
// Streaming interface, for processing G-codes just generated by PrusaSlicer in a pipelined fashion.
void initialize(const std::string& filename);
void initialize_result_moves() {
// 1st move must be a dummy move
assert(m_result.moves.empty());
m_result.moves.emplace_back(GCodeProcessorResult::MoveVertex());
}
void process_buffer(const std::string& buffer);
void finalize(bool post_process);
@ -884,9 +873,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; }
@ -917,7 +904,16 @@ class Print;
// Move
void process_G0(const GCodeReader::GCodeLine& line);
void process_G1(const GCodeReader::GCodeLine& line, const std::optional<unsigned int>& remaining_internal_g1_lines = std::nullopt);
void process_G2_G3(const GCodeReader::GCodeLine& line);
enum class G1DiscretizationOrigin {
G1,
G2G3,
};
void process_G1(const std::array<std::optional<double>, 4>& axes = { std::nullopt, std::nullopt, std::nullopt, std::nullopt },
const std::optional<double>& feedrate = std::nullopt, G1DiscretizationOrigin origin = G1DiscretizationOrigin::G1,
const std::optional<unsigned int>& remaining_internal_g1_lines = std::nullopt);
// Arc Move
void process_G2_G3(const GCodeReader::GCodeLine& line, bool clockwise);
void process_VG1(const GCodeReader::GCodeLine& line);
@ -1054,7 +1050,7 @@ class Print;
void run_post_process();
//BBS: different path_type is only used for arc move
void store_move_vertex(EMoveType type, EMovePathType path_type = EMovePathType::Noop_move);
void store_move_vertex(EMoveType type, EMovePathType path_type = EMovePathType::Noop_move, bool internal_only = false);
void set_extrusion_role(ExtrusionRole role);
@ -1077,10 +1073,15 @@ 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);
void update_estimated_times_stats();
double extract_absolute_position_on_axis(Axis axis, const GCodeReader::GCodeLine& line, double area_filament_cross_section);
//BBS:
void update_slice_warnings();

View file

@ -528,12 +528,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;
@ -553,18 +550,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;
@ -602,13 +587,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)
{
@ -647,12 +627,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)
@ -1212,9 +1189,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

@ -222,6 +222,28 @@ bool GCodeReader::parse_file_raw(const std::string &filename, raw_line_callback_
[](size_t){});
}
const char* GCodeReader::axis_pos(const char *raw_str, char axis)
{
const char *c = raw_str;
// Skip the whitespaces.
c = skip_whitespaces(c);
// Skip the command.
c = skip_word(c);
// Up to the end of line or comment.
while (! is_end_of_gcode_line(*c)) {
// Skip whitespaces.
c = skip_whitespaces(c);
if (is_end_of_gcode_line(*c))
break;
// Check the name of the axis.
if (*c == axis)
return c;
// Skip the rest of the word.
c = skip_word(c);
}
return nullptr;
}
bool GCodeReader::GCodeLine::has(char axis) const
{
const char *c = m_raw.c_str();
@ -244,6 +266,29 @@ bool GCodeReader::GCodeLine::has(char axis) const
return false;
}
std::string_view GCodeReader::GCodeLine::axis_pos(char axis) const
{
const std::string &s = this->raw();
const char *c = GCodeReader::axis_pos(this->raw().c_str(), axis);
return c ? std::string_view{ c, s.size() - (c - s.data()) } : std::string_view();
}
bool GCodeReader::GCodeLine::has_value(std::string_view axis_pos, float &value)
{
if (const char *c = axis_pos.data(); c) {
// Try to parse the numeric value.
double v = 0.;
const char *end = axis_pos.data() + axis_pos.size();
auto [pend, ec] = fast_float::from_chars(++ c, end, v);
if (pend != c && is_end_of_word(*pend)) {
// The axis value has been parsed correctly.
value = float(v);
return true;
}
}
return false;
}
bool GCodeReader::GCodeLine::has_value(char axis, float &value) const
{
assert(is_decimal_separator_point());

View file

@ -26,11 +26,15 @@ public:
const std::string_view comment() const
{ size_t pos = m_raw.find(';'); return (pos == std::string::npos) ? std::string_view() : std::string_view(m_raw).substr(pos + 1); }
// Return position in this->raw() string starting with the "axis" character.
std::string_view axis_pos(char axis) const;
void clear() { m_raw.clear(); }
bool has(Axis axis) const { return (m_mask & (1 << int(axis))) != 0; }
float value(Axis axis) const { return m_axis[axis]; }
bool has(char axis) const;
bool has_value(char axis, float &value) const;
// Parse value of an axis from raw string starting at axis_pos.
static bool has_value(std::string_view axis_pos, float &value);
float new_X(const GCodeReader &reader) const { return this->has(X) ? this->x() : reader.x(); }
float new_Y(const GCodeReader &reader) const { return this->has(Y) ? this->y() : reader.y(); }
float new_Z(const GCodeReader &reader) const { return this->has(Z) ? this->z() : reader.z(); }
@ -190,6 +194,7 @@ private:
; // silence -Wempty-body
return c;
}
static const char* axis_pos(const char *raw_str, char axis);
GCodeConfig m_config;
float m_position[NUM_AXES];

View file

@ -0,0 +1,32 @@
// The following code for merging circles into arches originates from https://github.com/FormerLurker/ArcWelderLib
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Arc Welder: Anti-Stutter Library
//
// Compresses many G0/G1 commands into G2/G3(arc) commands where possible, ensuring the tool paths stay within the specified resolution.
// This reduces file size and the number of gcodes per second.
//
// Uses the 'Gcode Processor Library' for gcode parsing, position processing, logging, and other various functionality.
//
// Copyright(C) 2021 - Brad Hochgesang
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// This program is free software : you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published
// by the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
// GNU Affero General Public License for more details.
//
//
// You can contact the author at the following email address:
// FormerLurker@pm.me
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#include "ArcWelder.hpp"
namespace Slic3r { namespace Geometry { namespace ArcWelder {
} } } // namespace Slic3r::Geometry::ArcWelder

View file

@ -0,0 +1,71 @@
#ifndef slic3r_Geometry_ArcWelder_hpp_
#define slic3r_Geometry_ArcWelder_hpp_
#include <assert.h>
#include <stddef.h>
#include <stdint.h>
#include <Eigen/Geometry>
#include <type_traits>
#include <cassert>
#include "libslic3r/libslic3r.h"
namespace Slic3r { namespace Geometry { namespace ArcWelder {
// Calculate center point (center of a circle) of an arc given two points and a radius.
// positive radius: take shorter arc
// negative radius: take longer arc
// radius must NOT be zero!
template<typename Derived, typename Derived2, typename Float>
inline Eigen::Matrix<Float, 2, 1, Eigen::DontAlign> arc_center(
const Eigen::MatrixBase<Derived> &start_pos,
const Eigen::MatrixBase<Derived2> &end_pos,
const Float radius,
const bool is_ccw)
{
static_assert(Derived::IsVectorAtCompileTime && int(Derived::SizeAtCompileTime) == 2, "arc_center(): first parameter is not a 2D vector");
static_assert(Derived2::IsVectorAtCompileTime && int(Derived2::SizeAtCompileTime) == 2, "arc_center(): second parameter is not a 2D vector");
static_assert(std::is_same<typename Derived::Scalar, typename Derived2::Scalar>::value, "arc_center(): Both vectors must be of the same type.");
static_assert(std::is_same<typename Derived::Scalar, Float>::value, "arc_center(): Radius must be of the same type as the vectors.");
assert(radius != 0);
using Vector = Eigen::Matrix<Float, 2, 1, Eigen::DontAlign>;
auto v = end_pos - start_pos;
Float q2 = v.squaredNorm();
assert(q2 > 0);
Float t2 = sqr(radius) / q2 - Float(.25f);
// If the start_pos and end_pos are nearly antipodal, t2 may become slightly negative.
// In that case return a centroid of start_point & end_point.
Float t = t2 > 0 ? sqrt(t2) : Float(0);
auto mid = Float(0.5) * (start_pos + end_pos);
Vector vp{ -v.y() * t, v.x() * t };
return (radius > Float(0)) == is_ccw ? (mid + vp).eval() : (mid - vp).eval();
}
// Return number of linear segments necessary to interpolate arc of a given positive radius and positive angle to satisfy
// maximum deviation of an interpolating polyline from an analytic arc.
template<typename FloatType>
size_t arc_discretization_steps(const FloatType radius, const FloatType angle, const FloatType deviation)
{
assert(radius > 0);
assert(angle > 0);
assert(angle <= FloatType(2. * M_PI));
assert(deviation > 0);
FloatType d = radius - deviation;
return d < EPSILON ?
// Radius smaller than deviation.
( // Acute angle: a single segment interpolates the arc with sufficient accuracy.
angle < M_PI ||
// Obtuse angle: Test whether the furthest point (center) of an arc is closer than deviation to the center of a line segment.
radius * (FloatType(1.) + cos(M_PI - FloatType(.5) * angle)) < deviation ?
// Single segment is sufficient
1 :
// Two segments are necessary, the middle point is at the center of the arc.
2) :
size_t(ceil(angle / (2. * acos(d / radius))));
}
} } } // namespace Slic3r::Geometry::ArcWelder
#endif // slic3r_Geometry_ArcWelder_hpp_

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
@ -39,28 +35,21 @@
// Enable rework of Reload from disk command
#define ENABLE_RELOAD_FROM_DISK_REWORK 1
//====================
// 2.4.0.beta1 techs
//====================
#define ENABLE_2_4_0_BETA1 1
// Enable rendering modifiers and similar objects always as transparent
#define ENABLE_MODIFIERS_ALWAYS_TRANSPARENT (1 && ENABLE_2_4_0_BETA1)
//====================
// 2.4.0.beta2 techs
//====================
#define ENABLE_2_4_0_BETA2 1
#define ENABLE_MODIFIERS_ALWAYS_TRANSPARENT 1
// Enable modified ImGuiWrapper::slider_float() to create a compound widget where
// an additional button can be used to set the keyboard focus into the slider
// to allow the user to type in the desired value
#define ENABLE_ENHANCED_IMGUI_SLIDER_FLOAT (1 && ENABLE_2_4_0_BETA2)
#define ENABLE_ENHANCED_IMGUI_SLIDER_FLOAT 1
// Enable fit print volume command for circular printbeds
#define ENABLE_ENHANCED_PRINT_VOLUME_FIT (1 && ENABLE_2_4_0_BETA2)
#define ENABLE_ENHANCED_PRINT_VOLUME_FIT 1
// 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

@ -85,6 +85,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

@ -1378,6 +1378,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,225 @@
///|/ 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
{
Summary, // ORCA
FeatureType,
ColorPrint,
Speed,
ActualSpeed,
Height,
Width,
VolumetricFlowRate,
ActualVolumetricFlowRate,
LayerTimeLinear,
LayerTimeLogarithmic,
FanSpeed,
Temperature,
Tool,
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,
// ORCA
BottomSurface,
InternalBridgeInfill,
Brim,
SupportTransition,
Mixed,
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,423 @@
///|/ 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,
// ORCA
EGCodeExtrusionRole::BottomSurface, EGCodeExtrusionRole::InternalBridgeInfill, EGCodeExtrusionRole::Brim,
EGCodeExtrusionRole::SupportTransition, EGCodeExtrusionRole::Mixed
}) 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,76 @@
///|/ 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
true, // 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
// ORCA
true, // BottomSurface
true, // InternalBridgeInfill
true, // Brim
true, // SupportTransition
true, // Mixed
};
};
} // namespace libvgcode
#endif // VGCODE_SETTINGS_HPP

View file

@ -0,0 +1,303 @@
///|/ 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.2;\n"
"const float ambient = 0.2;\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"
#ifndef _WIN32
"const float scaling_factor = 0.75;\n"
#else
"const float scaling_factor = 1.5;\n"
#endif
"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,470 @@
///|/ 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,
// ORCA
EGCodeExtrusionRole::BottomSurface, EGCodeExtrusionRole::InternalBridgeInfill, EGCodeExtrusionRole::Brim,
EGCodeExtrusionRole::SupportTransition, EGCodeExtrusionRole::Mixed
}) 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

@ -299,6 +299,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
@ -707,13 +709,15 @@ source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR} FILES ${SLIC3R_GUI_SOURCES})
encoding_check(libslic3r_gui)
if(APPLE AND CMAKE_VERSION VERSION_GREATER_EQUAL "4.0")
set(_opengl_link_lib "")
else()
set(_opengl_link_lib OpenGL::GL)
endif()
target_link_libraries(libslic3r_gui libslic3r cereal::cereal imgui imguizmo minilzo GLEW::GLEW ${_opengl_link_lib} 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

@ -936,7 +936,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,584 +37,44 @@ 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 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 };
GCodeProcessorResult::MoveVertex m_curr_move;
float m_z_offset{ 0.0f };
// z offset of the model
float m_model_z_offset{ 0.5f };
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;
@ -619,16 +83,28 @@ 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; }
void set_z_offset(float z_offset) { m_z_offset = z_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, int canvas_width, int canvas_height);
void on_change_color_mode(bool is_dark) { m_is_dark = is_dark; }
void update_curr_move(const GCodeProcessorResult::MoveVertex move);
};
class GCodeWindow
@ -672,33 +148,12 @@ 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
{
std::vector<ColorRGBA> m_tool_colors;
std::vector<bool> m_tool_visibles;
};
struct ExtruderFilament
{
std::string type;
@ -706,24 +161,6 @@ public:
unsigned char filament_id;
bool is_support_filament;
};
enum class EViewType : unsigned char
{
Summary = 0,
FeatureType,
Height,
Width,
Feedrate,
FanSpeed,
Temperature,
VolumetricRate,
Tool,
ColorPrint,
FilamentId,
LayerTime,
LayerTimeLog,
Count
};
// helper to render shells
struct Shells
{
@ -744,19 +181,16 @@ 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;
//BBS: extruder dispensing filament
std::vector<ExtruderFilament> m_left_extruder_filament;
std::vector<ExtruderFilament> m_right_extruder_filament;
size_t m_nozzle_nums;
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
@ -764,41 +198,38 @@ private:
//BBS: add shell bounding box
BoundingBoxf3 m_shell_bounding_box;
float m_max_print_height{ 0.0f };
float m_z_offset{ 0.0f };
//BBS save m_tools_color and m_tools_visible
ETools m_tools;
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;
#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 };
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;
@ -806,6 +237,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();
@ -818,11 +252,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);
@ -836,11 +269,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();
@ -848,8 +281,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);
@ -860,56 +300,56 @@ public:
void enable_moves_slider(bool enable) const;
void update_moves_slider(bool set_to_max = false);
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(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){
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 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);
@ -917,16 +357,6 @@ private:
void render_legend(float &legend_height, int canvas_width, int canvas_height, int right_margin);
void render_legend_color_arr_recommen(float window_padding);
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

@ -286,8 +286,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);
@ -327,25 +327,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; }
@ -638,6 +633,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()
{
@ -685,7 +683,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();
@ -700,7 +698,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();
@ -764,22 +762,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(ObjectFilamentResults* object_results = nullptr) 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);
@ -788,7 +797,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; }
@ -832,22 +841,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/OrcaSlicer/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();
@ -855,10 +870,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();
@ -963,9 +978,6 @@ public:
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);
//BBS
void select_curr_plate_all();
void select_object_from_idx(std::vector<int>& object_idxs);
@ -976,18 +988,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);
@ -1003,16 +1011,16 @@ 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 load_sla_preview();
//void load_preview(const std::vector<std::string>& str_tool_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);
@ -1079,7 +1087,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
@ -1101,7 +1110,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; }
@ -1111,8 +1120,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();
@ -1234,7 +1243,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();
@ -1260,7 +1269,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);
@ -1271,23 +1280,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,13 +50,21 @@ 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
valid &= append_shader("thumbnail", { prefix + "thumbnail.vs", prefix + "thumbnail.fs"});
// used to render printbed
valid &= append_shader("printbed", { prefix + "printbed.vs", prefix + "printbed.fs" });
valid &= append_shader("hotbed", {"110/hotbed.vs", "110/hotbed.fs"});
valid &= append_shader("hotbed", {prefix + "hotbed.vs", prefix + "hotbed.fs"});
// used to render options in gcode preview
if (GUI::wxGetApp().is_gl_version_greater_or_equal_to(3, 3)) {
valid &= append_shader("gouraud_light_instanced", { prefix + "gouraud_light_instanced.vs", prefix + "gouraud_light_instanced.fs" });

View file

@ -2278,7 +2278,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()
@ -6567,7 +6568,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,8 +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);
//BBS: GUI refactor: GLToolbar
if (wxGetApp().is_editor()) {
m_canvas->enable_select_plate_toolbar(true);
@ -332,50 +339,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 +369,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 +553,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 +585,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 +674,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 +697,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 +712,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 +728,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 +739,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 +763,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

@ -989,11 +989,19 @@ void GLGizmoAdvancedCut::render_cut_plane_and_grabbers()
}
glsafe(::glDisable(GL_DEPTH_TEST));
glsafe(::glLineWidth(m_hover_id != -1 ? 2.0f : 1.5f));
glLineStipple(1, 0x0FFF);
glEnable(GL_LINE_STIPPLE);
// ORCA: OpenGL Core Profile
#if !SLIC3R_OPENGL_ES
if (!OpenGLManager::get_gl_info().is_core_profile()) {
glsafe(::glLineWidth(m_hover_id != -1 ? 2.0f : 1.5f));
glLineStipple(1, 0x0FFF);
glEnable(GL_LINE_STIPPLE);
}
#endif // !SLIC3R_OPENGL_ES
m_grabber_connection.render();
glDisable(GL_LINE_STIPPLE);
#if !SLIC3R_OPENGL_ES
if (!OpenGLManager::get_gl_info().is_core_profile())
glDisable(GL_LINE_STIPPLE);
#endif // !SLIC3R_OPENGL_ES
shader->stop_using();
}
@ -1147,10 +1155,18 @@ void GLGizmoAdvancedCut::render_cut_line()
shader->set_uniform("view_model_matrix", camera.get_view_matrix());
shader->set_uniform("projection_matrix", camera.get_projection_matrix());
glEnable(GL_LINE_STIPPLE);
glLineStipple(1, 0x0FFF);
// ORCA: OpenGL Core Profile
#if !SLIC3R_OPENGL_ES
if (!OpenGLManager::get_gl_info().is_core_profile()) {
glEnable(GL_LINE_STIPPLE);
glLineStipple(1, 0x0FFF);
}
#endif // !SLIC3R_OPENGL_ES
m_cut_line.render();
glDisable(GL_LINE_STIPPLE);
#if !SLIC3R_OPENGL_ES
if (!OpenGLManager::get_gl_info().is_core_profile())
glDisable(GL_LINE_STIPPLE);
#endif // !SLIC3R_OPENGL_ES
shader->stop_using();
}

View file

@ -231,7 +231,11 @@ void GLGizmoBase::render_cross_mark(const Vec3f &target, bool is_single)
{
const float half_length = 4.0f;
glsafe(::glLineWidth(2.0f));
// ORCA: OpenGL Core Profile
#if !SLIC3R_OPENGL_ES
if (!OpenGLManager::get_gl_info().is_core_profile())
glsafe(::glLineWidth(2.0f));
#endif // !SLIC3R_OPENGL_ES
auto render_line = [](const Vec3f& p1, const Vec3f& p2, const ColorRGBA& color) {
GLModel::Geometry init_data;

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

@ -887,6 +887,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();
}
@ -895,6 +905,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);
@ -902,6 +919,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");
@ -922,17 +946,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;
};

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