Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/supermerill/SuperSlicer.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEnrico Turri <enricoturri@seznam.cz>2018-02-13 17:19:55 +0300
committerEnrico Turri <enricoturri@seznam.cz>2018-02-13 17:19:55 +0300
commit8885f5e3447d83e333cf30185189befdee3e9f92 (patch)
treeb79b277fa93291d2d6b81ed9b752e584cb3b3c10 /xs/src/libslic3r
parent33553e1c5092f1b0e4fe68b209895d498e91ed66 (diff)
3mf import/export of config data
Diffstat (limited to 'xs/src/libslic3r')
-rw-r--r--xs/src/libslic3r/Config.cpp46
-rw-r--r--xs/src/libslic3r/Config.hpp3
-rw-r--r--xs/src/libslic3r/Format/3mf.cpp126
-rw-r--r--xs/src/libslic3r/Format/3mf.hpp11
-rw-r--r--xs/src/libslic3r/GCode.cpp29
-rw-r--r--xs/src/libslic3r/GCode.hpp3
-rw-r--r--xs/src/libslic3r/Model.cpp29
-rw-r--r--xs/src/libslic3r/Model.hpp2
8 files changed, 182 insertions, 67 deletions
diff --git a/xs/src/libslic3r/Config.cpp b/xs/src/libslic3r/Config.cpp
index 474be7237..1a0b8fb4a 100644
--- a/xs/src/libslic3r/Config.cpp
+++ b/xs/src/libslic3r/Config.cpp
@@ -324,7 +324,7 @@ void ConfigBase::setenv_()
void ConfigBase::load(const std::string &file)
{
if (boost::iends_with(file, ".gcode") || boost::iends_with(file, ".g"))
- this->load_from_gcode(file);
+ this->load_from_gcode_file(file);
else
this->load_from_ini(file);
}
@@ -349,10 +349,10 @@ void ConfigBase::load(const boost::property_tree::ptree &tree)
}
}
-// Load the config keys from the tail of a G-code.
-void ConfigBase::load_from_gcode(const std::string &file)
+// Load the config keys from the tail of a G-code file.
+void ConfigBase::load_from_gcode_file(const std::string &file)
{
- // 1) Read a 64k block from the end of the G-code.
+ // Read a 64k block from the end of the G-code.
boost::nowide::ifstream ifs(file);
{
const char slic3r_gcode_header[] = "; generated by Slic3r ";
@@ -365,30 +365,39 @@ void ConfigBase::load_from_gcode(const std::string &file)
auto file_length = ifs.tellg();
auto data_length = std::min<std::fstream::streampos>(65535, file_length);
ifs.seekg(file_length - data_length, ifs.beg);
- std::vector<char> data(size_t(data_length) + 1, 0);
- ifs.read(data.data(), data_length);
+ std::vector<char> data(size_t(data_length) + 1, 0);
+ ifs.read(data.data(), data_length);
ifs.close();
- // 2) Walk line by line in reverse until a non-configuration key appears.
- char *data_start = data.data();
+ load_from_gcode_string(data.data());
+}
+
+// Load the config keys from the given string.
+void ConfigBase::load_from_gcode_string(const char* str)
+{
+ if (str == nullptr)
+ return;
+
+ // Walk line by line in reverse until a non-configuration key appears.
+ char *data_start = const_cast<char*>(str);
// boost::nowide::ifstream seems to cook the text data somehow, so less then the 64k of characters may be retrieved.
- char *end = data_start + strlen(data.data());
+ char *end = data_start + strlen(str);
size_t num_key_value_pairs = 0;
for (;;) {
// Extract next line.
- for (-- end; end > data_start && (*end == '\r' || *end == '\n'); -- end);
+ for (--end; end > data_start && (*end == '\r' || *end == '\n'); --end);
if (end == data_start)
break;
char *start = end;
- *(++ end) = 0;
- for (; start > data_start && *start != '\r' && *start != '\n'; -- start);
+ *(++end) = 0;
+ for (; start > data_start && *start != '\r' && *start != '\n'; --start);
if (start == data_start)
break;
// Extracted a line from start to end. Extract the key = value pair.
- if (end - (++ start) < 10 || start[0] != ';' || start[1] != ' ')
+ if (end - (++start) < 10 || start[0] != ';' || start[1] != ' ')
break;
char *key = start + 2;
- if (! (*key >= 'a' && *key <= 'z') || (*key >= 'A' && *key <= 'Z'))
+ if (!(*key >= 'a' && *key <= 'z') || (*key >= 'A' && *key <= 'Z'))
// A key must start with a letter.
break;
char *sep = strchr(key, '=');
@@ -402,8 +411,8 @@ void ConfigBase::load_from_gcode(const std::string &file)
break;
*key_end = 0;
// The key may contain letters, digits and underscores.
- for (char *c = key; c != key_end; ++ c)
- if (! ((*c >= 'a' && *c <= 'z') || (*c >= 'A' && *c <= 'Z') || (*c >= '0' && *c <= '9') || *c == '_')) {
+ for (char *c = key; c != key_end; ++c)
+ if (!((*c >= 'a' && *c <= 'z') || (*c >= 'A' && *c <= 'Z') || (*c >= '0' && *c <= '9') || *c == '_')) {
key = nullptr;
break;
}
@@ -411,8 +420,9 @@ void ConfigBase::load_from_gcode(const std::string &file)
break;
try {
this->set_deserialize(key, value);
- ++ num_key_value_pairs;
- } catch (UnknownOptionException & /* e */) {
+ ++num_key_value_pairs;
+ }
+ catch (UnknownOptionException & /* e */) {
// ignore
}
end = start;
diff --git a/xs/src/libslic3r/Config.hpp b/xs/src/libslic3r/Config.hpp
index e04f4df82..db4b155e8 100644
--- a/xs/src/libslic3r/Config.hpp
+++ b/xs/src/libslic3r/Config.hpp
@@ -1049,7 +1049,8 @@ public:
void setenv_();
void load(const std::string &file);
void load_from_ini(const std::string &file);
- void load_from_gcode(const std::string &file);
+ void load_from_gcode_file(const std::string &file);
+ void load_from_gcode_string(const char* str);
void load(const boost::property_tree::ptree &tree);
void save(const std::string &file) const;
diff --git a/xs/src/libslic3r/Format/3mf.cpp b/xs/src/libslic3r/Format/3mf.cpp
index 7fe9352b3..e8c9cfb32 100644
--- a/xs/src/libslic3r/Format/3mf.cpp
+++ b/xs/src/libslic3r/Format/3mf.cpp
@@ -1,10 +1,14 @@
#include "../libslic3r.h"
#include "../Model.hpp"
+#include "../Utils.hpp"
+#include "../GCode.hpp"
+#include "../slic3r/GUI/PresetBundle.hpp"
#include "3mf.hpp"
#include <boost/algorithm/string/classification.hpp>
#include <boost/algorithm/string/split.hpp>
+#include <boost/algorithm/string/predicate.hpp>
#include <boost/filesystem/operations.hpp>
#include <boost/nowide/fstream.hpp>
@@ -17,6 +21,7 @@ const std::string MODEL_EXTENSION = ".model";
const std::string MODEL_FILE = "3D/3dmodel.model"; // << this is the only format of the string which works with CURA
const std::string CONTENT_TYPES_FILE = "[Content_Types].xml";
const std::string RELATIONSHIPS_FILE = "_rels/.rels";
+const std::string CONFIG_FILE = "Metadata/Slic3r_PE.config";
const char* MODEL_TAG = "model";
const char* RESOURCES_TAG = "resources";
@@ -217,7 +222,7 @@ namespace Slic3r {
_3MF_Importer();
~_3MF_Importer();
- bool load_model_from_file(const std::string& filename, Model& model);
+ bool load_model_from_file(const std::string& filename, Model& model, PresetBundle& bundle);
const std::vector<std::string>& get_errors() const;
@@ -225,8 +230,9 @@ namespace Slic3r {
void _destroy_xml_parser();
void _stop_xml_parser();
- bool _load_model_from_file_miniz(const std::string& filename, Model& model);
- bool _extract_model_from_archive_miniz(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat);
+ bool _load_model_from_file(const std::string& filename, Model& model, PresetBundle& bundle);
+ bool _extract_model_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat);
+ bool _extract_config_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat, PresetBundle& bundle, const std::string& archive_filename);
void _handle_start_xml_element(const char* name, const char** attributes);
void _handle_end_xml_element(const char* name);
@@ -331,7 +337,7 @@ namespace Slic3r {
_destroy_xml_parser();
}
- bool _3MF_Importer::load_model_from_file(const std::string& filename, Model& model)
+ bool _3MF_Importer::load_model_from_file(const std::string& filename, Model& model, PresetBundle& bundle)
{
m_model = &model;
m_unit_factor = 1.0f;
@@ -341,7 +347,7 @@ namespace Slic3r {
m_instances.clear();
m_errors.clear();
- return _load_model_from_file_miniz(filename, model);
+ return _load_model_from_file(filename, model, bundle);
}
const std::vector<std::string>& _3MF_Importer::get_errors() const
@@ -364,7 +370,7 @@ namespace Slic3r {
XML_StopParser(m_xml_parser, false);
}
- bool _3MF_Importer::_load_model_from_file_miniz(const std::string& filename, Model& model)
+ bool _3MF_Importer::_load_model_from_file(const std::string& filename, Model& model, PresetBundle& bundle)
{
mz_zip_archive archive;
mz_zip_zero_struct(&archive);
@@ -384,21 +390,28 @@ namespace Slic3r {
if (mz_zip_reader_file_stat(&archive, i, &stat))
{
std::string name(stat.m_filename);
- std::transform(name.begin(), name.end(), name.begin(), [](unsigned char c) -> unsigned char { return std::tolower(c); });
std::replace(name.begin(), name.end(), '\\', '/');
- std::string lc_model_folder(MODEL_FOLDER);
- std::transform(lc_model_folder.begin(), lc_model_folder.end(), lc_model_folder.begin(), [](unsigned char c) -> unsigned char { return std::tolower(c); });
-
- if ((name.find(lc_model_folder) == 0) && (name.rfind(MODEL_EXTENSION) == name.length() - MODEL_EXTENSION.length()))
+ if (boost::algorithm::istarts_with(name, MODEL_FOLDER) && boost::algorithm::iends_with(name, MODEL_EXTENSION))
{
- if (!_extract_model_from_archive_miniz(archive, stat))
+ // valid model name -> extract model
+ if (!_extract_model_from_archive(archive, stat))
{
mz_zip_reader_end(&archive);
m_errors.push_back("Archive does not contain a valid model");
return false;
}
}
+ else if (boost::algorithm::iequals(name, CONFIG_FILE))
+ {
+ // extract slic3r config file
+ if (!_extract_config_from_archive(archive, stat, bundle, filename))
+ {
+ mz_zip_reader_end(&archive);
+ m_errors.push_back("Archive does not contain a valid config");
+ return false;
+ }
+ }
}
}
@@ -406,7 +419,7 @@ namespace Slic3r {
return true;
}
- bool _3MF_Importer::_extract_model_from_archive_miniz(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat)
+ bool _3MF_Importer::_extract_model_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat)
{
_destroy_xml_parser();
@@ -430,7 +443,7 @@ namespace Slic3r {
mz_bool res = mz_zip_reader_extract_file_to_mem(&archive, stat.m_filename, parser_buffer, (size_t)stat.m_uncomp_size, 0);
if (res == 0)
{
- m_errors.push_back("Error while reading data to buffer");
+ m_errors.push_back("Error while reading model data to buffer");
return false;
}
@@ -445,6 +458,25 @@ namespace Slic3r {
return true;
}
+ bool _3MF_Importer::_extract_config_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat, PresetBundle& bundle, const std::string& archive_filename)
+ {
+ if (stat.m_uncomp_size > 0)
+ {
+ std::vector<char> buffer((size_t)stat.m_uncomp_size + 1, 0);
+ mz_bool res = mz_zip_reader_extract_file_to_mem(&archive, stat.m_filename, (void*)buffer.data(), (size_t)stat.m_uncomp_size, 0);
+ if (res == 0)
+ {
+ m_errors.push_back("Error while reading config data to buffer");
+ return false;
+ }
+
+ buffer.back() = '\0';
+ bundle.load_config_string(buffer.data(), archive_filename.c_str());
+ }
+
+ return true;
+ }
+
void _3MF_Importer::_handle_start_xml_element(const char* name, const char** attributes)
{
if (m_xml_parser == nullptr)
@@ -994,18 +1026,19 @@ namespace Slic3r {
std::vector<std::string> m_errors;
public:
- bool save_model_to_file(const std::string& filename, Model& model);
+ bool save_model_to_file(const std::string& filename, Model& model, const Print& print);
const std::vector<std::string>& get_errors() const;
private:
- bool _save_model_to_file_miniz(const std::string& filename, Model& model);
- bool _add_content_types_file_to_archive_miniz(mz_zip_archive& archive);
- bool _add_relationships_file_to_archive_miniz(mz_zip_archive& archive);
- bool _add_model_file_to_archive_miniz(mz_zip_archive& archive, Model& model);
+ bool _save_model_to_file(const std::string& filename, Model& model, const Print& print);
+ bool _add_content_types_file_to_archive(mz_zip_archive& archive);
+ bool _add_relationships_file_to_archive(mz_zip_archive& archive);
+ bool _add_model_file_to_archive(mz_zip_archive& archive, Model& model);
bool _add_object_to_model_stream(std::stringstream& stream, unsigned int& object_id, ModelObject& object, BuildItemsList& build_items);
bool _add_mesh_to_object_stream(std::stringstream& stream, ModelObject& object);
bool _add_build_to_model_stream(std::stringstream& stream, const BuildItemsList& build_items);
+ bool _add_config_file_to_archive(mz_zip_archive& archive, const Print& print);
};
_3MF_Exporter::BuildItem::BuildItem(unsigned int id, const Matrix4x4& matrix)
@@ -1014,9 +1047,9 @@ namespace Slic3r {
{
}
- bool _3MF_Exporter::save_model_to_file(const std::string& filename, Model& model)
+ bool _3MF_Exporter::save_model_to_file(const std::string& filename, Model& model, const Print& print)
{
- return _save_model_to_file_miniz(filename, model);
+ return _save_model_to_file(filename, model, print);
}
const std::vector<std::string>& _3MF_Exporter::get_errors() const
@@ -1024,7 +1057,7 @@ namespace Slic3r {
return m_errors;
}
- bool _3MF_Exporter::_save_model_to_file_miniz(const std::string& filename, Model& model)
+ bool _3MF_Exporter::_save_model_to_file(const std::string& filename, Model& model, const Print& print)
{
mz_zip_archive archive;
mz_zip_zero_struct(&archive);
@@ -1037,7 +1070,7 @@ namespace Slic3r {
}
// adds content types file
- if (!_add_content_types_file_to_archive_miniz(archive))
+ if (!_add_content_types_file_to_archive(archive))
{
mz_zip_writer_end(&archive);
boost::filesystem::remove(filename);
@@ -1045,7 +1078,7 @@ namespace Slic3r {
}
// adds relationships file
- if (!_add_relationships_file_to_archive_miniz(archive))
+ if (!_add_relationships_file_to_archive(archive))
{
mz_zip_writer_end(&archive);
boost::filesystem::remove(filename);
@@ -1053,7 +1086,15 @@ namespace Slic3r {
}
// adds model file
- if (!_add_model_file_to_archive_miniz(archive, model))
+ if (!_add_model_file_to_archive(archive, model))
+ {
+ mz_zip_writer_end(&archive);
+ boost::filesystem::remove(filename);
+ return false;
+ }
+
+ // adds slic3r config file
+ if (!_add_config_file_to_archive(archive, print))
{
mz_zip_writer_end(&archive);
boost::filesystem::remove(filename);
@@ -1073,7 +1114,7 @@ namespace Slic3r {
return true;
}
- bool _3MF_Exporter::_add_content_types_file_to_archive_miniz(mz_zip_archive& archive)
+ bool _3MF_Exporter::_add_content_types_file_to_archive(mz_zip_archive& archive)
{
std::stringstream stream;
stream << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
@@ -1093,7 +1134,7 @@ namespace Slic3r {
return true;
}
- bool _3MF_Exporter::_add_relationships_file_to_archive_miniz(mz_zip_archive& archive)
+ bool _3MF_Exporter::_add_relationships_file_to_archive(mz_zip_archive& archive)
{
std::stringstream stream;
stream << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
@@ -1112,7 +1153,7 @@ namespace Slic3r {
return true;
}
- bool _3MF_Exporter::_add_model_file_to_archive_miniz(mz_zip_archive& archive, Model& model)
+ bool _3MF_Exporter::_add_model_file_to_archive(mz_zip_archive& archive, Model& model)
{
std::stringstream stream;
stream << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
@@ -1298,13 +1339,30 @@ namespace Slic3r {
return true;
}
- bool load_3mf(const char* path, Model* model)
+ bool _3MF_Exporter::_add_config_file_to_archive(mz_zip_archive& archive, const Print& print)
+ {
+ char buffer[1024];
+ sprintf(buffer, "; %s\n\n", header_slic3r_generated().c_str());
+ std::string out = buffer;
+
+ GCode::append_full_config(print, out);
+
+ if (!mz_zip_writer_add_mem(&archive, CONFIG_FILE.c_str(), (const void*)out.data(), out.length(), MZ_DEFAULT_COMPRESSION))
+ {
+ m_errors.push_back("Unable to add config file to archive");
+ return false;
+ }
+
+ return true;
+ }
+
+ bool load_3mf(const char* path, PresetBundle* bundle, Model* model)
{
- if ((path == nullptr) || (model == nullptr))
+ if ((path == nullptr) || (bundle == nullptr) || (model == nullptr))
return false;
_3MF_Importer importer;
- bool res = importer.load_model_from_file(path, *model);
+ bool res = importer.load_model_from_file(path, *model, *bundle);
if (!res)
const std::vector<std::string>& errors = importer.get_errors();
@@ -1312,13 +1370,13 @@ namespace Slic3r {
return res;
}
- bool store_3mf(const char* path, Model* model)
+ bool store_3mf(const char* path, Model* model, Print* print)
{
- if ((path == nullptr) || (model == nullptr))
+ if ((path == nullptr) || (model == nullptr) || (print == nullptr))
return false;
_3MF_Exporter exporter;
- bool res = exporter.save_model_to_file(path, *model);
+ bool res = exporter.save_model_to_file(path, *model, *print);
if (!res)
const std::vector<std::string>& errors = exporter.get_errors();
diff --git a/xs/src/libslic3r/Format/3mf.hpp b/xs/src/libslic3r/Format/3mf.hpp
index ff178e3de..9b48c860b 100644
--- a/xs/src/libslic3r/Format/3mf.hpp
+++ b/xs/src/libslic3r/Format/3mf.hpp
@@ -4,13 +4,16 @@
namespace Slic3r {
class Model;
+ class Print;
+ class PresetBundle;
- // Load a 3mf file into the given model.
- extern bool load_3mf(const char* path, Model* model);
+ // Load the content of a 3mf file into the given model and preset bundle.
+ extern bool load_3mf(const char* path, PresetBundle* bundle, Model* model);
- // Save the given model into a 3mf file.
+ // Save the given model and the config data contained in the given Print into a 3mf file.
// The model could be modified during the export process if meshes are not repaired or have no shared vertices
- extern bool store_3mf(const char* path, Model* model);
+ extern bool store_3mf(const char* path, Model* model, Print* print);
+
}; // namespace Slic3r
#endif /* slic3r_Format_3mf_hpp_ */
diff --git a/xs/src/libslic3r/GCode.cpp b/xs/src/libslic3r/GCode.cpp
index d22040799..d42a61290 100644
--- a/xs/src/libslic3r/GCode.cpp
+++ b/xs/src/libslic3r/GCode.cpp
@@ -802,13 +802,10 @@ void GCode::_do_export(Print &print, FILE *file)
// Append full config.
_write(file, "\n");
{
- StaticPrintConfig *configs[] = { &print.config, &print.default_object_config, &print.default_region_config };
- for (size_t i = 0; i < sizeof(configs) / sizeof(configs[0]); ++ i) {
- StaticPrintConfig *cfg = configs[i];
- for (const std::string &key : cfg->keys())
- if (key != "compatible_printers")
- _write_format(file, "; %s = %s\n", key.c_str(), cfg->serialize(key).c_str());
- }
+ std::string full_config = "";
+ append_full_config(print, full_config);
+ if (!full_config.empty())
+ _write(file, full_config);
}
}
@@ -1372,6 +1369,24 @@ void GCode::apply_print_config(const PrintConfig &print_config)
m_config.apply(print_config);
}
+void GCode::append_full_config(const Print& print, std::string& str)
+{
+ char buff[1024];
+
+ const StaticPrintConfig *configs[] = { &print.config, &print.default_object_config, &print.default_region_config };
+ for (size_t i = 0; i < sizeof(configs) / sizeof(configs[0]); ++i) {
+ const StaticPrintConfig *cfg = configs[i];
+ for (const std::string &key : cfg->keys())
+ {
+ if (key != "compatible_printers")
+ {
+ sprintf(buff, "; %s = %s\n", key.c_str(), cfg->serialize(key).c_str());
+ str += buff;
+ }
+ }
+ }
+}
+
void GCode::set_extruders(const std::vector<unsigned int> &extruder_ids)
{
m_writer.set_extruders(extruder_ids);
diff --git a/xs/src/libslic3r/GCode.hpp b/xs/src/libslic3r/GCode.hpp
index 5c622ec2d..8129ca1c5 100644
--- a/xs/src/libslic3r/GCode.hpp
+++ b/xs/src/libslic3r/GCode.hpp
@@ -155,6 +155,9 @@ public:
void set_layer_count(unsigned int value) { m_layer_count = value; }
void apply_print_config(const PrintConfig &print_config);
+ // append full config to the given string
+ static void append_full_config(const Print& print, std::string& str);
+
protected:
void _do_export(Print &print, FILE *file);
diff --git a/xs/src/libslic3r/Model.cpp b/xs/src/libslic3r/Model.cpp
index b86b7e55e..891438407 100644
--- a/xs/src/libslic3r/Model.cpp
+++ b/xs/src/libslic3r/Model.cpp
@@ -54,10 +54,8 @@ Model Model::read_from_file(const std::string &input_file, bool add_default_inst
else if (boost::algorithm::iends_with(input_file, ".prusa"))
result = load_prus(input_file.c_str(), &model);
#endif /* SLIC3R_PRUS */
- else if (boost::algorithm::iends_with(input_file, ".3mf"))
- result = load_3mf(input_file.c_str(), &model);
else
- throw std::runtime_error("Unknown file format. Input file must have .stl, .obj, .amf(.xml), .3mf or .prusa extension.");
+ throw std::runtime_error("Unknown file format. Input file must have .stl, .obj, .amf(.xml) or .prusa extension.");
if (! result)
throw std::runtime_error("Loading of a model file failed.");
@@ -74,6 +72,31 @@ Model Model::read_from_file(const std::string &input_file, bool add_default_inst
return model;
}
+Model Model::read_from_archive(const std::string &input_file, PresetBundle* bundle, bool add_default_instances)
+{
+ Model model;
+
+ bool result = false;
+ if (boost::algorithm::iends_with(input_file, ".3mf"))
+ result = load_3mf(input_file.c_str(), bundle, &model);
+ else
+ throw std::runtime_error("Unknown file format. Input file must have .3mf extension.");
+
+ if (!result)
+ throw std::runtime_error("Loading of a model file failed.");
+
+ if (model.objects.empty())
+ throw std::runtime_error("The supplied file couldn't be read because it's empty");
+
+ for (ModelObject *o : model.objects)
+ o->input_file = input_file;
+
+ if (add_default_instances)
+ model.add_default_instances();
+
+ return model;
+}
+
ModelObject* Model::add_object()
{
this->objects.emplace_back(new ModelObject(this));
diff --git a/xs/src/libslic3r/Model.hpp b/xs/src/libslic3r/Model.hpp
index 317d7ccbb..cf9bfd85a 100644
--- a/xs/src/libslic3r/Model.hpp
+++ b/xs/src/libslic3r/Model.hpp
@@ -19,6 +19,7 @@ class ModelInstance;
class ModelMaterial;
class ModelObject;
class ModelVolume;
+class PresetBundle;
typedef std::string t_model_material_id;
typedef std::string t_model_material_attribute;
@@ -239,6 +240,7 @@ public:
~Model() { this->clear_objects(); this->clear_materials(); }
static Model read_from_file(const std::string &input_file, bool add_default_instances = true);
+ static Model read_from_archive(const std::string &input_file, PresetBundle* bundle, bool add_default_instances = true);
ModelObject* add_object();
ModelObject* add_object(const char *name, const char *path, const TriangleMesh &mesh);