Follow-up of d6fdf2d5c2 -> Automatic generation of missing thumbnails

This commit is contained in:
enricoturri1966 2021-07-13 11:57:19 +02:00
parent 0cdc54b710
commit 44d31f9bf2
7 changed files with 140 additions and 73 deletions

View File

@ -25,19 +25,19 @@ std::string Camera::get_type_as_string() const
{
switch (m_type)
{
case Unknown: return "unknown";
case Perspective: return "perspective";
case EType::Unknown: return "unknown";
case EType::Perspective: return "perspective";
default:
case Ortho: return "orthographic";
case EType::Ortho: return "orthographic";
};
}
void Camera::set_type(EType type)
{
if (m_type != type) {
if (m_type != type && (type == EType::Ortho || type == EType::Perspective)) {
m_type = type;
if (m_update_config_on_type_change_enabled) {
wxGetApp().app_config->set("use_perspective_camera", (m_type == Perspective) ? "1" : "0");
wxGetApp().app_config->set("use_perspective_camera", (m_type == EType::Perspective) ? "1" : "0");
wxGetApp().app_config->save();
}
}
@ -46,7 +46,7 @@ void Camera::set_type(EType type)
void Camera::select_next_type()
{
unsigned char next = (unsigned char)m_type + 1;
if (next == (unsigned char)Num_types)
if (next == (unsigned char)EType::Num_types)
next = 1;
set_type((EType)next);
@ -95,10 +95,10 @@ double Camera::get_fov() const
{
switch (m_type)
{
case Perspective:
case EType::Perspective:
return 2.0 * Geometry::rad2deg(std::atan(1.0 / m_projection_matrix.matrix()(1, 1)));
default:
case Ortho:
case EType::Ortho:
return 0.0;
};
}
@ -143,12 +143,12 @@ void Camera::apply_projection(const BoundingBoxf3& box, double near_z, double fa
switch (m_type)
{
default:
case Ortho:
case EType::Ortho:
{
m_gui_scale = 1.0;
break;
}
case Perspective:
case EType::Perspective:
{
// scale near plane to keep w and h constant on the plane at z = m_distance
const double scale = m_frustrum_zs.first / m_distance;
@ -165,12 +165,12 @@ void Camera::apply_projection(const BoundingBoxf3& box, double near_z, double fa
switch (m_type)
{
default:
case Ortho:
case EType::Ortho:
{
glsafe(::glOrtho(-w, w, -h, h, m_frustrum_zs.first, m_frustrum_zs.second));
break;
}
case Perspective:
case EType::Perspective:
{
glsafe(::glFrustum(-w, w, -h, h, m_frustrum_zs.first, m_frustrum_zs.second));
break;
@ -501,7 +501,7 @@ void Camera::set_default_orientation()
const Vec3d camera_pos = m_target + m_distance * Vec3d(sin_theta * ::sin(phi_rad), sin_theta * ::cos(phi_rad), ::cos(theta_rad));
m_view_rotation = Eigen::AngleAxisd(theta_rad, Vec3d::UnitX()) * Eigen::AngleAxisd(phi_rad, Vec3d::UnitZ());
m_view_rotation.normalize();
m_view_matrix.fromPositionOrientationScale(m_view_rotation * (- camera_pos), m_view_rotation, Vec3d(1., 1., 1.));
m_view_matrix.fromPositionOrientationScale(m_view_rotation * (-camera_pos), m_view_rotation, Vec3d::Ones());
}
Vec3d Camera::validate_target(const Vec3d& target) const

View File

@ -18,7 +18,7 @@ struct Camera
static double FrustrumZMargin;
static double MaxFovDeg;
enum EType : unsigned char
enum class EType : unsigned char
{
Unknown,
Ortho,
@ -29,7 +29,7 @@ struct Camera
bool requires_zoom_to_bed{ false };
private:
EType m_type{ Perspective };
EType m_type{ EType::Perspective };
bool m_update_config_on_type_change_enabled{ false };
Vec3d m_target{ Vec3d::Zero() };
float m_zenit{ 45.0f };
@ -54,7 +54,7 @@ public:
std::string get_type_as_string() const;
void set_type(EType type);
// valid values for type: "0" -> ortho, "1" -> perspective
void set_type(const std::string& type) { set_type((type == "1") ? Perspective : Ortho); }
void set_type(const std::string& type) { set_type((type == "1") ? EType::Perspective : EType::Ortho); }
void select_next_type();
void enable_update_config_on_type_change(bool enable) { m_update_config_on_type_change_enabled = enable; }

View File

@ -2417,7 +2417,7 @@ void GCodeViewer::render_toolpaths() const
const Camera& camera = wxGetApp().plater()->get_camera();
double zoom = camera.get_zoom();
const std::array<int, 4>& viewport = camera.get_viewport();
float near_plane_height = camera.get_type() == Camera::Perspective ? static_cast<float>(viewport[3]) / (2.0f * static_cast<float>(2.0 * std::tan(0.5 * Geometry::deg2rad(camera.get_fov())))) :
float near_plane_height = camera.get_type() == Camera::EType::Perspective ? static_cast<float>(viewport[3]) / (2.0f * static_cast<float>(2.0 * std::tan(0.5 * Geometry::deg2rad(camera.get_fov())))) :
static_cast<float>(viewport[3]) * 0.0005;
auto set_uniform_color = [](const std::array<float, 3>& color, GLShaderProgram& shader) {

View File

@ -21,7 +21,6 @@
#include "slic3r/GUI/GUI_Preview.hpp"
#include "slic3r/GUI/OpenGLManager.hpp"
#include "slic3r/GUI/3DBed.hpp"
#include "slic3r/GUI/Camera.hpp"
#include "slic3r/GUI/Plater.hpp"
#include "slic3r/GUI/MainFrame.hpp"
@ -697,7 +696,7 @@ void GLCanvas3D::Labels::render(const std::vector<const ModelInstance*>& sorted_
Vec3d screen_box_center = world_to_screen * owner.world_box.center();
float x = 0.0f;
float y = 0.0f;
if (camera.get_type() == Camera::Perspective) {
if (camera.get_type() == Camera::EType::Perspective) {
x = (0.5f + 0.001f * 0.5f * (float)screen_box_center(0)) * viewport[2];
y = (0.5f - 0.001f * 0.5f * (float)screen_box_center(1)) * viewport[3];
} else {
@ -1589,13 +1588,18 @@ void GLCanvas3D::render()
#endif // ENABLE_RENDER_STATISTICS
}
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)
void GLCanvas3D::render_thumbnail(ThumbnailData& thumbnail_data, unsigned int w, unsigned int h, const ThumbnailsParams& thumbnail_params, Camera::EType camera_type)
{
render_thumbnail(thumbnail_data, w, h, thumbnail_params, m_volumes, camera_type);
}
void GLCanvas3D::render_thumbnail(ThumbnailData& thumbnail_data, unsigned int w, unsigned int h, const ThumbnailsParams& thumbnail_params, const GLVolumeCollection& volumes, Camera::EType camera_type)
{
switch (OpenGLManager::get_framebuffers_type())
{
case OpenGLManager::EFramebufferType::Arb: { _render_thumbnail_framebuffer(thumbnail_data, w, h, printable_only, parts_only, show_bed, transparent_background); break; }
case OpenGLManager::EFramebufferType::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, show_bed, transparent_background); break; }
case OpenGLManager::EFramebufferType::Arb: { _render_thumbnail_framebuffer(thumbnail_data, w, h, thumbnail_params, volumes, camera_type); break; }
case OpenGLManager::EFramebufferType::Ext: { _render_thumbnail_framebuffer_ext(thumbnail_data, w, h, thumbnail_params, volumes, camera_type); break; }
default: { _render_thumbnail_legacy(thumbnail_data, w, h, thumbnail_params, volumes, camera_type); break; }
}
}
@ -4086,7 +4090,7 @@ static void debug_output_thumbnail(const ThumbnailData& thumbnail_data)
}
#endif // ENABLE_THUMBNAIL_GENERATOR_DEBUG_OUTPUT
void GLCanvas3D::_render_thumbnail_internal(ThumbnailData& thumbnail_data, bool printable_only, bool parts_only, bool show_bed, bool transparent_background)
void GLCanvas3D::_render_thumbnail_internal(ThumbnailData& thumbnail_data, const ThumbnailsParams& thumbnail_params, const GLVolumeCollection& volumes, Camera::EType camera_type)
{
auto is_visible = [](const GLVolume& v) {
bool ret = v.printable;
@ -4099,9 +4103,9 @@ void GLCanvas3D::_render_thumbnail_internal(ThumbnailData& thumbnail_data, bool
GLVolumePtrs visible_volumes;
for (GLVolume* vol : m_volumes.volumes) {
if (!vol->is_modifier && !vol->is_wipe_tower && (!parts_only || (vol->composite_id.volume_id >= 0))) {
if (!printable_only || is_visible(*vol))
for (GLVolume* vol : volumes.volumes) {
if (!vol->is_modifier && !vol->is_wipe_tower && (!thumbnail_params.parts_only || vol->composite_id.volume_id >= 0)) {
if (!thumbnail_params.printable_only || is_visible(*vol))
visible_volumes.emplace_back(vol);
}
}
@ -4109,37 +4113,37 @@ void GLCanvas3D::_render_thumbnail_internal(ThumbnailData& thumbnail_data, bool
if (visible_volumes.empty())
return;
BoundingBoxf3 box;
BoundingBoxf3 volumes_box;
for (const GLVolume* vol : visible_volumes) {
box.merge(vol->transformed_bounding_box());
volumes_box.merge(vol->transformed_bounding_box());
}
Camera camera;
camera.set_type(Camera::Ortho);
camera.set_type(camera_type);
camera.set_scene_box(scene_bounding_box());
camera.apply_viewport(0, 0, thumbnail_data.width, thumbnail_data.height);
camera.zoom_to_volumes(visible_volumes);
camera.zoom_to_box(volumes_box);
camera.apply_view_matrix();
double near_z = -1.0;
double far_z = -1.0;
if (show_bed) {
if (thumbnail_params.show_bed) {
// extends the near and far z of the frustrum to avoid the bed being clipped
// box in eye space
BoundingBoxf3 t_bed_box = wxGetApp().plater()->get_bed().get_bounding_box(true).transformed(camera.get_view_matrix());
near_z = -t_bed_box.max(2);
far_z = -t_bed_box.min(2);
near_z = -t_bed_box.max.z();
far_z = -t_bed_box.min.z();
}
camera.apply_projection(box, near_z, far_z);
camera.apply_projection(volumes_box, near_z, far_z);
GLShaderProgram* shader = wxGetApp().get_shader("gouraud_light");
if (shader == nullptr)
return;
if (transparent_background)
if (thumbnail_params.transparent_background)
glsafe(::glClearColor(0.0f, 0.0f, 0.0f, 0.0f));
glsafe(::glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT));
@ -4161,15 +4165,15 @@ void GLCanvas3D::_render_thumbnail_internal(ThumbnailData& thumbnail_data, bool
glsafe(::glDisable(GL_DEPTH_TEST));
if (show_bed)
if (thumbnail_params.show_bed)
_render_bed(!camera.is_looking_downward(), false);
// restore background color
if (transparent_background)
if (thumbnail_params.transparent_background)
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 show_bed, bool transparent_background)
void GLCanvas3D::_render_thumbnail_framebuffer(ThumbnailData& thumbnail_data, unsigned int w, unsigned int h, const ThumbnailsParams& thumbnail_params, const GLVolumeCollection& volumes, Camera::EType camera_type)
{
thumbnail_data.set(w, h);
if (!thumbnail_data.is_valid())
@ -4219,7 +4223,7 @@ void GLCanvas3D::_render_thumbnail_framebuffer(ThumbnailData& thumbnail_data, un
glsafe(::glDrawBuffers(1, drawBufs));
if (::glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE) {
_render_thumbnail_internal(thumbnail_data, printable_only, parts_only, show_bed, transparent_background);
_render_thumbnail_internal(thumbnail_data, thumbnail_params, volumes, camera_type);
if (multisample) {
GLuint resolve_fbo;
@ -4268,7 +4272,7 @@ void GLCanvas3D::_render_thumbnail_framebuffer(ThumbnailData& thumbnail_data, un
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 show_bed, bool transparent_background)
void GLCanvas3D::_render_thumbnail_framebuffer_ext(ThumbnailData& thumbnail_data, unsigned int w, unsigned int h, const ThumbnailsParams& thumbnail_params, const GLVolumeCollection& volumes, Camera::EType camera_type)
{
thumbnail_data.set(w, h);
if (!thumbnail_data.is_valid())
@ -4318,7 +4322,7 @@ void GLCanvas3D::_render_thumbnail_framebuffer_ext(ThumbnailData& thumbnail_data
glsafe(::glDrawBuffers(1, drawBufs));
if (::glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT) == GL_FRAMEBUFFER_COMPLETE_EXT) {
_render_thumbnail_internal(thumbnail_data, printable_only, parts_only, show_bed, transparent_background);
_render_thumbnail_internal(thumbnail_data, thumbnail_params, volumes, camera_type);
if (multisample) {
GLuint resolve_fbo;
@ -4367,7 +4371,7 @@ void GLCanvas3D::_render_thumbnail_framebuffer_ext(ThumbnailData& thumbnail_data
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 show_bed, bool transparent_background)
void GLCanvas3D::_render_thumbnail_legacy(ThumbnailData& thumbnail_data, unsigned int w, unsigned int h, const ThumbnailsParams& thumbnail_params, const GLVolumeCollection& volumes, Camera::EType camera_type)
{
// check that thumbnail size does not exceed the default framebuffer size
const Size& cnv_size = get_canvas_size();
@ -4383,7 +4387,7 @@ void GLCanvas3D::_render_thumbnail_legacy(ThumbnailData& thumbnail_data, unsigne
if (!thumbnail_data.is_valid())
return;
_render_thumbnail_internal(thumbnail_data, printable_only, parts_only, show_bed, transparent_background);
_render_thumbnail_internal(thumbnail_data, thumbnail_params, volumes, camera_type);
glsafe(::glReadPixels(0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, (void*)thumbnail_data.pixels.data()));
#if ENABLE_THUMBNAIL_GENERATOR_DEBUG_OUTPUT

View File

@ -15,6 +15,7 @@
#include "MeshUtils.hpp"
#include "libslic3r/GCode/GCodeProcessor.hpp"
#include "GCodeViewer.hpp"
#include "Camera.hpp"
#include "libslic3r/Slicing.hpp"
@ -37,9 +38,9 @@ class wxGLContext;
namespace Slic3r {
struct Camera;
class BackgroundSlicingProcess;
struct ThumbnailData;
struct ThumbnailsParams;
class ModelObject;
class ModelInstance;
class PrintObject;
@ -622,7 +623,8 @@ public:
void render();
// printable_only == false -> render also non printable volumes as grayed
// 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 show_bed, bool transparent_background);
void render_thumbnail(ThumbnailData& thumbnail_data, unsigned int w, unsigned int h, const ThumbnailsParams& thumbnail_params, Camera::EType camera_type);
void render_thumbnail(ThumbnailData& thumbnail_data, unsigned int w, unsigned int h, const ThumbnailsParams& thumbnail_params, const GLVolumeCollection& volumes, Camera::EType camera_type);
void select_all();
void deselect_all();
@ -846,13 +848,13 @@ private:
bool _render_undo_redo_stack(const bool is_undo, float pos_x);
bool _render_search_list(float pos_x);
bool _render_arrange_menu(float pos_x);
void _render_thumbnail_internal(ThumbnailData& thumbnail_data, bool printable_only, bool parts_only, bool show_bed, bool transparent_background);
void _render_thumbnail_internal(ThumbnailData& thumbnail_data, const ThumbnailsParams& thumbnail_params, const GLVolumeCollection& volumes, Camera::EType camera_type);
// 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 show_bed, bool transparent_background);
void _render_thumbnail_framebuffer(ThumbnailData& thumbnail_data, unsigned int w, unsigned int h, const ThumbnailsParams& thumbnail_params, const GLVolumeCollection& volumes, Camera::EType camera_type);
// 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 show_bed, bool transparent_background);
void _render_thumbnail_framebuffer_ext(ThumbnailData& thumbnail_data, unsigned int w, unsigned int h, const ThumbnailsParams& thumbnail_params, const GLVolumeCollection& volumes, Camera::EType camera_type);
// 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 show_bed, bool transparent_background);
void _render_thumbnail_legacy(ThumbnailData& thumbnail_data, unsigned int w, unsigned int h, const ThumbnailsParams& thumbnail_params, const GLVolumeCollection& volumes, Camera::EType camera_type);
void _update_volumes_hover_state();

View File

@ -3,7 +3,9 @@
#include <cstddef>
#include <vector>
#include <string>
#include <boost/algorithm/string.hpp>
#include <boost/log/trivial.hpp>
#include <wx/sizer.h>
#include <wx/stattext.h>
@ -11,16 +13,22 @@
#include <wx/button.h>
#include <wx/statbox.h>
#include <wx/wupdlock.h>
#include <wx/notebook.h>
#include "GUI.hpp"
#include "GUI_App.hpp"
#include "format.hpp"
#include "wxExtensions.hpp"
#include "I18N.hpp"
#include "Notebook.hpp"
#include "3DScene.hpp"
#include "GLCanvas3D.hpp"
#include "Plater.hpp"
#include "3DBed.hpp"
#include "libslic3r/Utils.hpp"
#include "libslic3r/AppConfig.hpp"
#include <wx/notebook.h>
#include "Notebook.hpp"
#include "libslic3r/Model.hpp"
#include "libslic3r/GCode/ThumbnailData.hpp"
namespace Slic3r {
namespace GUI {
@ -209,7 +217,7 @@ static void add_lock(wxImage& image)
// add_border(image);
}
static void add_def_img(wxImageList* img_list, bool is_system, std::string stl_path)
static void add_default_image(wxImageList* img_list, bool is_system, std::string stl_path)
{
wxBitmap bmp = create_scaled_bitmap("cog", nullptr, IMG_PX_CNT, true);
@ -243,11 +251,63 @@ static std::string get_dir_path(bool sys_dir)
#endif
}
static std::string name_from_path(fs::path path)
static void generate_thumbnail_from_stl(const std::string& filename)
{
std::string filename = path.filename().string();
filename.erase(filename.size() - 4); // Remove the extention suffix.
return filename;
if (!boost::algorithm::iends_with(filename, ".stl")) {
BOOST_LOG_TRIVIAL(error) << "Found invalid file type in generate_thumbnail_from_stl() [" << filename << "]";
return;
}
Model model;
try {
model = Model::read_from_file(filename);
}
catch (std::exception&) {
BOOST_LOG_TRIVIAL(error) << "Error loading model from " << filename << " in generate_thumbnail_from_stl()";
return;
}
assert(model.objects.size() == 1);
assert(model.objects[0]->volumes.size() == 1);
assert(model.objects[0]->instances.size() == 1);
model.objects[0]->center_around_origin(false);
model.objects[0]->ensure_on_bed(false);
const Vec3d bed_center_3d = wxGetApp().plater()->get_bed().get_bounding_box(false).center();
const Vec2d bed_center_2d = { bed_center_3d.x(), bed_center_3d.y()};
model.center_instances_around_point(bed_center_2d);
GLVolumeCollection volumes;
volumes.volumes.push_back(new GLVolume());
GLVolume* volume = volumes.volumes[0];
volume->indexed_vertex_array.load_mesh(model.mesh());
volume->indexed_vertex_array.finalize_geometry(true);
volume->set_instance_transformation(model.objects[0]->instances[0]->get_transformation());
volume->set_volume_transformation(model.objects[0]->volumes[0]->get_transformation());
ThumbnailData thumbnail_data;
const ThumbnailsParams thumbnail_params = { {}, false, false, false, true };
wxGetApp().plater()->canvas3D()->render_thumbnail(thumbnail_data, 256, 256, thumbnail_params, volumes, Camera::EType::Perspective);
if (thumbnail_data.width == 0 || thumbnail_data.height == 0)
return;
wxImage image(thumbnail_data.width, thumbnail_data.height);
image.InitAlpha();
for (unsigned int r = 0; r < thumbnail_data.height; ++r) {
unsigned int rr = (thumbnail_data.height - 1 - r) * thumbnail_data.width;
for (unsigned int c = 0; c < thumbnail_data.width; ++c) {
unsigned char* px = (unsigned char*)thumbnail_data.pixels.data() + 4 * (rr + c);
image.SetRGB((int)c, (int)r, px[0], px[1], px[2]);
image.SetAlpha((int)c, (int)r, px[3]);
}
}
fs::path out_path = fs::path(filename);
out_path.replace_extension("png");
image.SaveFile(out_path.string(), wxBITMAP_TYPE_PNG);
}
void GalleryDialog::load_label_icon_list()
@ -260,12 +320,14 @@ void GalleryDialog::load_label_icon_list()
for (auto& dir_entry : fs::directory_iterator(dir))
if (is_stl_file(dir_entry)) {
std::string name = name_from_path(dir_entry.path());
std::string name = dir_entry.path().stem().string();
Item item = Item{ name, sys_dir };
items.push_back(item);
}
};
wxBusyCursor busy;
std::string m_sys_dir_path, m_cust_dir_path;
std::vector<Item> list_items;
add_files_from_gallery(list_items, true, m_sys_dir_path);
@ -282,15 +344,13 @@ void GalleryDialog::load_label_icon_list()
for (const auto& item : list_items) {
std::string img_name = (item.is_system ? m_sys_dir_path : m_cust_dir_path) + item.name + ext;
std::string stl_name = (item.is_system ? m_sys_dir_path : m_cust_dir_path) + item.name + ".stl";
if (!fs::exists(img_name)) {
add_def_img(m_image_list, item.is_system, stl_name);
continue;
}
if (!fs::exists(img_name))
generate_thumbnail_from_stl(stl_name);
wxImage image;
if (!image.LoadFile(from_u8(img_name), wxBITMAP_TYPE_PNG) ||
image.GetWidth() == 0 || image.GetHeight() == 0) {
add_def_img(m_image_list, item.is_system, stl_name);
add_default_image(m_image_list, item.is_system, stl_name);
continue;
}
image.Rescale(px_cnt, px_cnt, wxIMAGE_QUALITY_BILINEAR);
@ -435,12 +495,12 @@ bool GalleryDialog::load_files(const wxArrayString& input_files)
if (!fs::exists(dest_dir / current.filename()))
fs::copy_file(current, dest_dir / current.filename());
else {
std::string filename = name_from_path(current);
std::string filename = current.stem().string();
int file_idx = 0;
for (auto& dir_entry : fs::directory_iterator(dest_dir))
if (is_stl_file(dir_entry)) {
std::string name = name_from_path(dir_entry.path());
std::string name = dir_entry.path().stem().string();
if (filename == name) {
if (file_idx == 0)
file_idx++;

View File

@ -1788,8 +1788,8 @@ struct Plater::priv
bool can_replace_with_stl() const;
bool can_split(bool to_objects) const;
void generate_thumbnail(ThumbnailData& data, unsigned int w, unsigned int h, bool printable_only, bool parts_only, bool show_bed, bool transparent_background);
ThumbnailsList generate_thumbnails(const ThumbnailsParams& params);
void generate_thumbnail(ThumbnailData& data, unsigned int w, unsigned int h, const ThumbnailsParams& thumbnail_params, Camera::EType camera_type);
ThumbnailsList generate_thumbnails(const ThumbnailsParams& params, Camera::EType camera_type);
void bring_instance_forward() const;
@ -1865,7 +1865,7 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame)
background_process.set_fff_print(&fff_print);
background_process.set_sla_print(&sla_print);
background_process.set_gcode_result(&gcode_result);
background_process.set_thumbnail_cb([this](const ThumbnailsParams& params) { return this->generate_thumbnails(params); });
background_process.set_thumbnail_cb([this](const ThumbnailsParams& params) { return this->generate_thumbnails(params, Camera::EType::Ortho); });
background_process.set_slicing_completed_event(EVT_SLICING_COMPLETED);
background_process.set_finished_event(EVT_PROCESS_COMPLETED);
background_process.set_export_began_event(EVT_EXPORT_BEGAN);
@ -4074,18 +4074,18 @@ void Plater::priv::on_3dcanvas_mouse_dragging_finished(SimpleEvent&)
}
}
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)
void Plater::priv::generate_thumbnail(ThumbnailData& data, unsigned int w, unsigned int h, const ThumbnailsParams& thumbnail_params, Camera::EType camera_type)
{
view3D->get_canvas3d()->render_thumbnail(data, w, h, printable_only, parts_only, show_bed, transparent_background);
view3D->get_canvas3d()->render_thumbnail(data, w, h, thumbnail_params, camera_type);
}
ThumbnailsList Plater::priv::generate_thumbnails(const ThumbnailsParams& params)
ThumbnailsList Plater::priv::generate_thumbnails(const ThumbnailsParams& params, Camera::EType camera_type)
{
ThumbnailsList thumbnails;
for (const Vec2d& size : params.sizes) {
thumbnails.push_back(ThumbnailData());
Point isize(size); // round to ints
generate_thumbnail(thumbnails.back(), isize.x(), isize.y(), params.printable_only, params.parts_only, params.show_bed, params.transparent_background);
generate_thumbnail(thumbnails.back(), isize.x(), isize.y(), params, camera_type);
if (!thumbnails.back().is_valid())
thumbnails.pop_back();
}
@ -5630,7 +5630,8 @@ void Plater::export_3mf(const boost::filesystem::path& output_path)
wxBusyCursor wait;
bool full_pathnames = wxGetApp().app_config->get("export_sources_full_pathnames") == "1";
ThumbnailData thumbnail_data;
p->generate_thumbnail(thumbnail_data, THUMBNAIL_SIZE_3MF.first, THUMBNAIL_SIZE_3MF.second, false, true, true, true);
ThumbnailsParams thumbnail_params = { {}, false, true, true, true };
p->generate_thumbnail(thumbnail_data, THUMBNAIL_SIZE_3MF.first, THUMBNAIL_SIZE_3MF.second, thumbnail_params, Camera::EType::Ortho);
#if ENABLE_PROJECT_DIRTY_STATE
bool ret = Slic3r::store_3mf(path_u8.c_str(), &p->model, export_config ? &cfg : nullptr, full_pathnames, &thumbnail_data);
if (ret) {