GCodeViewer -> Newer version of shader for options

This commit is contained in:
enricoturri1966 2020-05-27 16:19:40 +02:00
parent aa04f0e555
commit 35190936a3
13 changed files with 187 additions and 98 deletions

View file

@ -5,7 +5,7 @@ uniform vec3 uniform_color;
uniform float percent_outline_radius;
uniform float percent_center_radius;
vec4 hard_color(float sq_radius)
vec4 hardcoded_color(float sq_radius)
{
if ((sq_radius < 0.005625) || (sq_radius > 0.180625))
return vec4(0.5 * uniform_color, 1.0);
@ -13,7 +13,7 @@ vec4 hard_color(float sq_radius)
return vec4(uniform_color, 1.0);
}
vec4 custom_color(float sq_radius)
vec4 customizable_color(float sq_radius)
{
float in_radius = 0.5 * percent_center_radius;
float out_radius = 0.5 * (1.0 - percent_outline_radius);
@ -30,5 +30,6 @@ void main()
if (sq_radius > 0.25)
discard;
gl_FragColor = custom_color(sq_radius);
gl_FragColor = customizable_color(sq_radius);
// gl_FragColor = hardcoded_color(sq_radius);
}

View file

@ -0,0 +1,88 @@
// version 120 is needed for gl_PointCoord
#version 120
#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 vec3 uniform_color;
uniform float percent_outline_radius;
uniform float percent_center_radius;
// x = width, y = height
uniform ivec2 viewport_sizes;
uniform vec2 z_range;
uniform mat4 inv_proj_matrix;
varying vec3 eye_center;
float radius = 0.5;
// x = tainted, y = specular;
vec2 intensity;
vec3 eye_position_from_fragment()
{
// Convert screen coordinates to normalized device coordinates (NDC)
vec4 ndc = vec4(
(gl_FragCoord.x / viewport_sizes.x - 0.5) * 2.0,
(gl_FragCoord.y / viewport_sizes.y - 0.5) * 2.0,
(gl_FragCoord.z - 0.5) * 2.0,
1.0);
// Convert NDC throuch inverse clip coordinates to view coordinates
vec4 clip = inv_proj_matrix * ndc;
return (clip / clip.w).xyz;
}
vec3 eye_position_on_sphere(vec3 eye_fragment_position)
{
vec3 eye_dir = normalize(eye_fragment_position);
float a = dot(eye_dir, eye_dir);
float b = 2.0 * dot(-eye_center, eye_dir);
float c = dot(eye_center, eye_center) - radius * radius;
float discriminant = b * b - 4 * a * c;
float t = -(b + sqrt(discriminant)) / (2.0 * a);
return t * eye_dir;
}
vec4 on_sphere_color(vec3 eye_on_sphere_position)
{
vec3 eye_normal = normalize(eye_on_sphere_position - eye_center);
// 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(eye_normal, LIGHT_TOP_DIR), 0.0);
intensity.x = INTENSITY_AMBIENT + NdotL * LIGHT_TOP_DIFFUSE;
intensity.y = LIGHT_TOP_SPECULAR * pow(max(dot(-normalize(eye_on_sphere_position), reflect(-LIGHT_TOP_DIR, eye_normal)), 0.0), LIGHT_TOP_SHININESS);
// Perform the same lighting calculation for the 2nd light source (no specular applied).
NdotL = max(dot(eye_normal, LIGHT_FRONT_DIR), 0.0);
intensity.x += NdotL * LIGHT_FRONT_DIFFUSE;
return vec4(vec3(intensity.y, intensity.y, intensity.y) + uniform_color.rgb * intensity.x, 1.0);
}
void main()
{
vec2 pos = gl_PointCoord - vec2(0.5, 0.5);
float sq_radius = dot(pos, pos);
if (sq_radius > 0.25)
discard;
vec3 eye_on_sphere_position = eye_position_on_sphere(eye_position_from_fragment());
// gl_FragDepth = eye_on_sphere_position.z;
// gl_FragDepth = (eye_on_sphere_position.z - z_range.x) / (z_range.y - z_range.x);
gl_FragColor = on_sphere_color(eye_on_sphere_position);
}

