diff --git a/src/libslic3r/Format/PRUS.cpp b/src/libslic3r/Format/PRUS.cpp
index 27095acef..bd6beeb21 100644
--- a/src/libslic3r/Format/PRUS.cpp
+++ b/src/libslic3r/Format/PRUS.cpp
@@ -1,12 +1,10 @@
-#ifdef SLIC3R_PRUS
-
 #include <string.h>
+#include <exception>
 
+#include <boost/algorithm/string.hpp>
 #include <boost/nowide/convert.hpp>
 
-#include <wx/string.h>
-#include <wx/wfstream.h>
-#include <wx/zipstrm.h>
+#include <miniz/miniz_zip.h>
 
 #include <Eigen/Geometry>
 
@@ -35,64 +33,28 @@ struct StlHeader
 
 static_assert(sizeof(StlHeader) == 84, "StlHeader size not correct");
 
-// Buffered line reader for the wxInputStream.
+// Buffered line reader to a string buffer.
 class LineReader
 {
 public:
-    LineReader(wxInputStream &input_stream, const char *initial_data, int initial_len) : 
-        m_input_stream(input_stream),
-        m_pos(0),
-        m_len(initial_len)
-    {
-        assert(initial_len >= 0 && initial_len < m_bufsize);
-        memcpy(m_buffer, initial_data, initial_len);
-    }
+    LineReader(std::vector<char> &data) : m_buffer(data), m_pos(0), m_len(data.size()) {}
 
     const char* next_line() {
-        for (;;) {
-            // Skip empty lines.
-            while (m_pos < m_len && (m_buffer[m_pos] == '\r' || m_buffer[m_pos] == '\n'))
-                ++ m_pos;
-            if (m_pos == m_len) {
-                // Empty buffer, fill it from the input stream.
-                m_pos = 0;
-                m_input_stream.Read(m_buffer, m_bufsize - 1);
-                m_len = m_input_stream.LastRead();
-				assert(m_len >= 0 && m_len < m_bufsize);
-                if (m_len == 0)
-                    // End of file.
-                    return nullptr;
-                // Skip empty lines etc.
-                continue;
-            }
-            // The buffer is nonempty and it does not start with end of lines. Find the first end of line.
-            int end = m_pos + 1;
-            while (end < m_len && m_buffer[end] != '\r' && m_buffer[end] != '\n')
-                ++ end;
-            if (end == m_len && ! m_input_stream.Eof() && m_len < m_bufsize) {
-                // Move the buffer content to the buffer start and fill the rest of the buffer.
-                assert(m_pos > 0);
-                memmove(m_buffer, m_buffer + m_pos, m_len - m_pos);
-				m_len -= m_pos;
-				assert(m_len >= 0 && m_len < m_bufsize);
-				m_pos = 0;
-                m_input_stream.Read(m_buffer + m_len, m_bufsize - 1 - m_len);
-                int new_data = m_input_stream.LastRead();
-                if (new_data > 0) {
-                    m_len += new_data;
-					assert(m_len >= 0 && m_len < m_bufsize);
-					continue;
-                }
-            }
-            char *ptr_out = m_buffer + m_pos;
-            m_pos = end + 1;
-            m_buffer[end] = 0;
-            if (m_pos >= m_len) {
-                m_pos = 0;
-                m_len = 0;
-            }
-            return ptr_out;
+        // Skip empty lines.
+        while (m_pos < m_len && (m_buffer[m_pos] == '\r' || m_buffer[m_pos] == '\n'))
+            ++ m_pos;
+        if (m_pos == m_len) {
+            // End of file.
+            return nullptr;
         }
+        // The buffer is nonempty and it does not start with end of lines. Find the first end of line.
+        int end = m_pos + 1;
+        while (end < m_len && m_buffer[end] != '\r' && m_buffer[end] != '\n')
+            ++ end;
+        char *ptr_out = m_buffer.data() + m_pos;
+        m_pos = end + 1;
+        m_buffer[end] = 0;
+        return ptr_out;
     }
 
     int next_line_scanf(const char *format, ...)
@@ -109,303 +71,314 @@ public:
     }
 
 private:
-    wxInputStream &m_input_stream;
-    static const int m_bufsize = 4096;
-    char m_buffer[m_bufsize];
-    int  m_pos = 0;
-    int  m_len = 0;
+    std::vector<char>  &m_buffer;
+    int                 m_pos;
+    int                 m_len;
 };
 
