From 045de596e2ff1ad6d7cc44888d8e7bbc25b4c9f8 Mon Sep 17 00:00:00 2001 From: bubnikv Date: Mon, 20 Mar 2017 12:05:20 +0100 Subject: [PATCH] Use OpenGL 2.0 shaders for the layer height rendering. Use OpenGL 2.0 shaders for the print path rendering for performance reasons. --- lib/Slic3r/GUI.pm | 1 - lib/Slic3r/GUI/3DScene.pm | 346 +++++++++++++++++++++++++--------- lib/Slic3r/GUI/GLShader.pm | 193 ------------------- xs/lib/Slic3r/XS.pm | 3 + xs/src/perlglue.cpp | 1 + xs/src/slic3r/GUI/3DScene.cpp | 128 ++++++++++--- xs/src/slic3r/GUI/3DScene.hpp | 17 +- xs/xsp/GUI_3DScene.xsp | 34 +++- xs/xsp/my.map | 2 + xs/xsp/typemap.xspt | 2 + 10 files changed, 403 insertions(+), 324 deletions(-) delete mode 100644 lib/Slic3r/GUI/GLShader.pm diff --git a/lib/Slic3r/GUI.pm b/lib/Slic3r/GUI.pm index 6a85760cf..54f30c276 100644 --- a/lib/Slic3r/GUI.pm +++ b/lib/Slic3r/GUI.pm @@ -14,7 +14,6 @@ use Slic3r::GUI::ConfigWizard; use Slic3r::GUI::Controller; use Slic3r::GUI::Controller::ManualControlDialog; use Slic3r::GUI::Controller::PrinterPanel; -use Slic3r::GUI::GLShader; use Slic3r::GUI::MainFrame; use Slic3r::GUI::Notifier; use Slic3r::GUI::Plater; diff --git a/lib/Slic3r/GUI/3DScene.pm b/lib/Slic3r/GUI/3DScene.pm index bee3bc0f6..391105c0d 100644 --- a/lib/Slic3r/GUI/3DScene.pm +++ b/lib/Slic3r/GUI/3DScene.pm @@ -149,8 +149,6 @@ sub new { $self->{layer_height_edit_last_z} = 0.; $self->{layer_height_edit_last_action} = 0; - $self->{use_VBOs} = 0; - $self->reset_objects; EVT_PAINT($self, sub { @@ -194,28 +192,23 @@ sub layer_editing_enabled { if (! $self->{layer_editing_initialized}) { # Enabling the layer editing for the first time. This triggers compilation of the necessary OpenGL shaders. # If compilation fails, a message box is shown with the error codes. - my $shader = $self->{shader} = new Slic3r::GUI::GLShader; + my $shader = new Slic3r::GUI::_3DScene::GLShader; my $error_message; - if (ref($shader)) { - my $info = $shader->Load($self->_fragment_shader, $self->_vertex_shader); - if (defined($info)) { - # Compilation or linking of the shaders failed. - $error_message = "Cannot compile an OpenGL Shader, therefore the Variable Layer Editing will be disabled.\n\n" - . $info; - } 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_WRAP_S, GL_CLAMP); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 1); - glBindTexture(GL_TEXTURE_2D, 0); - } + if (! $shader->load($self->_fragment_shader_variable_layer_height, $self->_vertex_shader_variable_layer_height)) { + # Compilation or linking of the shaders failed. + $error_message = "Cannot compile an OpenGL Shader, therefore the Variable Layer Editing will be disabled.\n\n" + . $shader->last_error; + $shader = undef; } 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; + $self->{layer_height_edit_shader} = $shader; + ($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_WRAP_S, GL_CLAMP); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 1); + glBindTexture(GL_TEXTURE_2D, 0); } if (defined($error_message)) { # Don't enable the layer editing tool. @@ -361,6 +354,7 @@ sub mouse_event { # Index 2 means no editing, just wait for mouse up event. $self->_layer_height_edited(2); $self->Refresh; + $self->Update; } else { # Select volume in this 3D canvas. # Don't deselect a volume if layer editing is enabled. We want the object to stay selected @@ -380,6 +374,7 @@ sub mouse_event { } $self->Refresh; + $self->Update; } # propagate event through callback @@ -421,6 +416,7 @@ sub mouse_event { $self->_drag_start_pos($cur_pos); $self->_dragged(1); $self->Refresh; + $self->Update; } elsif ($e->Dragging) { if ($self->_layer_height_edited && $object_idx_selected != -1) { $self->_variable_layer_thickness_action($e) if ($self->_layer_height_edited == 1); @@ -445,6 +441,7 @@ sub mouse_event { } $self->on_viewport_changed->() if $self->on_viewport_changed; $self->Refresh; + $self->Update; } $self->_drag_start_pos($pos); } elsif ($e->MiddleIsDown || $e->RightIsDown) { @@ -459,6 +456,7 @@ sub mouse_event { ); $self->on_viewport_changed->() if $self->on_viewport_changed; $self->Refresh; + $self->Update; } $self->_drag_start_xy($pos); } @@ -488,7 +486,10 @@ sub mouse_event { $self->_mouse_pos($pos); # Only refresh if picking is enabled, in that case the objects may get highlighted if the mouse cursor # hovers over. - $self->Refresh if ($self->enable_picking); + if ($self->enable_picking) { + $self->Update; + $self->Refresh; + } } else { $e->Skip(); } @@ -540,8 +541,8 @@ sub mouse_wheel_event { # Reset selection. sub reset_objects { my ($self) = @_; - if ($self->{use_VBOs}) { - $self->GetContext; + if ($self->GetContext) { + $self->SetCurrent($self->GetContext); $self->volumes->release_geometry; } $self->volumes->erase; @@ -898,6 +899,24 @@ sub SetCurrent { } } +sub UseVBOs { + my ($self) = @_; + + if (! defined ($self->{use_VBOs})) { + # Don't use VBOs if anything fails. + $self->{use_VBOs} = 0; + if ($self->GetContext) { + $self->SetCurrent($self->GetContext); + my @gl_version = split(/\./, glGetString(GL_VERSION)); + $self->{use_VBOs} = int($gl_version[0]) >= 2; + # print "InitGL $self OpenGL major: $gl_version[0], minor: $gl_version[1]. Use VBOs: ", $self->{use_VBOs}, "\n"; + } + #FIXME + $self->{use_VBOs} = 0; + } + return $self->{use_VBOs}; +} + sub Resize { my ($self, $x, $y) = @_; @@ -948,10 +967,6 @@ sub InitGL { return unless $self->GetContext; $self->init(1); - my @gl_version = split(/\./, glGetString(GL_VERSION)); - $self->{use_VBOs} = int($gl_version[0]) >= 2; -# print "OpenGL major: $gl_version[0], minor: $gl_version[1]. Use VBOs: ", $self->{use_VBOs}, "\n"; - glClearColor(0, 0, 0, 1); glColor3f(1, 0, 0); glEnable(GL_DEPTH_TEST); @@ -982,10 +997,10 @@ sub InitGL { # Enables Smooth Color Shading; try GL_FLAT for (lack of) fun. glShadeModel(GL_SMOOTH); - glMaterialfv_p(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, 0.5, 0.3, 0.3, 1); - glMaterialfv_p(GL_FRONT_AND_BACK, GL_SPECULAR, 1, 1, 1, 1); - glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, 50); - glMaterialfv_p(GL_FRONT_AND_BACK, GL_EMISSION, 0.1, 0, 0, 0.9); +# glMaterialfv_p(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, 0.5, 0.3, 0.3, 1); +# glMaterialfv_p(GL_FRONT_AND_BACK, GL_SPECULAR, 1, 1, 1, 1); +# glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, 50); +# glMaterialfv_p(GL_FRONT_AND_BACK, GL_EMISSION, 0.1, 0, 0, 0.9); # A handy trick -- have surface material mirror the color. glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE); @@ -993,12 +1008,31 @@ sub InitGL { glEnable(GL_MULTISAMPLE); Slic3r::GUI::_3DScene::_glew_init; + + if ($self->UseVBOs) { + my $shader = new Slic3r::GUI::_3DScene::GLShader; + if (! $shader->load($self->_fragment_shader_Gouraud, $self->_vertex_shader_Gouraud)) { +# if (! $shader->load($self->_fragment_shader_Phong, $self->_vertex_shader_Phong)) { + print "Compilaton of path shader failed: \n" . $shader->last_error . "\n"; + $shader = undef; + } else { + $self->{plain_shader} = $shader; + } + } } sub DestroyGL { my $self = shift; - if ($self->init && $self->GetContext) { - delete $self->{shader}; + if ($self->GetContext) { + $self->SetCurrent($self->GetContext); + if ($self->{plain_shader}) { + $self->{plain_shader}->release; + delete $self->{plain_shader}; + } + if ($self->{layer_height_edit_shader}) { + $self->{layer_height_edit_shader}->release; + delete $self->{layer_height_edit_shader}; + } $self->volumes->release_geometry; } } @@ -1173,7 +1207,15 @@ sub Render { glEnable(GL_LIGHTING); # draw objects - $self->draw_volumes; + if ($self->enable_picking) { + $self->draw_volumes; + } elsif ($self->UseVBOs) { + $self->{plain_shader}->enable if $self->{plain_shader}; + $self->volumes->render_VBOs; + $self->{plain_shader}->disable; + } else { + $self->volumes->render_legacy; + } # draw cutting plane if (defined $self->cutting_plane_z) { @@ -1199,7 +1241,7 @@ sub Render { $self->SwapBuffers(); # Calling glFinish has a performance penalty, but it seems to fix some OpenGL driver hang-up with extremely large scenes. - glFinish(); +# glFinish(); } sub draw_volumes { @@ -1217,23 +1259,15 @@ sub draw_volumes { my $volume = $self->volumes->[$volume_idx]; my $shader_active = 0; - if ($self->layer_editing_enabled && ! $fakecolor && $volume->selected && $self->{shader} && $volume->has_layer_height_texture) { + if ($self->layer_editing_enabled && ! $fakecolor && $volume->selected && $self->{layer_height_edit_shader} && $volume->has_layer_height_texture) { # Update the height texture if the ModelObject::layer_height_texture is invalid. $volume->generate_layer_height_texture( $self->{print}->get_object(int($volume->select_group_id / 1000000)), 0); - $self->{shader}->Enable; - my $z_to_texture_row_id = $self->{shader}->Map('z_to_texture_row'); - my $z_texture_row_to_normalized_id = $self->{shader}->Map('z_texture_row_to_normalized'); - my $z_cursor_id = $self->{shader}->Map('z_cursor'); - my $z_cursor_band_width_id = $self->{shader}->Map('z_cursor_band_width'); - die if ! defined($z_to_texture_row_id); - die if ! defined($z_texture_row_to_normalized_id); - die if ! defined($z_cursor_id); - die if ! defined($z_cursor_band_width_id); - glUniform1fARB($z_to_texture_row_id, $volume->layer_height_texture_z_to_row_id); - glUniform1fARB($z_texture_row_to_normalized_id, 1. / $volume->layer_height_texture_height); - glUniform1fARB($z_cursor_id, $volume->bounding_box->z_max * $z_cursor_relative); - glUniform1fARB($z_cursor_band_width_id, $self->{layer_height_edit_band_width}); + $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); @@ -1266,7 +1300,7 @@ sub draw_volumes { if ($shader_active) { glBindTexture(GL_TEXTURE_2D, 0); - $self->{shader}->Disable; + $self->{layer_height_edit_shader}->disable; } } glDisableClientState(GL_NORMAL_ARRAY); @@ -1356,7 +1390,7 @@ sub draw_active_object_annotations { # $fakecolor is a boolean indicating, that the objects shall be rendered in a color coding the object index for picking. my ($self) = @_; - return if (! $self->{shader} || ! $self->layer_editing_enabled); + return if (! $self->{layer_height_edit_shader} || ! $self->layer_editing_enabled); my $volume; foreach my $volume_idx (0..$#{$self->volumes}) { @@ -1374,13 +1408,11 @@ sub draw_active_object_annotations { my ($reset_left, $reset_bottom, $reset_right, $reset_top) = $self->_variable_layer_thickness_reset_rect_viewport; my $z_cursor_relative = $self->_variable_layer_thickness_bar_mouse_cursor_z_relative; - $self->{shader}->Enable; - my $z_to_texture_row_id = $self->{shader}->Map('z_to_texture_row'); - my $z_texture_row_to_normalized_id = $self->{shader}->Map('z_texture_row_to_normalized'); - my $z_cursor_id = $self->{shader}->Map('z_cursor'); - glUniform1fARB($z_to_texture_row_id, $volume->layer_height_texture_z_to_row_id); - glUniform1fARB($z_texture_row_to_normalized_id, 1. / $volume->layer_height_texture_height); - glUniform1fARB($z_cursor_id, $volume->bounding_box->z_max * $z_cursor_relative); + $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}); 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); @@ -1405,7 +1437,7 @@ sub draw_active_object_annotations { glVertex3f($bar_left, $bar_top, $volume->bounding_box->z_max); glEnd(); glBindTexture(GL_TEXTURE_2D, 0); - $self->{shader}->Disable; + $self->{layer_height_edit_shader}->disable; # Paint the tooltip. if ($self->_variable_layer_thickness_load_overlay_image) { @@ -1455,9 +1487,7 @@ sub opengl_info my $gl_version = glGetString(GL_VERSION); 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 $glsl_version = glGetString(GL_SHADING_LANGUAGE_VERSION); my $out = ''; $out .= "$tag{h2start}OpenGL installation$tag{h2end}$tag{eol}"; @@ -1467,24 +1497,14 @@ sub opengl_info $out .= " $tag{bstart}renderer: $tag{bend}${gl_renderer}$tag{eol}"; $out .= " $tag{bstart}GLSL version: $tag{bend}${glsl_version}$tag{eol}"; - # Check for required OpenGL extensions - $out .= "$tag{h2start}Required extensions (* implemented):$tag{h2end}$tag{eol}"; - my @extensions_required = qw(GL_ARB_shader_objects GL_ARB_fragment_shader GL_ARB_vertex_shader GL_ARB_shading_language_100); - foreach my $ext (sort @extensions_required) { - my $stat = glpCheckExtension($ext); - $out .= sprintf("%s ${ext}$tag{eol}", $stat?' ':'*'); - $out .= sprintf(" ${stat}$tag{eol}") if ($stat && $stat !~ m|^$ext |); - } # Check for other OpenGL extensions $out .= "$tag{h2start}Installed extensions (* implemented in the module):$tag{h2end}$tag{eol}"; my $extensions = glGetString(GL_EXTENSIONS); my @extensions = split(' ',$extensions); foreach my $ext (sort @extensions) { - if(! grep(/^$extensions$/, @extensions_required)) { - my $stat = glpCheckExtension($ext); - $out .= sprintf("%s ${ext}$tag{eol}", $stat?' ':'*'); - $out .= sprintf(" ${stat}$tag{eol}") if ($stat && $stat !~ m|^$ext |); - } + my $stat = glpCheckExtension($ext); + $out .= sprintf("%s ${ext}$tag{eol}", $stat?' ':'*'); + $out .= sprintf(" ${stat}$tag{eol}") if ($stat && $stat !~ m|^$ext |); } return $out; @@ -1519,17 +1539,167 @@ sub _report_opengl_state } } -sub _vertex_shader { +sub _vertex_shader_Gouraud { + return <<'VERTEX'; +#version 110 + +#define INTENSITY_CORRECTION 0.7 + +#define LIGHT_TOP_DIR -0.6/1.31, 0.6/1.31, 1./1.31 +#define LIGHT_TOP_DIFFUSE (0.8 * INTENSITY_CORRECTION) +#define LIGHT_TOP_SPECULAR (0.5 * INTENSITY_CORRECTION) +#define LIGHT_TOP_SHININESS 50. + +#define LIGHT_FRONT_DIR 1./1.43, 0.2/1.43, 1./1.43 +#define LIGHT_FRONT_DIFFUSE (0.3 * INTENSITY_CORRECTION) +#define LIGHT_FRONT_SPECULAR (0.0 * INTENSITY_CORRECTION) +#define LIGHT_FRONT_SHININESS 50. + +#define INTENSITY_AMBIENT 0.3 + +varying float intensity_specular; +varying float intensity_tainted; + +void main() +{ + vec3 eye, normal, lightDir, viewVector, halfVector; + float NdotL, NdotHV; + + eye = vec3(0., 0., 1.); + + // First transform the normal into eye space and normalize the result. + 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); + + // 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); + + intensity_tainted = INTENSITY_AMBIENT + NdotL * LIGHT_TOP_DIFFUSE; + intensity_specular = 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); + + gl_Position = ftransform(); +} + +VERTEX +} + +sub _fragment_shader_Gouraud { + return <<'FRAGMENT'; +#version 110 + +varying float intensity_specular; +varying float intensity_tainted; + +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; +} + +FRAGMENT +} + +sub _vertex_shader_Phong { + return <<'VERTEX'; +#version 110 + +varying vec3 normal; +varying vec3 eye; +void main(void) +{ + eye = normalize(vec3(gl_ModelViewMatrix * gl_Vertex)); + normal = normalize(gl_NormalMatrix * gl_Normal); + gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex; +} +VERTEX +} + +sub _fragment_shader_Phong { + return <<'FRAGMENT'; +#version 110 + +#define INTENSITY_CORRECTION 0.7 + +#define LIGHT_TOP_DIR -0.6/1.31, 0.6/1.31, 1./1.31 +#define LIGHT_TOP_DIFFUSE (0.8 * INTENSITY_CORRECTION) +#define LIGHT_TOP_SPECULAR (0.5 * INTENSITY_CORRECTION) +//#define LIGHT_TOP_SHININESS 50. +#define LIGHT_TOP_SHININESS 10. + +#define LIGHT_FRONT_DIR 1./1.43, 0.2/1.43, 1./1.43 +#define LIGHT_FRONT_DIFFUSE (0.3 * INTENSITY_CORRECTION) +#define LIGHT_FRONT_SPECULAR (0.0 * INTENSITY_CORRECTION) +#define LIGHT_FRONT_SHININESS 50. + +#define INTENSITY_AMBIENT 0.0 + +varying vec3 normal; +varying vec3 eye; +uniform vec4 uniform_color; +void main() { + + float intensity_specular = 0.; + float intensity_tainted = 0.; + float intensity = max(dot(normal,vec3(LIGHT_TOP_DIR)), 0.0); + // if the vertex is lit compute the specular color + if (intensity > 0.0) { + intensity_tainted = LIGHT_TOP_DIFFUSE * intensity; + // compute the half vector + vec3 h = normalize(vec3(LIGHT_TOP_DIR) + eye); + // compute the specular term into spec + intensity_specular = LIGHT_TOP_SPECULAR * pow(max(dot(h, normal), 0.0), LIGHT_TOP_SHININESS); + } + intensity = max(dot(normal,vec3(LIGHT_FRONT_DIR)), 0.0); + // if the vertex is lit compute the specular color + if (intensity > 0.0) { + intensity_tainted += LIGHT_FRONT_DIFFUSE * intensity; + // compute the half vector +// vec3 h = normalize(vec3(LIGHT_FRONT_DIR) + eye); + // 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); + gl_FragColor.a = uniform_color.a; +} +FRAGMENT +} + +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 LIGHT_FRONT_DIR 0., 0., 1. #define LIGHT_FRONT_DIFFUSE 0.5 #define LIGHT_FRONT_SPECULAR 0.3 +#define LIGHT_FRONT_SHININESS 50. #define INTENSITY_AMBIENT 0.1 @@ -1562,7 +1732,7 @@ void main() intensity_specular = 0.; // if (NdotL > 0.0) -// intensity_specular = LIGHT_TOP_SPECULAR * pow(max(dot(normal, halfVector), 0.0), gl_FrontMaterial.shininess); +// 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); @@ -1572,7 +1742,7 @@ void main() // 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), gl_FrontMaterial.shininess); + intensity_specular += LIGHT_FRONT_SPECULAR * pow(max(dot(normal, halfVector), 0.0), LIGHT_FRONT_SHININESS); // Scaled to widths of the Z texture. object_z = gl_Vertex.z / gl_Vertex.w; @@ -1583,7 +1753,7 @@ void main() VERTEX } -sub _fragment_shader { +sub _fragment_shader_variable_layer_height { return <<'FRAGMENT'; #version 110 @@ -1662,6 +1832,8 @@ sub new { sub load_object { my ($self, $model, $print, $obj_idx, $instance_idxs) = @_; + $self->SetCurrent($self->GetContext) if $self->UseVBOs; + my $model_object; if ($model->isa('Slic3r::Model::Object')) { $model_object = $model; @@ -1672,7 +1844,9 @@ sub load_object { } $instance_idxs ||= [0..$#{$model_object->instances}]; - my $volume_indices = $self->volumes->load_object($model_object, $obj_idx, $instance_idxs, $self->color_by, $self->select_by, $self->drag_by); + my $volume_indices = $self->volumes->load_object( + $model_object, $obj_idx, $instance_idxs, $self->color_by, $self->select_by, $self->drag_by, + $self->UseVBOs); return @{$volume_indices}; } @@ -1681,8 +1855,8 @@ sub load_object { sub load_print_toolpaths { my ($self, $print) = @_; - $self->GetContext if ($self->{use_VBOs}); - Slic3r::GUI::_3DScene::_load_print_toolpaths($print, $self->volumes, $self->{use_VBOs}) + $self->SetCurrent($self->GetContext) if $self->UseVBOs; + Slic3r::GUI::_3DScene::_load_print_toolpaths($print, $self->volumes, $self->UseVBOs) if ($print->step_done(STEP_SKIRT) && $print->step_done(STEP_BRIM)); } @@ -1692,8 +1866,8 @@ sub load_print_toolpaths { sub load_print_object_toolpaths { my ($self, $object) = @_; - $self->GetContext if ($self->{use_VBOs}); - Slic3r::GUI::_3DScene::_load_print_object_toolpaths($object, $self->volumes, $self->{use_VBOs}); + $self->SetCurrent($self->GetContext) if $self->UseVBOs; + Slic3r::GUI::_3DScene::_load_print_object_toolpaths($object, $self->volumes, $self->UseVBOs); } sub set_toolpaths_range { diff --git a/lib/Slic3r/GUI/GLShader.pm b/lib/Slic3r/GUI/GLShader.pm deleted file mode 100644 index 8db05f5e8..000000000 --- a/lib/Slic3r/GUI/GLShader.pm +++ /dev/null @@ -1,193 +0,0 @@ -############################################################ -# -# Stripped down from the Perl OpenGL::Shader package by Vojtech Bubnik -# to only support the GLSL shaders. The original source was not maintained -# and did not install properly through the CPAN archive, and it was unnecessary -# complex. -# -# Original copyright: -# -# Copyright 2007 Graphcomp - ALL RIGHTS RESERVED -# Author: Bob "grafman" Free - grafman@graphcomp.com -# -# This program is free software; you can redistribute it and/or -# modify it under the same terms as Perl itself. -# -############################################################ - -package Slic3r::GUI::GLShader; -use OpenGL(':all'); - -# Avoid cloning this class by the worker threads. -sub CLONE_SKIP { 1 } - -# Shader constructor -sub new -{ - # Check for required OpenGL extensions - my $error_message = ''; - my $extensions_valid = 1; - foreach my $i (map "GL_ARB_$_", qw(shader_objects fragment_shader vertex_shader shading_language_100)) { - if (OpenGL::glpCheckExtension($i)) { - $error_message .= "Missing OpenGL extension: $i\n"; - $extensions_valid = 0; - } - } - - if (! $extensions_valid) { - # Cannot create a shader object, because some of the necessary OpenGL extensions are missing. - # Form an error message. - my $gl_version = glGetString(GL_VERSION); - 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' && $gl_vendor eq 'Microsoft Corporation' && $gl_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; - } - - my $this = shift; - my $class = ref($this) || $this; - my($type) = @_; - my $self = {type => uc($type)}; - bless($self, $class); - - # 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 -# Must be disabled first -sub DESTROY -{ - my($self) = @_; - - if ($self->{program}) { - glDetachObjectARB($self->{program},$self->{fragment_id}) if ($self->{fragment_id}); - glDetachObjectARB($self->{program},$self->{vertex_id}) if ($self->{vertex_id}); - glDeleteProgramsARB_p($self->{program}); - } - - glDeleteProgramsARB_p($self->{fragment_id}) if ($self->{fragment_id}); - glDeleteProgramsARB_p($self->{vertex_id}) if ($self->{vertex_id}); -} - -# Load shader strings -sub Load -{ - my($self, $fragment, $vertex) = @_; - - # Load fragment code - if ($fragment) { - $self->{fragment_id} = glCreateShaderObjectARB(GL_FRAGMENT_SHADER); - return "glCreateShaderObjectARB failed." 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); - } - - # Load vertex code - if ($vertex) { - $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); - } - - # Link shaders - my $sp = glCreateProgramObjectARB(); - 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.'; - } - - $self->{program} = $sp; - return undef; -} - -# Enable shader -sub Enable -{ - my($self) = @_; - glUseProgramObjectARB($self->{program}) if ($self->{program}); -} - -# Disable shader -sub Disable -{ - my($self) = @_; - glUseProgramObjectARB(0) if ($self->{program}); -} - -# Return shader vertex attribute ID -sub MapAttr -{ - my($self,$attr) = @_; - return undef if (!$self->{program}); - my $id = glGetAttribLocationARB_p($self->{program},$attr); - return undef if ($id < 0); - return $id; -} - -# Return shader uniform variable ID -sub Map -{ - my($self,$var) = @_; - return undef if (!$self->{program}); - my $id = glGetUniformLocationARB_p($self->{program},$var); - return undef if ($id < 0); - return $id; -} - -# Set shader vector -sub SetVector -{ - my($self,$var,@values) = @_; - - my $id = $self->Map($var); - return 'Unable to map $var' if (!defined($id)); - - my $count = scalar(@values); - eval('glUniform'.$count.'fARB($id,@values)'); - - return ''; -} - -# Set shader 4x4 matrix -sub SetMatrix -{ - my($self,$var,$oga) = @_; - - my $id = $self->Map($var); - return 'Unable to map $var' if (!defined($id)); - - glUniformMatrix4fvARB_c($id,1,0,$oga->ptr()); - return ''; -} - -1; -__END__ diff --git a/xs/lib/Slic3r/XS.pm b/xs/lib/Slic3r/XS.pm index 3baf0dfe3..ea0d12be6 100644 --- a/xs/lib/Slic3r/XS.pm +++ b/xs/lib/Slic3r/XS.pm @@ -247,6 +247,9 @@ sub new { ); } +package Slic3r::GUI::_3DScene::GLShader; +sub CLONE_SKIP { 1 } + package Slic3r::GUI::_3DScene::GLVolume::Collection; use overload '@{}' => sub { $_[0]->arrayref }, diff --git a/xs/src/perlglue.cpp b/xs/src/perlglue.cpp index d8f9db480..d76671833 100644 --- a/xs/src/perlglue.cpp +++ b/xs/src/perlglue.cpp @@ -60,6 +60,7 @@ REGISTER_CLASS(Surface, "Surface"); REGISTER_CLASS(SurfaceCollection, "Surface::Collection"); REGISTER_CLASS(PrintObjectSupportMaterial, "Print::SupportMaterial2"); REGISTER_CLASS(TriangleMesh, "TriangleMesh"); +REGISTER_CLASS(GLShader, "GUI::_3DScene::GLShader"); REGISTER_CLASS(GLVolume, "GUI::_3DScene::GLVolume"); REGISTER_CLASS(GLVolumeCollection, "GUI::_3DScene::GLVolume::Collection"); diff --git a/xs/src/slic3r/GUI/3DScene.cpp b/xs/src/slic3r/GUI/3DScene.cpp index 3140aa85d..09fb23b6f 100644 --- a/xs/src/slic3r/GUI/3DScene.cpp +++ b/xs/src/slic3r/GUI/3DScene.cpp @@ -34,8 +34,6 @@ void GLIndexedVertexArray::load_mesh_flat_shading(const TriangleMesh &mesh) 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); } - - vertices_and_normals_interleaved_size = this->vertices_and_normals_interleaved.size(); } void GLIndexedVertexArray::finalize_geometry(bool use_VBOs) @@ -85,11 +83,20 @@ void GLIndexedVertexArray::release_geometry() void GLIndexedVertexArray::render() const { + if (this->vertices_and_normals_interleaved_VBO_id) { + glBindBuffer(GL_ARRAY_BUFFER, this->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); + } else { + glVertexPointer(3, GL_FLOAT, 6 * sizeof(float), this->vertices_and_normals_interleaved.data() + 3); + glNormalPointer(GL_FLOAT, 6 * sizeof(float), this->vertices_and_normals_interleaved.data()); + } + glEnableClientState(GL_VERTEX_ARRAY); + glEnableClientState(GL_NORMAL_ARRAY); + if (this->indexed()) { if (this->vertices_and_normals_interleaved_VBO_id) { // Render using the Vertex Buffer Objects. - glBindBuffer(GL_ARRAY_BUFFER, this->vertices_and_normals_interleaved_VBO_id); - glInterleavedArrays(GL_N3F_V3F, 0, nullptr); if (this->triangle_indices_size > 0) { glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, this->triangle_indices_VBO_id); glDrawElements(GL_TRIANGLES, GLsizei(this->triangle_indices_size), GL_UNSIGNED_INT, nullptr); @@ -98,32 +105,21 @@ void GLIndexedVertexArray::render() const glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, this->quad_indices_VBO_id); glDrawElements(GL_QUADS, GLsizei(this->quad_indices_size), GL_UNSIGNED_INT, nullptr); } - glBindBuffer(GL_ARRAY_BUFFER, 0); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); } else { // Render in an immediate mode. - glInterleavedArrays(GL_N3F_V3F, 0, this->vertices_and_normals_interleaved.data()); - // Due to issues with the Intel drivers, rather limit the amount of vertices processed per draw command. if (! this->triangle_indices.empty()) glDrawElements(GL_TRIANGLES, GLsizei(this->triangle_indices_size), GL_UNSIGNED_INT, this->triangle_indices.data()); if (! this->quad_indices.empty()) glDrawElements(GL_QUADS, GLsizei(this->quad_indices_size), GL_UNSIGNED_INT, this->quad_indices.data()); } - } else { - if (this->vertices_and_normals_interleaved_VBO_id) { - // Render using the Vertex Buffer Objects. - glBindBuffer(GL_ARRAY_BUFFER, this->vertices_and_normals_interleaved_VBO_id); - glInterleavedArrays(GL_N3F_V3F, 0, nullptr); - glDrawArrays(GL_TRIANGLES, 0, GLsizei(this->vertices_and_normals_interleaved_size / 6)); - glBindBuffer(GL_ARRAY_BUFFER, 0); - } else { - // Render in an immediate mode. - glInterleavedArrays(GL_N3F_V3F, 0, this->vertices_and_normals_interleaved.data()); - glDrawArrays(GL_TRIANGLES, 0, GLsizei(this->vertices_and_normals_interleaved_size / 6)); - } - } + } else + glDrawArrays(GL_TRIANGLES, 0, GLsizei(this->vertices_and_normals_interleaved_size / 6)); - glInterleavedArrays(GL_N3F_V3F, 0, nullptr); + if (this->vertices_and_normals_interleaved_VBO_id) + glBindBuffer(GL_ARRAY_BUFFER, 0); + glDisableClientState(GL_VERTEX_ARRAY); + glDisableClientState(GL_NORMAL_ARRAY); } void GLIndexedVertexArray::render( @@ -137,7 +133,10 @@ void GLIndexedVertexArray::render( if (this->vertices_and_normals_interleaved_VBO_id) { // Render using the Vertex Buffer Objects. glBindBuffer(GL_ARRAY_BUFFER, this->vertices_and_normals_interleaved_VBO_id); - glInterleavedArrays(GL_N3F_V3F, 0, nullptr); + glVertexPointer(3, GL_FLOAT, 6 * sizeof(float), (const void*)(3 * sizeof(float))); + glNormalPointer(GL_FLOAT, 6 * sizeof(float), nullptr); + glEnableClientState(GL_VERTEX_ARRAY); + glEnableClientState(GL_NORMAL_ARRAY); if (this->triangle_indices_size > 0) { glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, this->triangle_indices_VBO_id); glDrawElements(GL_TRIANGLES, GLsizei(std::min(this->triangle_indices_size, tverts_range.second - tverts_range.first)), GL_UNSIGNED_INT, (const void*)(tverts_range.first * 4)); @@ -150,22 +149,26 @@ void GLIndexedVertexArray::render( glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); } else { // Render in an immediate mode. - glInterleavedArrays(GL_N3F_V3F, 0, this->vertices_and_normals_interleaved.data()); + glVertexPointer(3, GL_FLOAT, 6 * sizeof(float), this->vertices_and_normals_interleaved.data() + 3); + glNormalPointer(GL_FLOAT, 6 * sizeof(float), this->vertices_and_normals_interleaved.data()); + glEnableClientState(GL_VERTEX_ARRAY); + glEnableClientState(GL_NORMAL_ARRAY); if (! this->triangle_indices.empty()) glDrawElements(GL_TRIANGLES, GLsizei(std::min(this->triangle_indices_size, tverts_range.second - tverts_range.first)), GL_UNSIGNED_INT, (const void*)(this->triangle_indices.data() + tverts_range.first)); if (! this->quad_indices.empty()) glDrawElements(GL_QUADS, GLsizei(std::min(this->quad_indices_size, qverts_range.second - qverts_range.first)), GL_UNSIGNED_INT, (const void*)(this->quad_indices.data() + qverts_range.first)); } - glInterleavedArrays(GL_N3F_V3F, 0, nullptr); + glDisableClientState(GL_VERTEX_ARRAY); + glDisableClientState(GL_NORMAL_ARRAY); } void GLVolume::set_range(double min_z, double max_z) { this->qverts_range.first = 0; - this->qverts_range.second = this->indexed_vertex_array.quad_indices.size(); + this->qverts_range.second = this->indexed_vertex_array.quad_indices_size; this->tverts_range.first = 0; - this->tverts_range.second = this->indexed_vertex_array.triangle_indices.size(); + this->tverts_range.second = this->indexed_vertex_array.triangle_indices_size; if (! this->print_zs.empty()) { // The Z layer range is specified. // First test whether the Z span of this object is not out of (min_z, max_z) completely. @@ -246,7 +249,8 @@ std::vector GLVolumeCollection::load_object( const std::vector &instance_idxs, const std::string &color_by, const std::string &select_by, - const std::string &drag_by) + const std::string &drag_by, + bool use_VBOs) { static float colors[4][4] = { { 1.0f, 1.0f, 0.0f, 1.f }, @@ -272,7 +276,9 @@ std::vector GLVolumeCollection::load_object( this->volumes.emplace_back(new GLVolume(color)); GLVolume &v = *this->volumes.back(); 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); v.composite_id = obj_idx * 1000000 + volume_idx * 1000 + instance_idx; if (select_by == "object") v.select_group_id = obj_idx * 1000000; @@ -292,6 +298,74 @@ std::vector GLVolumeCollection::load_object( return volumes_idx; } +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); + + GLint current_program_id; + glGetIntegerv(GL_CURRENT_PROGRAM, ¤t_program_id); + GLint color_id = (current_program_id > 0) ? glGetUniformLocation(current_program_id, "uniform_color") : -1; + + for (GLVolume *volume : this->volumes) { + if (! volume->indexed_vertex_array.vertices_and_normals_interleaved_VBO_id) + continue; + 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) + continue; + if (color_id >= 0) + glUniform4fv(color_id, 1, (const GLfloat*)volume->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); + 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)); + } + 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_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 +{ + glCullFace(GL_BACK); + glEnableClientState(GL_VERTEX_ARRAY); + glEnableClientState(GL_NORMAL_ARRAY); + + for (GLVolume *volume : this->volumes) { + assert(! volume->indexed_vertex_array.vertices_and_normals_interleaved_VBO_id); + 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) + continue; + glColor4f(volume->color[0], volume->color[1], volume->color[2], volume->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()); + if (n_triangles > 0) + glDrawElements(GL_TRIANGLES, n_triangles, GL_UNSIGNED_INT, volume->indexed_vertex_array.triangle_indices.data() + volume->tverts_range.first); + if (n_quads > 0) + glDrawElements(GL_QUADS, n_quads, GL_UNSIGNED_INT, volume->indexed_vertex_array.quad_indices.data() + volume->qverts_range.first); + } + + glDisableClientState(GL_VERTEX_ARRAY); + glDisableClientState(GL_NORMAL_ARRAY); +} + // caller is responsible for supplying NO lines with zero length static void thick_lines_to_indexed_vertex_array( const Lines &lines, diff --git a/xs/src/slic3r/GUI/3DScene.hpp b/xs/src/slic3r/GUI/3DScene.hpp index c6ec3b42c..4653d5466 100644 --- a/xs/src/slic3r/GUI/3DScene.hpp +++ b/xs/src/slic3r/GUI/3DScene.hpp @@ -189,10 +189,7 @@ public: selected(false), hover(false), qverts_range(0, size_t(-1)), - tverts_range(0, size_t(-1)), - name_vertex_buffer(0), - name_normal_buffer(0), - name_index_buffer(0) + tverts_range(0, size_t(-1)) { color[0] = r; color[1] = g; @@ -238,12 +235,6 @@ public: // Offset into qverts & tverts, or offsets into indices stored into an OpenGL name_index_buffer. std::vector offsets; - // OpenGL buffers for vertices and their normals. - int name_vertex_buffer; - int name_normal_buffer; - // OpenGL buffer of the indices. - int name_index_buffer; - int object_idx() const { return this->composite_id / 1000000; } int volume_idx() const { return (this->composite_id / 1000) % 1000; } int instance_idx() const { return this->composite_id % 1000; } @@ -296,8 +287,12 @@ public: const std::vector &instance_idxs, const std::string &color_by, const std::string &select_by, - const std::string &drag_by); + const std::string &drag_by, + bool use_VBOs); + // Render the volumes by OpenGL. + void render_VBOs() const; + void render_legacy() const; // Release the geometry data assigned to the volumes. // If OpenGL VBOs were allocated, an OpenGL context has to be active to release them. void release_geometry() { for (auto *v : volumes) v->release_geometry(); } diff --git a/xs/xsp/GUI_3DScene.xsp b/xs/xsp/GUI_3DScene.xsp index b70d99abe..06ae7ce13 100644 --- a/xs/xsp/GUI_3DScene.xsp +++ b/xs/xsp/GUI_3DScene.xsp @@ -1,8 +1,28 @@ %module{Slic3r::XS}; #include +#include "slic3r/GUI/GLShader.hpp" #include "slic3r/GUI/3DScene.hpp" +%name{Slic3r::GUI::_3DScene::GLShader} class GLShader { + GLShader(); + ~GLShader(); + + bool load(const char *fragment_shader, const char *vertex_shader); + void release(); + + int get_attrib_location(const char *name) const; + int get_uniform_location(const char *name) const; + + bool set_uniform(const char *name, float value) const; + + void enable() const; + void disable() const; + + std::string last_error() const + %code%{ RETVAL = THIS->last_error; %}; +}; + %name{Slic3r::GUI::_3DScene::GLVolume} class GLVolume { GLVolume(); ~GLVolume(); @@ -55,7 +75,7 @@ GLVolumeCollection(); ~GLVolumeCollection(); - std::vector load_object(ModelObject *object, int obj_idx, std::vector instance_idxs, std::string color_by, std::string select_by, std::string drag_by); + std::vector load_object(ModelObject *object, int obj_idx, std::vector instance_idxs, std::string color_by, std::string select_by, std::string drag_by, bool use_VBOs); void erase() %code{% THIS->clear(); %}; @@ -65,7 +85,9 @@ void set_range(double low, double high); - void release_geometry(); + void render_VBOs() const; + void render_legacy() const; + void release_geometry(); %{ SV* @@ -97,16 +119,16 @@ void _load_print_toolpaths(print, volumes, use_VBOs) Print *print; GLVolumeCollection *volumes; - bool use_VBOs; + int use_VBOs; CODE: - _3DScene::_load_print_toolpaths(print, volumes, use_VBOs); + _3DScene::_load_print_toolpaths(print, volumes, use_VBOs != 0); void _load_print_object_toolpaths(print_object, volumes, use_VBOs) PrintObject *print_object; GLVolumeCollection *volumes; - bool use_VBOs; + int use_VBOs; CODE: - _3DScene::_load_print_object_toolpaths(print_object, volumes, use_VBOs); + _3DScene::_load_print_object_toolpaths(print_object, volumes, use_VBOs != 0); %} diff --git a/xs/xsp/my.map b/xs/xsp/my.map index 75c73d93d..e48c0eec7 100644 --- a/xs/xsp/my.map +++ b/xs/xsp/my.map @@ -233,6 +233,8 @@ PrintObjectSupportMaterial* O_OBJECT_SLIC3R Ref O_OBJECT_SLIC3R_T Clone O_OBJECT_SLIC3R_T +GLShader* O_OBJECT_SLIC3R +Ref O_OBJECT_SLIC3R_T GLVolume* O_OBJECT_SLIC3R Ref O_OBJECT_SLIC3R_T GLVolumeCollection* O_OBJECT_SLIC3R diff --git a/xs/xsp/typemap.xspt b/xs/xsp/typemap.xspt index 8e22ddbce..9a0efb8d8 100644 --- a/xs/xsp/typemap.xspt +++ b/xs/xsp/typemap.xspt @@ -211,6 +211,8 @@ %typemap{ModelInstancePtrs*}; %typemap{Ref}{simple}; %typemap{Clone}{simple}; +%typemap{GLShader*}; +%typemap{Ref}{simple}; %typemap{GLVolume*}; %typemap{Ref}{simple}; %typemap{GLVolumeCollection*};