Browse Source

now complete apths for scripts, texture, models.
fixes for to_prusa, search with uppercase, .3mf loading
update tooltips

supermerill 2 years ago
parent
commit
de1f4a9bd6

+ 6 - 0
BuildLinux.sh

@@ -74,6 +74,12 @@ then
         echo -e "\nFind libgtk-3, installing: libgtk-3-dev libglew-dev libudev-dev libdbus-1-dev cmake git\n"
         apt install libgtk-3-dev libglew-dev libudev-dev libdbus-1-dev cmake git
     fi
+    # for ubuntu 22.04:
+    ubu_version="$(cat /etc/issue)" 
+    if [[ $ubu_version == "Ubuntu 22.04"* ]]
+    then
+        apt install curl libssl-dev libcurl4-openssl-dev m4
+    fi
     if [[ -n "$BUILD_DEBUG" ]]
     then
         echo -e "\nInstalling: libssl-dev libcurl4-openssl-dev\n"

+ 8 - 8
create_release.py

@@ -68,14 +68,14 @@ with urlopen("https://api.github.com/repos/"+repo+"/actions/artifacts") as f:
 			z = zipfile.ZipFile(io.BytesIO(resp.content));
 			z.extractall(release_path);
 			os.rename(release_path+"/"+program_name+".dmg", release_path+"/"+program_name+"_"+version+"_macos_"+date_str+".dmg");
-		if entry["name"] == "rc_arm_macos.dmg" and not found_macos_arm:
-			found_macos_arm = True;
-			print("ask for: "+entry["archive_download_url"]);
-			resp = requests.get(entry["archive_download_url"], headers={'Authorization': 'token ' + github_auth_token,}, allow_redirects=True);
-			print("macos-arm: " +str(resp));
-			z = zipfile.ZipFile(io.BytesIO(resp.content));
-			z.extractall(release_path);
-			os.rename(release_path+"/"+program_name+".dmg", release_path+"/"+program_name+"_"+version+"_macos_arm_"+date_str+".dmg");
+		# if entry["name"] == "rc_arm_macos.dmg" and not found_macos_arm:
+			# found_macos_arm = True;
+			# print("ask for: "+entry["archive_download_url"]);
+			# resp = requests.get(entry["archive_download_url"], headers={'Authorization': 'token ' + github_auth_token,}, allow_redirects=True);
+			# print("macos-arm: " +str(resp));
+			# z = zipfile.ZipFile(io.BytesIO(resp.content));
+			# z.extractall(release_path);
+			# os.rename(release_path+"/"+program_name+".dmg", release_path+"/"+program_name+"_"+version+"_macos_arm_"+date_str+".dmg");
 		if entry["name"] == "rc-"+program_name+"-gtk2.AppImage" and not found_linux_appimage_gtk2:
 			found_linux_appimage_gtk2 = True;
 			print("ask for: "+entry["archive_download_url"]);

+ 73 - 32
src/libslic3r/GCode/PostProcessor.cpp

@@ -7,18 +7,26 @@
 #include <boost/algorithm/string.hpp>
 #include <boost/log/trivial.hpp>
 #include <boost/format.hpp>
-#include <boost/filesystem.hpp>
 #include <boost/nowide/convert.hpp>
 #include <boost/nowide/cenv.hpp>
 #include <boost/nowide/fstream.hpp>
 
+#include <cstdlib>   // getenv()
 #ifdef WIN32
-
 // The standard Windows includes.
 #define WIN32_LEAN_AND_MEAN
 #define NOMINMAX
 #include <Windows.h>
 #include <shellapi.h>
+#else
+// POSIX
+#include <sstream>
+#include <boost/process.hpp>
+#include <unistd.h>     //readlink
+#endif
+
+
+#ifdef WIN32
 
 // https://blogs.msdn.microsoft.com/twistylittlepassagesallalike/2011/04/23/everyone-quotes-command-line-arguments-the-wrong-way/
 // This routine appends the given argument to a command line such that CommandLineToArgvW will return the argument string unchanged.