View file

@ -0,0 +1,14 @@
#version 120
uniform float zoom;
// x = min, y = max
uniform vec2 point_sizes;
varying vec3 eye_center;
void main()
{
gl_PointSize = clamp(zoom, point_sizes.x, point_sizes.y);
eye_center = (gl_ModelViewMatrix * gl_Vertex).xyz;
gl_Position = ftransform();
}

View file

@ -1,13 +0,0 @@
#version 110
const vec3 ZERO = vec3(0.0, 0.0, 0.0);
uniform vec4 uniform_color;
// x = tainted, y = specular;
varying vec2 intensity;
void main()
{
gl_FragColor = vec4(vec3(intensity.y, intensity.y, intensity.y) + uniform_color.rgb * intensity.x, uniform_color.a);
}

View file

@ -1,42 +0,0 @@
#version 110
#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
// x = tainted, y = specular;
varying vec2 intensity;
void main()
{
// First transform the normal into camera space and normalize the result.
vec3 normal = normalize(gl_NormalMatrix * gl_Normal);
// Compute the cos of the angle between the normal and lights direction. The light is directional so the direction is constant for every vertex.
// Since these two are normalized the cosine is the dot product. We also need to clamp the result to the [0,1] range.
float NdotL = max(dot(normal, LIGHT_TOP_DIR), 0.0);
intensity.x = INTENSITY_AMBIENT + NdotL * LIGHT_TOP_DIFFUSE;
intensity.y = 0.0;
if (NdotL > 0.0)
{
vec3 position = (gl_ModelViewMatrix * gl_Vertex).xyz;
intensity.y += LIGHT_TOP_SPECULAR * pow(max(dot(-normalize(position), reflect(-LIGHT_TOP_DIR, normal)), 0.0), LIGHT_TOP_SHININESS);
}
// Perform the same lighting calculation for the 2nd light source (no specular applied).
intensity.x += max(dot(normal, LIGHT_FRONT_DIR), 0.0) * LIGHT_FRONT_DIFFUSE;
gl_Position = ftransform();
}

View file

@ -15,7 +15,7 @@
#define ENABLE_RENDER_STATISTICS 0
// Shows an imgui dialog with camera related data
#define ENABLE_CAMERA_STATISTICS 0
// Render the picking pass instead of the main scene (use [T] key to toggle between regular rendering and picking pass only rendering)
// Render the picking pass instead of the main scene (use [T] key to toggle between regular rendering and picking pass only rendering)
#define ENABLE_RENDER_PICKING_PASS 0
// Enable extracting thumbnails from selected gcode and save them as png files
#define ENABLE_THUMBNAIL_GENERATOR_DEBUG 0

View file

@ -84,6 +84,7 @@ public:
double get_near_z() const { return m_frustrum_zs.first; }
double get_far_z() const { return m_frustrum_zs.second; }
const std::pair<double, double>& get_z_range() const { return m_frustrum_zs; }
double get_fov() const;

View file

