Error reporting on initialization of the Layer Editing OpenGL shaders.
The shaders are initialized when the layer editing button is pressed for the first time. If the initialization fails, a message box is shown and the layer editing will stay disabled.
This commit is contained in:
parent
70229be9bc
commit
898deb48c4
@ -19,7 +19,7 @@ package Slic3r::GUI::3DScene::Base;
|
|||||||
use strict;
|
use strict;
|
||||||
use warnings;
|
use warnings;
|
||||||
|
|
||||||
use Wx qw(:timer :bitmap);
|
use Wx qw(:timer :bitmap :icon :dialog);
|
||||||
use Wx::Event qw(EVT_PAINT EVT_SIZE EVT_ERASE_BACKGROUND EVT_IDLE EVT_MOUSEWHEEL EVT_MOUSE_EVENTS EVT_TIMER);
|
use Wx::Event qw(EVT_PAINT EVT_SIZE EVT_ERASE_BACKGROUND EVT_IDLE EVT_MOUSEWHEEL EVT_MOUSE_EVENTS EVT_TIMER);
|
||||||
# must load OpenGL *before* Wx::GLCanvas
|
# must load OpenGL *before* Wx::GLCanvas
|
||||||
use OpenGL qw(:glconstants :glfunctions :glufunctions :gluconstants);
|
use OpenGL qw(:glconstants :glfunctions :glufunctions :gluconstants);
|
||||||
@ -193,24 +193,58 @@ sub layer_editing_enabled {
|
|||||||
my ($self, $value) = @_;
|
my ($self, $value) = @_;
|
||||||
if (@_ == 2) {
|
if (@_ == 2) {
|
||||||
$self->{layer_editing_enabled} = $value;
|
$self->{layer_editing_enabled} = $value;
|
||||||
if ($value && ! $self->{layer_editing_initialized}) {
|
if ($value) {
|
||||||
# Enabling the layer editing for the first time. This triggers compilation of the necessary OpenGL shaders.
|
if (! $self->{layer_editing_initialized}) {
|
||||||
# If compilation fails, the compile log is printed into the console.
|
# Enabling the layer editing for the first time. This triggers compilation of the necessary OpenGL shaders.
|
||||||
$self->{layer_editing_initialized} = 1;
|
# If compilation fails, a message box is shown with the error codes.
|
||||||
my $shader = $self->{shader} = new Slic3r::GUI::GLShader;
|
my $shader = $self->{shader} = new Slic3r::GUI::GLShader;
|
||||||
my $info = $shader->Load($self->_fragment_shader, $self->_vertex_shader);
|
my $error_message;
|
||||||
print $info if $info;
|
if (ref($shader)) {
|
||||||
($self->{layer_preview_z_texture_id}) = glGenTextures_p(1);
|
my $info = $shader->Load($self->_fragment_shader, $self->_vertex_shader);
|
||||||
glBindTexture(GL_TEXTURE_2D, $self->{layer_preview_z_texture_id});
|
if (defined($info)) {
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
# Compilation or linking of the shaders failed.
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
|
$error_message = "Cannot compile an OpenGL Shader, therefore the Variable Layer Editing will be disabled.\n\n"
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 1);
|
. $info;
|
||||||
glBindTexture(GL_TEXTURE_2D, 0);
|
} else {
|
||||||
|
($self->{layer_preview_z_texture_id}) = glGenTextures_p(1);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, $self->{layer_preview_z_texture_id});
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 1);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, 0);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
# Cannot initialize the Shader object, some of the OpenGL capabilities are missing.
|
||||||
|
$error_message = "Cannot instantiate an OpenGL Shader, therefore the Variable Layer Editing will be disabled.\n\n"
|
||||||
|
. $shader;
|
||||||
|
}
|
||||||
|
if (defined($error_message)) {
|
||||||
|
# Don't enable the layer editing tool.
|
||||||
|
$self->{layer_editing_enabled} = 0;
|
||||||
|
# 2 means failed
|
||||||
|
$self->{layer_editing_initialized} = 2;
|
||||||
|
# Show the error message.
|
||||||
|
Wx::MessageBox($error_message, "Slic3r Error", wxOK | wxICON_EXCLAMATION, $self);
|
||||||
|
} else {
|
||||||
|
$self->{layer_editing_initialized} = 1;
|
||||||
|
}
|
||||||
|
} elsif ($self->{layer_editing_initialized} == 2) {
|
||||||
|
# Initilization failed before. Don't try to initialize and disable layer editing.
|
||||||
|
$self->{layer_editing_enabled} = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return $self->{layer_editing_enabled};
|
return $self->{layer_editing_enabled};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sub layer_editing_allowed {
|
||||||
|
my ($self) = @_;
|
||||||
|
# Allow layer editing if either the shaders were not initialized yet and we don't know
|
||||||
|
# whether it will be possible to initialize them,
|
||||||
|
# or if the initialization was done already and it failed.
|
||||||
|
return ! (defined($self->{layer_editing_initialized}) && $self->{layer_editing_initialized} == 2);
|
||||||
|
}
|
||||||
|
|
||||||
sub _first_selected_object_id {
|
sub _first_selected_object_id {
|
||||||
my ($self) = @_;
|
my ($self) = @_;
|
||||||
for my $i (0..$#{$self->volumes}) {
|
for my $i (0..$#{$self->volumes}) {
|
||||||
|
@ -24,160 +24,171 @@ sub CLONE_SKIP { 1 }
|
|||||||
# Shader constructor
|
# Shader constructor
|
||||||
sub new
|
sub new
|
||||||
{
|
{
|
||||||
# Check for required OpenGL extensions
|
# Check for required OpenGL extensions
|
||||||
return undef if (OpenGL::glpCheckExtension('GL_ARB_shader_objects'));
|
my $error_message = '';
|
||||||
return undef if (OpenGL::glpCheckExtension('GL_ARB_fragment_shader'));
|
my $extensions_valid = 1;
|
||||||
return undef if (OpenGL::glpCheckExtension('GL_ARB_vertex_shader'));
|
foreach my $i (map "GL_ARB_$_", qw(shader_objects fragment_shader vertex_shader shading_language_100)) {
|
||||||
return undef if (OpenGL::glpCheckExtension('GL_ARB_shading_language_100'));
|
if (OpenGL::glpCheckExtension($i)) {
|
||||||
# my $glsl_version = glGetString(GL_SHADING_LANGUAGE_VERSION);
|
$error_message .= "Missing OpenGL extension: $i\n";
|
||||||
# my $glsl_version_ARB = glGetString(GL_SHADING_LANGUAGE_VERSION_ARB );
|
$extensions_valid = 0;
|
||||||
# print "GLSL version: $glsl_version, ARB: $glsl_version_ARB\n";
|
}
|
||||||
|
}
|
||||||
|
|
||||||
my $this = shift;
|
if (! $extensions_valid) {
|
||||||
my $class = ref($this) || $this;
|
# Cannot create a shader object, because some of the necessary OpenGL extensions are missing.
|
||||||
my($type) = @_;
|
# Form an error message.
|
||||||
my $self = {type => uc($type)};
|
my $gl_version = glGetString(GL_VERSION);
|
||||||
bless($self,$class);
|
my $gl_vendor = glGetString(GL_VENDOR);
|
||||||
|
my $gl_renderer = glGetString(GL_RENDERER);
|
||||||
|
my $glsl_version_ARB = glGetString(GL_SHADING_LANGUAGE_VERSION_ARB) // '';
|
||||||
|
my $glsl_version = glGetString(GL_SHADING_LANGUAGE_VERSION) // $glsl_version_ARB;
|
||||||
|
$glsl_version .= 'ARB(' . $glsl_version_ARB . ')' if ($glsl_version_ARB ne '' && $glsl_version ne $glsl_version_ARB);
|
||||||
|
my $out = '';
|
||||||
|
if ($^O eq 'MSWin32') {
|
||||||
|
if ($gl_vendor eq 'Microsoft Corporation' && $renderer eq 'GDI Generic') {
|
||||||
|
$out .= "Windows is using a software OpenGL renderer.\n";
|
||||||
|
$out .= "You are either connected over remote desktop,\n";
|
||||||
|
$out .= "or a hardware acceleration is not available.\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$out .= "GL version: ${gl_version}\n";
|
||||||
|
$out .= "vendor: ${gl_vendor}\n";
|
||||||
|
$out .= "renderer: ${gl_renderer}\n";
|
||||||
|
$out .= "GLSL version: ${glsl_version}\n";
|
||||||
|
$error_message = $out . $error_message;
|
||||||
|
return $error_message;
|
||||||
|
}
|
||||||
|
|
||||||
# Get GL_SHADING_LANGUAGE_VERSION_ARB
|
my $this = shift;
|
||||||
my $shader_ver = glGetString(0x8B8C);
|
my $class = ref($this) || $this;
|
||||||
$shader_ver =~ m|([\d\.]+)|;
|
my($type) = @_;
|
||||||
$self->{version} = $1 || '0';
|
my $self = {type => uc($type)};
|
||||||
print
|
bless($self, $class);
|
||||||
return $self;
|
|
||||||
|
# Get GL_SHADING_LANGUAGE_VERSION_ARB
|
||||||
|
my $shader_ver = glGetString(0x8B8C);
|
||||||
|
$shader_ver =~ m|([\d\.]+)|;
|
||||||
|
$self->{version} = $1 || '0';
|
||||||
|
# print "Shader version: $self->{version}\n";
|
||||||
|
return $self;
|
||||||
}
|
}
|
||||||
|
|
||||||
# Shader destructor
|
# Shader destructor
|
||||||
# Must be disabled first
|
# Must be disabled first
|
||||||
sub DESTROY
|
sub DESTROY
|
||||||
{
|
{
|
||||||
my($self) = @_;
|
my($self) = @_;
|
||||||
|
|
||||||
if ($self->{program})
|
if ($self->{program}) {
|
||||||
{
|
glDetachObjectARB($self->{program},$self->{fragment_id}) if ($self->{fragment_id});
|
||||||
glDetachObjectARB($self->{program},$self->{fragment_id}) if ($self->{fragment_id});
|
glDetachObjectARB($self->{program},$self->{vertex_id}) if ($self->{vertex_id});
|
||||||
glDetachObjectARB($self->{program},$self->{vertex_id}) if ($self->{vertex_id});
|
glDeleteProgramsARB_p($self->{program});
|
||||||
glDeleteProgramsARB_p($self->{program});
|
}
|
||||||
}
|
|
||||||
|
|
||||||
glDeleteProgramsARB_p($self->{fragment_id}) if ($self->{fragment_id});
|
glDeleteProgramsARB_p($self->{fragment_id}) if ($self->{fragment_id});
|
||||||
glDeleteProgramsARB_p($self->{vertex_id}) if ($self->{vertex_id});
|
glDeleteProgramsARB_p($self->{vertex_id}) if ($self->{vertex_id});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
# Load shader strings
|
# Load shader strings
|
||||||
sub Load
|
sub Load
|
||||||
{
|
{
|
||||||
my($self,$fragment,$vertex) = @_;
|
my($self, $fragment, $vertex) = @_;
|
||||||
|
|
||||||
# Load fragment code
|
# Load fragment code
|
||||||
if ($fragment)
|
if ($fragment) {
|
||||||
{
|
$self->{fragment_id} = glCreateShaderObjectARB(GL_FRAGMENT_SHADER);
|
||||||
$self->{fragment_id} = glCreateShaderObjectARB(GL_FRAGMENT_SHADER);
|
return "glCreateShaderObjectARB failed." if (!$self->{fragment_id});
|
||||||
return undef if (!$self->{fragment_id});
|
glShaderSourceARB_p($self->{fragment_id}, $fragment);
|
||||||
|
glCompileShaderARB($self->{fragment_id});
|
||||||
|
my $stat = glGetInfoLogARB_p($self->{fragment_id});
|
||||||
|
return "Fragment shader compilation failed:\n$stat" if ($stat);
|
||||||
|
}
|
||||||
|
|
||||||
glShaderSourceARB_p($self->{fragment_id}, $fragment);
|
# Load vertex code
|
||||||
#my $frag = glGetShaderSourceARB_p($self->{fragment_id});
|
if ($vertex) {
|
||||||
#print STDERR "Loaded fragment:\n$frag\n";
|
$self->{vertex_id} = glCreateShaderObjectARB(GL_VERTEX_SHADER);
|
||||||
|
return "glCreateShaderObjectARB failed." if (!$self->{vertex_id});
|
||||||
|
glShaderSourceARB_p($self->{vertex_id}, $vertex);
|
||||||
|
glCompileShaderARB($self->{vertex_id});
|
||||||
|
$stat = glGetInfoLogARB_p($self->{vertex_id});
|
||||||
|
return "Vertex shader compilation failed:\n$stat" if ($stat);
|
||||||
|
}
|
||||||
|
|
||||||
glCompileShaderARB($self->{fragment_id});
|
# Link shaders
|
||||||
my $stat = glGetInfoLogARB_p($self->{fragment_id});
|
my $sp = glCreateProgramObjectARB();
|
||||||
return "Fragment shader: $stat" if ($stat);
|
return "glCreateProgramObjectARB failed." if (!sp);
|
||||||
}
|
glAttachObjectARB($sp, $self->{fragment_id}) if ($fragment);
|
||||||
|
glAttachObjectARB($sp, $self->{vertex_id}) if ($vertex);
|
||||||
|
glLinkProgramARB($sp);
|
||||||
|
my $linked = glGetObjectParameterivARB_p($sp, GL_OBJECT_LINK_STATUS_ARB);
|
||||||
|
if (!$linked) {
|
||||||
|
$stat = glGetInfoLogARB_p($sp);
|
||||||
|
return "Shader linking failed:\n$stat" if ($stat);
|
||||||
|
return 'Unable to link the shader.';
|
||||||
|
}
|
||||||
|
|
||||||
# Load vertex code
|
$self->{program} = $sp;
|
||||||
if ($vertex)
|
return undef;
|
||||||
{
|
|
||||||
$self->{vertex_id} = glCreateShaderObjectARB(GL_VERTEX_SHADER);
|
|
||||||
return undef if (!$self->{vertex_id});
|
|
||||||
|
|
||||||
glShaderSourceARB_p($self->{vertex_id}, $vertex);
|
|
||||||
#my $vert = glGetShaderSourceARB_p($self->{vertex_id});
|
|
||||||
#print STDERR "Loaded vertex:\n$vert\n";
|
|
||||||
|
|
||||||
glCompileShaderARB($self->{vertex_id});
|
|
||||||
$stat = glGetInfoLogARB_p($self->{vertex_id});
|
|
||||||
return "Vertex shader: $stat" if ($stat);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
# Link shaders
|
|
||||||
my $sp = glCreateProgramObjectARB();
|
|
||||||
glAttachObjectARB($sp, $self->{fragment_id}) if ($fragment);
|
|
||||||
glAttachObjectARB($sp, $self->{vertex_id}) if ($vertex);
|
|
||||||
glLinkProgramARB($sp);
|
|
||||||
my $linked = glGetObjectParameterivARB_p($sp, GL_OBJECT_LINK_STATUS_ARB);
|
|
||||||
if (!$linked)
|
|
||||||
{
|
|
||||||
$stat = glGetInfoLogARB_p($sp);
|
|
||||||
#print STDERR "Load shader: $stat\n";
|
|
||||||
return "Link shader: $stat" if ($stat);
|
|
||||||
return 'Unable to link shader';
|
|
||||||
}
|
|
||||||
|
|
||||||
$self->{program} = $sp;
|
|
||||||
|
|
||||||
return '';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
# Enable shader
|
# Enable shader
|
||||||
sub Enable
|
sub Enable
|
||||||
{
|
{
|
||||||
my($self) = @_;
|
my($self) = @_;
|
||||||
glUseProgramObjectARB($self->{program}) if ($self->{program});
|
glUseProgramObjectARB($self->{program}) if ($self->{program});
|
||||||
}
|
}
|
||||||
|
|
||||||
# Disable shader
|
# Disable shader
|
||||||
sub Disable
|
sub Disable
|
||||||
{
|
{
|
||||||
my($self) = @_;
|
my($self) = @_;
|
||||||
glUseProgramObjectARB(0) if ($self->{program});
|
glUseProgramObjectARB(0) if ($self->{program});
|
||||||
}
|
}
|
||||||
|
|
||||||
# Return shader vertex attribute ID
|
# Return shader vertex attribute ID
|
||||||
sub MapAttr
|
sub MapAttr
|
||||||
{
|
{
|
||||||
my($self,$attr) = @_;
|
my($self,$attr) = @_;
|
||||||
return undef if (!$self->{program});
|
return undef if (!$self->{program});
|
||||||
my $id = glGetAttribLocationARB_p($self->{program},$attr);
|
my $id = glGetAttribLocationARB_p($self->{program},$attr);
|
||||||
return undef if ($id < 0);
|
return undef if ($id < 0);
|
||||||
return $id;
|
return $id;
|
||||||
}
|
}
|
||||||
|
|
||||||
# Return shader uniform variable ID
|
# Return shader uniform variable ID
|
||||||
sub Map
|
sub Map
|
||||||
{
|
{
|
||||||
my($self,$var) = @_;
|
my($self,$var) = @_;
|
||||||
return undef if (!$self->{program});
|
return undef if (!$self->{program});
|
||||||
my $id = glGetUniformLocationARB_p($self->{program},$var);
|
my $id = glGetUniformLocationARB_p($self->{program},$var);
|
||||||
return undef if ($id < 0);
|
return undef if ($id < 0);
|
||||||
return $id;
|
return $id;
|
||||||
}
|
}
|
||||||
|
|
||||||
# Set shader vector
|
# Set shader vector
|
||||||
sub SetVector
|
sub SetVector
|
||||||
{
|
{
|
||||||
my($self,$var,@values) = @_;
|
my($self,$var,@values) = @_;
|
||||||
|
|
||||||
my $id = $self->Map($var);
|
my $id = $self->Map($var);
|
||||||
return 'Unable to map $var' if (!defined($id));
|
return 'Unable to map $var' if (!defined($id));
|
||||||
|
|
||||||
my $count = scalar(@values);
|
my $count = scalar(@values);
|
||||||
eval('glUniform'.$count.'fARB($id,@values)');
|
eval('glUniform'.$count.'fARB($id,@values)');
|
||||||
|
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
# Set shader 4x4 matrix
|
# Set shader 4x4 matrix
|
||||||
sub SetMatrix
|
sub SetMatrix
|
||||||
{
|
{
|
||||||
my($self,$var,$oga) = @_;
|
my($self,$var,$oga) = @_;
|
||||||
|
|
||||||
my $id = $self->Map($var);
|
my $id = $self->Map($var);
|
||||||
return 'Unable to map $var' if (!defined($id));
|
return 'Unable to map $var' if (!defined($id));
|
||||||
|
|
||||||
glUniformMatrix4fvARB_c($id,1,0,$oga->ptr());
|
glUniformMatrix4fvARB_c($id,1,0,$oga->ptr());
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
1;
|
1;
|
||||||
|
@ -528,6 +528,16 @@ sub _on_select_preset {
|
|||||||
sub on_layer_editing_toggled {
|
sub on_layer_editing_toggled {
|
||||||
my ($self, $new_state) = @_;
|
my ($self, $new_state) = @_;
|
||||||
$self->{canvas3D}->layer_editing_enabled($new_state);
|
$self->{canvas3D}->layer_editing_enabled($new_state);
|
||||||
|
if ($new_state && ! $self->{canvas3D}->layer_editing_enabled) {
|
||||||
|
# Initialization of the OpenGL shaders failed. Disable the tool.
|
||||||
|
if ($self->{htoolbar}) {
|
||||||
|
$self->{htoolbar}->EnableTool(TB_LAYER_EDITING, 0);
|
||||||
|
$self->{htoolbar}->ToggleTool(TB_LAYER_EDITING, 0);
|
||||||
|
} else {
|
||||||
|
$self->{"btn_layer_editing"}->Disable;
|
||||||
|
$self->{"btn_layer_editing"}->SetValue(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
$self->{canvas3D}->update;
|
$self->{canvas3D}->update;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1661,7 +1671,8 @@ sub on_config_change {
|
|||||||
}
|
}
|
||||||
$self->{canvas3D}->layer_editing_enabled(0);
|
$self->{canvas3D}->layer_editing_enabled(0);
|
||||||
$self->{canvas3D}->update;
|
$self->{canvas3D}->update;
|
||||||
} else {
|
} elsif ($self->{canvas3D}->layer_editing_allowed) {
|
||||||
|
# Want to allow the layer editing, but do it only if the OpenGL supports it.
|
||||||
if ($self->{htoolbar}) {
|
if ($self->{htoolbar}) {
|
||||||
$self->{htoolbar}->EnableTool(TB_LAYER_EDITING, 1);
|
$self->{htoolbar}->EnableTool(TB_LAYER_EDITING, 1);
|
||||||
} else {
|
} else {
|
||||||
@ -1774,17 +1785,18 @@ sub object_list_changed {
|
|||||||
|
|
||||||
# Enable/disable buttons depending on whether there are any objects on the platter.
|
# Enable/disable buttons depending on whether there are any objects on the platter.
|
||||||
my $have_objects = @{$self->{objects}} ? 1 : 0;
|
my $have_objects = @{$self->{objects}} ? 1 : 0;
|
||||||
|
my $variable_layer_height_allowed = $self->{config}->variable_layer_height && $self->{canvas3D}->layer_editing_allowed;
|
||||||
if ($self->{htoolbar}) {
|
if ($self->{htoolbar}) {
|
||||||
# On OSX or Linux
|
# On OSX or Linux
|
||||||
$self->{htoolbar}->EnableTool($_, $have_objects)
|
$self->{htoolbar}->EnableTool($_, $have_objects)
|
||||||
for (TB_RESET, TB_ARRANGE, TB_LAYER_EDITING);
|
for (TB_RESET, TB_ARRANGE, TB_LAYER_EDITING);
|
||||||
$self->{htoolbar}->EnableTool(TB_LAYER_EDITING, 0) if (! $self->{config}->variable_layer_height);
|
$self->{htoolbar}->EnableTool(TB_LAYER_EDITING, 0) if (! $variable_layer_height_allowed);
|
||||||
} else {
|
} else {
|
||||||
# On MSW
|
# On MSW
|
||||||
my $method = $have_objects ? 'Enable' : 'Disable';
|
my $method = $have_objects ? 'Enable' : 'Disable';
|
||||||
$self->{"btn_$_"}->$method
|
$self->{"btn_$_"}->$method
|
||||||
for grep $self->{"btn_$_"}, qw(reset arrange reslice export_gcode export_stl print send_gcode layer_editing);
|
for grep $self->{"btn_$_"}, qw(reset arrange reslice export_gcode export_stl print send_gcode layer_editing);
|
||||||
$self->{"btn_layer_editing"}->Disable if (! $self->{config}->variable_layer_height);
|
$self->{"btn_layer_editing"}->Disable if (! $variable_layer_height_allowed);
|
||||||
}
|
}
|
||||||
|
|
||||||
my $export_in_progress = $self->{export_gcode_output_file} || $self->{send_gcode_file};
|
my $export_in_progress = $self->{export_gcode_output_file} || $self->{send_gcode_file};
|
||||||
|
Loading…
Reference in New Issue
Block a user