@@ -108,66 +116,99 @@ static int run_script(const std::string &script, const std::string &gcode, std::
     }
 
     std::wstring command_line;
-    std::wstring command = szArglist[0];
-	if (! boost::filesystem::exists(boost::filesystem::path(command)))
-		throw Slic3r::RuntimeError(std::string("The configured post-processing script does not exist: ") + boost::nowide::narrow(command));
+    const std::wstring command = szArglist[0];
+    bool need_absolute_path = false;
+    // for perl and python, hope that the os can find it in the path.
     if (boost::iends_with(command, L".pl")) {
+        BOOST_LOG_TRIVIAL(debug) << boost::format("Executing script : detecting perl script");
         // This is a perl script. Run it through the perl interpreter.
-        // The current process may be slic3r.exe or slic3r-console.exe.
-        // Find the path of the process:
-        wchar_t wpath_exe[_MAX_PATH + 1];
-        ::GetModuleFileNameW(nullptr, wpath_exe, _MAX_PATH);
-        boost::filesystem::path path_exe(wpath_exe);
-        boost::filesystem::path path_perl = path_exe.parent_path() / "perl" / "perl.exe";
-        if (! boost::filesystem::exists(path_perl)) {
-			LocalFree(szArglist);
-			throw Slic3r::RuntimeError(std::string("Perl interpreter ") + path_perl.string() + " does not exist.");
-        }
-        // Replace it with the current perl interpreter.
-        quote_argv_winapi(boost::nowide::widen(path_perl.string()), command_line);
+        quote_argv_winapi(boost::nowide::widen("perl.exe"), command_line);
+        command_line += L" ";
+        need_absolute_path = true;
+    } else if (boost::iends_with(command, L".py")) {
+        BOOST_LOG_TRIVIAL(debug) << boost::format("Executing script : detecting python script");
+        // This is a python script. Run it through the python interpreter.
+        quote_argv_winapi(boost::nowide::widen("python.exe"), command_line);
         command_line += L" ";
+        need_absolute_path = true;
     } else if (boost::iends_with(command, ".bat")) {
+        BOOST_LOG_TRIVIAL(debug) << boost::format("Executing script : detecting bat script");
         // Run a batch file through the command line interpreter.
         command_line = L"cmd.exe /C ";
+        need_absolute_path = true;
+    }
+    
+    //try to find the file, in different directories
+    std::wstring absolute_command_path = Slic3r::find_full_path(boost::filesystem::path(command)).generic_wstring();
+    if (absolute_command_path.empty()) {
+        if (need_absolute_path) {
+            throw Slic3r::RuntimeError(std::string("The configured post-processing script does not exist: ") + boost::nowide::narrow(command));
+        } else {
+            absolute_command_path = command;
+        }
     }
+    quote_argv_winapi(absolute_command_path, command_line);
+    command_line += L" ";
 
-    for (int i = 0; i < nArgs; ++ i) {
+    for (int i = 1; i < nArgs; ++ i) {
         quote_argv_winapi(szArglist[i], command_line);
         command_line += L" ";
     }
     LocalFree(szArglist);
 	quote_argv_winapi(boost::nowide::widen(gcode), command_line);
+    BOOST_LOG_TRIVIAL(debug) << (boost::format("Executing script : %1%") % boost::nowide::narrow(command_line));
     return (int)execute_process_winapi(command_line);
 }
 
 #else