@ -415,12 +415,12 @@ void GCodeViewer::init_shaders()
{
switch (buffer_type(i))
{
case GCodeProcessor::EMoveType::Tool_change: { m_buffers[i].shader = wxGetApp().is_glsl_version_greater_or_equal_to(1, 20) ? "options_120" : "options_110"; break; }
case GCodeProcessor::EMoveType::Color_change: { m_buffers[i].shader = wxGetApp().is_glsl_version_greater_or_equal_to(1, 20) ? "options_120" : "options_110"; break; }
case GCodeProcessor::EMoveType::Pause_Print: { m_buffers[i].shader = wxGetApp().is_glsl_version_greater_or_equal_to(1, 20) ? "options_120" : "options_110"; break; }
case GCodeProcessor::EMoveType::Custom_GCode: { m_buffers[i].shader = wxGetApp().is_glsl_version_greater_or_equal_to(1, 20) ? "options_120" : "options_110"; break; }
case GCodeProcessor::EMoveType::Retract: { m_buffers[i].shader = wxGetApp().is_glsl_version_greater_or_equal_to(1, 20) ? "options_120" : "options_110"; break; }
case GCodeProcessor::EMoveType::Unretract: { m_buffers[i].shader = wxGetApp().is_glsl_version_greater_or_equal_to(1, 20) ? "options_120" : "options_110"; break; }
case GCodeProcessor::EMoveType::Tool_change: { m_buffers[i].shader = wxGetApp().is_glsl_version_greater_or_equal_to(1, 20) ? "options_120_solid" : "options_110"; break; }
case GCodeProcessor::EMoveType::Color_change: { m_buffers[i].shader = wxGetApp().is_glsl_version_greater_or_equal_to(1, 20) ? "options_120_solid" : "options_110"; break; }
case GCodeProcessor::EMoveType::Pause_Print: { m_buffers[i].shader = wxGetApp().is_glsl_version_greater_or_equal_to(1, 20) ? "options_120_solid" : "options_110"; break; }
case GCodeProcessor::EMoveType::Custom_GCode: { m_buffers[i].shader = wxGetApp().is_glsl_version_greater_or_equal_to(1, 20) ? "options_120_solid" : "options_110"; break; }
case GCodeProcessor::EMoveType::Retract: { m_buffers[i].shader = wxGetApp().is_glsl_version_greater_or_equal_to(1, 20) ? "options_120_solid" : "options_110"; break; }
case GCodeProcessor::EMoveType::Unretract: { m_buffers[i].shader = wxGetApp().is_glsl_version_greater_or_equal_to(1, 20) ? "options_120_solid" : "options_110"; break; }
case GCodeProcessor::EMoveType::Extrude: { m_buffers[i].shader = "extrusions"; break; }
case GCodeProcessor::EMoveType::Travel: { m_buffers[i].shader = "travels"; break; }
default: { break; }
@ -754,21 +754,26 @@ void GCodeViewer::refresh_render_paths(bool keep_sequential_current_first, bool
void GCodeViewer::render_toolpaths() const
{
#if ENABLE_GCODE_VIEWER_SHADERS_EDITOR
bool is_glsl_120 = m_shaders_editor.glsl_version == 1 && wxGetApp().is_glsl_version_greater_or_equal_to(1, 20);
bool is_glsl_120 = m_shaders_editor.shader_version >= 1 && wxGetApp().is_glsl_version_greater_or_equal_to(1, 20);
std::array<float, 2> point_sizes;
if (m_shaders_editor.size_dependent_on_zoom)
{
point_sizes = { std::min(static_cast<float>(m_shaders_editor.sizes[0]), m_detected_point_sizes[1]), std::min(static_cast<float>(m_shaders_editor.sizes[1]), m_detected_point_sizes[1]) };
}
else
point_sizes = { static_cast<float>(m_shaders_editor.fixed_size), static_cast<float>(m_shaders_editor.fixed_size) };
#else
bool is_glsl_120 = wxGetApp().is_glsl_version_greater_or_equal_to(1, 20);
std::array<float, 2> point_sizes = { std::min(8.0f, m_detected_point_sizes[1]), std::min(48.0f, m_detected_point_sizes[1]) };
#endif // ENABLE_GCODE_VIEWER_SHADERS_EDITOR
double zoom = wxGetApp().plater()->get_camera().get_zoom();
const Camera& camera = wxGetApp().plater()->get_camera();
double zoom = camera.get_zoom();
const std::array<int, 4>& viewport = camera.get_viewport();
std::array<int, 2> viewport_sizes = { viewport[2], viewport[3] };
const std::pair<double, double>& camera_z_range = camera.get_z_range();
std::array<float, 2> z_range = { static_cast<float>(camera_z_range.first), static_cast<float>(camera_z_range.second) };
auto render_options = [this, is_glsl_120, zoom, point_sizes](const IBuffer& buffer, EOptionsColors colors_id, GLShaderProgram& shader) {
Transform3d inv_proj = camera.get_projection_matrix().inverse();
auto render_options = [this, is_glsl_120, zoom, viewport, inv_proj, viewport_sizes, z_range, point_sizes](const IBuffer& buffer, EOptionsColors colors_id, GLShaderProgram& shader) {
shader.set_uniform("uniform_color", Options_Colors[static_cast<unsigned int>(colors_id)]);
#if ENABLE_GCODE_VIEWER_SHADERS_EDITOR
shader.set_uniform("zoom", m_shaders_editor.size_dependent_on_zoom ? zoom : 1.0f);
@ -779,6 +784,9 @@ void GCodeViewer::render_toolpaths() const
shader.set_uniform("percent_outline_radius", 0.15f);
shader.set_uniform("percent_center_radius", 0.15f);
#endif // ENABLE_GCODE_VIEWER_SHADERS_EDITOR
shader.set_uniform("viewport_sizes", viewport_sizes);
shader.set_uniform("inv_proj_matrix", inv_proj);
shader.set_uniform("z_range", z_range);
shader.set_uniform("point_sizes", point_sizes);
glsafe(::glEnable(GL_VERTEX_PROGRAM_POINT_SIZE));
if (is_glsl_120)
@ -896,7 +904,7 @@ void GCodeViewer::render_shells() const
if (!m_shells.visible || m_shells.volumes.empty())
return;
GLShaderProgram* shader = wxGetApp().get_shader("shells");
GLShaderProgram* shader = wxGetApp().get_shader("gouraud_light");
if (shader == nullptr)
return;
@ -954,25 +962,25 @@ void GCodeViewer::render_legend() const
{
#if ENABLE_GCODE_VIEWER_SHADERS_EDITOR
draw_list->AddCircle({ 0.5f * (pos.x + pos.x + icon_size), 0.5f * (pos.y + pos.y + icon_size) }, 0.5f * icon_size, ICON_BORDER_COLOR, 16);
draw_list->AddCircleFilled({ 0.5f * (pos.x + pos.x + icon_size), 0.5f * (pos.y + pos.y + icon_size) }, (0.5f * icon_size) - 2.0f,
ImGui::GetColorU32({ 0.5f * color[0], 0.5f * color[1], 0.5f * color[2], 1.0f }), 16);
float radius = ((0.5f * icon_size) - 2.0f) * (1.0f - 0.01f * static_cast<float>(m_shaders_editor.percent_outline));
draw_list->AddCircleFilled({ 0.5f * (pos.x + pos.x + icon_size), 0.5f * (pos.y + pos.y + icon_size) }, radius,
ImGui::GetColorU32({ color[0], color[1], color[2], 1.0f }), 16);
if (m_shaders_editor.percent_center > 0)
{
radius = ((0.5f * icon_size) - 2.0f) * 0.01f * static_cast<float>(m_shaders_editor.percent_center);
draw_list->AddCircleFilled({ 0.5f * (pos.x + pos.x + icon_size), 0.5f * (pos.y + pos.y + icon_size) }, radius,
if (m_shaders_editor.shader_version == 1) {
draw_list->AddCircleFilled({ 0.5f * (pos.x + pos.x + icon_size), 0.5f * (pos.y + pos.y + icon_size) }, (0.5f * icon_size) - 2.0f,
ImGui::GetColorU32({ 0.5f * color[0], 0.5f * color[1], 0.5f * color[2], 1.0f }), 16);
float radius = ((0.5f * icon_size) - 2.0f) * (1.0f - 0.01f * static_cast<float>(m_shaders_editor.percent_outline));
draw_list->AddCircleFilled({ 0.5f * (pos.x + pos.x + icon_size), 0.5f * (pos.y + pos.y + icon_size) }, radius,
ImGui::GetColorU32({ color[0], color[1], color[2], 1.0f }), 16);
if (m_shaders_editor.percent_center > 0) {
radius = ((0.5f * icon_size) - 2.0f) * 0.01f * static_cast<float>(m_shaders_editor.percent_center);
draw_list->AddCircleFilled({ 0.5f * (pos.x + pos.x + icon_size), 0.5f * (pos.y + pos.y + icon_size) }, radius,
ImGui::GetColorU32({ 0.5f * color[0], 0.5f * color[1], 0.5f * color[2], 1.0f }), 16);
}
} else {
draw_list->AddCircleFilled({ 0.5f * (pos.x + pos.x + icon_size), 0.5f * (pos.y + pos.y + icon_size) }, (0.5f * icon_size) - 2.0f,
ImGui::GetColorU32({ color[0], color[1], color[2], 1.0f }), 16);
}
#else
draw_list->AddCircle({ 0.5f * (pos.x + pos.x + icon_size), 0.5f * (pos.y + pos.y + icon_size) }, 0.5f * icon_size, ICON_BORDER_COLOR, 16);
draw_list->AddCircleFilled({ 0.5f * (pos.x + pos.x + icon_size), 0.5f * (pos.y + pos.y + icon_size) }, (0.5f * icon_size) - 2.0f,
ImGui::GetColorU32({ 0.5f * color[0], 0.5f * color[1], 0.5f * color[2], 1.0f }), 16);
draw_list->AddCircleFilled({ 0.5f * (pos.x + pos.x + icon_size), 0.5f * (pos.y + pos.y + icon_size) }, (0.5f * icon_size) - 3.0f,
ImGui::GetColorU32({ color[0], color[1], color[2], 1.0f }), 16);
draw_list->AddCircleFilled({ 0.5f * (pos.x + pos.x + icon_size), 0.5f * (pos.y + pos.y + icon_size) }, 1.5f,
ImGui::GetColorU32({ 0.5f * color[0], 0.5f * color[1], 0.5f * color[2], 1.0f }), 16);
#endif // ENABLE_GCODE_VIEWER_SHADERS_EDITOR
break;
}
@ -1195,7 +1203,11 @@ void GCodeViewer::render_legend() const
auto add_option = [this, add_item](GCodeProcessor::EMoveType move_type, EOptionsColors color, const std::string& text) {
const IBuffer& buffer = m_buffers[buffer_id(move_type)];
if (buffer.visible && buffer.indices_count > 0)
add_item(EItemType::Circle, Options_Colors[static_cast<unsigned int>(color)], text);
#if ENABLE_GCODE_VIEWER_SHADERS_EDITOR
add_item((m_shaders_editor.shader_version == 0) ? EItemType::Rect : EItemType::Circle, Options_Colors[static_cast<unsigned int>(color)], text);
#else
add_item((buffer.shader == "options_110") ? EItemType::Rect : EItemType::Circle, Options_Colors[static_cast<unsigned int>(color)], text);
#endif // ENABLE_GCODE_VIEWER_SHADERS_EDITOR
};
// options
@ -1337,12 +1349,15 @@ void GCodeViewer::render_shaders_editor() const
imgui.set_next_window_pos(static_cast<float>(cnv_size.get_width()), 0.5f * static_cast<float>(cnv_size.get_height()), ImGuiCond_Once, 1.0f, 0.5f);
imgui.begin(std::string("Shaders editor (DEV only)"), ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoResize);
ImGui::RadioButton("glsl version 1.10 (low end PCs)", &m_shaders_editor.glsl_version, 0);
ImGui::RadioButton("glsl version 1.20 (default)", &m_shaders_editor.glsl_version, 1);
switch (m_shaders_editor.glsl_version)
ImGui::RadioButton("glsl version 1.10 (low end PCs)", &m_shaders_editor.shader_version, 0);
ImGui::RadioButton("glsl version 1.20 flat (billboards)", &m_shaders_editor.shader_version, 1);
ImGui::RadioButton("glsl version 1.20 solid (spheres default)", &m_shaders_editor.shader_version, 2);
switch (m_shaders_editor.shader_version)
{
case 0: { set_shader("options_110"); break; }
case 1: { set_shader("options_120"); break; }
case 1: { set_shader("options_120_flat"); break; }
case 2: { set_shader("options_120_solid"); break; }
}
if (ImGui::CollapsingHeader("Options", ImGuiTreeNodeFlags_DefaultOpen))
@ -1364,7 +1379,7 @@ void GCodeViewer::render_shaders_editor() const
else
ImGui::SliderInt("fixed size", &m_shaders_editor.fixed_size, 1, 100);
if (m_shaders_editor.glsl_version == 1)
if (m_shaders_editor.shader_version == 1)
{
ImGui::SliderInt("percent outline", &m_shaders_editor.percent_outline, 0, 50);
ImGui::SliderInt("percent center", &m_shaders_editor.percent_center, 0, 50);

View file

@ -205,12 +205,12 @@ class GCodeViewer
#if ENABLE_GCODE_VIEWER_SHADERS_EDITOR
struct ShadersEditor
{
int glsl_version{ 1 };
int shader_version{ 2 };
bool size_dependent_on_zoom{ true };
int fixed_size{ 16 };
std::array<int, 2> sizes{ 8, 64 };
int percent_outline{ 15 };
int percent_center{ 15 };
std::array<int, 2> sizes{ 3, 21 };
int percent_outline{ 0 };
int percent_center{ 33 };
};
#endif // ENABLE_GCODE_VIEWER_SHADERS_EDITOR

View file

@ -215,6 +215,26 @@ bool GLShaderProgram::set_uniform(const char* name, double value) const
return set_uniform(name, static_cast<float>(value));
}
bool GLShaderProgram::set_uniform(const char* name, const std::array<int, 2>& value) const
{
int id = get_uniform_location(name);
if (id >= 0) {
glsafe(::glUniform2iv(id, 1, static_cast<const GLint*>(value.data())));
return true;
}
return false;
}
bool GLShaderProgram::set_uniform(const char* name, const std::array<int, 3>& value) const
{
int id = get_uniform_location(name);
if (id >= 0) {
glsafe(::glUniform3iv(id, 1, static_cast<const GLint*>(value.data())));
return true;
}
return false;
}
bool GLShaderProgram::set_uniform(const char* name, const std::array<int, 4>& value) const
{
int id = get_uniform_location(name);

View file

@ -43,6 +43,8 @@ public:
bool set_uniform(const char* name, bool value) const;
bool set_uniform(const char* name, float value) const;
bool set_uniform(const char* name, double value) const;
bool set_uniform(const char* name, const std::array<int, 2>& value) const;
bool set_uniform(const char* name, const std::array<int, 3>& value) const;
bool set_uniform(const char* name, const std::array<int, 4>& value) const;
bool set_uniform(const char* name, const std::array<float, 2>& value) const;
bool set_uniform(const char* name, const std::array<float, 3>& value) const;

View file

@ -1,6 +1,7 @@
#include "libslic3r/libslic3r.h"
#include "GLShadersManager.hpp"
#include "3DScene.hpp"
#include "GUI_App.hpp"
#include <cassert>
#include <algorithm>
@ -28,19 +29,21 @@ std::pair<bool, std::string> GLShadersManager::init()
bool valid = true;
// used to render bed axes and model, selection hints, gcode sequential view marker model
// used to render bed axes and model, selection hints, gcode sequential view marker model, preview shells
valid &= append_shader("gouraud_light", { "gouraud_light.vs", "gouraud_light.fs" });
// used to render printbed
valid &= append_shader("printbed", { "printbed.vs", "printbed.fs" });
// used to render options in gcode preview
valid &= append_shader("options_110", { "options_110.vs", "options_110.fs" });
valid &= append_shader("options_120", { "options_120.vs", "options_120.fs" });
if (GUI::wxGetApp().is_glsl_version_greater_or_equal_to(1, 20))
{
valid &= append_shader("options_120_flat", { "options_120_flat.vs", "options_120_flat.fs" });
valid &= append_shader("options_120_solid", { "options_120_solid.vs", "options_120_solid.fs" });
}
// used to render extrusion paths in gcode preview
valid &= append_shader("extrusions", { "extrusions.vs", "extrusions.fs" });
// used to render travel paths in gcode preview
valid &= append_shader("travels", { "travels.vs", "travels.fs" });
// used to render shells in gcode preview
valid &= append_shader("shells", { "shells.vs", "shells.fs" });
// used to render objects in 3d editor
valid &= append_shader("gouraud", { "gouraud.vs", "gouraud.fs" });
// used to render variable layers heights in 3d editor