diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index 8ea22363b..0a4941c93 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -53,6 +53,12 @@ void PrintConfigDef::init_common_params() def->mode = comAdvanced; def->set_default_value(new ConfigOptionPoints{ Vec2d(0, 0), Vec2d(200, 0), Vec2d(200, 200), Vec2d(0, 200) }); + def = this->add("custom_bed_view", coString); + def->label = L("Prefix for custom bed rendering"); + def->tooltip = L("Filename prefix (filename without extension) of the custom bed .stl and .svg files"); + def->set_default_value(new ConfigOptionString()); + def->cli = ConfigOptionDef::nocli; + def = this->add("layer_height", coFloat); def->label = L("Base Layer height"); def->category = L("Layers and Perimeters"); diff --git a/src/slic3r/GUI/3DBed.cpp b/src/slic3r/GUI/3DBed.cpp index d73e423e0..c465a7709 100644 --- a/src/slic3r/GUI/3DBed.cpp +++ b/src/slic3r/GUI/3DBed.cpp @@ -273,7 +273,7 @@ void Bed3D::Axes::render_axis(double length) const } Bed3D::Bed3D() - : m_type(Custom) + : m_type(Custom), m_bed_view_prefix("") , m_requires_canvas_update(false) #if ENABLE_TEXTURES_FROM_SVG , m_vbo_id(0) @@ -284,13 +284,16 @@ Bed3D::Bed3D() bool Bed3D::set_shape(const Pointfs& shape) { - EType new_type = detect_type(shape); - if (m_shape == shape && m_type == new_type) + std::string new_bed_view_prefix; + EType new_type; + std::tie(new_type, new_bed_view_prefix) = detect_type(shape); + if (m_shape == shape && m_type == new_type && m_bed_view_prefix == new_bed_view_prefix) // No change, no need to update the UI. return false; m_shape = shape; m_type = new_type; + m_bed_view_prefix = new_bed_view_prefix; calc_bounding_boxes(); @@ -352,6 +355,11 @@ void Bed3D::render(GLCanvas3D* canvas, float theta, bool useVBOs, float scale_fa render_prusa(canvas, "sl1", theta > 90.0f); break; } + case CustomBedView: + { + render_custom_bed(theta > 90.0f); + break; + } default: case Custom: { @@ -385,6 +393,11 @@ void Bed3D::render(GLCanvas3D* canvas, float theta, bool useVBOs, float scale_fa render_prusa(canvas, "sl1", theta, useVBOs); break; } + case CustomBedView: + { + render_custom_bed(theta, useVBOs); + break; + } default: case Custom: { @@ -457,9 +470,10 @@ void Bed3D::calc_gridlines(const ExPolygon& poly, const BoundingBox& bed_bbox) printf("Unable to create bed grid lines\n"); } -Bed3D::EType Bed3D::detect_type(const Pointfs& shape) const +std::pair Bed3D::detect_type(const Pointfs& shape) const { EType type = Custom; + std::string bed_view_prefix = ""; auto bundle = wxGetApp().preset_bundle; if (bundle != nullptr) @@ -469,6 +483,23 @@ Bed3D::EType Bed3D::detect_type(const Pointfs& shape) const { if (curr->config.has("bed_shape")) { + if (curr->config.has("custom_bed_view") && (shape == dynamic_cast(curr->config.option("bed_shape"))->values)) + { + if (!static_cast(curr->config.option("custom_bed_view"))->value.empty()) { + bed_view_prefix = static_cast(curr->config.option("custom_bed_view"))->value; + boost::filesystem::path path = bed_view_prefix + ".stl"; + if (!path.is_absolute()) + { + bed_view_prefix = (boost::filesystem::path(Slic3r::data_dir()) / "printer" / bed_view_prefix).string(); + path = bed_view_prefix + ".stl"; + } + type = CustomBedView; + if (!boost::filesystem::exists(path)) { + type = Custom; + } + break; + } + } if ((curr->vendor != nullptr) && (curr->vendor->name == "Prusa Research") && (shape == dynamic_cast(curr->config.option("bed_shape"))->values)) { if (boost::contains(curr->name, "SL1")) @@ -493,7 +524,7 @@ Bed3D::EType Bed3D::detect_type(const Pointfs& shape) const } } - return type; + return std::make_pair(type, bed_view_prefix); } #if ENABLE_TEXTURES_FROM_SVG @@ -650,6 +681,86 @@ void Bed3D::render_prusa_shader(bool transparent) const m_shader.stop_using(); } } + +void Bed3D::render_custom_bed(bool bottom) const +{ + // use anisotropic filter if graphic card allows + GLfloat max_anisotropy = 0.0f; + if (glewIsSupported("GL_EXT_texture_filter_anisotropic")) + glsafe(::glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &max_anisotropy)); + + // use higher resolution images if graphic card allows + GLint max_tex_size; + glsafe(::glGetIntegerv(GL_MAX_TEXTURE_SIZE, &max_tex_size)); + + // clamp or the texture generation becomes too slow + max_tex_size = std::min(max_tex_size, 8192); + + std::string filename = m_bed_view_prefix + ".svg"; + + if ((m_texture.get_id() == 0) || (m_texture.get_source() != filename)) + { + if (!m_texture.load_from_svg_file(filename, true, max_tex_size)) + { + render_custom(); + return; + } + + if (max_anisotropy > 0.0f) + { + glsafe(::glBindTexture(GL_TEXTURE_2D, m_texture.get_id())); + glsafe(::glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, max_anisotropy)); + glsafe(::glBindTexture(GL_TEXTURE_2D, 0)); + } + } + + if (!bottom) + { + filename = m_bed_view_prefix + ".stl"; + if ((m_model.get_filename() != filename) && m_model.init_from_file(filename, true)) { + Vec3d offset = m_bounding_box.center() - Vec3d(0.0, 0.0, 0.5 * m_model.get_bounding_box().size()(2)); + offset += Vec3d(0.0, 0.0, -0.03); + m_model.center_around(offset); + } + + if (!m_model.get_filename().empty()) + { + glsafe(::glEnable(GL_LIGHTING)); + m_model.render(); + glsafe(::glDisable(GL_LIGHTING)); + } + } + + unsigned int triangles_vcount = m_triangles.get_vertices_count(); + if (triangles_vcount > 0) + { + if (m_vbo_id == 0) + { + glsafe(::glGenBuffers(1, &m_vbo_id)); + glsafe(::glBindBuffer(GL_ARRAY_BUFFER, m_vbo_id)); + glsafe(::glBufferData(GL_ARRAY_BUFFER, (GLsizeiptr)m_triangles.get_vertices_data_size(), (const GLvoid*)m_triangles.get_vertices_data(), GL_STATIC_DRAW)); + glsafe(::glBindBuffer(GL_ARRAY_BUFFER, 0)); + } + + glsafe(::glEnable(GL_DEPTH_TEST)); + glsafe(::glDepthMask(GL_FALSE)); + + glsafe(::glEnable(GL_BLEND)); + glsafe(::glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)); + + if (bottom) + glsafe(::glFrontFace(GL_CW)); + + render_prusa_shader(bottom); + + if (bottom) + glsafe(::glFrontFace(GL_CCW)); + + glsafe(::glDisable(GL_BLEND)); + glsafe(::glDepthMask(GL_TRUE)); + } + +} #else void Bed3D::render_prusa(const std::string &key, float theta, bool useVBOs) const { @@ -770,10 +881,141 @@ void Bed3D::render_prusa(const std::string &key, float theta, bool useVBOs) cons glsafe(::glDepthMask(GL_TRUE)); } } + +void Bed3D::render_custom_bed(float theta, bool useVBOs) const +{ + // use higher resolution images if graphic card allows + GLint max_tex_size; + glsafe(::glGetIntegerv(GL_MAX_TEXTURE_SIZE, &max_tex_size)); + + // temporary set to lowest resolution + max_tex_size = 2048; + + if (max_tex_size >= 8192) + tex_path += "_8192"; + else if (max_tex_size >= 4096) + tex_path += "_4096"; + + // use anisotropic filter if graphic card allows + GLfloat max_anisotropy = 0.0f; + if (glewIsSupported("GL_EXT_texture_filter_anisotropic")) + glsafe(::glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &max_anisotropy)); + + std::string filename = m_bed_view_prefix + "_top.png"; + if ((m_top_texture.get_id() == 0) || (m_top_texture.get_source() != filename)) + { + if (!m_top_texture.load_from_file(filename, true)) + { + render_custom(); + return; + } + + if (max_anisotropy > 0.0f) + { + glsafe(::glBindTexture(GL_TEXTURE_2D, m_top_texture.get_id())); + glsafe(::glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, max_anisotropy)); + glsafe(::glBindTexture(GL_TEXTURE_2D, 0)); + } + } + + filename = m_bed_view_prefix + "_bottom.png"; + if ((m_bottom_texture.get_id() == 0) || (m_bottom_texture.get_source() != filename)) + { + if (!m_bottom_texture.load_from_file(filename, true)) + { + render_custom(); + return; + } + + if (max_anisotropy > 0.0f) + { + glsafe(::glBindTexture(GL_TEXTURE_2D, m_bottom_texture.get_id())); + glsafe(::glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, max_anisotropy)); + glsafe(::glBindTexture(GL_TEXTURE_2D, 0)); + } + } + + if (theta <= 90.0f) + { + filename = m_bed_view_prefix + ".stl"; + if ((m_model.get_filename() != filename) && m_model.init_from_file(filename, useVBOs)) { + Vec3d offset = m_bounding_box.center() - Vec3d(0.0, 0.0, 0.5 * m_model.get_bounding_box().size()(2)); + if (key == "mk2") + // hardcoded value to match the stl model + offset += Vec3d(0.0, 7.5, -0.03); + else if (key == "mk3") + // hardcoded value to match the stl model + offset += Vec3d(0.0, 5.5, 2.43); + else if (key == "sl1") + // hardcoded value to match the stl model + offset += Vec3d(0.0, 0.0, -0.03); + + m_model.center_around(offset); + } + + if (!m_model.get_filename().empty()) + { + glsafe(::glEnable(GL_LIGHTING)); + m_model.render(); + glsafe(::glDisable(GL_LIGHTING)); + } + } + + unsigned int triangles_vcount = m_triangles.get_vertices_count(); + if (triangles_vcount > 0) + { + glsafe(::glEnable(GL_DEPTH_TEST)); + glsafe(::glDepthMask(GL_FALSE)); + + glsafe(::glEnable(GL_BLEND)); + glsafe(::glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)); + + glsafe(::glEnable(GL_TEXTURE_2D)); + glsafe(::glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE)); + + glsafe(::glEnableClientState(GL_VERTEX_ARRAY)); + glsafe(::glEnableClientState(GL_TEXTURE_COORD_ARRAY)); + + if (theta > 90.0f) + glsafe(::glFrontFace(GL_CW)); + + glsafe(::glBindTexture(GL_TEXTURE_2D, (theta <= 90.0f) ? (GLuint)m_top_texture.get_id() : (GLuint)m_bottom_texture.get_id())); + glsafe(::glVertexPointer(3, GL_FLOAT, 0, (GLvoid*)m_triangles.get_vertices())); + glsafe(::glTexCoordPointer(2, GL_FLOAT, 0, (GLvoid*)m_triangles.get_tex_coords())); + glsafe(::glDrawArrays(GL_TRIANGLES, 0, (GLsizei)triangles_vcount)); + + if (theta > 90.0f) + glsafe(::glFrontFace(GL_CCW)); + + glsafe(::glBindTexture(GL_TEXTURE_2D, 0)); + glsafe(::glDisableClientState(GL_TEXTURE_COORD_ARRAY)); + glsafe(::glDisableClientState(GL_VERTEX_ARRAY)); + + glsafe(::glDisable(GL_TEXTURE_2D)); + + glsafe(::glDisable(GL_BLEND)); + glsafe(::glDepthMask(GL_TRUE)); + } +} #endif // ENABLE_TEXTURES_FROM_SVG void Bed3D::render_custom() const { + printf("render_custom:\n"); + auto bundle = wxGetApp().preset_bundle; + if (bundle != nullptr) + { + const Preset* curr = &bundle->printers.get_selected_preset(); + if (curr->config.has("custom_bed_view")) { + printf("Config has custom_bed_view.\n"); + const ConfigOptionString *opt = static_cast(curr->config.option("custom_bed_view")); + printf("STL File: %s\n", opt->value.c_str()); + } else { + printf("Config does not have custom_bed_view.\n"); + } + } + //if ((curr->vendor != nullptr) && (curr->vendor->name == "Prusa Research") && (shape == dynamic_cast(curr->config.option("bed_shape"))->values)) + #if ENABLE_TEXTURES_FROM_SVG m_texture.reset(); #else @@ -834,4 +1076,4 @@ void Bed3D::reset() #endif // ENABLE_TEXTURES_FROM_SVG } // GUI -} // Slic3r \ No newline at end of file +} // Slic3r diff --git a/src/slic3r/GUI/3DBed.hpp b/src/slic3r/GUI/3DBed.hpp index 68a74f61c..28af58f44 100644 --- a/src/slic3r/GUI/3DBed.hpp +++ b/src/slic3r/GUI/3DBed.hpp @@ -80,6 +80,7 @@ public: MK2, MK3, SL1, + CustomBedView, Custom, Num_Types }; @@ -106,6 +107,7 @@ private: #endif // ENABLE_TEXTURES_FROM_SVG mutable GLBed m_model; Axes m_axes; + std::string m_bed_view_prefix; mutable float m_scale_factor; @@ -135,12 +137,14 @@ private: void calc_bounding_boxes() const; void calc_triangles(const ExPolygon& poly); void calc_gridlines(const ExPolygon& poly, const BoundingBox& bed_bbox); - EType detect_type(const Pointfs& shape) const; + std::pair detect_type(const Pointfs& shape) const; #if ENABLE_TEXTURES_FROM_SVG void render_prusa(GLCanvas3D* canvas, const std::string& key, bool bottom) const; void render_prusa_shader(bool transparent) const; + void render_custom_bed(bool bottom) const; #else void render_prusa(const std::string &key, float theta, bool useVBOs) const; + void render_custom_bed(float theta, bool useVBOs) const; #endif // ENABLE_TEXTURES_FROM_SVG void render_custom() const; #if ENABLE_TEXTURES_FROM_SVG diff --git a/src/slic3r/GUI/Preset.cpp b/src/slic3r/GUI/Preset.cpp index e92113d20..9e0f44fea 100644 --- a/src/slic3r/GUI/Preset.cpp +++ b/src/slic3r/GUI/Preset.cpp @@ -458,7 +458,7 @@ const std::vector& Preset::printer_options() if (s_opts.empty()) { s_opts = { "printer_technology", - "bed_shape", "z_offset", "gcode_flavor", "use_relative_e_distances", "serial_port", "serial_speed", + "bed_shape", "custom_bed_view", "z_offset", "gcode_flavor", "use_relative_e_distances", "serial_port", "serial_speed", "use_firmware_retraction", "use_volumetric_e", "variable_layer_height", "host_type", "print_host", "printhost_apikey", "printhost_cafile", "single_extruder_multi_material", "start_gcode", "end_gcode", "before_layer_gcode", "layer_gcode", "toolchange_gcode", @@ -561,7 +561,7 @@ const std::vector& Preset::sla_printer_options() if (s_opts.empty()) { s_opts = { "printer_technology", - "bed_shape", "max_print_height", + "bed_shape", "custom_bed_view", "max_print_height", "display_width", "display_height", "display_pixels_x", "display_pixels_y", "display_mirror_x", "display_mirror_y", "display_orientation",