-    // POSIX
-
-#include <cstdlib>   // getenv()
-#include <sstream>
-#include <boost/process.hpp>
 
 namespace process = boost::process;
 
 static int run_script(const std::string &script, const std::string &gcode, std::string &std_err)
 {
     // Try to obtain user's default shell
-    const char *shell = ::getenv("SHELL");
+    const char* shell = ::getenv("SHELL");
     if (shell == nullptr) { shell = "sh"; }
 
     // Quote and escape the gcode path argument
-    std::string command { script };
-    command.append(" '");
-    for (char c : gcode) {
-        if (c == '\'') { command.append("'\\''"); }
-        else { command.push_back(c); }
+    std::string command_line;
+    size_t first_space = script.find(' ');
+    bool need_absolute_path = false;
+    const std::string command = (std::string::npos != first_space) ? script.substr(0, first_space) : script;
+    const std::string args = (std::string::npos != first_space) ? script.substr(first_space) : "";
+    if (boost::iends_with(command, L".pl")) {
+        BOOST_LOG_TRIVIAL(trace) << boost::format("Executing script : detecting perl script");
+        // This is a perl script. Run it through the perl interpreter.
+        command_line = "perl ";
+        need_absolute_path = true;
+    } else if (boost::iends_with(command, L".py")) {
+        BOOST_LOG_TRIVIAL(trace) << boost::format("Executing script : detecting python script");
+        // This is a python script. Run it through the python interpreter.
+        command_line = "python ";
+        need_absolute_path = true;
+    }
+    //try to find the file, in different directories
+    std::string absolute_command_path = Slic3r::find_full_path(boost::filesystem::path(command)).generic_string();
+    if (absolute_command_path.empty()) {
+        if (need_absolute_path) {
+            throw Slic3r::RuntimeError(std::string("The configured post-processing script does not exist: ") + command);
+        } else {
+            absolute_command_path = command;
+        }
     }
-    command.push_back('\'');
+    command_line += absolute_command_path;
+    command_line += args;
 
-    BOOST_LOG_TRIVIAL(debug) << boost::format("Executing script, shell: %1%, command: %2%") % shell % command;
+    command_line.append(" '");
+    for (char c : gcode) {
+        if (c == '\'') { command_line.append("'\\''"); }
+        else { command_line.push_back(c); }
+    }
+    command_line.push_back('\'');
 
+    BOOST_LOG_TRIVIAL(trace) << boost::format("Executing script, shell: %1%, command: %2%") % shell % command_line;
     process::ipstream istd_err;
-    process::child child(shell, "-c", command, process::std_err > istd_err);
+    process::child child(shell, "-c", command_line, process::std_err > istd_err);
 
     std_err.clear();
     std::string line;

+ 2 - 0
src/libslic3r/GCode/PostProcessor.hpp

@@ -3,6 +3,8 @@
 
 #include <string>
 
+#include <boost/filesystem.hpp>
+
 #include "../libslic3r.h"
 #include "../PrintConfig.hpp"
 

+ 4 - 1
src/libslic3r/GCode/WipeTower.cpp

@@ -976,7 +976,10 @@ void WipeTower::toolchange_Unload(
         }
     }
 
-    writer.disable_linear_advance();
+    // Disable linear/pressure advance for ramming, as it can mess up the ramming procedure
+    if (i < m_filpar[m_current_tool].ramming_speed.size()) {
+        writer.disable_linear_advance();
+    }
 
     // now the ramming itself:
     while (i < m_filpar[m_current_tool].ramming_speed.size())

+ 21 - 9
src/libslic3r/PrintConfig.cpp

@@ -2,6 +2,7 @@
 #include "Config.hpp"
 #include "Flow.hpp"
 #include "I18N.hpp"
+#include "Utils.hpp"
 
 #include <set>
 #include <unordered_set>
@@ -3521,7 +3522,8 @@ void PrintConfigDef::init_fff_params()
     def->category = OptionCategory::speed;
     def->tooltip = L("If a top surface has to be printed and it's partially covered by another layer, it won't be considered at a top layer where its width is below this value."
         " This can be useful to not let the 'one perimeter on top' trigger on surface that should be covered only by perimeters."
-        " This value can be a mm or a % of the perimeter extrusion width.");
+        " This value can be a mm or a % of the perimeter extrusion width."
+        "\nWarning: If enabled, artifacts can be created is you have some thin features on the next layer, like letters. Set this setting to 0 to remove these artifacts.");
     def->sidetext = L("mm or %");
     def->ratio_over = "perimeter_extrusion_width";
     def->min = 0;
