ENABLE_THUMBNAIL_GENERATOR -> render printbed into thumbnails

This commit is contained in:
Enrico Turri 2019-11-28 14:18:24 +01:00
parent bd1ee8ee4a
commit ddd1df1552
8 changed files with 89 additions and 37 deletions

View File

@ -992,7 +992,7 @@ void GCode::_do_export(Print& print, FILE* file)
{ {
const size_t max_row_length = 78; const size_t max_row_length = 78;
ThumbnailsList thumbnails; ThumbnailsList thumbnails;
thumbnail_cb(thumbnails, print.full_print_config().option<ConfigOptionPoints>("thumbnails")->values, true, true, true); thumbnail_cb(thumbnails, print.full_print_config().option<ConfigOptionPoints>("thumbnails")->values, true, true, true, true);
for (const ThumbnailData& data : thumbnails) for (const ThumbnailData& data : thumbnails)
{ {
if (data.is_valid()) if (data.is_valid())

View File

@ -22,7 +22,7 @@ struct ThumbnailData
}; };
typedef std::vector<ThumbnailData> ThumbnailsList; typedef std::vector<ThumbnailData> ThumbnailsList;
typedef std::function<void(ThumbnailsList& thumbnails, const Vec2ds& sizes, bool printable_only, bool parts_only, bool transparent_background)> ThumbnailsGeneratorCallback; typedef std::function<void(ThumbnailsList & thumbnails, const Vec2ds & sizes, bool printable_only, bool parts_only, bool show_bed, bool transparent_background)> ThumbnailsGeneratorCallback;
} // namespace Slic3r } // namespace Slic3r

View File

@ -148,8 +148,8 @@ void BackgroundSlicingProcess::process_sla()
if (m_thumbnail_cb != nullptr) if (m_thumbnail_cb != nullptr)
{ {
ThumbnailsList thumbnails; ThumbnailsList thumbnails;
m_thumbnail_cb(thumbnails, current_print()->full_print_config().option<ConfigOptionPoints>("thumbnails")->values, true, true, true); m_thumbnail_cb(thumbnails, current_print()->full_print_config().option<ConfigOptionPoints>("thumbnails")->values, true, true, true, true);
// m_thumbnail_cb(thumbnails, current_print()->full_print_config().option<ConfigOptionPoints>("thumbnails")->values, true, false, true); // renders also supports and pad // m_thumbnail_cb(thumbnails, current_print()->full_print_config().option<ConfigOptionPoints>("thumbnails")->values, true, false, true, true); // renders also supports and pad
for (const ThumbnailData& data : thumbnails) for (const ThumbnailData& data : thumbnails)
{ {
if (data.is_valid()) if (data.is_valid())
@ -473,8 +473,8 @@ void BackgroundSlicingProcess::prepare_upload()
if (m_thumbnail_cb != nullptr) if (m_thumbnail_cb != nullptr)
{ {
ThumbnailsList thumbnails; ThumbnailsList thumbnails;
m_thumbnail_cb(thumbnails, current_print()->full_print_config().option<ConfigOptionPoints>("thumbnails")->values, true, true, true); m_thumbnail_cb(thumbnails, current_print()->full_print_config().option<ConfigOptionPoints>("thumbnails")->values, true, true, true, true);
// m_thumbnail_cb(thumbnails, current_print()->full_print_config().option<ConfigOptionPoints>("thumbnails")->values, true, false, true); // renders also supports and pad // m_thumbnail_cb(thumbnails, current_print()->full_print_config().option<ConfigOptionPoints>("thumbnails")->values, true, false, true, true); // renders also supports and pad
for (const ThumbnailData& data : thumbnails) for (const ThumbnailData& data : thumbnails)
{ {
if (data.is_valid()) if (data.is_valid())

View File

@ -196,7 +196,7 @@ void Camera::apply_view_matrix() const
glsafe(::glGetDoublev(GL_MODELVIEW_MATRIX, m_view_matrix.data())); glsafe(::glGetDoublev(GL_MODELVIEW_MATRIX, m_view_matrix.data()));
} }
void Camera::apply_projection(const BoundingBoxf3& box) const void Camera::apply_projection(const BoundingBoxf3& box, double near_z, double far_z) const
{ {
set_distance(DefaultDistance); set_distance(DefaultDistance);
@ -207,6 +207,12 @@ void Camera::apply_projection(const BoundingBoxf3& box) const
{ {
m_frustrum_zs = calc_tight_frustrum_zs_around(box); m_frustrum_zs = calc_tight_frustrum_zs_around(box);
if (near_z > 0.0)
m_frustrum_zs.first = std::min(m_frustrum_zs.first, near_z);
if (far_z > 0.0)
m_frustrum_zs.second = std::max(m_frustrum_zs.second, far_z);
w = 0.5 * (double)m_viewport[2]; w = 0.5 * (double)m_viewport[2];
h = 0.5 * (double)m_viewport[3]; h = 0.5 * (double)m_viewport[3];
@ -539,7 +545,7 @@ double Camera::calc_zoom_to_volumes_factor(const GLVolumePtrs& volumes, int canv
double dx = margin_factor * (max_x - min_x); double dx = margin_factor * (max_x - min_x);
double dy = margin_factor * (max_y - min_y); double dy = margin_factor * (max_y - min_y);
if ((dx == 0.0) || (dy == 0.0)) if ((dx <= 0.0) || (dy <= 0.0))
return -1.0f; return -1.0f;
return std::min((double)canvas_w / dx, (double)canvas_h / dy); return std::min((double)canvas_w / dx, (double)canvas_h / dy);

View File

@ -95,7 +95,9 @@ public:
void apply_viewport(int x, int y, unsigned int w, unsigned int h) const; void apply_viewport(int x, int y, unsigned int w, unsigned int h) const;
void apply_view_matrix() const; void apply_view_matrix() const;
void apply_projection(const BoundingBoxf3& box) const; // Calculates and applies the projection matrix tighting the frustrum z range around the given box.
// If larger z span is needed, pass the desired values of near and far z (negative values are ignored)
void apply_projection(const BoundingBoxf3& box, double near_z = -1.0, double far_z = -1.0) const;
#if ENABLE_THUMBNAIL_GENERATOR #if ENABLE_THUMBNAIL_GENERATOR
void zoom_to_box(const BoundingBoxf3& box, int canvas_w, int canvas_h, double margin_factor = DefaultZoomToBoxMarginFactor); void zoom_to_box(const BoundingBoxf3& box, int canvas_w, int canvas_h, double margin_factor = DefaultZoomToBoxMarginFactor);

View File

@ -1924,13 +1924,13 @@ void GLCanvas3D::render()
} }
#if ENABLE_THUMBNAIL_GENERATOR #if ENABLE_THUMBNAIL_GENERATOR
void GLCanvas3D::render_thumbnail(ThumbnailData& thumbnail_data, unsigned int w, unsigned int h, bool printable_only, bool parts_only, bool transparent_background) void GLCanvas3D::render_thumbnail(ThumbnailData& thumbnail_data, unsigned int w, unsigned int h, bool printable_only, bool parts_only, bool show_bed, bool transparent_background)
{ {
switch (GLCanvas3DManager::get_framebuffers_type()) switch (GLCanvas3DManager::get_framebuffers_type())
{ {
case GLCanvas3DManager::FB_Arb: { _render_thumbnail_framebuffer(thumbnail_data, w, h, printable_only, parts_only, transparent_background); break; } case GLCanvas3DManager::FB_Arb: { _render_thumbnail_framebuffer(thumbnail_data, w, h, printable_only, parts_only, show_bed, transparent_background); break; }
case GLCanvas3DManager::FB_Ext: { _render_thumbnail_framebuffer_ext(thumbnail_data, w, h, printable_only, parts_only, transparent_background); break; } case GLCanvas3DManager::FB_Ext: { _render_thumbnail_framebuffer_ext(thumbnail_data, w, h, printable_only, parts_only, show_bed, transparent_background); break; }
default: { _render_thumbnail_legacy(thumbnail_data, w, h, printable_only, parts_only, transparent_background); break; } default: { _render_thumbnail_legacy(thumbnail_data, w, h, printable_only, parts_only, show_bed, transparent_background); break; }
} }
} }
#endif // ENABLE_THUMBNAIL_GENERATOR #endif // ENABLE_THUMBNAIL_GENERATOR
@ -3884,7 +3884,7 @@ static void debug_output_thumbnail(const ThumbnailData& thumbnail_data)
} }
#endif // ENABLE_THUMBNAIL_GENERATOR_DEBUG_OUTPUT #endif // ENABLE_THUMBNAIL_GENERATOR_DEBUG_OUTPUT
void GLCanvas3D::_render_thumbnail_internal(ThumbnailData& thumbnail_data, bool printable_only, bool parts_only, bool transparent_background) void GLCanvas3D::_render_thumbnail_internal(ThumbnailData& thumbnail_data, bool printable_only, bool parts_only, bool show_bed, bool transparent_background)
{ {
auto is_visible = [](const GLVolume& v) -> bool auto is_visible = [](const GLVolume& v) -> bool
{ {
@ -3921,7 +3921,48 @@ void GLCanvas3D::_render_thumbnail_internal(ThumbnailData& thumbnail_data, bool
camera.zoom_to_volumes(visible_volumes, thumbnail_data.width, thumbnail_data.height); camera.zoom_to_volumes(visible_volumes, thumbnail_data.width, thumbnail_data.height);
camera.apply_viewport(0, 0, thumbnail_data.width, thumbnail_data.height); camera.apply_viewport(0, 0, thumbnail_data.width, thumbnail_data.height);
camera.apply_view_matrix(); camera.apply_view_matrix();
camera.apply_projection(box);
double near_z = -1.0;
double far_z = -1.0;
if (show_bed)
{
// extends the near and far z of the frustrum to avoid the bed being clipped
BoundingBoxf3 bed_box = m_bed.get_bounding_box(true);
// bed box vertices in world space
std::vector<Vec3d> vertices;
vertices.reserve(8);
vertices.push_back(bed_box.min);
vertices.emplace_back(bed_box.max(0), bed_box.min(1), bed_box.min(2));
vertices.emplace_back(bed_box.max(0), bed_box.max(1), bed_box.min(2));
vertices.emplace_back(bed_box.min(0), bed_box.max(1), bed_box.min(2));
vertices.emplace_back(bed_box.min(0), bed_box.min(1), bed_box.max(2));
vertices.emplace_back(bed_box.max(0), bed_box.min(1), bed_box.max(2));
vertices.push_back(bed_box.max);
vertices.emplace_back(bed_box.min(0), bed_box.max(1), bed_box.max(2));
double bed_box_min_z = DBL_MAX;
double bed_box_max_z = -DBL_MAX;
Transform3d view_matrix = camera.get_view_matrix();
for (const Vec3d& v : vertices)
{
Vec3d eye_v = view_matrix * v;
if (eye_v(2) < 0.0)
{
bed_box_min_z = std::min(bed_box_min_z, -eye_v(2));
bed_box_max_z = std::max(bed_box_max_z, -eye_v(2));
}
}
if (bed_box_min_z != DBL_MAX)
near_z = bed_box_min_z;
if (bed_box_max_z != -DBL_MAX)
far_z = bed_box_max_z;
}
camera.apply_projection(box, near_z, far_z);
if (transparent_background) if (transparent_background)
glsafe(::glClearColor(0.0f, 0.0f, 0.0f, 0.0f)); glsafe(::glClearColor(0.0f, 0.0f, 0.0f, 0.0f));
@ -3953,11 +3994,14 @@ void GLCanvas3D::_render_thumbnail_internal(ThumbnailData& thumbnail_data, bool
glsafe(::glDisable(GL_DEPTH_TEST)); glsafe(::glDisable(GL_DEPTH_TEST));
if (show_bed)
_render_bed(camera.get_theta(), false);
if (transparent_background) if (transparent_background)
glsafe(::glClearColor(1.0f, 1.0f, 1.0f, 1.0f)); glsafe(::glClearColor(1.0f, 1.0f, 1.0f, 1.0f));
} }
void GLCanvas3D::_render_thumbnail_framebuffer(ThumbnailData& thumbnail_data, unsigned int w, unsigned int h, bool printable_only, bool parts_only, bool transparent_background) void GLCanvas3D::_render_thumbnail_framebuffer(ThumbnailData& thumbnail_data, unsigned int w, unsigned int h, bool printable_only, bool parts_only, bool show_bed, bool transparent_background)
{ {
thumbnail_data.set(w, h); thumbnail_data.set(w, h);
if (!thumbnail_data.is_valid()) if (!thumbnail_data.is_valid())
@ -4010,7 +4054,7 @@ void GLCanvas3D::_render_thumbnail_framebuffer(ThumbnailData& thumbnail_data, un
if (::glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE) if (::glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE)
{ {
_render_thumbnail_internal(thumbnail_data, printable_only, parts_only, transparent_background); _render_thumbnail_internal(thumbnail_data, printable_only, parts_only, show_bed, transparent_background);
if (multisample) if (multisample)
{ {
@ -4061,7 +4105,7 @@ void GLCanvas3D::_render_thumbnail_framebuffer(ThumbnailData& thumbnail_data, un
glsafe(::glDisable(GL_MULTISAMPLE)); glsafe(::glDisable(GL_MULTISAMPLE));
} }
void GLCanvas3D::_render_thumbnail_framebuffer_ext(ThumbnailData& thumbnail_data, unsigned int w, unsigned int h, bool printable_only, bool parts_only, bool transparent_background) void GLCanvas3D::_render_thumbnail_framebuffer_ext(ThumbnailData& thumbnail_data, unsigned int w, unsigned int h, bool printable_only, bool parts_only, bool show_bed, bool transparent_background)
{ {
thumbnail_data.set(w, h); thumbnail_data.set(w, h);
if (!thumbnail_data.is_valid()) if (!thumbnail_data.is_valid())
@ -4114,7 +4158,7 @@ void GLCanvas3D::_render_thumbnail_framebuffer_ext(ThumbnailData& thumbnail_data
if (::glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT) == GL_FRAMEBUFFER_COMPLETE_EXT) if (::glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT) == GL_FRAMEBUFFER_COMPLETE_EXT)
{ {
_render_thumbnail_internal(thumbnail_data, printable_only, parts_only, transparent_background); _render_thumbnail_internal(thumbnail_data, printable_only, parts_only, show_bed, transparent_background);
if (multisample) if (multisample)
{ {
@ -4165,7 +4209,7 @@ void GLCanvas3D::_render_thumbnail_framebuffer_ext(ThumbnailData& thumbnail_data
glsafe(::glDisable(GL_MULTISAMPLE)); glsafe(::glDisable(GL_MULTISAMPLE));
} }
void GLCanvas3D::_render_thumbnail_legacy(ThumbnailData& thumbnail_data, unsigned int w, unsigned int h, bool printable_only, bool parts_only, bool transparent_background) void GLCanvas3D::_render_thumbnail_legacy(ThumbnailData& thumbnail_data, unsigned int w, unsigned int h, bool printable_only, bool parts_only, bool show_bed, bool transparent_background)
{ {
// check that thumbnail size does not exceed the default framebuffer size // check that thumbnail size does not exceed the default framebuffer size
const Size& cnv_size = get_canvas_size(); const Size& cnv_size = get_canvas_size();
@ -4182,7 +4226,7 @@ void GLCanvas3D::_render_thumbnail_legacy(ThumbnailData& thumbnail_data, unsigne
if (!thumbnail_data.is_valid()) if (!thumbnail_data.is_valid())
return; return;
_render_thumbnail_internal(thumbnail_data, printable_only, parts_only, transparent_background); _render_thumbnail_internal(thumbnail_data, printable_only, parts_only, show_bed, transparent_background);
glsafe(::glReadPixels(0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, (void*)thumbnail_data.pixels.data())); glsafe(::glReadPixels(0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, (void*)thumbnail_data.pixels.data()));
#if ENABLE_THUMBNAIL_GENERATOR_DEBUG_OUTPUT #if ENABLE_THUMBNAIL_GENERATOR_DEBUG_OUTPUT

View File

@ -571,7 +571,7 @@ public:
#if ENABLE_THUMBNAIL_GENERATOR #if ENABLE_THUMBNAIL_GENERATOR
// printable_only == false -> render also non printable volumes as grayed // printable_only == false -> render also non printable volumes as grayed
// parts_only == false -> render also sla support and pad // parts_only == false -> render also sla support and pad
void render_thumbnail(ThumbnailData& thumbnail_data, unsigned int w, unsigned int h, bool printable_only, bool parts_only, bool transparent_background); void render_thumbnail(ThumbnailData& thumbnail_data, unsigned int w, unsigned int h, bool printable_only, bool parts_only, bool show_bed, bool transparent_background);
#endif // ENABLE_THUMBNAIL_GENERATOR #endif // ENABLE_THUMBNAIL_GENERATOR
void select_all(); void select_all();
@ -725,13 +725,13 @@ private:
void _render_selection_sidebar_hints() const; void _render_selection_sidebar_hints() const;
void _render_undo_redo_stack(const bool is_undo, float pos_x); void _render_undo_redo_stack(const bool is_undo, float pos_x);
#if ENABLE_THUMBNAIL_GENERATOR #if ENABLE_THUMBNAIL_GENERATOR
void _render_thumbnail_internal(ThumbnailData& thumbnail_data, bool printable_only, bool parts_only, bool transparent_background); void _render_thumbnail_internal(ThumbnailData& thumbnail_data, bool printable_only, bool parts_only, bool show_bed, bool transparent_background);
// render thumbnail using an off-screen framebuffer // render thumbnail using an off-screen framebuffer
void _render_thumbnail_framebuffer(ThumbnailData& thumbnail_data, unsigned int w, unsigned int h, bool printable_only, bool parts_only, bool transparent_background); void _render_thumbnail_framebuffer(ThumbnailData& thumbnail_data, unsigned int w, unsigned int h, bool printable_only, bool parts_only, bool show_bed, bool transparent_background);
// render thumbnail using an off-screen framebuffer when GLEW_EXT_framebuffer_object is supported // render thumbnail using an off-screen framebuffer when GLEW_EXT_framebuffer_object is supported
void _render_thumbnail_framebuffer_ext(ThumbnailData& thumbnail_data, unsigned int w, unsigned int h, bool printable_only, bool parts_only, bool transparent_background); void _render_thumbnail_framebuffer_ext(ThumbnailData& thumbnail_data, unsigned int w, unsigned int h, bool printable_only, bool parts_only, bool show_bed, bool transparent_background);
// render thumbnail using the default framebuffer // render thumbnail using the default framebuffer
void _render_thumbnail_legacy(ThumbnailData& thumbnail_data, unsigned int w, unsigned int h, bool printable_only, bool parts_only, bool transparent_background); void _render_thumbnail_legacy(ThumbnailData& thumbnail_data, unsigned int w, unsigned int h, bool printable_only, bool parts_only, bool show_bed, bool transparent_background);
#endif // ENABLE_THUMBNAIL_GENERATOR #endif // ENABLE_THUMBNAIL_GENERATOR
void _update_volumes_hover_state() const; void _update_volumes_hover_state() const;

View File

@ -1947,8 +1947,8 @@ struct Plater::priv
bool can_reload_from_disk() const; bool can_reload_from_disk() const;
#if ENABLE_THUMBNAIL_GENERATOR #if ENABLE_THUMBNAIL_GENERATOR
void generate_thumbnail(ThumbnailData& data, unsigned int w, unsigned int h, bool printable_only, bool parts_only, bool transparent_background); void generate_thumbnail(ThumbnailData& data, unsigned int w, unsigned int h, bool printable_only, bool parts_only, bool show_bed, bool transparent_background);
void generate_thumbnails(ThumbnailsList& thumbnails, const Vec2ds& sizes, bool printable_only, bool parts_only, bool transparent_background); void generate_thumbnails(ThumbnailsList& thumbnails, const Vec2ds& sizes, bool printable_only, bool parts_only, bool show_bed, bool transparent_background);
#endif // ENABLE_THUMBNAIL_GENERATOR #endif // ENABLE_THUMBNAIL_GENERATOR
void msw_rescale_object_menu(); void msw_rescale_object_menu();
@ -2019,13 +2019,13 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame)
background_process.set_sla_print(&sla_print); background_process.set_sla_print(&sla_print);
background_process.set_gcode_preview_data(&gcode_preview_data); background_process.set_gcode_preview_data(&gcode_preview_data);
#if ENABLE_THUMBNAIL_GENERATOR #if ENABLE_THUMBNAIL_GENERATOR
background_process.set_thumbnail_cb([this](ThumbnailsList& thumbnails, const Vec2ds& sizes, bool printable_only, bool parts_only, bool transparent_background) background_process.set_thumbnail_cb([this](ThumbnailsList& thumbnails, const Vec2ds& sizes, bool printable_only, bool parts_only, bool show_bed, bool transparent_background)
{ {
std::packaged_task<void(ThumbnailsList&, const Vec2ds&, bool, bool, bool)> task([this](ThumbnailsList& thumbnails, const Vec2ds& sizes, bool printable_only, bool parts_only, bool transparent_background) { std::packaged_task<void(ThumbnailsList&, const Vec2ds&, bool, bool, bool, bool)> task([this](ThumbnailsList& thumbnails, const Vec2ds& sizes, bool printable_only, bool parts_only, bool show_bed, bool transparent_background) {
generate_thumbnails(thumbnails, sizes, printable_only, parts_only, transparent_background); generate_thumbnails(thumbnails, sizes, printable_only, parts_only, show_bed, transparent_background);
}); });
std::future<void> result = task.get_future(); std::future<void> result = task.get_future();
wxTheApp->CallAfter([&]() { task(thumbnails, sizes, printable_only, parts_only, transparent_background); }); wxTheApp->CallAfter([&]() { task(thumbnails, sizes, printable_only, parts_only, show_bed, transparent_background); });
result.wait(); result.wait();
}); });
#endif // ENABLE_THUMBNAIL_GENERATOR #endif // ENABLE_THUMBNAIL_GENERATOR
@ -3653,19 +3653,19 @@ bool Plater::priv::init_object_menu()
} }
#if ENABLE_THUMBNAIL_GENERATOR #if ENABLE_THUMBNAIL_GENERATOR
void Plater::priv::generate_thumbnail(ThumbnailData& data, unsigned int w, unsigned int h, bool printable_only, bool parts_only, bool transparent_background) void Plater::priv::generate_thumbnail(ThumbnailData& data, unsigned int w, unsigned int h, bool printable_only, bool parts_only, bool show_bed, bool transparent_background)
{ {
view3D->get_canvas3d()->render_thumbnail(data, w, h, printable_only, parts_only, transparent_background); view3D->get_canvas3d()->render_thumbnail(data, w, h, printable_only, parts_only, show_bed, transparent_background);
} }
void Plater::priv::generate_thumbnails(ThumbnailsList& thumbnails, const Vec2ds& sizes, bool printable_only, bool parts_only, bool transparent_background) void Plater::priv::generate_thumbnails(ThumbnailsList& thumbnails, const Vec2ds& sizes, bool printable_only, bool parts_only, bool show_bed, bool transparent_background)
{ {
thumbnails.clear(); thumbnails.clear();
for (const Vec2d& size : sizes) for (const Vec2d& size : sizes)
{ {
thumbnails.push_back(ThumbnailData()); thumbnails.push_back(ThumbnailData());
Point isize(size); // round to ints Point isize(size); // round to ints
generate_thumbnail(thumbnails.back(), isize.x(), isize.y(), printable_only, parts_only, transparent_background); generate_thumbnail(thumbnails.back(), isize.x(), isize.y(), printable_only, parts_only, show_bed, transparent_background);
if (!thumbnails.back().is_valid()) if (!thumbnails.back().is_valid())
thumbnails.pop_back(); thumbnails.pop_back();
} }
@ -4713,7 +4713,7 @@ void Plater::export_3mf(const boost::filesystem::path& output_path)
wxBusyCursor wait; wxBusyCursor wait;
#if ENABLE_THUMBNAIL_GENERATOR #if ENABLE_THUMBNAIL_GENERATOR
ThumbnailData thumbnail_data; ThumbnailData thumbnail_data;
p->generate_thumbnail(thumbnail_data, THUMBNAIL_SIZE_3MF.first, THUMBNAIL_SIZE_3MF.second, false, true, true); p->generate_thumbnail(thumbnail_data, THUMBNAIL_SIZE_3MF.first, THUMBNAIL_SIZE_3MF.second, false, true, true, true);
if (Slic3r::store_3mf(path_u8.c_str(), &p->model, export_config ? &cfg : nullptr, &thumbnail_data)) { if (Slic3r::store_3mf(path_u8.c_str(), &p->model, export_config ? &cfg : nullptr, &thumbnail_data)) {
#else #else
if (Slic3r::store_3mf(path_u8.c_str(), &p->model, export_config ? &cfg : nullptr)) { if (Slic3r::store_3mf(path_u8.c_str(), &p->model, export_config ? &cfg : nullptr)) {