+static void extract_model_from_archive(
+    // name of the model file
+    const char              *name,
+    // path to the archive
+    const char              *path,
+    // content of scene.xml
+    const std::vector<char> &scene_xml_data,
+    // loaded data of this STL
+    std::vector<char>       &data,
+    // Model, to which the newly loaded objects will be added
+    Model                   *model,
+    // To map multiple STLs into a single model object for multi-material prints.
+    std::map<int, ModelObject*> &group_to_model_object)
+{
+    // Find the model entry in the XML data.
+    char model_name_tag[1024];
+    sprintf(model_name_tag, "<model name=\"%s\">", name);
+    const char *model_xml = strstr(scene_xml_data.data(), model_name_tag);
+    const char *zero_tag  = "<zero>";
+    const char *zero_xml  = strstr(scene_xml_data.data(), zero_tag);
+    float  trafo[3][4] = { 0 };
+#if ENABLE_MODELINSTANCE_3D_ROTATION
+    Vec3d  instance_rotation = Vec3d::Zero();
+#else
+    double instance_rotation = 0.;
+#endif // ENABLE_MODELINSTANCE_3D_ROTATION
+    double instance_scaling_factor = 1.f;
+#if ENABLE_MODELINSTANCE_3D_OFFSET
+    Vec3d  instance_offset = Vec3d::Zero();
+#else
+    Vec2d  instance_offset(0., 0.);
+#endif // ENABLE_MODELINSTANCE_3D_OFFSET
+    bool         trafo_set    = false;
+    unsigned int group_id     = (unsigned int)-1;
+    unsigned int extruder_id  = (unsigned int)-1;
+    ModelObject *model_object = nullptr;
+    if (model_xml != nullptr) {
+        model_xml += strlen(model_name_tag);
+        const char *position_tag = "<position>";
+        const char *position_xml = strstr(model_xml, position_tag);
+        const char *rotation_tag = "<rotation>";
+        const char *rotation_xml = strstr(model_xml, rotation_tag);
+        const char *scale_tag    = "<scale>";
+        const char *scale_xml    = strstr(model_xml, scale_tag);
+        float position[3], rotation[3], scale[3], zero[3];
+        if (position_xml != nullptr && rotation_xml != nullptr && scale_xml != nullptr && zero_xml != nullptr &&
+            sscanf(position_xml+strlen(position_tag), 
+                "[%f, %f, %f]", position, position+1, position+2) == 3 &&
+            sscanf(rotation_xml+strlen(rotation_tag), 
+                "[%f, %f, %f]", rotation, rotation+1, rotation+2) == 3 &&
+            sscanf(scale_xml+strlen(scale_tag),
+                "[%f, %f, %f]", scale, scale+1, scale+2) == 3 &&
+            sscanf(zero_xml+strlen(zero_tag), 
+                "[%f, %f, %f]", zero, zero+1, zero+2) == 3) {
+            if (scale[0] == scale[1] && scale[1] == scale[2]) {
+                instance_scaling_factor = scale[0];
+                scale[0] = scale[1] = scale[2] = 1.;
+            }
+#if ENABLE_MODELINSTANCE_3D_ROTATION
+            instance_rotation = Vec3d(-(double)rotation[0], -(double)rotation[1], -(double)rotation[2]);
+#else
+            if (rotation[0] == 0. && rotation[1] == 0.) {
+                instance_rotation = - rotation[2];
+                rotation[2] = 0.;
+            }
+#endif // ENABLE_MODELINSTANCE_3D_ROTATION
+            Eigen::Matrix3f mat_rot, mat_scale, mat_trafo;
+            mat_rot = Eigen::AngleAxisf(-rotation[2], Eigen::Vector3f::UnitZ()) * 
+                      Eigen::AngleAxisf(-rotation[1], Eigen::Vector3f::UnitY()) *
+                      Eigen::AngleAxisf(-rotation[0], Eigen::Vector3f::UnitX());
+            mat_scale = Eigen::Scaling(scale[0], scale[1], scale[2]);
+            mat_trafo = mat_rot * mat_scale;
+            for (size_t r = 0; r < 3; ++ r) {
+                for (size_t c = 0; c < 3; ++ c)
+                    trafo[r][c] += mat_trafo(r, c);
+            }
+#if ENABLE_MODELINSTANCE_3D_OFFSET
+            instance_offset = Vec3d((double)(position[0] - zero[0]), (double)(position[1] - zero[1]), (double)(position[2] - zero[2]));
+#else
+            instance_offset(0) = position[0] - zero[0];
+            instance_offset(1) = position[1] - zero[1];
+#endif // ENABLE_MODELINSTANCE_3D_OFFSET
+            trafo[2][3] = position[2] / instance_scaling_factor;
+            trafo_set = true;
+        }
+        const char *group_tag    = "<group>";
+        const char *group_xml    = strstr(model_xml, group_tag);
+        const char *extruder_tag = "<extruder>";
+        const char *extruder_xml = strstr(model_xml, extruder_tag);
+        if (group_xml != nullptr) {
+            int group = atoi(group_xml + strlen(group_tag));
+            if (group > 0) {
+                group_id = group;
+                auto it = group_to_model_object.find(group_id);
+                if (it != group_to_model_object.end())
+                    model_object = it->second;
+            }
+        }
+        if (extruder_xml != nullptr) {
+            int e = atoi(extruder_xml + strlen(extruder_tag));
+            if (e > 0)
+            extruder_id = e;
+        }
+    }
+    if (! trafo_set)
+        throw std::runtime_error(std::string("Archive ") + path + " does not contain a valid entry in scene.xml for " + name);
+
+    // Extract the STL.
+    StlHeader header;
+    TriangleMesh mesh;
+    bool mesh_valid = false;
+    bool stl_ascii  = false;
+    if (data.size() > sizeof(StlHeader)) {
+        memcpy((char*)&header, data.data(), sizeof(StlHeader));
+        if (strncmp(header.comment, "solid ", 6) == 0)
+            stl_ascii = true;
+        else {
+            // Header has been extracted. Now read the faces.
+            stl_file &stl = mesh.stl;
+            stl.error = 0;
+            stl.stats.type = inmemory;
+            stl.stats.number_of_facets = header.nTriangles;
+            stl.stats.original_num_facets = header.nTriangles;
+            stl_allocate(&stl);
+            if (header.nTriangles > 0 && data.size() == 50 * header.nTriangles + sizeof(StlHeader)) {
+                memcpy((char*)stl.facet_start, data.data() + sizeof(StlHeader), 50 * header.nTriangles);
+                if (sizeof(stl_facet) > SIZEOF_STL_FACET) {
+                    // The stl.facet_start is not packed tightly. Unpack the array of stl_facets.
+                    unsigned char *data = (unsigned char*)stl.facet_start;
+                    for (size_t i = header.nTriangles - 1; i > 0; -- i)
+                        memmove(data + i * sizeof(stl_facet), data + i * SIZEOF_STL_FACET, SIZEOF_STL_FACET);
+                }
+                // All the faces have been read.
+                stl_get_size(&stl);
+                mesh.repair();
+                // Transform the model.
+                stl_transform(&stl, &trafo[0][0]);
+                if (std::abs(stl.stats.min(2)) < EPSILON)
+                    stl.stats.min(2) = 0.;
+                // Add a mesh to a model.
+                if (mesh.facets_count() > 0)
+                    mesh_valid = true;
+            }
+        }
+    } else
+        stl_ascii = true;
+
+    if (stl_ascii) {
+        // Try to parse ASCII STL.
+        char                    normal_buf[3][32];
+        stl_facet               facet;
+        std::vector<stl_facet>  facets;
+        LineReader              line_reader(data);
+        std::string             solid_name;
+        facet.extra[0] = facet.extra[1] = 0;
+        for (;;) {
+            const char *line = line_reader.next_line();
+            if (line == nullptr)
+                // End of file.
+                break;
+            if (strncmp(line, "solid", 5) == 0) {
+                // Opening the "solid" block.
+                if (! solid_name.empty()) {
+                    // Error, solid block is already open.
+                    facets.clear();
+                    break;
+                }
+                solid_name = line + 5;
+                if (solid_name.empty())
+                    solid_name = "unknown";
+                continue;
+            }
+            if (strncmp(line, "endsolid", 8) == 0) {
+                // Closing the "solid" block.
+                if (solid_name.empty()) {
+                    // Error, no solid block is open.
+                    facets.clear();
+                    break;
+                }
+                solid_name.clear();
+                continue;
+            }
+            // Line has to start with the word solid.
+            int res_normal      = sscanf(line, " facet normal %31s %31s %31s", normal_buf[0], normal_buf[1], normal_buf[2]);
+            assert(res_normal == 3);
+            int res_outer_loop  = line_reader.next_line_scanf(" outer loop");
+            assert(res_outer_loop == 0);
+            int res_vertex1 = line_reader.next_line_scanf(" vertex %f %f %f", &facet.vertex[0](0), &facet.vertex[0](1), &facet.vertex[0](2));
+            assert(res_vertex1 == 3);
+            int res_vertex2 = line_reader.next_line_scanf(" vertex %f %f %f", &facet.vertex[1](0), &facet.vertex[1](1), &facet.vertex[1](2));
+            assert(res_vertex2 == 3);
+            int res_vertex3 = line_reader.next_line_scanf(" vertex %f %f %f", &facet.vertex[2](0), &facet.vertex[2](1), &facet.vertex[2](2));
+            assert(res_vertex3 == 3);
+            int res_endloop = line_reader.next_line_scanf(" endloop");
+            assert(res_endloop == 0);
+            int res_endfacet = line_reader.next_line_scanf(" endfacet");
+            if (res_normal != 3 || res_outer_loop != 0 || res_vertex1 != 3 || res_vertex2 != 3 || res_vertex3 != 3 || res_endloop != 0 || res_endfacet != 0) {
+                // perror("Something is syntactically very wrong with this ASCII STL!");
+                facets.clear();
+                break;
+            }
+            // The facet normal has been parsed as a single string as to workaround for not a numbers in the normal definition.
+            if (sscanf(normal_buf[0], "%f", &facet.normal(0)) != 1 ||
+                sscanf(normal_buf[1], "%f", &facet.normal(1)) != 1 ||
+                sscanf(normal_buf[2], "%f", &facet.normal(2)) != 1) {
+                // Normal was mangled. Maybe denormals or "not a number" were stored?
+                // Just reset the normal and silently ignore it.
+                memset(&facet.normal, 0, sizeof(facet.normal));
+            }
+            facets.emplace_back(facet);
+        }
+        if (! facets.empty() && solid_name.empty()) {
+            stl_file &stl = mesh.stl;
+            stl.stats.type = inmemory;
+            stl.stats.number_of_facets = facets.size();
+            stl.stats.original_num_facets = facets.size();
+            stl_allocate(&stl);
+            memcpy((void*)stl.facet_start, facets.data(), facets.size() * 50);
+            stl_get_size(&stl);
+            mesh.repair();
+            // Transform the model.
+            stl_transform(&stl, &trafo[0][0]);
+            // Add a mesh to a model.
+            if (mesh.facets_count() > 0)
+                mesh_valid = true;
+        }
+    }
+
+    if (! mesh_valid)
+        throw std::runtime_error(std::string("Archive ") + path + " does not contain a valid mesh for " + name);
+
+    // Add this mesh to the model.
+    ModelVolume *volume = nullptr;
+    if (model_object == nullptr) {
+        // This is a first mesh of a group. Create a new object & volume.
+        model_object = model->add_object(name, path, std::move(mesh));
+        volume = model_object->volumes.front();
+        ModelInstance *instance  = model_object->add_instance();
+#if ENABLE_MODELINSTANCE_3D_ROTATION
+        instance->set_rotation(instance_rotation);
+#else
+        instance->rotation = instance_rotation;
+#endif // ENABLE_MODELINSTANCE_3D_ROTATION
+        instance->scaling_factor = instance_scaling_factor;
+#if ENABLE_MODELINSTANCE_3D_OFFSET
+        instance->set_offset(instance_offset);
+#else
+        instance->offset = instance_offset;
+#endif // ENABLE_MODELINSTANCE_3D_OFFSET
+        if (group_id != (size_t)-1)
+            group_to_model_object[group_id] = model_object;
+    } else {
+        // This is not the 1st mesh of a group. Add it to the ModelObject.
+        volume = model_object->add_volume(std::move(mesh));
+        volume->name = name;
+    }
+    // Set the extruder to the volume.
+    if (extruder_id != (unsigned int)-1) {
+        char str_extruder[64];
+        sprintf(str_extruder, "%ud", extruder_id);
+        volume->config.set_deserialize("extruder", str_extruder);
+    }
+}
+
 // Load a PrusaControl project file into a provided model.
 bool load_prus(const char *path, Model *model)
 {
-    // To receive the content of the zipped 'scene.xml' file.
-    std::vector<char>           scene_xml_data;
-    wxFFileInputStream          in(
-#ifdef WIN32
-        // On Windows, convert to a 16bit unicode string.
-        boost::nowide::widen(path).c_str()
-#else
-        path
-#endif
-        );
-    wxZipInputStream            zip(in);
-    std::unique_ptr<wxZipEntry> entry;
-    size_t                      num_models = 0;
-    std::map<int, ModelObject*> group_to_model_object;
-    while (entry.reset(zip.GetNextEntry()), entry.get() != NULL) {
-        wxString name = entry->GetName();
-        if (name == "scene.xml") {
-            if (! scene_xml_data.empty()) {
-                // scene.xml has been found more than once in the archive.
-                return false;
-            }
-            size_t size_last = 0;
-            size_t size_incr = 4096;
-            scene_xml_data.resize(size_incr);
-            while (! zip.Read(scene_xml_data.data() + size_last, size_incr).Eof()) {
-                size_last += zip.LastRead();
-                if (scene_xml_data.size() < size_last + size_incr)
-                    scene_xml_data.resize(size_last + size_incr);
-            }
-            size_last += zip.LastRead();
-            if (scene_xml_data.size() == size_last)
-                scene_xml_data.resize(size_last + 1);
-            else if (scene_xml_data.size() > size_last + 1)
-                scene_xml_data.erase(scene_xml_data.begin() + size_last + 1, scene_xml_data.end());
-            scene_xml_data[size_last] = 0;
-        }
-        else if (name.EndsWith(".stl") || name.EndsWith(".STL")) {
-            // Find the model entry in the XML data.
-            const wxScopedCharBuffer name_utf8 = name.ToUTF8();
-            char model_name_tag[1024];
-            sprintf(model_name_tag, "<model name=\"%s\">", name_utf8.data());
-            const char *model_xml = strstr(scene_xml_data.data(), model_name_tag);
-            const char *zero_tag  = "<zero>";
-			const char *zero_xml  = strstr(scene_xml_data.data(), zero_tag);
-            float  trafo[3][4] = { 0 };
-#if ENABLE_MODELINSTANCE_3D_ROTATION
-            Vec3d instance_rotation = Vec3d::Zero();
-#else
-            double instance_rotation = 0.;
-#endif // ENABLE_MODELINSTANCE_3D_ROTATION
-            double instance_scaling_factor = 1.f;
-#if ENABLE_MODELINSTANCE_3D_OFFSET
-            Vec3d instance_offset = Vec3d::Zero();
-#else
-            Vec2d instance_offset(0., 0.);
-#endif // ENABLE_MODELINSTANCE_3D_OFFSET
-            bool   trafo_set = false;
-            unsigned int group_id     = (unsigned int)-1;
-            unsigned int extruder_id  = (unsigned int)-1;
-            ModelObject *model_object = nullptr;
-            if (model_xml != nullptr) {
-                model_xml += strlen(model_name_tag);
-                const char *position_tag = "<position>";
-                const char *position_xml = strstr(model_xml, position_tag);
-                const char *rotation_tag = "<rotation>";
-                const char *rotation_xml = strstr(model_xml, rotation_tag);
-                const char *scale_tag    = "<scale>";
-                const char *scale_xml    = strstr(model_xml, scale_tag);
-                float position[3], rotation[3], scale[3], zero[3];
-                if (position_xml != nullptr && rotation_xml != nullptr && scale_xml != nullptr && zero_xml != nullptr &&
-                    sscanf(position_xml+strlen(position_tag), 
-                        "[%f, %f, %f]", position, position+1, position+2) == 3 &&
-                    sscanf(rotation_xml+strlen(rotation_tag), 
-                        "[%f, %f, %f]", rotation, rotation+1, rotation+2) == 3 &&
-                    sscanf(scale_xml+strlen(scale_tag),
-                        "[%f, %f, %f]", scale, scale+1, scale+2) == 3 &&
-                    sscanf(zero_xml+strlen(zero_tag), 
-                        "[%f, %f, %f]", zero, zero+1, zero+2) == 3) {
-                    if (scale[0] == scale[1] && scale[1] == scale[2]) {
-                        instance_scaling_factor = scale[0];
-                        scale[0] = scale[1] = scale[2] = 1.;
-                    }
-#if ENABLE_MODELINSTANCE_3D_ROTATION
-                    instance_rotation = Vec3d(-(double)rotation[0], -(double)rotation[1], -(double)rotation[2]);
-#else
-                    if (rotation[0] == 0. && rotation[1] == 0.) {
-                        instance_rotation = - rotation[2];
-                        rotation[2] = 0.;
-                    }
-#endif // ENABLE_MODELINSTANCE_3D_ROTATION
-                    Eigen::Matrix3f mat_rot, mat_scale, mat_trafo;
-                    mat_rot = Eigen::AngleAxisf(-rotation[2], Eigen::Vector3f::UnitZ()) * 
-                              Eigen::AngleAxisf(-rotation[1], Eigen::Vector3f::UnitY()) *
-                              Eigen::AngleAxisf(-rotation[0], Eigen::Vector3f::UnitX());
-                    mat_scale = Eigen::Scaling(scale[0], scale[1], scale[2]);
-                    mat_trafo = mat_rot * mat_scale;
-                    for (size_t r = 0; r < 3; ++ r) {
-                        for (size_t c = 0; c < 3; ++ c)
-                            trafo[r][c] += mat_trafo(r, c);
-                    }
-#if ENABLE_MODELINSTANCE_3D_OFFSET
-                    instance_offset = Vec3d((double)(position[0] - zero[0]), (double)(position[1] - zero[1]), (double)(position[2] - zero[2]));
-#else
-                    instance_offset(0) = position[0] - zero[0];
-                    instance_offset(1) = position[1] - zero[1];
-#endif // ENABLE_MODELINSTANCE_3D_OFFSET
-                    trafo[2][3] = position[2] / instance_scaling_factor;
-                    trafo_set = true;
-                }
-                const char *group_tag    = "<group>";
-                const char *group_xml    = strstr(model_xml, group_tag);
-                const char *extruder_tag = "<extruder>";
-                const char *extruder_xml = strstr(model_xml, extruder_tag);
-                if (group_xml != nullptr) {
-                    int group = atoi(group_xml + strlen(group_tag));
-                    if (group > 0) {
-                        group_id = group;
-                        auto it = group_to_model_object.find(group_id);
-                        if (it != group_to_model_object.end())
-                            model_object = it->second;
-                    }
-                }
-                if (extruder_xml != nullptr) {
-                    int e = atoi(extruder_xml + strlen(extruder_tag));
-                    if (e > 0)
-                    extruder_id = e;
-                }
-            }
-            if (trafo_set) {
-				// Extract the STL.
-				StlHeader header;
-                TriangleMesh mesh;
-                bool mesh_valid = false;
-				bool stl_ascii = false;
-				if (!zip.Read((void*)&header, sizeof(StlHeader)).Eof()) {
-					if (strncmp(header.comment, "solid ", 6) == 0)
-						stl_ascii = true;
-					else {
-						// Header has been extracted. Now read the faces.
-						stl_file &stl = mesh.stl;
-						stl.error = 0;
-						stl.stats.type = inmemory;
-						stl.stats.number_of_facets = header.nTriangles;
-						stl.stats.original_num_facets = header.nTriangles;
-						stl_allocate(&stl);
-						if (header.nTriangles > 0 && zip.ReadAll((void*)stl.facet_start, 50 * header.nTriangles)) {
-							if (sizeof(stl_facet) > SIZEOF_STL_FACET) {
-                                // The stl.facet_start is not packed tightly. Unpack the array of stl_facets.
-                                unsigned char *data = (unsigned char*)stl.facet_start;
-                                for (size_t i = header.nTriangles - 1; i > 0; -- i)
-                                    memmove(data + i * sizeof(stl_facet), data + i * SIZEOF_STL_FACET, SIZEOF_STL_FACET);
-                            }
-							// All the faces have been read.
-							stl_get_size(&stl);
-							mesh.repair();
-							// Transform the model.
-							stl_transform(&stl, &trafo[0][0]);
-							if (std::abs(stl.stats.min(2)) < EPSILON)
-								stl.stats.min(2) = 0.;
-							// Add a mesh to a model.
-							if (mesh.facets_count() > 0)
-                                mesh_valid = true;
-						}
-					}
-				} else
-					stl_ascii = true;
-				if (stl_ascii) {
-					// Try to parse ASCII STL.
-                    char                    normal_buf[3][32];
-                    stl_facet               facet;
-                    std::vector<stl_facet>  facets;
-                    LineReader              line_reader(zip, (char*)&header, zip.LastRead());
-                    std::string             solid_name;
-                    facet.extra[0] = facet.extra[1] = 0;
-                    for (;;) {
-                        const char *line = line_reader.next_line();
-                        if (line == nullptr)
-                            // End of file.
-                            break;
-                        if (strncmp(line, "solid", 5) == 0) {
-                            // Opening the "solid" block.
-                            if (! solid_name.empty()) {
-                                // Error, solid block is already open.
-                                facets.clear();
-                                break;
-                            }
-                            solid_name = line + 5;
-                            if (solid_name.empty())
-                                solid_name = "unknown";
-                            continue;
-                        }
-                        if (strncmp(line, "endsolid", 8) == 0) {
-                            // Closing the "solid" block.
-                            if (solid_name.empty()) {
-                                // Error, no solid block is open.
-                                facets.clear();
-                                break;
-                            }
-							solid_name.clear();
-                            continue;
-                        }
-                        // Line has to start with the word solid.
-						int res_normal		= sscanf(line, " facet normal %31s %31s %31s", normal_buf[0], normal_buf[1], normal_buf[2]);
-						assert(res_normal == 3);
-                        int res_outer_loop	= line_reader.next_line_scanf(" outer loop");
-						assert(res_outer_loop == 0);
-						int res_vertex1 = line_reader.next_line_scanf(" vertex %f %f %f", &facet.vertex[0](0), &facet.vertex[0](1), &facet.vertex[0](2));
-						assert(res_vertex1 == 3);
-						int res_vertex2 = line_reader.next_line_scanf(" vertex %f %f %f", &facet.vertex[1](0), &facet.vertex[1](1), &facet.vertex[1](2));
-						assert(res_vertex2 == 3);
-						int res_vertex3 = line_reader.next_line_scanf(" vertex %f %f %f", &facet.vertex[2](0), &facet.vertex[2](1), &facet.vertex[2](2));
-						assert(res_vertex3 == 3);
-						int res_endloop = line_reader.next_line_scanf(" endloop");
-						assert(res_endloop == 0);
-						int res_endfacet = line_reader.next_line_scanf(" endfacet");
-						if (res_normal != 3 || res_outer_loop != 0 || res_vertex1 != 3 || res_vertex2 != 3 || res_vertex3 != 3 || res_endloop != 0 || res_endfacet != 0) {
-                            // perror("Something is syntactically very wrong with this ASCII STL!");
-                            facets.clear();
-                            break;
-                        }
-                        // The facet normal has been parsed as a single string as to workaround for not a numbers in the normal definition.
-                        if (sscanf(normal_buf[0], "%f", &facet.normal(0)) != 1 ||
-                            sscanf(normal_buf[1], "%f", &facet.normal(1)) != 1 ||
-                            sscanf(normal_buf[2], "%f", &facet.normal(2)) != 1) {
-                            // Normal was mangled. Maybe denormals or "not a number" were stored?
-                            // Just reset the normal and silently ignore it.
-                            memset(&facet.normal, 0, sizeof(facet.normal));
-                        }
-                        facets.emplace_back(facet);
-                    }
-                    if (! facets.empty() && solid_name.empty()) {
-                        stl_file &stl = mesh.stl;
-                        stl.stats.type = inmemory;
-                        stl.stats.number_of_facets = facets.size();
-                        stl.stats.original_num_facets = facets.size();
-                        stl_allocate(&stl);
-                        memcpy((void*)stl.facet_start, facets.data(), facets.size() * 50);
-                        stl_get_size(&stl);
-                        mesh.repair();
-                        // Transform the model.
-                        stl_transform(&stl, &trafo[0][0]);
-                        // Add a mesh to a model.
-                        if (mesh.facets_count() > 0)
-                            mesh_valid = true;
-                    }
-				}
-
-                if (mesh_valid) {
-                    // Add this mesh to the model.
-                    ModelVolume *volume = nullptr;
-                    if (model_object == nullptr) {
-                        // This is a first mesh of a group. Create a new object & volume.
-                        model_object = model->add_object(name_utf8.data(), path, std::move(mesh));
-                        volume = model_object->volumes.front();
-                        ModelInstance *instance     = model_object->add_instance();
-#if ENABLE_MODELINSTANCE_3D_ROTATION
-                        instance->set_rotation(instance_rotation);
-#else
-                        instance->rotation = instance_rotation;
-#endif // ENABLE_MODELINSTANCE_3D_ROTATION
-                        instance->scaling_factor = instance_scaling_factor;
-#if ENABLE_MODELINSTANCE_3D_OFFSET
-                        instance->set_offset(instance_offset);
-#else
-                        instance->offset = instance_offset;
-#endif // ENABLE_MODELINSTANCE_3D_OFFSET
-                        ++num_models;
-                        if (group_id != (size_t)-1)
-                            group_to_model_object[group_id] = model_object;
-                    } else {
-                        // This is not the 1st mesh of a group. Add it to the ModelObject.
-                        volume = model_object->add_volume(std::move(mesh));
-                        volume->name = name_utf8.data();
-                    }
-                    // Set the extruder to the volume.
-                    if (extruder_id != (unsigned int)-1) {
-                        char str_extruder[64];
-                        sprintf(str_extruder, "%ud", extruder_id);
-                        volume->config.set_deserialize("extruder", str_extruder);
-                    }
-                }
+    mz_zip_archive archive;
+    mz_zip_zero_struct(&archive);
+    mz_bool res = mz_zip_reader_init_file(&archive, path, 0);
+    size_t  n_models_initial = model->objects.size();
+    try {
+        if (res == MZ_FALSE)
+            throw std::runtime_error(std::string("Unable to init zip reader for ") + path);
+        std::vector<char>           scene_xml_data;
+        // For grouping multiple STLs into a single ModelObject for multi-material prints.
+        std::map<int, ModelObject*> group_to_model_object;
+        mz_uint                     num_entries = mz_zip_reader_get_num_files(&archive);
+        for (mz_uint i = 0; i < num_entries; ++ i) {
+            mz_zip_archive_file_stat stat;
+            if (! mz_zip_reader_file_stat(&archive, i, &stat))
+                continue;
+            std::vector<char> buffer;
+            buffer.assign((size_t)stat.m_uncomp_size + 1, 0);
+            res = mz_zip_reader_extract_file_to_mem(&archive, stat.m_filename, (char*)buffer.data(), (size_t)stat.m_uncomp_size, 0);
+            if (res == MZ_FALSE)
+                std::runtime_error(std::string("Error while extracting a file from ") + path);
+            if (strcmp(stat.m_filename, "scene.xml") == 0) {
+                if (! scene_xml_data.empty())
+                    throw std::runtime_error(std::string("Multiple scene.xml were found in the archive.") + path);
+                scene_xml_data = std::move(buffer);
+            } else if (boost::iends_with(stat.m_filename, ".stl")) {
+                // May throw std::exception
+                extract_model_from_archive(stat.m_filename, path, scene_xml_data, buffer, model, group_to_model_object);
             }
         }
+    } catch (std::exception &ex) {
+        mz_zip_reader_end(&archive);
+        throw ex;
     }
-    return num_models > 0;
+
+    mz_zip_reader_end(&archive);
+    return model->objects.size() > n_models_initial;
 }
 
 }; // namespace Slic3r
-
-#endif /* SLIC3R_PRUS */
diff --git a/src/libslic3r/Format/PRUS.hpp b/src/libslic3r/Format/PRUS.hpp
index 8559a70d6..be5c5c61a 100644
--- a/src/libslic3r/Format/PRUS.hpp
+++ b/src/libslic3r/Format/PRUS.hpp
@@ -1,4 +1,3 @@
-#if defined(SLIC3R_PRUS) && ! defined(slic3r_Format_PRUS_hpp_)
 #define slic3r_Format_PRUS_hpp_
 
 namespace Slic3r {
@@ -10,5 +9,3 @@ class Model;
 extern bool load_prus(const char *path, Model *model);
 
 }; // namespace Slic3r
-
-#endif /* SLIC3R_PRUS && ! defined(slic3r_Format_PRUS_hpp_) */
diff --git a/src/libslic3r/Model.cpp b/src/libslic3r/Model.cpp
index ae74ab18e..1128e57fc 100644
--- a/src/libslic3r/Model.cpp
+++ b/src/libslic3r/Model.cpp
@@ -62,10 +62,8 @@ Model Model::read_from_file(const std::string &input_file, DynamicPrintConfig *c
         result = load_amf(input_file.c_str(), config, &model);
     else if (boost::algorithm::iends_with(input_file, ".3mf"))
         result = load_3mf(input_file.c_str(), config, &model);
-#ifdef SLIC3R_PRUS
     else if (boost::algorithm::iends_with(input_file, ".prusa"))
         result = load_prus(input_file.c_str(), &model);
-#endif /* SLIC3R_PRUS */
     else
         throw std::runtime_error("Unknown file format. Input file must have .stl, .obj, .amf(.xml) or .prusa extension.");
 
diff --git a/src/libslic3r/TriangleMesh.cpp b/src/libslic3r/TriangleMesh.cpp
index 4bf13330f..c56b66de3 100644
--- a/src/libslic3r/TriangleMesh.cpp
+++ b/src/libslic3r/TriangleMesh.cpp
@@ -134,25 +134,31 @@ void TriangleMesh::repair()
     
     // remove_unconnected
     if (stl.stats.connected_facets_3_edge <  stl.stats.number_of_facets) {
+        BOOST_LOG_TRIVIAL(trace) << "\tstl_remove_unconnected_facets";
         stl_remove_unconnected_facets(&stl);
     }
     
     // fill_holes
     if (stl.stats.connected_facets_3_edge < stl.stats.number_of_facets) {
+        BOOST_LOG_TRIVIAL(trace) << "\tstl_fill_holes";
         stl_fill_holes(&stl);
         stl_clear_error(&stl);
     }
 
     // normal_directions
+    BOOST_LOG_TRIVIAL(trace) << "\tstl_fix_normal_directions";
     stl_fix_normal_directions(&stl);
 
     // normal_values
+    BOOST_LOG_TRIVIAL(trace) << "\tstl_fix_normal_values";
     stl_fix_normal_values(&stl);
     
     // always calculate the volume and reverse all normals if volume is negative
+    BOOST_LOG_TRIVIAL(trace) << "\tstl_calculate_volume";
     stl_calculate_volume(&stl);
     
     // neighbors
+    BOOST_LOG_TRIVIAL(trace) << "\tstl_verify_neighbors";
     stl_verify_neighbors(&stl);
 
     this->repaired = true;
diff --git a/src/libslic3r/Utils.hpp b/src/libslic3r/Utils.hpp
index 8feb17747..863ca6b2f 100644
--- a/src/libslic3r/Utils.hpp
+++ b/src/libslic3r/Utils.hpp
@@ -117,10 +117,10 @@ inline uint64_t next_highest_power_of_2(uint64_t v)
 inline size_t next_highest_power_of_2(size_t v)
 { 
 #if SSIZE_MAX == 9223372036854775807
-    static_assert(sizeof(size_t) == sizeof(uint64_t));
+    static_assert(sizeof(size_t) == sizeof(uint64_t), "sizeof(size_t) == sizeof(uint64_t)");
     return next_highest_power_of_2(uint64_t(v));
 #else
-    static_assert(sizeof(size_t) == sizeof(uint32_t));
+    static_assert(sizeof(size_t) == sizeof(uint32_t), "sizeof(size_t) == sizeof(uint32_t)");
     return next_highest_power_of_2(uint32_t(v));
 #endif
 }