@@ -3914,7 +3916,7 @@ void PrintConfigDef::init_fff_params()
     def->full_label = L("Round corners for perimeters");
     def->category = OptionCategory::perimeter;
     def->tooltip = L("Internal perimeters will go around sharp corners by turning around instead of making the same sharp corner."
-                        " This can help when there are visible holes in sharp corners on perimeters. It also help to print the letters on the benchy stern."
+                        " This can help when there are visible holes in sharp corners on internal perimeters."
                         "\nCan incur some more processing time, and corners are a bit less sharp.");
     def->mode = comAdvancedE | comSuSi;
     def->set_default_value(new ConfigOptionBool(false));
@@ -3954,7 +3956,9 @@ void PrintConfigDef::init_fff_params()
     def->tooltip = L("If you want to process the output G-code through custom scripts, "
                    "just list their absolute paths here. Separate multiple scripts with a semicolon. "
                    "Scripts will be passed the absolute path to the G-code file as the first argument, "
-                   "and they can access the Slic3r config settings by reading environment variables.");
+                   "and they can access the Slic3r config settings by reading environment variables."
+                   "\nThe script, if passed as a relative path, will also be searched from the slic3r directory, "
+                   "the slic3r configuration directory and the user directory.");
     def->gui_flags = "serialized";
     def->multiline = true;
     def->full_width = true;
@@ -6756,7 +6760,7 @@ void PrintConfigDef::init_sla_params()
     def->enum_labels.push_back(L("Masked CWS"));
     def->enum_labels.push_back(L("Prusa SL1"));
     def->mode = comAdvancedE | comSuSi; // output_format should be preconfigured in profiles;
-    def->set_default_value(new ConfigOptionEnum<OutputFormat>(ofMaskedCWS));
+    def->set_default_value(new ConfigOptionEnum<OutputFormat>(ofSL1));
 
     def = this->add("sla_output_precision", coFloat);
     def->label = L("SLA output precision");
