diff --git a/lib/Slic3r/GUI/3DScene.pm b/lib/Slic3r/GUI/3DScene.pm index db05860da..75a154281 100644 --- a/lib/Slic3r/GUI/3DScene.pm +++ b/lib/Slic3r/GUI/3DScene.pm @@ -68,6 +68,7 @@ __PACKAGE__->mk_accessors( qw(_quat _dirty init _zoom _legend_enabled + _warning_enabled _apply_zoom_to_volumes_filter ) ); @@ -142,6 +143,7 @@ sub new { $self->_sphi(45); $self->_zoom(1); $self->_legend_enabled(0); + $self->_warning_enabled(0); $self->use_plain_shader(0); $self->_apply_zoom_to_volumes_filter(0); @@ -217,7 +219,12 @@ sub new { sub set_legend_enabled { my ($self, $value) = @_; - $self->_legend_enabled($value); + $self->_legend_enabled($value); +} + +sub set_warning_enabled { + my ($self, $value) = @_; + $self->_warning_enabled($value); } sub Destroy { @@ -1300,11 +1307,16 @@ sub Render { } glEnable(GL_LIGHTING); - + # draw objects if (! $self->use_plain_shader) { $self->draw_volumes; } elsif ($self->UseVBOs) { + if ($self->enable_picking) { + $self->mark_volumes_for_layer_height; + $self->volumes->set_print_box($self->bed_bounding_box->x_min, $self->bed_bounding_box->y_min, 0.0, $self->bed_bounding_box->x_max, $self->bed_bounding_box->y_max, $self->{config}->get('max_print_height')); + $self->volumes->update_outside_state($self->{config}, 0); + } $self->{plain_shader}->enable if $self->{plain_shader}; $self->volumes->render_VBOs; $self->{plain_shader}->disable; @@ -1331,6 +1343,9 @@ sub Render { glDisable(GL_BLEND); } + # draw warning message + $self->draw_warning; + # draw gcode preview legend $self->draw_legend; @@ -1349,36 +1364,10 @@ sub draw_volumes { glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_NORMAL_ARRAY); - my $z_cursor_relative = $self->_variable_layer_thickness_bar_mouse_cursor_z_relative; foreach my $volume_idx (0..$#{$self->volumes}) { my $volume = $self->volumes->[$volume_idx]; - my $shader_active = 0; - my $object_id = int($volume->select_group_id / 1000000); - if ($self->layer_editing_enabled && ! $fakecolor && $volume->selected && $self->{layer_height_edit_shader} && - $volume->has_layer_height_texture && $object_id < $self->{print}->object_count) { - # Update the height texture if the ModelObject::layer_height_texture is invalid. - $volume->generate_layer_height_texture($self->{print}->get_object($object_id), 0); - $self->{layer_height_edit_shader}->enable; - $self->{layer_height_edit_shader}->set_uniform('z_to_texture_row', $volume->layer_height_texture_z_to_row_id); - $self->{layer_height_edit_shader}->set_uniform('z_texture_row_to_normalized', 1. / $volume->layer_height_texture_height); - $self->{layer_height_edit_shader}->set_uniform('z_cursor', $volume->bounding_box->z_max * $z_cursor_relative); - $self->{layer_height_edit_shader}->set_uniform('z_cursor_band_width', $self->{layer_height_edit_band_width}); - glBindTexture(GL_TEXTURE_2D, $self->{layer_preview_z_texture_id}); -# glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_LEVEL, 0); -# glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 1); - glTexImage2D_c(GL_TEXTURE_2D, 0, GL_RGBA8, $volume->layer_height_texture_width, $volume->layer_height_texture_height, - 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); - glTexImage2D_c(GL_TEXTURE_2D, 1, GL_RGBA8, $volume->layer_height_texture_width / 2, $volume->layer_height_texture_height / 2, - 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); -# glPixelStorei(GL_UNPACK_ALIGNMENT, 1); -# glPixelStorei(GL_UNPACK_ROW_LENGTH, $self->{layer_preview_z_texture_width}); - glTexSubImage2D_c(GL_TEXTURE_2D, 0, 0, 0, $volume->layer_height_texture_width, $volume->layer_height_texture_height, - GL_RGBA, GL_UNSIGNED_BYTE, $volume->layer_height_texture_data_ptr_level0); - glTexSubImage2D_c(GL_TEXTURE_2D, 1, 0, 0, $volume->layer_height_texture_width / 2, $volume->layer_height_texture_height / 2, - GL_RGBA, GL_UNSIGNED_BYTE, $volume->layer_height_texture_data_ptr_level1); - $shader_active = 1; - } elsif ($fakecolor) { + if ($fakecolor) { # Object picking mode. Render the object with a color encoding the object index. my $r = ($volume_idx & 0x000000FF) >> 0; my $g = ($volume_idx & 0x0000FF00) >> 8; @@ -1393,11 +1382,6 @@ sub draw_volumes { } $volume->render; - - if ($shader_active) { - glBindTexture(GL_TEXTURE_2D, 0); - $self->{layer_height_edit_shader}->disable; - } } glDisableClientState(GL_NORMAL_ARRAY); glDisable(GL_BLEND); @@ -1412,6 +1396,22 @@ sub draw_volumes { glDisableClientState(GL_VERTEX_ARRAY); } +sub mark_volumes_for_layer_height { + my ($self) = @_; + + foreach my $volume_idx (0..$#{$self->volumes}) { + my $volume = $self->volumes->[$volume_idx]; + my $object_id = int($volume->select_group_id / 1000000); + if ($self->layer_editing_enabled && $volume->selected && $self->{layer_height_edit_shader} && + $volume->has_layer_height_texture && $object_id < $self->{print}->object_count) { + $volume->set_layer_height_texture_data($self->{layer_preview_z_texture_id}, $self->{layer_height_edit_shader}->shader_program_id, + $self->{print}->get_object($object_id), $self->_variable_layer_thickness_bar_mouse_cursor_z_relative, $self->{layer_height_edit_band_width}); + } else { + $volume->reset_layer_height_texture_data(); + } + } +} + sub _load_image_set_texture { my ($self, $file_name) = @_; # Load a PNG with an alpha channel. @@ -1603,31 +1603,65 @@ sub draw_active_object_annotations { sub draw_legend { my ($self) = @_; - if ($self->_legend_enabled) - { - # If the legend texture has not been loaded into the GPU, do it now. - my $tex_id = Slic3r::GUI::_3DScene::finalize_legend_texture; - if ($tex_id > 0) - { - my $tex_w = Slic3r::GUI::_3DScene::get_legend_texture_width; - my $tex_h = Slic3r::GUI::_3DScene::get_legend_texture_height; - if (($tex_w > 0) && ($tex_h > 0)) - { - glDisable(GL_DEPTH_TEST); - glPushMatrix(); - glLoadIdentity(); - - my ($cw, $ch) = $self->GetSizeWH; - - my $l = (-0.5 * $cw) / $self->_zoom; - my $t = (0.5 * $ch) / $self->_zoom; - my $r = $l + $tex_w / $self->_zoom; - my $b = $t - $tex_h / $self->_zoom; - $self->_render_texture($tex_id, $l, $r, $b, $t); + if (!$self->_legend_enabled) { + return; + } - glPopMatrix(); - glEnable(GL_DEPTH_TEST); - } + # If the legend texture has not been loaded into the GPU, do it now. + my $tex_id = Slic3r::GUI::_3DScene::finalize_legend_texture; + if ($tex_id > 0) + { + my $tex_w = Slic3r::GUI::_3DScene::get_legend_texture_width; + my $tex_h = Slic3r::GUI::_3DScene::get_legend_texture_height; + if (($tex_w > 0) && ($tex_h > 0)) + { + glDisable(GL_DEPTH_TEST); + glPushMatrix(); + glLoadIdentity(); + + my ($cw, $ch) = $self->GetSizeWH; + + my $l = (-0.5 * $cw) / $self->_zoom; + my $t = (0.5 * $ch) / $self->_zoom; + my $r = $l + $tex_w / $self->_zoom; + my $b = $t - $tex_h / $self->_zoom; + $self->_render_texture($tex_id, $l, $r, $b, $t); + + glPopMatrix(); + glEnable(GL_DEPTH_TEST); + } + } +} + +sub draw_warning { + my ($self) = @_; + + if (!$self->_warning_enabled) { + return; + } + + # If the warning texture has not been loaded into the GPU, do it now. + my $tex_id = Slic3r::GUI::_3DScene::finalize_warning_texture; + if ($tex_id > 0) + { + my $tex_w = Slic3r::GUI::_3DScene::get_warning_texture_width; + my $tex_h = Slic3r::GUI::_3DScene::get_warning_texture_height; + if (($tex_w > 0) && ($tex_h > 0)) + { + glDisable(GL_DEPTH_TEST); + glPushMatrix(); + glLoadIdentity(); + + my ($cw, $ch) = $self->GetSizeWH; + + my $l = (-0.5 * $tex_w) / $self->_zoom; + my $t = (-0.5 * $ch + $tex_h) / $self->_zoom; + my $r = $l + $tex_w / $self->_zoom; + my $b = $t - $tex_h / $self->_zoom; + $self->_render_texture($tex_id, $l, $r, $b, $t); + + glPopMatrix(); + glEnable(GL_DEPTH_TEST); } } } @@ -1696,57 +1730,77 @@ sub _vertex_shader_Gouraud { return <<'VERTEX'; #version 110 -#define INTENSITY_CORRECTION 0.7 +#define INTENSITY_CORRECTION 0.6 -#define LIGHT_TOP_DIR -0.6/1.31, 0.6/1.31, 1./1.31 +// 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.5 * INTENSITY_CORRECTION) -#define LIGHT_TOP_SHININESS 50. +#define LIGHT_TOP_SPECULAR (0.25 * INTENSITY_CORRECTION) +#define LIGHT_TOP_SHININESS 200.0 -#define LIGHT_FRONT_DIR 1./1.43, 0.2/1.43, 1./1.43 +// 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 LIGHT_FRONT_SPECULAR (0.0 * INTENSITY_CORRECTION) -#define LIGHT_FRONT_SHININESS 50. +//#define LIGHT_FRONT_SPECULAR (0.0 * INTENSITY_CORRECTION) +//#define LIGHT_FRONT_SHININESS 5.0 #define INTENSITY_AMBIENT 0.3 -varying float intensity_specular; -varying float intensity_tainted; +const vec3 ZERO = vec3(0.0, 0.0, 0.0); + +struct PrintBoxDetection +{ + vec3 min; + vec3 max; + // xyz contains the offset, if w == 1.0 detection needs to be performed + vec4 volume_origin; +}; + +uniform PrintBoxDetection print_box; + +// x = tainted, y = specular; +varying vec2 intensity; + +varying vec3 delta_box_min; +varying vec3 delta_box_max; void main() { - vec3 eye, normal, lightDir, viewVector, halfVector; - float NdotL, NdotHV; + vec3 eye = -normalize((gl_ModelViewMatrix * gl_Vertex).xyz); - eye = vec3(0., 0., 1.); - - // First transform the normal into eye space and normalize the result. - normal = normalize(gl_NormalMatrix * gl_Normal); + // First transform the normal into camera space and normalize the result. + vec3 normal = normalize(gl_NormalMatrix * gl_Normal); // Now normalize the light's direction. Note that according to the OpenGL specification, the light is stored in eye space. // Also since we're talking about a directional light, the position field is actually direction. - lightDir = vec3(LIGHT_TOP_DIR); - halfVector = normalize(lightDir + eye); + vec3 halfVector = normalize(LIGHT_TOP_DIR + eye); // 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. - NdotL = max(dot(normal, lightDir), 0.0); + float NdotL = max(dot(normal, LIGHT_TOP_DIR), 0.0); - intensity_tainted = INTENSITY_AMBIENT + NdotL * LIGHT_TOP_DIFFUSE; - intensity_specular = 0.; + intensity.x = INTENSITY_AMBIENT + NdotL * LIGHT_TOP_DIFFUSE; + intensity.y = 0.0; if (NdotL > 0.0) - intensity_specular = LIGHT_TOP_SPECULAR * pow(max(dot(normal, halfVector), 0.0), LIGHT_TOP_SHININESS); + intensity.y += LIGHT_TOP_SPECULAR * pow(max(dot(normal, halfVector), 0.0), LIGHT_TOP_SHININESS); - // Perform the same lighting calculation for the 2nd light source. - lightDir = vec3(LIGHT_FRONT_DIR); -// halfVector = normalize(lightDir + eye); - NdotL = max(dot(normal, lightDir), 0.0); - intensity_tainted += NdotL * LIGHT_FRONT_DIFFUSE; + // 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; - // compute the specular term if NdotL is larger than zero -// if (NdotL > 0.0) -// intensity_specular += LIGHT_FRONT_SPECULAR * pow(max(dot(normal, halfVector), 0.0), LIGHT_FRONT_SHININESS); + // compute deltas for out of print volume detection (world coordinates) + if (print_box.volume_origin.w == 1.0) + { + vec3 v = gl_Vertex.xyz + print_box.volume_origin.xyz; + delta_box_min = v - print_box.min; + delta_box_max = v - print_box.max; + } + else + { + delta_box_min = ZERO; + delta_box_max = ZERO; + } gl_Position = ftransform(); } @@ -1758,16 +1812,25 @@ sub _fragment_shader_Gouraud { return <<'FRAGMENT'; #version 110 -varying float intensity_specular; -varying float intensity_tainted; +const vec3 ZERO = vec3(0.0, 0.0, 0.0); + +// x = tainted, y = specular; +varying vec2 intensity; + +varying vec3 delta_box_min; +varying vec3 delta_box_max; uniform vec4 uniform_color; void main() { - gl_FragColor = - vec4(intensity_specular, intensity_specular, intensity_specular, 0.) + uniform_color * intensity_tainted; - gl_FragColor.a = uniform_color.a; + gl_FragColor = vec4(intensity.y, intensity.y, intensity.y, 0.0) + uniform_color * intensity.x; + + // if the fragment is outside the print volume darken it and set it as transparent + if (any(lessThan(delta_box_min, ZERO)) || any(greaterThan(delta_box_max, ZERO))) + gl_FragColor = vec4(mix(gl_FragColor.xyz, ZERO, 0.5), 0.5 * uniform_color.a); + else + gl_FragColor.a = uniform_color.a; } FRAGMENT @@ -1832,6 +1895,7 @@ void main() { // compute the specular term into spec // intensity_specular += LIGHT_FRONT_SPECULAR * pow(max(dot(h,normal), 0.0), LIGHT_FRONT_SHININESS); } + gl_FragColor = max( vec4(intensity_specular, intensity_specular, intensity_specular, 0.) + uniform_color * intensity_tainted, INTENSITY_AMBIENT * uniform_color); @@ -1844,61 +1908,55 @@ sub _vertex_shader_variable_layer_height { return <<'VERTEX'; #version 110 -#define LIGHT_TOP_DIR 0., 1., 0. -#define LIGHT_TOP_DIFFUSE 0.2 -#define LIGHT_TOP_SPECULAR 0.3 -#define LIGHT_TOP_SHININESS 50. +#define INTENSITY_CORRECTION 0.6 -#define LIGHT_FRONT_DIR 0., 0., 1. -#define LIGHT_FRONT_DIFFUSE 0.5 -#define LIGHT_FRONT_SPECULAR 0.3 -#define LIGHT_FRONT_SHININESS 50. +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.25 * INTENSITY_CORRECTION) +#define LIGHT_TOP_SHININESS 200.0 -#define INTENSITY_AMBIENT 0.1 +const vec3 LIGHT_FRONT_DIR = vec3(0.6985074, 0.1397015, 0.6985074); +#define LIGHT_FRONT_DIFFUSE (0.3 * INTENSITY_CORRECTION) +//#define LIGHT_FRONT_SPECULAR (0.0 * INTENSITY_CORRECTION) +//#define LIGHT_FRONT_SHININESS 5.0 + +#define INTENSITY_AMBIENT 0.3 uniform float z_to_texture_row; -varying float intensity_specular; -varying float intensity_tainted; + +// x = tainted, y = specular; +varying vec2 intensity; + varying float object_z; void main() { - vec3 eye, normal, lightDir, viewVector, halfVector; - float NdotL, NdotHV; + vec3 eye = -normalize((gl_ModelViewMatrix * gl_Vertex).xyz); -// eye = gl_ModelViewMatrixInverse[3].xyz; - eye = vec3(0., 0., 1.); - - // First transform the normal into eye space and normalize the result. - normal = normalize(gl_NormalMatrix * gl_Normal); + // First transform the normal into camera space and normalize the result. + vec3 normal = normalize(gl_NormalMatrix * gl_Normal); // Now normalize the light's direction. Note that according to the OpenGL specification, the light is stored in eye space. // Also since we're talking about a directional light, the position field is actually direction. - lightDir = vec3(LIGHT_TOP_DIR); - halfVector = normalize(lightDir + eye); + vec3 halfVector = normalize(LIGHT_TOP_DIR + eye); // 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. - NdotL = max(dot(normal, lightDir), 0.0); + float NdotL = max(dot(normal, LIGHT_TOP_DIR), 0.0); - intensity_tainted = INTENSITY_AMBIENT + NdotL * LIGHT_TOP_DIFFUSE; - intensity_specular = 0.; + intensity.x = INTENSITY_AMBIENT + NdotL * LIGHT_TOP_DIFFUSE; + intensity.y = 0.0; -// if (NdotL > 0.0) -// intensity_specular = LIGHT_TOP_SPECULAR * pow(max(dot(normal, halfVector), 0.0), LIGHT_TOP_SHININESS); - - // Perform the same lighting calculation for the 2nd light source. - lightDir = vec3(LIGHT_FRONT_DIR); - halfVector = normalize(lightDir + eye); - NdotL = max(dot(normal, lightDir), 0.0); - intensity_tainted += NdotL * LIGHT_FRONT_DIFFUSE; - - // compute the specular term if NdotL is larger than zero if (NdotL > 0.0) - intensity_specular += LIGHT_FRONT_SPECULAR * pow(max(dot(normal, halfVector), 0.0), LIGHT_FRONT_SHININESS); + intensity.y += LIGHT_TOP_SPECULAR * pow(max(dot(normal, halfVector), 0.0), LIGHT_TOP_SHININESS); + // Perform the same lighting calculation for the 2nd light source (no specular) + NdotL = max(dot(normal, LIGHT_FRONT_DIR), 0.0); + + intensity.x += NdotL * LIGHT_FRONT_DIFFUSE; + // Scaled to widths of the Z texture. - object_z = gl_Vertex.z / gl_Vertex.w; + object_z = gl_Vertex.z; gl_Position = ftransform(); } @@ -1917,13 +1975,14 @@ uniform sampler2D z_texture; // Scaling from the Z texture rows coordinate to the normalized texture row coordinate. uniform float z_to_texture_row; uniform float z_texture_row_to_normalized; - -varying float intensity_specular; -varying float intensity_tainted; -varying float object_z; uniform float z_cursor; uniform float z_cursor_band_width; +// x = tainted, y = specular; +varying vec2 intensity; + +varying float object_z; + void main() { float object_z_row = z_to_texture_row * object_z; @@ -1942,15 +2001,12 @@ void main() float lod = clamp(0.5 * log2(max(dx_vtc*dx_vtc, dy_vtc*dy_vtc)), 0., 1.); // Sample the Z texture. Texture coordinates are normalized to <0, 1>. vec4 color = - (1. - lod) * texture2D(z_texture, vec2(z_texture_col, z_texture_row_to_normalized * (z_texture_row + 0.5 )), -10000.) + - lod * texture2D(z_texture, vec2(z_texture_col, z_texture_row_to_normalized * (z_texture_row * 2. + 1.)), 10000.); + mix(texture2D(z_texture, vec2(z_texture_col, z_texture_row_to_normalized * (z_texture_row + 0.5 )), -10000.), + texture2D(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(intensity_specular, intensity_specular, intensity_specular, 1.) + - (1. - z_blend) * intensity_tainted * color + - z_blend * vec4(1., 1., 0., 0.); - // and reset the transparency. - gl_FragColor.a = 1.; + vec4(intensity.y, intensity.y, intensity.y, 1.0) + intensity.x * mix(color, vec4(1.0, 1.0, 0.0, 1.0), z_blend); } FRAGMENT diff --git a/lib/Slic3r/GUI/Plater.pm b/lib/Slic3r/GUI/Plater.pm index a99bbddef..423cefe59 100644 --- a/lib/Slic3r/GUI/Plater.pm +++ b/lib/Slic3r/GUI/Plater.pm @@ -55,6 +55,7 @@ sub new { serial_port serial_speed octoprint_host octoprint_apikey octoprint_cafile nozzle_diameter single_extruder_multi_material wipe_tower wipe_tower_x wipe_tower_y wipe_tower_width wipe_tower_per_color_wipe extruder_colour filament_colour + max_print_height )]); # C++ Slic3r::Model with Perl extensions in Slic3r/Model.pm $self->{model} = Slic3r::Model->new; @@ -113,6 +114,7 @@ sub new { $self->{canvas3D}->set_on_decrease_objects(sub { $self->decrease() }); $self->{canvas3D}->set_on_remove_object(sub { $self->remove() }); $self->{canvas3D}->set_on_instances_moved($on_instances_moved); + $self->{canvas3D}->use_plain_shader(1); $self->{canvas3D}->set_on_wipe_tower_moved(sub { my ($new_pos_3f) = @_; my $cfg = Slic3r::Config->new; @@ -1741,6 +1743,8 @@ sub on_config_change { $update_scheduled = 1; my $extruder_colors = $config->get('extruder_colour'); $self->{preview3D}->set_number_extruders(scalar(@{$extruder_colors})); + } elsif ($opt_key eq 'max_print_height') { + $update_scheduled = 1; } } diff --git a/lib/Slic3r/GUI/Plater/3D.pm b/lib/Slic3r/GUI/Plater/3D.pm index 1c123e741..37e1321ae 100644 --- a/lib/Slic3r/GUI/Plater/3D.pm +++ b/lib/Slic3r/GUI/Plater/3D.pm @@ -8,6 +8,8 @@ use Wx qw(:misc :pen :brush :sizer :font :cursor :keycode wxTAB_TRAVERSAL); use Wx::Event qw(EVT_KEY_DOWN EVT_CHAR); use base qw(Slic3r::GUI::3DScene Class::Accessor); +use Wx::Locale gettext => 'L'; + __PACKAGE__->mk_accessors(qw( on_arrange on_rotate_object_left on_rotate_object_right on_scale_object_uniformly on_remove_object on_increase_objects on_decrease_objects)); @@ -208,6 +210,19 @@ sub reload_scene { $self->{model}->bounding_box->z_max, $self->UseVBOs); } } + + # checks for geometry outside the print volume to render it accordingly + if (scalar @{$self->volumes} > 0) + { + if (!$self->{model}->fits_print_volume($self->{config})) { + $self->set_warning_enabled(1); + Slic3r::GUI::_3DScene::generate_warning_texture(L("Detected object outside print volume")); + } else { + $self->set_warning_enabled(0); + $self->volumes->update_outside_state($self->{config}, 1); + Slic3r::GUI::_3DScene::reset_warning_texture(); + } + } } sub update_bed_size { diff --git a/xs/src/libslic3r/BoundingBox.hpp b/xs/src/libslic3r/BoundingBox.hpp index a7334308c..92a2bd451 100644 --- a/xs/src/libslic3r/BoundingBox.hpp +++ b/xs/src/libslic3r/BoundingBox.hpp @@ -94,6 +94,14 @@ public: void translate(const Pointf3 &pos) { this->translate(pos.x, pos.y, pos.z); } void offset(coordf_t delta); PointClass center() const; + + bool contains(const PointClass &point) const { + return BoundingBoxBase::contains(point) && point.z >= this->min.z && point.z <= this->max.z; + } + + bool contains(const BoundingBox3Base& other) const { + return contains(other.min) && contains(other.max); + } }; class BoundingBox : public BoundingBoxBase diff --git a/xs/src/libslic3r/Model.cpp b/xs/src/libslic3r/Model.cpp index f394e553c..6f1ce1ce5 100644 --- a/xs/src/libslic3r/Model.cpp +++ b/xs/src/libslic3r/Model.cpp @@ -222,7 +222,7 @@ bool Model::add_default_instances() } // this returns the bounding box of the *transformed* instances -BoundingBoxf3 Model::bounding_box() +BoundingBoxf3 Model::bounding_box() const { BoundingBoxf3 bb; for (ModelObject *o : this->objects) @@ -230,6 +230,14 @@ BoundingBoxf3 Model::bounding_box() return bb; } +BoundingBoxf3 Model::transformed_bounding_box() const +{ + BoundingBoxf3 bb; + for (const ModelObject* obj : this->objects) + bb.merge(obj->tight_bounding_box(false)); + return bb; +} + void Model::center_instances_around_point(const Pointf &point) { // BoundingBoxf3 bb = this->bounding_box(); @@ -428,6 +436,32 @@ void Model::adjust_min_z() } } +bool Model::fits_print_volume(const DynamicPrintConfig* config) const +{ + if (config == nullptr) + return false; + + if (objects.empty()) + return true; + + const ConfigOptionPoints* opt = dynamic_cast(config->option("bed_shape")); + if (opt == nullptr) + return false; + + BoundingBox bed_box_2D = get_extents(Polygon::new_scale(opt->values)); + BoundingBoxf3 print_volume(Pointf3(unscale(bed_box_2D.min.x), unscale(bed_box_2D.min.y), 0.0), Pointf3(unscale(bed_box_2D.max.x), unscale(bed_box_2D.max.y), config->opt_float("max_print_height"))); + return print_volume.contains(transformed_bounding_box()); +} + +bool Model::fits_print_volume(const FullPrintConfig &config) const +{ + if (objects.empty()) + return true; + BoundingBox bed_box_2D = get_extents(Polygon::new_scale(config.bed_shape.values)); + BoundingBoxf3 print_volume(Pointf3(unscale(bed_box_2D.min.x), unscale(bed_box_2D.min.y), 0.0), Pointf3(unscale(bed_box_2D.max.x), unscale(bed_box_2D.max.y), config.max_print_height)); + return print_volume.contains(transformed_bounding_box()); +} + ModelObject::ModelObject(Model *model, const ModelObject &other, bool copy_volumes) : name(other.name), input_file(other.input_file), @@ -558,7 +592,7 @@ void ModelObject::clear_instances() // Returns the bounding box of the transformed instances. // This bounding box is approximate and not snug. -BoundingBoxf3 ModelObject::bounding_box() +const BoundingBoxf3& ModelObject::bounding_box() { if (! m_bounding_box_valid) { BoundingBoxf3 raw_bbox; @@ -574,6 +608,54 @@ BoundingBoxf3 ModelObject::bounding_box() return m_bounding_box; } +BoundingBoxf3 ModelObject::tight_bounding_box(bool include_modifiers) const +{ + BoundingBoxf3 bb; + + for (const ModelVolume* vol : this->volumes) + { + if (include_modifiers || !vol->modifier) + { + for (const ModelInstance* inst : this->instances) + { + double c = cos(inst->rotation); + double s = sin(inst->rotation); + + for (int f = 0; f < vol->mesh.stl.stats.number_of_facets; ++f) + { + const stl_facet& facet = vol->mesh.stl.facet_start[f]; + + for (int i = 0; i < 3; ++i) + { + // original point + const stl_vertex& v = facet.vertex[i]; + Pointf3 p((double)v.x, (double)v.y, (double)v.z); + + // scale + p.x *= inst->scaling_factor; + p.y *= inst->scaling_factor; + p.z *= inst->scaling_factor; + + // rotate Z + double x = p.x; + double y = p.y; + p.x = c * x - s * y; + p.y = s * x + c * y; + + // translate + p.x += inst->offset.x; + p.y += inst->offset.y; + + bb.merge(p); + } + } + } + } + } + + return bb; +} + // A mesh containing all transformed instances of this object. TriangleMesh ModelObject::mesh() const { @@ -690,10 +772,7 @@ void ModelObject::transform(const float* matrix3x4) v->mesh.transform(matrix3x4); } -//##################################################################################################### origin_translation = Pointf3(0.0, 0.0, 0.0); -// origin_translation = Pointf3(0.0f, 0.0f, 0.0f); -//##################################################################################################### invalidate_bounding_box(); } diff --git a/xs/src/libslic3r/Model.hpp b/xs/src/libslic3r/Model.hpp index d3faf38ef..bf7f60e36 100644 --- a/xs/src/libslic3r/Model.hpp +++ b/xs/src/libslic3r/Model.hpp @@ -102,8 +102,12 @@ public: // Returns the bounding box of the transformed instances. // This bounding box is approximate and not snug. - BoundingBoxf3 bounding_box(); + // This bounding box is being cached. + const BoundingBoxf3& bounding_box(); void invalidate_bounding_box() { m_bounding_box_valid = false; } + // Returns a snug bounding box of the transformed instances. + // This bounding box is not being cached. + BoundingBoxf3 tight_bounding_box(bool include_modifiers) const; // A mesh containing all transformed instances of this object. TriangleMesh mesh() const; @@ -260,7 +264,10 @@ public: void delete_material(t_model_material_id material_id); void clear_materials(); bool add_default_instances(); - BoundingBoxf3 bounding_box(); + // Returns approximate axis aligned bounding box of this model + BoundingBoxf3 bounding_box() const; + // Returns tight axis aligned bounding box of this model + BoundingBoxf3 transformed_bounding_box() const; void center_instances_around_point(const Pointf &point); void translate(coordf_t x, coordf_t y, coordf_t z) { for (ModelObject *o : this->objects) o->translate(x, y, z); } TriangleMesh mesh() const; @@ -276,6 +283,10 @@ public: // Ensures that the min z of the model is not negative void adjust_min_z(); + // Returs true if this model is contained into the print volume defined inside the given config + bool fits_print_volume(const DynamicPrintConfig* config) const; + bool fits_print_volume(const FullPrintConfig &config) const; + void print_info() const { for (const ModelObject *o : this->objects) o->print_info(); } }; diff --git a/xs/src/libslic3r/Print.cpp b/xs/src/libslic3r/Print.cpp index c689929c6..13f4fab79 100644 --- a/xs/src/libslic3r/Print.cpp +++ b/xs/src/libslic3r/Print.cpp @@ -120,6 +120,7 @@ bool Print::invalidate_state_by_config_options(const std::vectorobjects) { + if (! print_volume.contains(po->model_object()->tight_bounding_box(false))) + return "Some objects are outside of the print volume."; + } + if (this->config.complete_objects) { // Check horizontal clearance. { diff --git a/xs/src/libslic3r/PrintConfig.cpp b/xs/src/libslic3r/PrintConfig.cpp index 2b95ffa84..a1ca7cbfe 100644 --- a/xs/src/libslic3r/PrintConfig.cpp +++ b/xs/src/libslic3r/PrintConfig.cpp @@ -803,6 +803,13 @@ PrintConfigDef::PrintConfigDef() def->min = 0; def->default_value = new ConfigOptionFloats { 0. }; + def = this->add("max_print_height", coFloat); + def->label = L("Max print height"); + def->tooltip = L("Set this to the maximum height that can be reached by your extruder while printing."); + def->sidetext = L("mm"); + def->cli = "max-print-height=f"; + def->default_value = new ConfigOptionFloat(200.0); + def = this->add("max_print_speed", coFloat); def->label = L("Max print speed"); def->tooltip = L("When setting other speed settings to 0 Slic3r will autocalculate the optimal speed " diff --git a/xs/src/libslic3r/PrintConfig.hpp b/xs/src/libslic3r/PrintConfig.hpp index c589d917a..e87ea11bf 100644 --- a/xs/src/libslic3r/PrintConfig.hpp +++ b/xs/src/libslic3r/PrintConfig.hpp @@ -583,6 +583,7 @@ public: ConfigOptionFloats max_layer_height; ConfigOptionInts min_fan_speed; ConfigOptionFloats min_layer_height; + ConfigOptionFloat max_print_height; ConfigOptionFloats min_print_speed; ConfigOptionFloat min_skirt_length; ConfigOptionString notes; @@ -647,6 +648,7 @@ protected: OPT_PTR(max_layer_height); OPT_PTR(min_fan_speed); OPT_PTR(min_layer_height); + OPT_PTR(max_print_height); OPT_PTR(min_print_speed); OPT_PTR(min_skirt_length); OPT_PTR(notes); diff --git a/xs/src/slic3r/GUI/3DScene.cpp b/xs/src/slic3r/GUI/3DScene.cpp index 04e7f7dc6..f6be96a78 100644 --- a/xs/src/slic3r/GUI/3DScene.cpp +++ b/xs/src/slic3r/GUI/3DScene.cpp @@ -46,6 +46,25 @@ void GLIndexedVertexArray::load_mesh_flat_shading(const TriangleMesh &mesh) } } +void GLIndexedVertexArray::load_mesh_full_shading(const TriangleMesh &mesh) +{ + assert(triangle_indices.empty() && vertices_and_normals_interleaved_size == 0); + assert(quad_indices.empty() && triangle_indices_size == 0); + assert(vertices_and_normals_interleaved.size() % 6 == 0 && quad_indices_size == vertices_and_normals_interleaved.size()); + + this->vertices_and_normals_interleaved.reserve(this->vertices_and_normals_interleaved.size() + 3 * 3 * 2 * mesh.facets_count()); + + unsigned int vertices_count = 0; + for (int i = 0; i < mesh.stl.stats.number_of_facets; ++i) { + const stl_facet &facet = mesh.stl.facet_start[i]; + for (int j = 0; j < 3; ++j) + this->push_geometry(facet.vertex[j].x, facet.vertex[j].y, facet.vertex[j].z, facet.normal.x, facet.normal.y, facet.normal.z); + + this->push_triangle(vertices_count, vertices_count + 1, vertices_count + 2); + vertices_count += 3; + } +} + void GLIndexedVertexArray::finalize_geometry(bool use_VBOs) { assert(this->vertices_and_normals_interleaved_VBO_id == 0); @@ -173,6 +192,45 @@ void GLIndexedVertexArray::render( glDisableClientState(GL_NORMAL_ARRAY); } +const float GLVolume::SELECTED_COLOR[4] = { 0.0f, 1.0f, 0.0f, 1.0f }; +const float GLVolume::HOVER_COLOR[4] = { 0.4f, 0.9f, 0.1f, 1.0f }; +const float GLVolume::OUTSIDE_COLOR[4] = { 0.75f, 0.0f, 0.75f, 1.0f }; +const float GLVolume::SELECTED_OUTSIDE_COLOR[4] = { 1.0f, 0.0f, 1.0f, 1.0f }; + +void GLVolume::set_render_color(float r, float g, float b, float a) +{ + render_color[0] = r; + render_color[1] = g; + render_color[2] = b; + render_color[3] = a; +} + +void GLVolume::set_render_color(const float* rgba, unsigned int size) +{ + size = std::min((unsigned int)4, size); + for (int i = 0; i < size; ++i) + { + render_color[i] = rgba[i]; + } +} + +void GLVolume::set_render_color() +{ + if (selected) + { + if (is_outside) + set_render_color(SELECTED_OUTSIDE_COLOR, 4); + else + set_render_color(SELECTED_COLOR, 4); + } + else if (hover) + set_render_color(HOVER_COLOR, 4); + else if (is_outside) + set_render_color(OUTSIDE_COLOR, 4); + else + set_render_color(color, 4); +} + void GLVolume::set_range(double min_z, double max_z) { this->qverts_range.first = 0; @@ -223,6 +281,51 @@ void GLVolume::render() const glPopMatrix(); } +void GLVolume::render_using_layer_height() const +{ + if (!is_active) + return; + + GLint current_program_id; + glGetIntegerv(GL_CURRENT_PROGRAM, ¤t_program_id); + + if ((layer_height_texture_data.shader_id > 0) && (layer_height_texture_data.shader_id != current_program_id)) + glUseProgram(layer_height_texture_data.shader_id); + + GLint z_to_texture_row_id = (layer_height_texture_data.shader_id > 0) ? glGetUniformLocation(layer_height_texture_data.shader_id, "z_to_texture_row") : -1; + GLint z_texture_row_to_normalized_id = (layer_height_texture_data.shader_id > 0) ? glGetUniformLocation(layer_height_texture_data.shader_id, "z_texture_row_to_normalized") : -1; + GLint z_cursor_id = (layer_height_texture_data.shader_id > 0) ? glGetUniformLocation(layer_height_texture_data.shader_id, "z_cursor") : -1; + GLint z_cursor_band_width_id = (layer_height_texture_data.shader_id > 0) ? glGetUniformLocation(layer_height_texture_data.shader_id, "z_cursor_band_width") : -1; + + if (z_to_texture_row_id >= 0) + glUniform1f(z_to_texture_row_id, (GLfloat)layer_height_texture_z_to_row_id()); + + if (z_texture_row_to_normalized_id >= 0) + glUniform1f(z_texture_row_to_normalized_id, (GLfloat)(1.0f / layer_height_texture_height())); + + if (z_cursor_id >= 0) + glUniform1f(z_cursor_id, (GLfloat)(bounding_box.max.z * layer_height_texture_data.z_cursor_relative)); + + if (z_cursor_band_width_id >= 0) + glUniform1f(z_cursor_band_width_id, (GLfloat)layer_height_texture_data.edit_band_width); + + unsigned int w = layer_height_texture_width(); + unsigned int h = layer_height_texture_height(); + + glBindTexture(GL_TEXTURE_2D, layer_height_texture_data.texture_id); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); + glTexImage2D(GL_TEXTURE_2D, 1, GL_RGBA8, w / 2, h / 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, layer_height_texture_data_ptr_level0()); + glTexSubImage2D(GL_TEXTURE_2D, 1, 0, 0, w / 2, h / 2, GL_RGBA, GL_UNSIGNED_BYTE, layer_height_texture_data_ptr_level1()); + + render(); + + glBindTexture(GL_TEXTURE_2D, 0); + + if ((current_program_id > 0) && (layer_height_texture_data.shader_id != current_program_id)) + glUseProgram(current_program_id); +} + void GLVolume::generate_layer_height_texture(PrintObject *print_object, bool force) { GLTexture *tex = this->layer_height_texture.get(); @@ -288,7 +391,11 @@ std::vector GLVolumeCollection::load_object( color[3] = model_volume->modifier ? 0.5f : 1.f; this->volumes.emplace_back(new GLVolume(color)); GLVolume &v = *this->volumes.back(); - v.indexed_vertex_array.load_mesh_flat_shading(mesh); + if (use_VBOs) + v.indexed_vertex_array.load_mesh_full_shading(mesh); + else + v.indexed_vertex_array.load_mesh_flat_shading(mesh); + // finalize_geometry() clears the vertex arrays, therefore the bounding box has to be computed before finalize_geometry(). v.bounding_box = v.indexed_vertex_array.bounding_box(); v.indexed_vertex_array.finalize_geometry(use_VBOs); @@ -319,7 +426,11 @@ int GLVolumeCollection::load_wipe_tower_preview( this->volumes.emplace_back(new GLVolume(color)); GLVolume &v = *this->volumes.back(); auto mesh = make_cube(width, depth, height); - v.indexed_vertex_array.load_mesh_flat_shading(mesh); + if (use_VBOs) + v.indexed_vertex_array.load_mesh_full_shading(mesh); + else + v.indexed_vertex_array.load_mesh_flat_shading(mesh); + v.origin = Pointf3(pos_x, pos_y, 0.); // finalize_geometry() clears the vertex arrays, therefore the bounding box has to be computed before finalize_geometry(). v.bounding_box = v.indexed_vertex_array.bounding_box(); @@ -332,15 +443,19 @@ int GLVolumeCollection::load_wipe_tower_preview( void GLVolumeCollection::render_VBOs() const { -// glEnable(GL_BLEND); -// glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glCullFace(GL_BACK); - glEnableClientState(GL_VERTEX_ARRAY); - glEnableClientState(GL_NORMAL_ARRAY); + ::glEnable(GL_BLEND); + ::glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + ::glCullFace(GL_BACK); + ::glEnableClientState(GL_VERTEX_ARRAY); + ::glEnableClientState(GL_NORMAL_ARRAY); GLint current_program_id; - glGetIntegerv(GL_CURRENT_PROGRAM, ¤t_program_id); + ::glGetIntegerv(GL_CURRENT_PROGRAM, ¤t_program_id); GLint color_id = (current_program_id > 0) ? glGetUniformLocation(current_program_id, "uniform_color") : -1; + GLint print_box_min_id = (current_program_id > 0) ? glGetUniformLocation(current_program_id, "print_box.min") : -1; + GLint print_box_max_id = (current_program_id > 0) ? glGetUniformLocation(current_program_id, "print_box.max") : -1; + GLint print_box_origin_id = (current_program_id > 0) ? glGetUniformLocation(current_program_id, "print_box.volume_origin") : -1; for (GLVolume *volume : this->volumes) { if (!volume->is_active) @@ -348,61 +463,110 @@ void GLVolumeCollection::render_VBOs() const if (!volume->indexed_vertex_array.vertices_and_normals_interleaved_VBO_id) continue; + + if (volume->layer_height_texture_data.can_use()) + { + ::glDisableClientState(GL_VERTEX_ARRAY); + ::glDisableClientState(GL_NORMAL_ARRAY); + volume->generate_layer_height_texture(volume->layer_height_texture_data.print_object, false); + volume->render_using_layer_height(); + ::glEnableClientState(GL_VERTEX_ARRAY); + ::glEnableClientState(GL_NORMAL_ARRAY); + continue; + } + + volume->set_render_color(); + GLsizei n_triangles = GLsizei(std::min(volume->indexed_vertex_array.triangle_indices_size, volume->tverts_range.second - volume->tverts_range.first)); GLsizei n_quads = GLsizei(std::min(volume->indexed_vertex_array.quad_indices_size, volume->qverts_range.second - volume->qverts_range.first)); if (n_triangles + n_quads == 0) { - if (_render_interleaved_only_volumes.enabled) + ::glDisableClientState(GL_VERTEX_ARRAY); + ::glDisableClientState(GL_NORMAL_ARRAY); + + if (color_id >= 0) { - ::glDisableClientState(GL_VERTEX_ARRAY); - ::glDisableClientState(GL_NORMAL_ARRAY); - ::glEnable(GL_BLEND); - ::glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - - if (color_id >= 0) - { - float color[4]; - ::memcpy((void*)color, (const void*)volume->color, 3 * sizeof(float)); - color[3] = _render_interleaved_only_volumes.alpha; - ::glUniform4fv(color_id, 1, (const GLfloat*)color); - } - else - ::glColor4f(volume->color[0], volume->color[1], volume->color[2], _render_interleaved_only_volumes.alpha); - - volume->render(); - - ::glDisable(GL_BLEND); - ::glEnableClientState(GL_VERTEX_ARRAY); - ::glEnableClientState(GL_NORMAL_ARRAY); + float color[4]; + ::memcpy((void*)color, (const void*)volume->render_color, 4 * sizeof(float)); + ::glUniform4fv(color_id, 1, (const GLfloat*)color); } + else + ::glColor4f(volume->render_color[0], volume->render_color[1], volume->render_color[2], volume->render_color[3]); + + if (print_box_min_id != -1) + ::glUniform3fv(print_box_min_id, 1, (const GLfloat*)print_box_min); + + if (print_box_max_id != -1) + ::glUniform3fv(print_box_max_id, 1, (const GLfloat*)print_box_max); + + if (print_box_origin_id != -1) + { + float origin[4] = { (float)volume->origin.x, (float)volume->origin.y, (float)volume->origin.z, volume->outside_printer_detection_enabled ? 1.0f : 0.0f }; + ::glUniform4fv(print_box_origin_id, 1, (const GLfloat*)origin); + } + + volume->render(); + + ::glEnableClientState(GL_VERTEX_ARRAY); + ::glEnableClientState(GL_NORMAL_ARRAY); + continue; } + if (color_id >= 0) - glUniform4fv(color_id, 1, (const GLfloat*)volume->color); + ::glUniform4fv(color_id, 1, (const GLfloat*)volume->render_color); else - glColor4f(volume->color[0], volume->color[1], volume->color[2], volume->color[3]); - glBindBuffer(GL_ARRAY_BUFFER, volume->indexed_vertex_array.vertices_and_normals_interleaved_VBO_id); - glVertexPointer(3, GL_FLOAT, 6 * sizeof(float), (const void*)(3 * sizeof(float))); - glNormalPointer(GL_FLOAT, 6 * sizeof(float), nullptr); + ::glColor4f(volume->render_color[0], volume->render_color[1], volume->render_color[2], volume->render_color[3]); + + if (print_box_min_id != -1) + ::glUniform3fv(print_box_min_id, 1, (const GLfloat*)print_box_min); + + if (print_box_max_id != -1) + ::glUniform3fv(print_box_max_id, 1, (const GLfloat*)print_box_max); + + if (print_box_origin_id != -1) + { + float origin[4] = { (float)volume->origin.x, (float)volume->origin.y, (float)volume->origin.z, volume->outside_printer_detection_enabled ? 1.0f : 0.0f }; + ::glUniform4fv(print_box_origin_id, 1, (const GLfloat*)origin); + } + + ::glBindBuffer(GL_ARRAY_BUFFER, volume->indexed_vertex_array.vertices_and_normals_interleaved_VBO_id); + ::glVertexPointer(3, GL_FLOAT, 6 * sizeof(float), (const void*)(3 * sizeof(float))); + ::glNormalPointer(GL_FLOAT, 6 * sizeof(float), nullptr); + + bool has_offset = (volume->origin.x != 0) || (volume->origin.y != 0) || (volume->origin.z != 0); + if (has_offset) { + ::glPushMatrix(); + ::glTranslated(volume->origin.x, volume->origin.y, volume->origin.z); + } + if (n_triangles > 0) { - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, volume->indexed_vertex_array.triangle_indices_VBO_id); - glDrawElements(GL_TRIANGLES, n_triangles, GL_UNSIGNED_INT, (const void*)(volume->tverts_range.first * 4)); + ::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, volume->indexed_vertex_array.triangle_indices_VBO_id); + ::glDrawElements(GL_TRIANGLES, n_triangles, GL_UNSIGNED_INT, (const void*)(volume->tverts_range.first * 4)); } if (n_quads > 0) { - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, volume->indexed_vertex_array.quad_indices_VBO_id); - glDrawElements(GL_QUADS, n_quads, GL_UNSIGNED_INT, (const void*)(volume->qverts_range.first * 4)); + ::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, volume->indexed_vertex_array.quad_indices_VBO_id); + ::glDrawElements(GL_QUADS, n_quads, GL_UNSIGNED_INT, (const void*)(volume->qverts_range.first * 4)); } + + if (has_offset) + ::glPopMatrix(); } - glBindBuffer(GL_ARRAY_BUFFER, 0); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); - glDisableClientState(GL_VERTEX_ARRAY); - glDisableClientState(GL_NORMAL_ARRAY); -// glDisable(GL_BLEND); + ::glBindBuffer(GL_ARRAY_BUFFER, 0); + ::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); + + ::glDisableClientState(GL_VERTEX_ARRAY); + ::glDisableClientState(GL_NORMAL_ARRAY); + + ::glDisable(GL_BLEND); } void GLVolumeCollection::render_legacy() const { + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glCullFace(GL_BACK); glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_NORMAL_ARRAY); @@ -412,27 +576,25 @@ void GLVolumeCollection::render_legacy() const if (!volume->is_active) continue; + volume->set_render_color(); + GLsizei n_triangles = GLsizei(std::min(volume->indexed_vertex_array.triangle_indices_size, volume->tverts_range.second - volume->tverts_range.first)); GLsizei n_quads = GLsizei(std::min(volume->indexed_vertex_array.quad_indices_size, volume->qverts_range.second - volume->qverts_range.first)); if (n_triangles + n_quads == 0) { - if (_render_interleaved_only_volumes.enabled) - { - ::glDisableClientState(GL_VERTEX_ARRAY); - ::glDisableClientState(GL_NORMAL_ARRAY); - ::glEnable(GL_BLEND); - ::glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + ::glDisableClientState(GL_VERTEX_ARRAY); + ::glDisableClientState(GL_NORMAL_ARRAY); - ::glColor4f(volume->color[0], volume->color[1], volume->color[2], _render_interleaved_only_volumes.alpha); - volume->render(); + ::glColor4f(volume->render_color[0], volume->render_color[1], volume->render_color[2], volume->render_color[3]); + volume->render(); + + ::glEnableClientState(GL_VERTEX_ARRAY); + ::glEnableClientState(GL_NORMAL_ARRAY); - ::glDisable(GL_BLEND); - ::glEnableClientState(GL_VERTEX_ARRAY); - ::glEnableClientState(GL_NORMAL_ARRAY); - } continue; } - glColor4f(volume->color[0], volume->color[1], volume->color[2], volume->color[3]); + + glColor4f(volume->render_color[0], volume->render_color[1], volume->render_color[2], volume->render_color[3]); glVertexPointer(3, GL_FLOAT, 6 * sizeof(float), volume->indexed_vertex_array.vertices_and_normals_interleaved.data() + 3); glNormalPointer(GL_FLOAT, 6 * sizeof(float), volume->indexed_vertex_array.vertices_and_normals_interleaved.data()); bool has_offset = volume->origin.x != 0 || volume->origin.y != 0 || volume->origin.z != 0; @@ -445,11 +607,37 @@ void GLVolumeCollection::render_legacy() const if (n_quads > 0) glDrawElements(GL_QUADS, n_quads, GL_UNSIGNED_INT, volume->indexed_vertex_array.quad_indices.data() + volume->qverts_range.first); if (has_offset) - glPushMatrix(); + glPopMatrix(); } glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_NORMAL_ARRAY); + + glDisable(GL_BLEND); +} + +void GLVolumeCollection::update_outside_state(const DynamicPrintConfig* config, bool all_inside) +{ + if (config == nullptr) + return; + + const ConfigOptionPoints* opt = dynamic_cast(config->option("bed_shape")); + if (opt == nullptr) + return; + + BoundingBox bed_box_2D = get_extents(Polygon::new_scale(opt->values)); + BoundingBoxf3 print_volume(Pointf3(unscale(bed_box_2D.min.x), unscale(bed_box_2D.min.y), 0.0), Pointf3(unscale(bed_box_2D.max.x), unscale(bed_box_2D.max.y), config->opt_float("max_print_height"))); + + for (GLVolume* volume : this->volumes) + { + if (all_inside) + { + volume->is_outside = false; + continue; + } + + volume->is_outside = !print_volume.contains(volume->transformed_bounding_box()); + } } std::vector GLVolumeCollection::get_current_print_zs() const @@ -1133,6 +1321,100 @@ static void point3_to_verts(const Point3& point, double width, double height, GL _3DScene::GCodePreviewVolumeIndex _3DScene::s_gcode_preview_volume_index; _3DScene::LegendTexture _3DScene::s_legend_texture; +_3DScene::WarningTexture _3DScene::s_warning_texture; + +unsigned int _3DScene::TextureBase::finalize() +{ + if (!m_data.empty()) { + // sends buffer to gpu + ::glGenTextures(1, &m_tex_id); + ::glBindTexture(GL_TEXTURE_2D, m_tex_id); + ::glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, (GLsizei)m_tex_width, (GLsizei)m_tex_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, (const GLvoid*)m_data.data()); + ::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + ::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + ::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 1); + ::glBindTexture(GL_TEXTURE_2D, 0); + m_data.clear(); + } + return (m_tex_width > 0 && m_tex_height > 0) ? m_tex_id : 0; +} + +void _3DScene::TextureBase::_destroy_texture() +{ + if (m_tex_id > 0) + { + ::glDeleteTextures(1, &m_tex_id); + m_tex_id = 0; + m_tex_height = 0; + m_tex_width = 0; + } + m_data.clear(); +} + + +const unsigned char _3DScene::WarningTexture::Background_Color[3] = { 9, 91, 134 }; +const unsigned char _3DScene::WarningTexture::Opacity = 255; + +// Generate a texture data, but don't load it into the GPU yet, as the GPU context may not yet be valid. +bool _3DScene::WarningTexture::generate(const std::string& msg) +{ + // Mark the texture as released, but don't release the texture from the GPU yet. + m_tex_width = m_tex_height = 0; + m_data.clear(); + + if (msg.empty()) + return false; + + wxMemoryDC memDC; + // select default font + memDC.SetFont(wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT)); + + // calculates texture size + wxCoord w, h; + memDC.GetTextExtent(msg, &w, &h); + m_tex_width = (unsigned int)w; + m_tex_height = (unsigned int)h; + + // generates bitmap + wxBitmap bitmap(m_tex_width, m_tex_height); + +#if defined(__APPLE__) || defined(_MSC_VER) + bitmap.UseAlpha(); +#endif + + memDC.SelectObject(bitmap); + memDC.SetBackground(wxBrush(wxColour(Background_Color[0], Background_Color[1], Background_Color[2]))); + memDC.Clear(); + + memDC.SetTextForeground(*wxWHITE); + + // draw message + memDC.DrawText(msg, 0, 0); + + memDC.SelectObject(wxNullBitmap); + + // Convert the bitmap into a linear data ready to be loaded into the GPU. + { + wxImage image = bitmap.ConvertToImage(); + image.SetMaskColour(Background_Color[0], Background_Color[1], Background_Color[2]); + + // prepare buffer + m_data.assign(4 * m_tex_width * m_tex_height, 0); + for (unsigned int h = 0; h < m_tex_height; ++h) + { + unsigned int hh = h * m_tex_width; + unsigned char* px_ptr = m_data.data() + 4 * hh; + for (unsigned int w = 0; w < m_tex_width; ++w) + { + *px_ptr++ = image.GetRed(w, h); + *px_ptr++ = image.GetGreen(w, h); + *px_ptr++ = image.GetBlue(w, h); + *px_ptr++ = image.IsTransparent(w, h) ? 0 : Opacity; + } + } + } + return true; +} const unsigned char _3DScene::LegendTexture::Squares_Border_Color[3] = { 64, 64, 64 }; const unsigned char _3DScene::LegendTexture::Background_Color[3] = { 9, 91, 134 }; @@ -1276,34 +1558,6 @@ bool _3DScene::LegendTexture::generate(const GCodePreviewData& preview_data, con return true; } -unsigned int _3DScene::LegendTexture::finalize() -{ - if (! m_data.empty()) { - // sends buffer to gpu - ::glGenTextures(1, &m_tex_id); - ::glBindTexture(GL_TEXTURE_2D, m_tex_id); - ::glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, (GLsizei)m_tex_width, (GLsizei)m_tex_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, (const GLvoid*)m_data.data()); - ::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - ::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - ::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 1); - ::glBindTexture(GL_TEXTURE_2D, 0); - m_data.clear(); - } - return (m_tex_width > 0 && m_tex_height > 0) ? m_tex_id : 0; -} - -void _3DScene::LegendTexture::_destroy_texture() -{ - if (m_tex_id > 0) - { - ::glDeleteTextures(1, &m_tex_id); - m_tex_id = 0; - m_tex_height = 0; - m_tex_width = 0; - } - m_data.clear(); -} - void _3DScene::_glew_init() { glewInit(); @@ -1353,27 +1607,17 @@ void _3DScene::load_gcode_preview(const Print* print, const GCodePreviewData* pr _load_gcode_unretractions(*preview_data, *volumes, use_VBOs); if (volumes->empty()) - { reset_legend_texture(); - volumes->set_render_interleaved_only_volumes(GLVolumeCollection::RenderInterleavedOnlyVolumes(false, 0.0f)); - } else { _generate_legend_texture(*preview_data, tool_colors); - _load_shells(*print, *volumes, use_VBOs); - volumes->set_render_interleaved_only_volumes(GLVolumeCollection::RenderInterleavedOnlyVolumes(true, 0.25f)); } } _update_gcode_volumes_visibility(*preview_data, *volumes); } -unsigned int _3DScene::get_legend_texture_id() -{ - return s_legend_texture.get_texture_id(); -} - unsigned int _3DScene::get_legend_texture_width() { return s_legend_texture.get_texture_width(); @@ -1389,6 +1633,36 @@ void _3DScene::reset_legend_texture() s_legend_texture.reset_texture(); } +unsigned int _3DScene::finalize_legend_texture() +{ + return s_legend_texture.finalize(); +} + +unsigned int _3DScene::get_warning_texture_width() +{ + return s_warning_texture.get_texture_width(); +} + +unsigned int _3DScene::get_warning_texture_height() +{ + return s_warning_texture.get_texture_height(); +} + +void _3DScene::generate_warning_texture(const std::string& msg) +{ + s_warning_texture.generate(msg); +} + +void _3DScene::reset_warning_texture() +{ + s_warning_texture.reset_texture(); +} + +unsigned int _3DScene::finalize_warning_texture() +{ + return s_warning_texture.finalize(); +} + // Create 3D thick extrusion lines for a skirt and brim. // Adds a new Slic3r::GUI::3DScene::Volume to volumes. void _3DScene::_load_print_toolpaths( @@ -1501,6 +1775,7 @@ void _3DScene::_load_print_object_toolpaths( auto new_volume = [volumes, &new_volume_mutex](const float *color) -> GLVolume* { auto *volume = new GLVolume(color); new_volume_mutex.lock(); + volume->outside_printer_detection_enabled = false; volumes->volumes.emplace_back(volume); new_volume_mutex.unlock(); return volume; @@ -1651,6 +1926,7 @@ void _3DScene::_load_wipe_tower_toolpaths( auto new_volume = [volumes, &new_volume_mutex](const float *color) -> GLVolume* { auto *volume = new GLVolume(color); new_volume_mutex.lock(); + volume->outside_printer_detection_enabled = false; volumes->volumes.emplace_back(volume); new_volume_mutex.unlock(); return volume; @@ -2221,6 +2497,7 @@ void _3DScene::_update_gcode_volumes_visibility(const GCodePreviewData& preview_ for (std::vector::iterator it = begin; it != end; ++it) { GLVolume* volume = *it; + volume->outside_printer_detection_enabled = false; switch (s_gcode_preview_volume_index.first_volumes[i].type) { @@ -2253,6 +2530,7 @@ void _3DScene::_update_gcode_volumes_visibility(const GCodePreviewData& preview_ case GCodePreviewVolumeIndex::Shell: { volume->is_active = preview_data.shell.is_visible; + volume->color[3] = 0.25f; volume->zoom_to_volumes = false; break; } @@ -2272,11 +2550,6 @@ void _3DScene::_generate_legend_texture(const GCodePreviewData& preview_data, co s_legend_texture.generate(preview_data, tool_colors); } -unsigned int _3DScene::finalize_legend_texture() -{ - return s_legend_texture.finalize(); -} - void _3DScene::_load_shells(const Print& print, GLVolumeCollection& volumes, bool use_VBOs) { size_t initial_volumes_count = volumes.volumes.size(); diff --git a/xs/src/slic3r/GUI/3DScene.hpp b/xs/src/slic3r/GUI/3DScene.hpp index 3e26bf6d3..0fd31d8d6 100644 --- a/xs/src/slic3r/GUI/3DScene.hpp +++ b/xs/src/slic3r/GUI/3DScene.hpp @@ -16,6 +16,7 @@ class PrintObject; class Model; class ModelObject; class GCodePreviewData; +class DynamicPrintConfig; // A container for interleaved arrays of 3D vertices and normals, // possibly indexed by triangles and / or quads. @@ -85,6 +86,7 @@ public: unsigned int quad_indices_VBO_id; void load_mesh_flat_shading(const TriangleMesh &mesh); + void load_mesh_full_shading(const TriangleMesh &mesh); inline bool has_VBOs() const { return vertices_and_normals_interleaved_VBO_id != 0; } @@ -208,7 +210,38 @@ public: }; class GLVolume { + struct LayerHeightTextureData + { + // ID of the layer height texture + unsigned int texture_id; + // ID of the shader used to render with the layer height texture + unsigned int shader_id; + // The print object to update when generating the layer height texture + PrintObject* print_object; + + float z_cursor_relative; + float edit_band_width; + + LayerHeightTextureData() { reset(); } + + void reset() + { + texture_id = 0; + shader_id = 0; + print_object = nullptr; + z_cursor_relative = 0.0f; + edit_band_width = 0.0f; + } + + bool can_use() { return (texture_id > 0) && (shader_id > 0) && (print_object != nullptr); } + }; + public: + static const float SELECTED_COLOR[4]; + static const float HOVER_COLOR[4]; + static const float OUTSIDE_COLOR[4]; + static const float SELECTED_OUTSIDE_COLOR[4]; + GLVolume(float r = 1.f, float g = 1.f, float b = 1.f, float a = 1.f) : composite_id(-1), select_group_id(-1), @@ -216,6 +249,8 @@ public: selected(false), is_active(true), zoom_to_volumes(true), + outside_printer_detection_enabled(true), + is_outside(false), hover(false), tverts_range(0, size_t(-1)), qverts_range(0, size_t(-1)) @@ -224,6 +259,7 @@ public: color[1] = g; color[2] = b; color[3] = a; + set_render_color(r, g, b, a); } GLVolume(const float *rgba) : GLVolume(rgba[0], rgba[1], rgba[2], rgba[3]) {} @@ -243,7 +279,8 @@ public: Pointf3 origin; // Color of the triangles / quads held by this volume. float color[4]; - + // Color used to render this volume. + float render_color[4]; // An ID containing the object ID, volume ID and instance ID. int composite_id; // An ID for group selection. It may be the same for all meshes of all object instances, or for just a single object instance. @@ -256,6 +293,10 @@ public: bool is_active; // Whether or not to use this volume when applying zoom_to_volumes() bool zoom_to_volumes; + // Wheter or not this volume is enabled for outside print volume detection. + bool outside_printer_detection_enabled; + // Wheter or not this volume is outside print volume. + bool is_outside; // Boolean: Is mouse over this object? bool hover; @@ -271,6 +312,10 @@ public: // Offset into qverts & tverts, or offsets into indices stored into an OpenGL name_index_buffer. std::vector offsets; + void set_render_color(float r, float g, float b, float a); + void set_render_color(const float* rgba, unsigned int size); + // Sets render color in dependence of current state + void set_render_color(); int object_idx() const { return this->composite_id / 1000000; } int volume_idx() const { return (this->composite_id / 1000) % 1000; } @@ -282,11 +327,14 @@ public: void set_range(coordf_t low, coordf_t high); void render() const; + void render_using_layer_height() const; void finalize_geometry(bool use_VBOs) { this->indexed_vertex_array.finalize_geometry(use_VBOs); } void release_geometry() { this->indexed_vertex_array.release_geometry(); } /************************************************ Layer height texture ****************************************************/ std::shared_ptr layer_height_texture; + // Data to render this volume using the layer height texture + LayerHeightTextureData layer_height_texture_data; bool has_layer_height_texture() const { return this->layer_height_texture.get() != nullptr; } @@ -296,11 +344,11 @@ public: { return (this->layer_height_texture.get() == nullptr) ? 0 : this->layer_height_texture->height; } size_t layer_height_texture_cells() const { return (this->layer_height_texture.get() == nullptr) ? 0 : this->layer_height_texture->cells; } - void* layer_height_texture_data_ptr_level0() { + void* layer_height_texture_data_ptr_level0() const { return (layer_height_texture.get() == nullptr) ? 0 : (void*)layer_height_texture->data.data(); } - void* layer_height_texture_data_ptr_level1() { + void* layer_height_texture_data_ptr_level1() const { return (layer_height_texture.get() == nullptr) ? 0 : (void*)(layer_height_texture->data.data() + layer_height_texture->width * layer_height_texture->height * 4); } @@ -309,31 +357,24 @@ public: double(this->layer_height_texture->cells - 1) / (double(this->layer_height_texture->width) * bounding_box.max.z); } void generate_layer_height_texture(PrintObject *print_object, bool force); + + void set_layer_height_texture_data(unsigned int texture_id, unsigned int shader_id, PrintObject* print_object, float z_cursor_relative, float edit_band_width) + { + layer_height_texture_data.texture_id = texture_id; + layer_height_texture_data.shader_id = shader_id; + layer_height_texture_data.print_object = print_object; + layer_height_texture_data.z_cursor_relative = z_cursor_relative; + layer_height_texture_data.edit_band_width = edit_band_width; + } + + void reset_layer_height_texture_data() { layer_height_texture_data.reset(); } }; class GLVolumeCollection { -public: - struct RenderInterleavedOnlyVolumes - { - bool enabled; - float alpha; // [0..1] - - RenderInterleavedOnlyVolumes() - : enabled(false) - , alpha(0.0f) - { - } - - RenderInterleavedOnlyVolumes(bool enabled, float alpha) - : enabled(enabled) - , alpha(alpha) - { - } - }; - -private: - RenderInterleavedOnlyVolumes _render_interleaved_only_volumes; + // min and max vertex of the print box volume + float print_box_min[3]; + float print_box_max[3]; public: std::vector volumes; @@ -370,7 +411,12 @@ public: bool empty() const { return volumes.empty(); } void set_range(double low, double high) { for (GLVolume *vol : this->volumes) vol->set_range(low, high); } - void set_render_interleaved_only_volumes(const RenderInterleavedOnlyVolumes& render_interleaved_only_volumes) { _render_interleaved_only_volumes = render_interleaved_only_volumes; } + void set_print_box(float min_x, float min_y, float min_z, float max_x, float max_y, float max_z) { + print_box_min[0] = min_x; print_box_min[1] = min_y; print_box_min[2] = min_z; + print_box_max[0] = max_x; print_box_max[1] = max_y; print_box_max[2] = max_z; + } + + void update_outside_state(const DynamicPrintConfig* config, bool all_inside); // Returns a vector containing the sorted list of all the print_zs of the volumes contained in this collection std::vector get_current_print_zs() const; @@ -411,27 +457,20 @@ class _3DScene static GCodePreviewVolumeIndex s_gcode_preview_volume_index; - class LegendTexture + class TextureBase { - static const unsigned int Px_Title_Offset = 5; - static const unsigned int Px_Text_Offset = 5; - static const unsigned int Px_Square = 20; - static const unsigned int Px_Square_Contour = 1; - static const unsigned int Px_Border = Px_Square / 2; - static const unsigned char Squares_Border_Color[3]; - static const unsigned char Background_Color[3]; - static const unsigned char Opacity; - + protected: unsigned int m_tex_id; unsigned int m_tex_width; unsigned int m_tex_height; + // generate() fills in m_data with the pixels, while finalize() moves the data to the GPU before rendering. + std::vector m_data; + public: - LegendTexture() : m_tex_id(0), m_tex_width(0), m_tex_height(0) {} - ~LegendTexture() { _destroy_texture(); } - - // Generate a texture data, but don't load it into the GPU yet, as the glcontext may not be valid yet. - bool generate(const GCodePreviewData& preview_data, const std::vector& tool_colors); + TextureBase() : m_tex_id(0), m_tex_width(0), m_tex_height(0) {} + virtual ~TextureBase() { _destroy_texture(); } + // If not loaded, load the texture data into the GPU. Return a texture ID or 0 if the texture has zero size. unsigned int finalize(); @@ -442,26 +481,61 @@ class _3DScene void reset_texture() { _destroy_texture(); } private: - bool _create_texture(const GCodePreviewData& preview_data, const wxBitmap& bitmap); void _destroy_texture(); - // generate() fills in m_data with the pixels, while finalize() moves the data to the GPU before rendering. - std::vector m_data; + }; + + class WarningTexture : public TextureBase + { + static const unsigned char Background_Color[3]; + static const unsigned char Opacity; + + public: + WarningTexture() : TextureBase() {} + + // Generate a texture data, but don't load it into the GPU yet, as the glcontext may not be valid yet. + bool generate(const std::string& msg); + }; + + class LegendTexture : public TextureBase + { + static const unsigned int Px_Title_Offset = 5; + static const unsigned int Px_Text_Offset = 5; + static const unsigned int Px_Square = 20; + static const unsigned int Px_Square_Contour = 1; + static const unsigned int Px_Border = Px_Square / 2; + static const unsigned char Squares_Border_Color[3]; + static const unsigned char Background_Color[3]; + static const unsigned char Opacity; + + public: + LegendTexture() : TextureBase() {} + + // Generate a texture data, but don't load it into the GPU yet, as the glcontext may not be valid yet. + bool generate(const GCodePreviewData& preview_data, const std::vector& tool_colors); }; static LegendTexture s_legend_texture; + static WarningTexture s_warning_texture; public: static void _glew_init(); static void load_gcode_preview(const Print* print, const GCodePreviewData* preview_data, GLVolumeCollection* volumes, const std::vector& str_tool_colors, bool use_VBOs); - static unsigned int get_legend_texture_id(); static unsigned int get_legend_texture_width(); static unsigned int get_legend_texture_height(); static void reset_legend_texture(); static unsigned int finalize_legend_texture(); + static unsigned int get_warning_texture_width(); + static unsigned int get_warning_texture_height(); + + // generates a warning texture containing the given message + static void generate_warning_texture(const std::string& msg); + static void reset_warning_texture(); + static unsigned int finalize_warning_texture(); + static void _load_print_toolpaths( const Print *print, GLVolumeCollection *volumes, diff --git a/xs/src/slic3r/GUI/Preset.cpp b/xs/src/slic3r/GUI/Preset.cpp index 52717e1fc..aa1917bd5 100644 --- a/xs/src/slic3r/GUI/Preset.cpp +++ b/xs/src/slic3r/GUI/Preset.cpp @@ -226,7 +226,7 @@ const std::vector& Preset::printer_options() "bed_shape", "z_offset", "gcode_flavor", "use_relative_e_distances", "serial_port", "serial_speed", "octoprint_host", "octoprint_apikey", "octoprint_cafile", "use_firmware_retraction", "use_volumetric_e", "variable_layer_height", "single_extruder_multi_material", "start_gcode", "end_gcode", "before_layer_gcode", "layer_gcode", "toolchange_gcode", - "between_objects_gcode", "printer_notes" + "between_objects_gcode", "printer_notes", "max_print_height" }; s_opts.insert(s_opts.end(), Preset::nozzle_options().begin(), Preset::nozzle_options().end()); } diff --git a/xs/src/slic3r/GUI/Tab.cpp b/xs/src/slic3r/GUI/Tab.cpp index 858eb8bcf..1da228e90 100644 --- a/xs/src/slic3r/GUI/Tab.cpp +++ b/xs/src/slic3r/GUI/Tab.cpp @@ -1028,7 +1028,8 @@ void TabPrinter::build() return sizer; }; optgroup->append_line(line); - optgroup->append_single_option_line("z_offset"); + optgroup->append_single_option_line("max_print_height"); + optgroup->append_single_option_line("z_offset"); optgroup = page->new_optgroup(_(L("Capabilities"))); ConfigOptionDef def; diff --git a/xs/xsp/GUI_3DScene.xsp b/xs/xsp/GUI_3DScene.xsp index 4670c5c7e..25aa6b81a 100644 --- a/xs/xsp/GUI_3DScene.xsp +++ b/xs/xsp/GUI_3DScene.xsp @@ -19,6 +19,9 @@ void enable() const; void disable() const; + int shader_program_id() const + %code%{ RETVAL = THIS->shader_program_id; %}; + std::string last_error() const %code%{ RETVAL = THIS->last_error; %}; }; @@ -45,6 +48,9 @@ int zoom_to_volumes() %code%{ RETVAL = THIS->zoom_to_volumes; %}; + void set_layer_height_texture_data(unsigned int texture_id, unsigned int shader_id, PrintObject* print_object, float z_cursor_relative, float edit_band_width); + void reset_layer_height_texture_data(); + int object_idx() const; int volume_idx() const; int instance_idx() const; @@ -97,6 +103,9 @@ void finalize_geometry(bool use_VBOs); void release_geometry(); + void set_print_box(float min_x, float min_y, float min_z, float max_x, float max_y, float max_z); + void update_outside_state(DynamicPrintConfig* config, bool all_inside); + bool move_volume_up(int idx) %code%{ if (idx > 0 && idx < int(THIS->volumes.size())) { @@ -154,13 +163,6 @@ finalize_legend_texture() OUTPUT: RETVAL -unsigned int -get_legend_texture_id() - CODE: - RETVAL = _3DScene::get_legend_texture_id(); - OUTPUT: - RETVAL - unsigned int get_legend_texture_width() CODE: @@ -179,7 +181,38 @@ void reset_legend_texture() CODE: _3DScene::reset_legend_texture(); - + +void +generate_warning_texture(std::string msg) + CODE: + _3DScene::generate_warning_texture(msg); + +unsigned int +finalize_warning_texture() + CODE: + RETVAL = _3DScene::finalize_warning_texture(); + OUTPUT: + RETVAL + +unsigned int +get_warning_texture_width() + CODE: + RETVAL = _3DScene::get_warning_texture_width(); + OUTPUT: + RETVAL + +unsigned int +get_warning_texture_height() + CODE: + RETVAL = _3DScene::get_warning_texture_height(); + OUTPUT: + RETVAL + +void +reset_warning_texture() + CODE: + _3DScene::reset_warning_texture(); + void _load_print_toolpaths(print, volumes, tool_colors, use_VBOs) Print *print; diff --git a/xs/xsp/Model.xsp b/xs/xsp/Model.xsp index c0271ae75..78c94661e 100644 --- a/xs/xsp/Model.xsp +++ b/xs/xsp/Model.xsp @@ -99,6 +99,9 @@ void print_info() const; + bool fits_print_volume(DynamicPrintConfig* config) const + %code%{ RETVAL = THIS->fits_print_volume(config); %}; + bool store_stl(char *path, bool binary) %code%{ TriangleMesh mesh = THIS->mesh(); RETVAL = Slic3r::store_stl(path, &mesh, binary); %}; bool store_amf(char *path, Print* print) @@ -361,9 +364,9 @@ ModelMaterial::attributes() %code%{ RETVAL = &THIS->offset; %}; void set_rotation(double val) - %code%{ THIS->rotation = val; %}; + %code%{ THIS->rotation = val; THIS->get_object()->invalidate_bounding_box(); %}; void set_scaling_factor(double val) - %code%{ THIS->scaling_factor = val; %}; + %code%{ THIS->scaling_factor = val; THIS->get_object()->invalidate_bounding_box(); %}; void set_offset(Pointf *offset) %code%{ THIS->offset = *offset; %};