@@ -7408,9 +7412,14 @@ std::map<std::string, std::string> PrintConfigDef::to_prusa(t_config_option_key&
         if (std::set<std::string>{"extrusion_width", "first_layer_extrusion_width", "perimeter_extrusion_width", "external_perimeter_extrusion_width", 
             "infill_extrusion_width", "solid_infill_extrusion_width", "top_infill_extrusion_width"}.count(opt_key) > 0) {
             const ConfigOptionFloatOrPercent* opt = all_conf.option<ConfigOptionFloatOrPercent>(opt_key);
-            if (opt->is_phony()) {
-                //bypass the phony kill switch from Config::opt_serialize
-                value = opt->serialize();
+            if (opt->is_phony() || opt->percent) {
+                if (opt->percent) {
+                    ConfigOptionFloat opt_temp{ opt->get_abs_value(all_conf.option<ConfigOptionFloats>("nozzle_diameter")->values.front()) };
+                    value = opt_temp.serialize();
+                } else {
+                    //bypass the phony kill switch from Config::opt_serialize
+                    value = opt->serialize();
+                }
             }
         }
     }
@@ -7437,10 +7446,13 @@ std::map<std::string, std::string> PrintConfigDef::to_prusa(t_config_option_key&
     if ("host_type" == opt_key) {
         if ("klipper" == value || "mpmdv2" == value || "monoprice" == value) value = "octoprint";
     }
-    if ("fan_below_layer_time" == opt_key)
+    if ("fan_below_layer_time" == opt_key) {
         if (value.find('.') != std::string::npos)
             value = value.substr(0, value.find('.'));
-
+    }
+    if ("bed_custom_texture" == opt_key || "Bed custom texture" == opt_key) {
+        value = Slic3r::find_full_path(value, value).generic_string();
+    }
     return new_entries;
 }
 

+ 7 - 0
src/libslic3r/Utils.hpp

@@ -79,6 +79,13 @@ extern std::string normalize_utf8_nfc(const char *src);
 extern size_t get_utf8_sequence_length(const std::string& text, size_t pos = 0);
 extern size_t get_utf8_sequence_length(const char *seq, size_t size);
 
+// If the file has a relative path, it tries to find it in the exe directory, the configuration directory and the user directory.
+// If it can't find it, it returns an empty path
+extern boost::filesystem::path find_full_path(const boost::filesystem::path filename, const boost::filesystem::path return_fail = "");
+
+// If the filename is an absolute path, it remove the exe directory path, the configuration directory path or the user directory path to create a relative path.
+extern boost::filesystem::path shorten_path(const boost::filesystem::path filename);
+
 // Safely rename a file even if the target exists.
 // On Windows, the file explorer (or anti-virus or whatever else) often locks the file
 // for a short while, so the file may not be movable. Retry while we see recoverable errors.

+ 86 - 0
src/libslic3r/utils.cpp

@@ -71,6 +71,19 @@
     #define strcasecmp _stricmp
 #endif
 
+#include <cstdlib>   // getenv()
+#ifdef WIN32
+	// The standard Windows includes.
+#define WIN32_LEAN_AND_MEAN
+#define NOMINMAX
+#include <shellapi.h>
+#else
+	// POSIX
+#include <sstream>
+#include <boost/process.hpp>
+#include <unistd.h>     //readlink
+#endif
+
 namespace Slic3r {
 
 static boost::log::trivial::severity_level logSeverity = boost::log::trivial::error;
@@ -469,6 +482,79 @@ namespace WindowsSupport
 } // namespace WindowsSupport
 #endif /* _WIN32 */
 
+
+// Try to find where the file can be.
+// First try without any modification, for absolute apth and relative path fromt he current directory
+// Then try from the slic3r.exe directory
+// Then from the configuration directory
+// Then from the USER directory
+boost::filesystem::path find_full_path(const boost::filesystem::path filename, const boost::filesystem::path return_fail) {
+	boost::filesystem::path ret = filename;
+	if (!boost::filesystem::exists(filename)) {
+		// try from our install directory 
+#ifdef WIN32
+		wchar_t wpath_exe[_MAX_PATH + 1];
+		::GetModuleFileNameW(nullptr, wpath_exe, _MAX_PATH);
+		boost::filesystem::path local_dir = boost::filesystem::path(wpath_exe).parent_path();
+#else
+		char result[PATH_MAX + 1];
+		size_t count = readlink("/proc/self/exe", result, sizeof(result) - 1);
+		boost::filesystem::path local_dir = boost::filesystem::path(std::string(result, (count > 0) ? count : 0)).parent_path();
+#endif
+		if (!boost::filesystem::exists(local_dir / filename)) {
+			//try with configuration directory
+			local_dir = boost::filesystem::path(Slic3r::data_dir());
+		}
+		if (!boost::filesystem::exists(local_dir / filename)) {
+			//try with configuration directory
+#ifdef WIN32
+			local_dir = boost::filesystem::path(::getenv("USERPROFILE"));
+#else
+			local_dir = boost::filesystem::path(::getenv("HOME"));
+#endif
+		}
+		if (!boost::filesystem::exists(local_dir / filename)) {
+			return return_fail;
+		} else {
+			ret = local_dir / filename;
+		}
+	}
+	return ret;
+}
+
+boost::filesystem::path shorten_path(const boost::filesystem::path filename) {
+	std::string current_filename = filename.generic_string();
+	// try from our install directory 
+#ifdef WIN32
+	wchar_t wpath_exe[_MAX_PATH + 1];
+	::GetModuleFileNameW(nullptr, wpath_exe, _MAX_PATH);
+	std::string local_dir = boost::filesystem::path(wpath_exe).parent_path().generic_string();
+#else
+	char result[PATH_MAX + 1];
+	size_t count = readlink("/proc/self/exe", result, sizeof(result) - 1);
+	std::string local_dir = boost::filesystem::path(std::string(result, (count > 0) ? count : 0)).parent_path().generic_string();
+#endif
+	if (boost::starts_with(current_filename, local_dir)) {
+		return boost::filesystem::path(current_filename.substr(local_dir.size() + 1));
+	}
+	//try with configuration directory
+	local_dir = Slic3r::data_dir();
+	if (boost::starts_with(current_filename, local_dir)) {
+		return boost::filesystem::path(current_filename.substr(local_dir.size() + 1));
+	}
+	//try with configuration directory
+#ifdef WIN32
+	local_dir = boost::filesystem::path(::getenv("USERPROFILE")).generic_string();
+#else
+	local_dir = boost::filesystem::path(::getenv("HOME")).generic_string();
+#endif
+	if (boost::starts_with(current_filename, local_dir)) {
+		return boost::filesystem::path(current_filename.substr(local_dir.size() + 1));
+	}
+	return filename;
+}
+
+
 // borrowed from LVVM lib/Support/Windows/Path.inc
 std::error_code rename_file(const std::string &from, const std::string &to)
 {

+ 20 - 13
src/slic3r/GUI/3DBed.cpp

@@ -5,6 +5,7 @@
 #include "libslic3r/Polygon.hpp"
 #include "libslic3r/ClipperUtils.hpp"
 #include "libslic3r/BoundingBox.hpp"
+#include "libslic3r/GCode/PostProcessor.hpp"
 #include "libslic3r/Geometry/Circle.hpp"
 #include "libslic3r/Tesselate.hpp"
 #include "libslic3r/PresetBundle.hpp"
@@ -188,12 +189,12 @@ bool Bed3D::set_shape(const Pointfs& bed_shape, const double max_print_height, c
 {
     auto check_texture = [](const std::string& texture) {
         boost::system::error_code ec; // so the exists call does not throw (e.g. after a permission problem)
-        return !texture.empty() && (boost::algorithm::iends_with(texture, ".png") || boost::algorithm::iends_with(texture, ".svg")) && boost::filesystem::exists(texture, ec);
+        return !texture.empty() && (boost::algorithm::iends_with(texture, ".png") || boost::algorithm::iends_with(texture, ".svg")) && boost::filesystem::exists(Slic3r::find_full_path(texture), ec);
     };
 
     auto check_model = [](const std::string& model) {
         boost::system::error_code ec;
-        return !model.empty() && boost::algorithm::iends_with(model, ".stl") && boost::filesystem::exists(model, ec);
+        return !model.empty() && boost::algorithm::iends_with(model, ".stl") && boost::filesystem::exists(Slic3r::find_full_path(model), ec);
     };
 
     Type type;
@@ -208,11 +209,12 @@ bool Bed3D::set_shape(const Pointfs& bed_shape, const double max_print_height, c
         texture = system_texture;
         m_texture_with_grid = system_with_grid;
     }
-
     std::string texture_filename = custom_texture.empty() ? texture : custom_texture;
     if (! texture_filename.empty() && ! check_texture(texture_filename)) {
         BOOST_LOG_TRIVIAL(error) << "Unable to load bed texture: " << texture_filename;
         texture_filename.clear();
+    } else {
+
     }
 
     std::string model_filename = custom_model.empty() ? model : custom_model;
@@ -229,7 +231,9 @@ bool Bed3D::set_shape(const Pointfs& bed_shape, const double max_print_height, c
     m_type = type;
     m_build_volume = BuildVolume { bed_shape, max_print_height };
     m_texture_filename = texture_filename;
+    m_texture_path = Slic3r::find_full_path(m_texture_filename, m_texture_filename);
     m_model_filename = model_filename;
+    m_model_path = Slic3r::find_full_path(m_model_filename, m_model_filename);
     m_extended_bounding_box = this->calc_extended_bounding_box();
 
     ExPolygon poly{ Polygon::new_scale(bed_shape) };
@@ -423,16 +427,17 @@ void Bed3D::render_texture(bool bottom, GLCanvas3D& canvas) const
         render_default(bottom, false);
         return;
     }
+    std::string texture_absolute_filename = m_texture_path.generic_string();
 
-    if (texture->get_id() == 0 || texture->get_source() != m_texture_filename) {
+    if (texture->get_id() == 0 || texture->get_source() != texture_absolute_filename) {
         texture->reset();
 
-        if (boost::algorithm::iends_with(m_texture_filename, ".svg")) {
+        if (boost::algorithm::iends_with(texture_absolute_filename, ".svg")) {
             // use higher resolution images if graphic card and opengl version allow
             GLint max_tex_size = OpenGLManager::get_gl_info().get_max_tex_size();
-            if (temp_texture->get_id() == 0 || temp_texture->get_source() != m_texture_filename) {
+            if (temp_texture->get_id() == 0 || temp_texture->get_source() != texture_absolute_filename) {
                 // generate a temporary lower resolution texture to show while no main texture levels have been compressed
-                if (!temp_texture->load_from_svg_file(m_texture_filename, false, false, false, max_tex_size / 8)) {
+                if (!temp_texture->load_from_svg_file(texture_absolute_filename, false, false, false, max_tex_size / 8)) {
                     render_default(bottom, false);
                     return;
                 }
@@ -440,15 +445,15 @@ void Bed3D::render_texture(bool bottom, GLCanvas3D& canvas) const
             }
 
             // starts generating the main texture, compression will run asynchronously
-            if (!texture->load_from_svg_file(m_texture_filename, true, true, true, max_tex_size)) {
+            if (!texture->load_from_svg_file(texture_absolute_filename, true, true, true, max_tex_size)) {
                 render_default(bottom, false);
                 return;
             }
         } 
-        else if (boost::algorithm::iends_with(m_texture_filename, ".png")) {
+        else if (boost::algorithm::iends_with(texture_absolute_filename, ".png")) {
             // generate a temporary lower resolution texture to show while no main texture levels have been compressed
-            if (temp_texture->get_id() == 0 || temp_texture->get_source() != m_texture_filename) {
-                if (!temp_texture->load_from_file(m_texture_filename, false, GLTexture::None, false)) {
+            if (temp_texture->get_id() == 0 || temp_texture->get_source() != texture_absolute_filename) {
+                if (!temp_texture->load_from_file(texture_absolute_filename, false, GLTexture::None, false)) {
                     render_default(bottom, false);
                     return;
                 }
@@ -456,7 +461,7 @@ void Bed3D::render_texture(bool bottom, GLCanvas3D& canvas) const
             }
 
             // starts generating the main texture, compression will run asynchronously
-            if (!texture->load_from_file(m_texture_filename, true, GLTexture::MultiThreaded, true)) {
+            if (!texture->load_from_file(texture_absolute_filename, true, GLTexture::MultiThreaded, true)) {
                 render_default(bottom, false);
                 return;
             }
@@ -575,9 +580,11 @@ void Bed3D::render_model() const
     if (m_model_filename.empty())
         return;
 
+    std::string model_absolute_filename = m_model_path.generic_string();
+
     GLModel* model = const_cast<GLModel*>(&m_model);
 
-    if (model->get_filename() != m_model_filename && model->init_from_file(m_model_filename)) {
+    if (model->get_filename() != model_absolute_filename && model->init_from_file(model_absolute_filename)) {
         model->set_color(-1, DEFAULT_MODEL_COLOR);
 
         // move the model so that its origin (0.0, 0.0, 0.0) goes into the bed shape center and a bit down to avoid z-fighting with the texture quad

+ 6 - 0
src/slic3r/GUI/3DBed.hpp

@@ -75,9 +75,15 @@ public:
 private:
     BuildVolume m_build_volume;
     Type m_type{ Type::Custom };
+    // m_texture_filename can be relative or absolute
     std::string m_texture_filename;
+    // absolute path for m_texture_filename
+    boost::filesystem::path m_texture_path;
     bool m_texture_with_grid = false;
+    // m_model_filename can be relative or absolute
     std::string m_model_filename;
+    // absolute path for m_model_filename
+    boost::filesystem::path m_model_path;
     // Print volume bounding box exteded with axes and model.
     BoundingBoxf3 m_extended_bounding_box;
     // Slightly expanded print bed polygon, for collision detection.

Some files were not shown because too many files changed in this diff