diff --git a/src/BambuStudio.cpp b/src/BambuStudio.cpp index 55b5f1519..ba8baff12 100644 --- a/src/BambuStudio.cpp +++ b/src/BambuStudio.cpp @@ -372,17 +372,18 @@ int CLI::run(int argc, char **argv) /*BOOST_LOG_TRIVIAL(info) << "begin to setup params, argc=" << argc << std::endl; for (int index=0; index < argc; index++) BOOST_LOG_TRIVIAL(info) << "index="<< index <<", arg is "<< argv[index] <setup(debug_argc, debug_argv))*/ if (!this->setup(argc, argv)) @@ -412,11 +413,13 @@ int CLI::run(int argc, char **argv) bool translate_old = false; int current_width, current_depth, current_height; - const std::vector &load_configs = m_config.option("load_settings", true)->values; + const std::vector &load_configs = m_config.option("load_settings", true)->values; //BBS: always use ForwardCompatibilitySubstitutionRule::Enable //const ForwardCompatibilitySubstitutionRule config_substitution_rule = m_config.option>("config_compatibility", true)->value; const ForwardCompatibilitySubstitutionRule config_substitution_rule = ForwardCompatibilitySubstitutionRule::Enable; - const std::vector &load_filaments = m_config.option("load_filaments", true)->values; + const std::vector &load_filaments = m_config.option("load_filaments", true)->values; + const std::vector &skip_objects = m_config.option("skip_objects", true)->values; + bool need_skip = (skip_objects.size() > 0)?true:false; if (start_gui) { BOOST_LOG_TRIVIAL(info) << "no action, start gui directly" << std::endl; @@ -1029,7 +1032,7 @@ int CLI::run(int argc, char **argv) boost::nowide::cerr << __FUNCTION__<<": can not found option " <def(). @@ -1218,11 +1223,7 @@ int CLI::run(int argc, char **argv) } ConfigOptionVectorBase* opt_vec_dst = static_cast(opt); const ConfigOptionVectorBase* opt_vec_src = static_cast(source_opt); - if (opt_key == "compatible_prints" || opt_key == "compatible_printers" || opt_key == "model_id" || opt_key == "dev_model_name" || opt_key == "filament_settings_id") - continue; - else { - opt_vec_dst->set_at(opt_vec_src, filament_index-1, 0); - } + opt_vec_dst->set_at(opt_vec_src, filament_index-1, 0); } } } @@ -1338,6 +1339,7 @@ int CLI::run(int argc, char **argv) partplate_list.reset_size(current_width, current_depth, current_height, true, true); } } + /*for (ModelObject *model_object : m_models[0].objects) for (ModelInstance *model_instance : model_object->instances) { @@ -1804,6 +1806,17 @@ int CLI::run(int argc, char **argv) if (partplate_list.get_plate_count() == 1) pre_check = false; bool finished = false; + + //skip model object + std::map skip_maps; + if (need_skip) { + BOOST_LOG_TRIVIAL(info) << boost::format("need to skip objects, size %1%:")%skip_objects.size(); + for (int index = 0; index < skip_objects.size(); index++) + { + skip_maps[skip_objects[index]] = false; + BOOST_LOG_TRIVIAL(info) << boost::format("object %1%, id %2%")%index %skip_objects[index]; + } + } /*if (opt_key == "export_gcode" && printer_technology == ptSLA) { boost::nowide::cerr << "error: cannot export G-code for an FFF configuration" << std::endl; flush_and_exit(1); @@ -1839,6 +1852,7 @@ int CLI::run(int argc, char **argv) BOOST_LOG_TRIVIAL(info) << "Skip plate " << index+1 << std::endl; continue; } + BOOST_LOG_TRIVIAL(info) << boost::format("Plate %1%: pre_check %2%, start")%(index+1)%pre_check; long long start_time = 0, end_time = 0; start_time = (long long)Slic3r::Utils::get_current_time_utc(); //get the current partplate @@ -1863,18 +1877,45 @@ int CLI::run(int argc, char **argv) % print_volume.min(2) % print_volume.max(0) % print_volume.max(1) % print_volume.max(2) << std::endl; #else BuildVolume build_volume(part_plate->get_shape(), print_height); - model.update_print_volume_state(build_volume); + //model.update_print_volume_state(build_volume); unsigned int count = model.update_print_volume_state(build_volume); if (count == 0) { BOOST_LOG_TRIVIAL(error) << "plate "<< index+1<< ": Nothing to be sliced, Either the print is empty or no object is fully inside the print volume before apply." << std::endl; flush_and_exit(CLI_NO_SUITABLE_OBJECTS); } - else { + else if ((plate_to_slice != 0) || pre_check) { long long triangle_count = 0; + int printable_instances = 0; + int skipped_count = 0; for (ModelObject* model_object : model.objects) for (ModelInstance *i : model_object->instances) { + if (skip_maps.find(i->loaded_id) != skip_maps.end()) { + skip_maps[i->loaded_id] = true; + i->printable = false; + if (i->print_volume_state == ModelInstancePVS_Inside) { + skipped_count++; + BOOST_LOG_TRIVIAL(info) << boost::format("Plate %1%: skip object %2%.")%(index+1)%i->loaded_id; + //need to regenerate the thumbnail + if (plate_data_src.size() > index) { + if (!plate_data_src[index]->thumbnail_file.empty()) { + BOOST_LOG_TRIVIAL(info) << boost::format("Plate %1%: clear loaded thumbnail %2%.")%(index+1)%plate_data_src[index]->thumbnail_file; + plate_data_src[index]->thumbnail_file.clear(); + } + if (!plate_data_src[index]->top_file.empty()) { + BOOST_LOG_TRIVIAL(info) << boost::format("Plate %1%: clear loaded top_thumbnail %2%.")%(index+1)%plate_data_src[index]->top_file; + plate_data_src[index]->top_file.clear(); + } + if (!plate_data_src[index]->pick_file.empty()) { + BOOST_LOG_TRIVIAL(info) << boost::format("Plate %1%: clear loaded pick_thumbnail %2%.")%(index+1)%plate_data_src[index]->pick_file; + plate_data_src[index]->pick_file.clear(); + } + } + } + continue; + } + if (i->print_volume_state == ModelInstancePVS_Partly_Outside) { BOOST_LOG_TRIVIAL(error) << "plate "<< index+1<< ": Found Object " << model_object->name <<" partly inside, can not be sliced." << std::endl; @@ -1896,7 +1937,15 @@ int CLI::run(int argc, char **argv) } } } + + if (i->print_volume_state == ModelInstancePVS_Inside) + printable_instances++; } + + if (printable_instances == 0) { + BOOST_LOG_TRIVIAL(error) << "plate "<< index+1<< ": Nothing to be sliced, after skipping "<{%4%, %5%, %6%}, has %7% printables") % print_volume.min(0) % print_volume.min(1) @@ -2017,7 +2066,7 @@ int CLI::run(int argc, char **argv) } } } catch (const std::exception &ex) { - BOOST_LOG_TRIVIAL(info) << "found slicing or export error for partplate "< thumbnails; + std::vector thumbnails, top_thumbnails, pick_thumbnails; std::vector plate_bboxes; PlateDataPtrs plate_data_list; partplate_list.store_to_3mf_structure(plate_data_list); @@ -2093,6 +2142,9 @@ int CLI::run(int argc, char **argv) #endif bool need_regenerate_thumbnail = oriented_or_arranged; + bool need_regenerate_top_thumbnail = oriented_or_arranged; + bool need_create_thumbnail_group = false, need_create_top_group = false; + // get type and color for platedata auto* filament_types = dynamic_cast(m_print_config.option("filament_type")); const ConfigOptionStrings* filament_color = dynamic_cast(m_print_config.option("filament_colour")); @@ -2100,6 +2152,8 @@ int CLI::run(int argc, char **argv) for (int i = 0; i < plate_data_list.size(); i++) { PlateData *plate_data = plate_data_list[i]; + bool skip_this_plate = ((plate_to_slice != 0) && (plate_to_slice != (i + 1)))?true:false; + for (auto it = plate_data->slice_filaments_info.begin(); it != plate_data->slice_filaments_info.end(); it++) { //it->filament_id = filament_id?filament_id->get_at(it->id):"unknown"; std::string display_filament_type; @@ -2113,15 +2167,41 @@ int CLI::run(int argc, char **argv) BOOST_LOG_TRIVIAL(info) << boost::format("thumbnails stage: plate %1%'s thumbnail data is invalid, check the file %2% exist or not")%(i+1) %plate_data->thumbnail_file; if (plate_data->thumbnail_file.empty() || (!boost::filesystem::exists(plate_data->thumbnail_file))) { BOOST_LOG_TRIVIAL(info) << boost::format("thumbnails stage: plate %1%'s thumbnail file also not there, need to regenerate")%(i+1); - need_regenerate_thumbnail = true; + if (!skip_this_plate) { + need_regenerate_thumbnail = true; + need_create_thumbnail_group = true; + } } else { BOOST_LOG_TRIVIAL(info) << boost::format("thumbnails stage: plate %1%'s thumbnail file exists, no need to regenerate")%(i+1); } } + else { + if (!skip_this_plate) { + need_create_thumbnail_group = true; + } + } + + if (plate_data->top_file.empty() || plate_data->pick_file.empty()) { + if (plate_data_src.size() > i) { + plate_data->top_file = plate_data_src[i]->top_file; + plate_data->pick_file = plate_data_src[i]->pick_file; + } + if (plate_data->top_file.empty()|| plate_data->pick_file.empty() + || (!boost::filesystem::exists(plate_data->top_file)) || (!boost::filesystem::exists(plate_data->pick_file))) { + BOOST_LOG_TRIVIAL(info) << boost::format("thumbnails stage: plate %1%'s top_file %2% also not there, need to regenerate")%(i+1)%plate_data->top_file; + if (!skip_this_plate) { + need_regenerate_top_thumbnail = true; + need_create_top_group = true; + } + } + else { + BOOST_LOG_TRIVIAL(info) << boost::format("thumbnails stage: plate %1%'s top_thumbnail file exists, no need to regenerate")%(i+1); + } + } } - if (need_regenerate_thumbnail) { + if (need_regenerate_thumbnail || need_regenerate_top_thumbnail) { std::vector colors; if (filament_color) { colors= filament_color->vserialize(); @@ -2199,7 +2279,7 @@ int CLI::run(int argc, char **argv) // continue; for (int instance_idx = 0; instance_idx < (int)model_object.instances.size(); ++ instance_idx) { const ModelInstance &model_instance = *model_object.instances[instance_idx]; - glvolume_collection.load_object_volume(&model_object, obj_idx, volume_idx, instance_idx, "volume", true); + glvolume_collection.load_object_volume(&model_object, obj_idx, volume_idx, instance_idx, "volume", true, false, true); //glvolume_collection.volumes.back()->geometry_id = key.geometry_id; std::string color = filament_color?filament_color->get_at(extruder_id - 1):"#00FF00"; @@ -2213,6 +2293,7 @@ int CLI::run(int argc, char **argv) new_color[2] = float(rgb_color[2]) / 255.f; new_color[3] = 1.f; glvolume_collection.volumes.back()->set_color(new_color); + glvolume_collection.volumes.back()->printable = model_instance.printable; } } } @@ -2227,39 +2308,145 @@ int CLI::run(int argc, char **argv) Slic3r::GUI::PartPlate *part_plate = partplate_list.get_plate(i); PlateData *plate_data = plate_data_list[i]; if (plate_data->plate_thumbnail.is_valid()) { - thumbnails.push_back(&plate_data->plate_thumbnail); - BOOST_LOG_TRIVIAL(info) << boost::format("plate %1% has a valid thumbnail, width %2%, height %3%, directly using it")%(i+1) %plate_data->plate_thumbnail.width %plate_data->plate_thumbnail.height; - continue; + if ((plate_to_slice != 0) && (plate_to_slice != (i + 1))) { + BOOST_LOG_TRIVIAL(info) << boost::format("Line %1%: regenerate thumbnail, reset plate %2%'s thumbnail.")%__LINE__%(i+1); + plate_data->plate_thumbnail.reset(); + } + else + BOOST_LOG_TRIVIAL(info) << boost::format("plate %1% has a valid thumbnail, width %2%, height %3%, directly using it")%(i+1) %plate_data->plate_thumbnail.width %plate_data->plate_thumbnail.height; } - BOOST_LOG_TRIVIAL(info) << boost::format("plate %1%'s thumbnail, need to regenerate")%(i+1); - ThumbnailData * thumbnail_data = new ThumbnailData(); - unsigned int thumbnail_width = 512, thumbnail_height = 512; - const ThumbnailsParams thumbnail_params = {{}, false, true, true, true, i}; - - switch (Slic3r::GUI::OpenGLManager::get_framebuffers_type()) + else if (!plate_data->thumbnail_file.empty() && (boost::filesystem::exists(plate_data->thumbnail_file))) { - case Slic3r::GUI::OpenGLManager::EFramebufferType::Arb: - { - BOOST_LOG_TRIVIAL(info) << boost::format("framebuffer_type: ARB"); - Slic3r::GUI::GLCanvas3D::render_thumbnail_framebuffer(*thumbnail_data, - thumbnail_width, thumbnail_height, thumbnail_params, - partplate_list, model.objects, glvolume_collection, colors_out, shader, Slic3r::GUI::Camera::EType::Ortho); - break; - } - case Slic3r::GUI::OpenGLManager::EFramebufferType::Ext: - { - BOOST_LOG_TRIVIAL(info) << boost::format("framebuffer_type: EXT"); - Slic3r::GUI::GLCanvas3D::render_thumbnail_framebuffer_ext(*thumbnail_data, - thumbnail_width, thumbnail_height, thumbnail_params, - partplate_list, model.objects, glvolume_collection, colors_out, shader, Slic3r::GUI::Camera::EType::Ortho); - break; - } - default: - BOOST_LOG_TRIVIAL(info) << boost::format("framebuffer_type: unknown"); - break; + if ((plate_to_slice != 0) && (plate_to_slice != (i + 1))) { + BOOST_LOG_TRIVIAL(info) << boost::format("Line %1%: regenerate thumbnail, clear plate %2%'s thumbnail file path to empty.")%__LINE__%(i+1); + plate_data->thumbnail_file.clear(); + } + else + BOOST_LOG_TRIVIAL(info) << boost::format("plate %1% has a valid thumbnail %2% extracted from 3mf, directly using it")%(i+1) %plate_data->thumbnail_file; + } + else { + ThumbnailData* thumbnail_data = &plate_data->plate_thumbnail; + + if ((plate_to_slice != 0) && (plate_to_slice != (i + 1))) { + BOOST_LOG_TRIVIAL(info) << boost::format("Line %1%: regenerate thumbnail, Skip plate %2%.")%__LINE__%(i+1); + } + else { + unsigned int thumbnail_width = 512, thumbnail_height = 512; + const ThumbnailsParams thumbnail_params = {{}, false, true, true, true, i}; + + BOOST_LOG_TRIVIAL(info) << boost::format("plate %1%'s thumbnail, need to regenerate")%(i+1); + switch (Slic3r::GUI::OpenGLManager::get_framebuffers_type()) + { + case Slic3r::GUI::OpenGLManager::EFramebufferType::Arb: + { + BOOST_LOG_TRIVIAL(info) << boost::format("framebuffer_type: ARB"); + Slic3r::GUI::GLCanvas3D::render_thumbnail_framebuffer(*thumbnail_data, + thumbnail_width, thumbnail_height, thumbnail_params, + partplate_list, model.objects, glvolume_collection, colors_out, shader, Slic3r::GUI::Camera::EType::Ortho); + break; + } + case Slic3r::GUI::OpenGLManager::EFramebufferType::Ext: + { + BOOST_LOG_TRIVIAL(info) << boost::format("framebuffer_type: EXT"); + Slic3r::GUI::GLCanvas3D::render_thumbnail_framebuffer_ext(*thumbnail_data, + thumbnail_width, thumbnail_height, thumbnail_params, + partplate_list, model.objects, glvolume_collection, colors_out, shader, Slic3r::GUI::Camera::EType::Ortho); + break; + } + default: + BOOST_LOG_TRIVIAL(info) << boost::format("framebuffer_type: unknown"); + break; + } + BOOST_LOG_TRIVIAL(info) << boost::format("plate %1%'s thumbnail,finished rendering")%(i+1); + } + } + if (need_create_thumbnail_group) { + thumbnails.push_back(&plate_data->plate_thumbnail); + BOOST_LOG_TRIVIAL(info) << boost::format("plate %1%: add thumbnail data into group")%(i+1); + } + + //top thumbnails + /*if (part_plate->top_thumbnail_data.is_valid() && part_plate->pick_thumbnail_data.is_valid()) { + if ((plate_to_slice != 0) && (plate_to_slice != (i + 1))) { + BOOST_LOG_TRIVIAL(info) << boost::format("Line %1%: regenerate thumbnail, reset plate %2%'s top/pick thumbnail.")%__LINE__%(i+1); + part_plate->top_thumbnail_data.reset(); + part_plate->pick_thumbnail_data.reset(); + plate_data->top_file.clear(); + plate_data->pick_file.clear(); + } + else { + plate_data->top_file = "valid_top"; + plate_data->pick_file = "valid_pick"; + BOOST_LOG_TRIVIAL(info) << boost::format("plate %1% has a valid top/pick thumbnail data, directly using it")%(i+1); + } + } + else*/ + if ((!plate_data->top_file.empty() && (boost::filesystem::exists(plate_data->top_file))) + &&(!plate_data->pick_file.empty() && (boost::filesystem::exists(plate_data->pick_file)))) + { + if ((plate_to_slice != 0) && (plate_to_slice != (i + 1))) { + BOOST_LOG_TRIVIAL(info) << boost::format("Line %1%: regenerate thumbnail, clear plate %2%'s top/pick thumbnail file path to empty.")%__LINE__%(i+1); + plate_data->top_file.clear(); + plate_data->pick_file.clear(); + } + else + BOOST_LOG_TRIVIAL(info) << boost::format("plate %1% has valid top/pick thumbnail extracted from 3mf, directly using it")%(i+1); + } + else{ + ThumbnailData* top_thumbnail = &part_plate->top_thumbnail_data; + ThumbnailData* picking_thumbnail = &part_plate->pick_thumbnail_data; + if ((plate_to_slice != 0) && (plate_to_slice != (i + 1))) { + BOOST_LOG_TRIVIAL(info) << boost::format("Line %1%: regenerate thumbnail, Skip plate %2%.")%__LINE__%(i+1); + part_plate->top_thumbnail_data.reset(); + part_plate->pick_thumbnail_data.reset(); + plate_data->top_file.clear(); + plate_data->pick_file.clear(); + } + else { + unsigned int thumbnail_width = 512, thumbnail_height = 512; + const ThumbnailsParams thumbnail_params = { {}, false, true, false, true, i }; + + BOOST_LOG_TRIVIAL(info) << boost::format("plate %1%'s top/pick thumbnail missed, need to regenerate")%(i+1); + + switch (Slic3r::GUI::OpenGLManager::get_framebuffers_type()) + { + case Slic3r::GUI::OpenGLManager::EFramebufferType::Arb: + { + BOOST_LOG_TRIVIAL(info) << boost::format("framebuffer_type: ARB"); + Slic3r::GUI::GLCanvas3D::render_thumbnail_framebuffer(*top_thumbnail, + thumbnail_width, thumbnail_height, thumbnail_params, + partplate_list, model.objects, glvolume_collection, colors_out, shader, Slic3r::GUI::Camera::EType::Ortho, true, false); + Slic3r::GUI::GLCanvas3D::render_thumbnail_framebuffer(*picking_thumbnail, + thumbnail_width, thumbnail_height, thumbnail_params, + partplate_list, model.objects, glvolume_collection, colors_out, shader, Slic3r::GUI::Camera::EType::Ortho, true, true); + break; + } + case Slic3r::GUI::OpenGLManager::EFramebufferType::Ext: + { + BOOST_LOG_TRIVIAL(info) << boost::format("framebuffer_type: EXT"); + Slic3r::GUI::GLCanvas3D::render_thumbnail_framebuffer_ext(*top_thumbnail, + thumbnail_width, thumbnail_height, thumbnail_params, + partplate_list, model.objects, glvolume_collection, colors_out, shader, Slic3r::GUI::Camera::EType::Ortho, true, false); + Slic3r::GUI::GLCanvas3D::render_thumbnail_framebuffer_ext(*picking_thumbnail, + thumbnail_width, thumbnail_height, thumbnail_params, + partplate_list, model.objects, glvolume_collection, colors_out, shader, Slic3r::GUI::Camera::EType::Ortho, true, true); + break; + } + default: + BOOST_LOG_TRIVIAL(info) << boost::format("framebuffer_type: unknown"); + break; + } + plate_data->top_file = "valid_top"; + plate_data->pick_file = "valid_pick"; + BOOST_LOG_TRIVIAL(info) << boost::format("plate %1%'s top_thumbnail,finished rendering")%(i+1); + } + } + + if (need_create_top_group) { + top_thumbnails.push_back(&part_plate->top_thumbnail_data); + pick_thumbnails.push_back(&part_plate->pick_thumbnail_data); + BOOST_LOG_TRIVIAL(info) << boost::format("plate %1%: add thumbnail data for top and pick into group")%(i+1); } - thumbnails.push_back(thumbnail_data); - BOOST_LOG_TRIVIAL(info) << boost::format("plate %1%'s thumbnail,finished rendering")%(i+1); } } } @@ -2267,17 +2454,42 @@ int CLI::run(int argc, char **argv) glfwTerminate(); } else { + BOOST_LOG_TRIVIAL(info) << boost::format("use previous thumbnails, no need to regenerate"); for (int i = 0; i < partplate_list.get_plate_count(); i++) { PlateData *plate_data = plate_data_list[i]; - if (plate_data->plate_thumbnail.is_valid()) { + bool skip_this_plate = ((plate_to_slice != 0) && (plate_to_slice != (i + 1)))?true:false; + Slic3r::GUI::PartPlate *part_plate = partplate_list.get_plate(i); + + if (skip_this_plate) { + BOOST_LOG_TRIVIAL(info) << boost::format("plate %1%'s all the thumbnails skipped, reset here")%(i+1); + plate_data->plate_thumbnail.reset(); + plate_data->thumbnail_file.clear(); + part_plate->top_thumbnail_data.reset(); + part_plate->pick_thumbnail_data.reset(); + plate_data->top_file.clear(); + plate_data->pick_file.clear(); + } + + if (need_create_thumbnail_group) { thumbnails.push_back(&plate_data->plate_thumbnail); - BOOST_LOG_TRIVIAL(info) << boost::format("plate %1% has a valid thumbnail data, width %2%, height %3%, directly using it")%(i+1) %plate_data->plate_thumbnail.width %plate_data->plate_thumbnail.height; + BOOST_LOG_TRIVIAL(info) << boost::format("plate %1%: add thumbnail data into group")%(i+1); + } + + if (need_create_top_group) { + top_thumbnails.push_back(&part_plate->top_thumbnail_data); + pick_thumbnails.push_back(&part_plate->pick_thumbnail_data); + BOOST_LOG_TRIVIAL(info) << boost::format("plate %1%: add thumbnail data for top and pick into group")%(i+1); } } } //generate first layer bboxes for (int i = 0; i < partplate_list.get_plate_count(); i++) { + if ((plate_to_slice != 0) && (plate_to_slice != (i + 1))) { + BOOST_LOG_TRIVIAL(info) << boost::format("Line %1%: generate bbox, Skip plate %2%.")%__LINE__%(i+1); + plate_bboxes.push_back(new PlateBBoxData()); + continue; + } Slic3r::GUI::PartPlate *part_plate = partplate_list.get_plate(i); //render calibration thumbnail if (!part_plate->get_slice_result() || !part_plate->is_slice_result_valid()) { @@ -2403,14 +2615,19 @@ int CLI::run(int argc, char **argv) #endif BOOST_LOG_TRIVIAL(info) << "will export 3mf to " << export_3mf_file << std::endl; - if (! this->export_project(&m_models[0], export_3mf_file, plate_data_list, project_presets, thumbnails, calibration_thumbnails, plate_bboxes, &m_print_config)) + if (! this->export_project(&m_models[0], export_3mf_file, plate_data_list, project_presets, thumbnails, top_thumbnails, pick_thumbnails, + calibration_thumbnails, plate_bboxes, &m_print_config)) { release_PlateData_list(plate_data_list); flush_and_exit(CLI_EXPORT_3MF_ERROR); } release_PlateData_list(plate_data_list); for (unsigned int i = 0; i < thumbnails.size(); i++) - delete thumbnails[i]; + thumbnails[i]->reset(); + for (unsigned int i = 0; i < top_thumbnails.size(); i++) + top_thumbnails[i]->reset(); + for (unsigned int i = 0; i < pick_thumbnails.size(); i++) + pick_thumbnails[i]->reset(); for (unsigned int i = 0; i < calibration_thumbnails.size(); i++) delete calibration_thumbnails[i]; @@ -2589,7 +2806,8 @@ bool CLI::export_models(IO::ExportFormat format) //BBS: add export_project function bool CLI::export_project(Model *model, std::string& path, PlateDataPtrs &partplate_data, - std::vector& project_presets, std::vector& thumbnails, std::vector& calibration_thumbnails, std::vector& plate_bboxes, const DynamicPrintConfig* config) + std::vector& project_presets, std::vector& thumbnails, std::vector& top_thumbnails, std::vector& pick_thumbnails, + std::vector& calibration_thumbnails, std::vector& plate_bboxes, const DynamicPrintConfig* config) { //const std::string path = this->output_filepath(*model, IO::TMF); bool success = false; @@ -2601,9 +2819,11 @@ bool CLI::export_project(Model *model, std::string& path, PlateDataPtrs &partpla store_params.project_presets = project_presets; store_params.config = (DynamicPrintConfig*)config; store_params.thumbnail_data = thumbnails; + store_params.top_thumbnail_data = top_thumbnails; + store_params.pick_thumbnail_data = pick_thumbnails; store_params.calibration_thumbnail_data = calibration_thumbnails; store_params.id_bboxes = plate_bboxes; - store_params.strategy = SaveStrategy::Silence|SaveStrategy::WithGcode|SaveStrategy::SplitModel; + store_params.strategy = SaveStrategy::Silence|SaveStrategy::WithGcode|SaveStrategy::SplitModel|SaveStrategy::UseLoadedId; success = Slic3r::store_bbs_3mf(store_params); diff --git a/src/BambuStudio.hpp b/src/BambuStudio.hpp index f5c5e6b73..c7fc5ae3e 100644 --- a/src/BambuStudio.hpp +++ b/src/BambuStudio.hpp @@ -39,7 +39,8 @@ private: bool export_models(IO::ExportFormat format); //BBS: add export_project function bool export_project(Model *model, std::string& path, PlateDataPtrs &partplate_data, std::vector& project_presets, - std::vector& thumbnails, std::vector& calibration_thumbnails, + std::vector& thumbnails, std::vector& top_thumbnails, std::vector& pick_thumbnails, + std::vector& calibration_thumbnails, std::vector& plate_bboxes, const DynamicPrintConfig* config); bool has_print_action() const { return m_config.opt_bool("export_gcode") || m_config.opt_bool("export_sla"); } diff --git a/src/libslic3r/Format/bbs_3mf.cpp b/src/libslic3r/Format/bbs_3mf.cpp index 8cc21b43e..769abf820 100644 --- a/src/libslic3r/Format/bbs_3mf.cpp +++ b/src/libslic3r/Format/bbs_3mf.cpp @@ -250,11 +250,13 @@ static constexpr const char* BED_TYPE_ATTR = "bed_type"; static constexpr const char* PRINT_SEQUENCE_ATTR = "print_sequence"; static constexpr const char* GCODE_FILE_ATTR = "gcode_file"; static constexpr const char* THUMBNAIL_FILE_ATTR = "thumbnail_file"; +static constexpr const char* TOP_FILE_ATTR = "top_file"; +static constexpr const char* PICK_FILE_ATTR = "pick_file"; static constexpr const char* PATTERN_FILE_ATTR = "pattern_file"; static constexpr const char* PATTERN_BBOX_FILE_ATTR = "pattern_bbox_file"; static constexpr const char* OBJECT_ID_ATTR = "object_id"; static constexpr const char* INSTANCEID_ATTR = "instance_id"; -static constexpr const char* ARRANGE_ORDER_ATTR = "arrange_order"; +static constexpr const char* IDENTIFYID_ATTR = "identify_id"; static constexpr const char* PLATERID_ATTR = "plater_id"; static constexpr const char* PLATE_IDX_ATTR = "index"; static constexpr const char* SLICE_PREDICTION_ATTR = "prediction"; @@ -614,7 +616,7 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) { int object_id; int instance_id; - int arrange_order; + int identify_id; }; struct Instance @@ -859,7 +861,7 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) std::string m_Profile_description; std::string m_profile_user_id; std::string m_profile_user_name; - + XML_Parser m_xml_parser; // Error code returned by the application side of the parser. In that case the expat may not reliably deliver the error state // after returning from XML_Parse() function, thus we keep the error state here. @@ -1139,7 +1141,7 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) m_plater_data.clear(); m_curr_instance.object_id = -1; m_curr_instance.instance_id = -1; - m_curr_instance.arrange_order = 0; + m_curr_instance.identify_id = 0; clear_errors(); // restore @@ -1794,12 +1796,15 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) plate_data_list[it->first-1]->slice_filaments_info = it->second->slice_filaments_info; plate_data_list[it->first-1]->warnings = it->second->warnings; plate_data_list[it->first-1]->thumbnail_file = (m_load_restore || it->second->thumbnail_file.empty()) ? it->second->thumbnail_file : m_backup_path + "/" + it->second->thumbnail_file; - plate_data_list[it->first-1]->pattern_file = (m_load_restore || it->second->pattern_file.empty()) ? it->second->pattern_file : m_backup_path + "/" + it->second->pattern_file; + //plate_data_list[it->first-1]->pattern_file = (m_load_restore || it->second->pattern_file.empty()) ? it->second->pattern_file : m_backup_path + "/" + it->second->pattern_file; + plate_data_list[it->first-1]->top_file = (m_load_restore || it->second->top_file.empty()) ? it->second->top_file : m_backup_path + "/" + it->second->top_file; + plate_data_list[it->first-1]->pick_file = (m_load_restore || it->second->pick_file.empty()) ? it->second->pick_file : m_backup_path + "/" + it->second->pick_file; plate_data_list[it->first-1]->pattern_bbox_file = (m_load_restore || it->second->pattern_bbox_file.empty()) ? it->second->pattern_bbox_file : m_backup_path + "/" + it->second->pattern_bbox_file; plate_data_list[it->first-1]->config = it->second->config; current_plate_data = plate_data_list[it->first - 1]; BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ":" << __LINE__ << boost::format(", plate %1%, thumbnail_file=%2%")%it->first %plate_data_list[it->first-1]->thumbnail_file; + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ":" << __LINE__ << boost::format(", top_thumbnail_file=%1%, pick_thumbnail_file=%2%")%plate_data_list[it->first-1]->top_file %plate_data_list[it->first-1]->pick_file; it++; //update the arrange order @@ -1835,7 +1840,7 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) continue; } ModelInstance* inst = obj->instances[inst_index]; - inst->arrange_order = map_it->second.second; + inst->loaded_id = map_it->second.second; map_it++; } } @@ -3525,10 +3530,18 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) { m_curr_plater->thumbnail_file = value; } - else if (key == PATTERN_FILE_ATTR) + else if (key == TOP_FILE_ATTR) { - m_curr_plater->pattern_file = value; + m_curr_plater->top_file = value; } + else if (key == PICK_FILE_ATTR) + { + m_curr_plater->pick_file = value; + } + //else if (key == PATTERN_FILE_ATTR) + //{ + // m_curr_plater->pattern_file = value; + //} else if (key == PATTERN_BBOX_FILE_ATTR) { m_curr_plater->pattern_bbox_file = value; @@ -3537,9 +3550,9 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) { m_curr_instance.instance_id = atoi(value.c_str()); } - else if (key == ARRANGE_ORDER_ATTR) + else if (key == IDENTIFYID_ATTR) { - m_curr_instance.arrange_order = atoi(value.c_str()); + m_curr_instance.identify_id = atoi(value.c_str()); } else if (key == OBJECT_ID_ATTR) { @@ -3694,13 +3707,13 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) //add_error("invalid object id/instance id"); //skip this instance m_curr_instance.object_id = m_curr_instance.instance_id = -1; - m_curr_instance.arrange_order = 0; + m_curr_instance.identify_id = 0; return true; } - m_curr_plater->obj_inst_map.emplace(m_curr_instance.object_id, std::make_pair(m_curr_instance.instance_id, m_curr_instance.arrange_order)); + m_curr_plater->obj_inst_map.emplace(m_curr_instance.object_id, std::make_pair(m_curr_instance.instance_id, m_curr_instance.identify_id)); m_curr_instance.object_id = m_curr_instance.instance_id = -1; - m_curr_instance.arrange_order = 0; + m_curr_instance.identify_id = 0; return true; } @@ -4744,6 +4757,7 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) bool m_save_gcode { false }; // whether to save gcode for normal save bool m_skip_model { false }; // skip model when exporting .gcode.3mf bool m_skip_auxiliary { false }; // skip normal axuiliary files + bool m_use_loaded_id { false }; // whether to use loaded id for identify_id public: //BBS: add plate data related logic @@ -4762,6 +4776,8 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) std::vector& project_presets, const DynamicPrintConfig* config, const std::vector& thumbnail_data, + const std::vector& top_thumbnail_data, + const std::vector& pick_thumbnail_data, Export3mfProgressFn proFn, const std::vector& calibration_data, const std::vector& id_bboxes, @@ -4772,7 +4788,7 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) bool _add_content_types_file_to_archive(mz_zip_archive& archive); - bool _add_thumbnail_file_to_archive(mz_zip_archive& archive, const ThumbnailData& thumbnail_data, int index); + bool _add_thumbnail_file_to_archive(mz_zip_archive& archive, const ThumbnailData& thumbnail_data, const char* local_path, int index); bool _add_calibration_file_to_archive(mz_zip_archive& archive, const ThumbnailData& thumbnail_data, int index); bool _add_bbox_file_to_archive(mz_zip_archive& archive, const PlateBBoxData& id_bboxes, int index); bool _add_relationships_file_to_archive(mz_zip_archive & archive, @@ -4795,7 +4811,7 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) bool _add_project_config_file_to_archive(mz_zip_archive& archive, const DynamicPrintConfig &config, Model& model); //BBS: add project embedded preset files bool _add_project_embedded_presets_to_archive(mz_zip_archive& archive, Model& model, std::vector project_presets); - bool _add_model_config_file_to_archive(mz_zip_archive& archive, const Model& model, PlateDataPtrs& plate_data_list, const IdToObjectDataMap &objects_data, int export_plate_idx = -1, bool save_gcode = true); + bool _add_model_config_file_to_archive(mz_zip_archive& archive, const Model& model, PlateDataPtrs& plate_data_list, const IdToObjectDataMap &objects_data, int export_plate_idx = -1, bool save_gcode = true, bool use_loaded_id = false); bool _add_slice_info_config_file_to_archive(mz_zip_archive& archive, const Model& model, PlateDataPtrs& plate_data_list); bool _add_gcode_file_to_archive(mz_zip_archive& archive, const Model& model, PlateDataPtrs& plate_data_list, Export3mfProgressFn proFn = nullptr); bool _add_custom_gcode_per_print_z_file_to_archive(mz_zip_archive& archive, Model& model, const DynamicPrintConfig* config); @@ -4829,12 +4845,15 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) m_skip_model = store_params.strategy & SaveStrategy::SkipModel; m_skip_auxiliary = store_params.strategy & SaveStrategy::SkipAuxiliary; + m_use_loaded_id = store_params.strategy & SaveStrategy::UseLoadedId; + boost::system::error_code ec; std::string filename = std::string(store_params.path); boost::filesystem::remove(filename + ".tmp", ec); bool result = _save_model_to_file(filename + ".tmp", *store_params.model, store_params.plate_data_list, store_params.project_presets, store_params.config, - store_params.thumbnail_data, store_params.proFn, store_params.calibration_thumbnail_data, store_params.id_bboxes, store_params.project, store_params.export_plate_idx); + store_params.thumbnail_data, store_params.top_thumbnail_data, store_params.pick_thumbnail_data, store_params.proFn, + store_params.calibration_thumbnail_data, store_params.id_bboxes, store_params.project, store_params.export_plate_idx); if (result) { boost::filesystem::rename(filename + ".tmp", filename, ec); if (ec) { @@ -4902,6 +4921,8 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) std::vector& project_presets, const DynamicPrintConfig* config, const std::vector& thumbnail_data, + const std::vector& top_thumbnail_data, + const std::vector& pick_thumbnail_data, Export3mfProgressFn proFn, const std::vector& calibration_data, const std::vector& id_bboxes, @@ -4916,7 +4937,8 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) bool cb_cancel = false; //BBS progress point - BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ":" <<__LINE__ << boost::format(",before open zip writer, m_skip_static %1%, m_save_gcode %2%\n")%m_skip_static %m_save_gcode; + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ":" <<__LINE__ << + boost::format(",before open zip writer, m_skip_static %1%, m_save_gcode %2%, m_use_loaded_id %3%")%m_skip_static %m_save_gcode %m_use_loaded_id; if (proFn) { proFn(EXPORT_STAGE_OPEN_3MF, 0, 1, cb_cancel); if (cb_cancel) @@ -4955,43 +4977,115 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) } //BBS progress point - BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ":" << __LINE__ << boost::format(",before add thumbnails, count %1%\n") % thumbnail_data.size(); + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ":" << __LINE__ << boost::format(",before add thumbnails, count %1%") % thumbnail_data.size(); + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ":" <<__LINE__ << boost::format(",top&&pick thumbnails, count %1%")%top_thumbnail_data.size(); //BBS: add thumbnail for each plate - if (!m_skip_static && thumbnail_data.size() > 0) { - // Adds the file Metadata/thumbnail.png. + if (!m_skip_static) { + std::vector thumbnail_status(plate_data_list.size(), false); + std::vector top_thumbnail_status(plate_data_list.size(), false); + std::vector pick_thumbnail_status(plate_data_list.size(), false); + + if ((thumbnail_data.size() > 0)&&(thumbnail_data.size() > plate_data_list.size())) { + BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << ":" << __LINE__ << boost::format(", thumbnail_data size %1% > plate count %2%") + % thumbnail_data.size() %plate_data_list.size(); + return false; + } + if ((top_thumbnail_data.size() > 0)&&(top_thumbnail_data.size() > plate_data_list.size())) { + BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << ":" << __LINE__ << boost::format(", top_thumbnail_data size %1% > plate count %2%") + % top_thumbnail_data.size() %plate_data_list.size(); + return false; + } + if ((pick_thumbnail_data.size() > 0)&&(pick_thumbnail_data.size() > plate_data_list.size())) { + BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << ":" << __LINE__ << boost::format(", pick_thumbnail_data size %1% > plate count %2%") + % pick_thumbnail_data.size() %plate_data_list.size(); + return false; + } + if (top_thumbnail_data.size() != pick_thumbnail_data.size()) { + BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << ":" << __LINE__ << boost::format(", top_thumbnail_data size %1% != pick_thumbnail_data size %2%") + % top_thumbnail_data.size() %pick_thumbnail_data.size(); + return false; + } + + if (proFn) { + proFn(EXPORT_STAGE_ADD_THUMBNAILS, 0, plate_data_list.size(), cb_cancel); + if (cb_cancel) + return false; + } + for (unsigned int index = 0; index < thumbnail_data.size(); index++) { - if (proFn) { - proFn(EXPORT_STAGE_ADD_THUMBNAILS, index, thumbnail_data.size(), cb_cancel); - if (cb_cancel) - return false; - } - if (thumbnail_data[index]->is_valid()) { - if (!_add_thumbnail_file_to_archive(archive, *thumbnail_data[index], index)) { + if (!_add_thumbnail_file_to_archive(archive, *thumbnail_data[index], "Metadata/plate", index)) { return false; } + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ":" <<__LINE__ << boost::format(",add thumbnail %1%'s data into 3mf")%(index+1); + thumbnail_status[index] = true; } } - } - else if (!m_skip_static && plate_data_list.size() > 0) { + + // Adds the file Metadata/top_i.png and Metadata/pick_i.png + for (unsigned int index = 0; index < top_thumbnail_data.size(); index++) + { + if (top_thumbnail_data[index]->is_valid()) + { + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ":" <<__LINE__ << boost::format(",add top thumbnail %1%'s data into 3mf")%(index+1); + if (!_add_thumbnail_file_to_archive(archive, *top_thumbnail_data[index], "Metadata/top", index)) { + return false; + } + top_thumbnail_status[index] = true; + } + + if (pick_thumbnail_data[index]->is_valid()) + { + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ":" <<__LINE__ << boost::format(",add pick thumbnail %1%'s data into 3mf")%(index+1); + if (!_add_thumbnail_file_to_archive(archive, *pick_thumbnail_data[index], "Metadata/pick", index)) { + return false; + } + pick_thumbnail_status[index] = true; + } + } + for (int i = 0; i < plate_data_list.size(); i++) { PlateData *plate_data = plate_data_list[i]; - if (proFn) { - proFn(EXPORT_STAGE_ADD_THUMBNAILS, i, plate_data_list.size(), cb_cancel); - if (cb_cancel) - return false; - } - if (!plate_data->thumbnail_file.empty() && (boost::filesystem::exists(plate_data->thumbnail_file))){ + + if (!thumbnail_status[i] && !plate_data->thumbnail_file.empty() && (boost::filesystem::exists(plate_data->thumbnail_file))){ std::string dst_in_3mf = (boost::format("Metadata/plate_%1%.png") % (i + 1)).str(); + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ":" <<__LINE__ << boost::format(", add thumbnail %1% from file %2%") % (i+1) %plate_data->thumbnail_file; if (!_add_file_to_archive(archive, dst_in_3mf, plate_data->thumbnail_file)) { BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << ":" << __LINE__ << boost::format(", add thumbnail %1% from file %2% failed\n") % (i+1) %plate_data->thumbnail_file; return false; } } + + if (!top_thumbnail_status[i] && !plate_data->top_file.empty() && (boost::filesystem::exists(plate_data->top_file))){ + std::string dst_in_3mf = (boost::format("Metadata/top_%1%.png") % (i + 1)).str(); + + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ":" <<__LINE__ << boost::format(", add top thumbnail %1% from file %2%") % (i+1) %plate_data->top_file; + if (!_add_file_to_archive(archive, dst_in_3mf, plate_data->top_file)) { + BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << ":" << __LINE__ << boost::format(", add top thumbnail %1% failed") % (i+1); + return false; + } + top_thumbnail_status[i] = true; + } + + if (!pick_thumbnail_status[i] && !plate_data->pick_file.empty() && (boost::filesystem::exists(plate_data->pick_file))){ + std::string dst_in_3mf = (boost::format("Metadata/pick_%1%.png") % (i + 1)).str(); + + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ":" <<__LINE__ << boost::format(", add pick thumbnail %1% from file %2%") % (i+1) %plate_data->pick_file; + if (!_add_file_to_archive(archive, dst_in_3mf, plate_data->pick_file)) { + BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << ":" << __LINE__ << boost::format(", add pick thumbnail %1% failed") % (i+1); + return false; + } + pick_thumbnail_status[i] = true; + } + } + if (proFn) { + proFn(EXPORT_STAGE_ADD_THUMBNAILS, plate_data_list.size(), plate_data_list.size(), cb_cancel); + if (cb_cancel) + return false; } } @@ -5183,7 +5277,7 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) // This file contains all the attributes of all ModelObjects and their ModelVolumes (names, parameter overrides). // As there is just a single Indexed Triangle Set data stored per ModelObject, offsets of volumes into their respective Indexed Triangle Set data // is stored here as well. - if (!_add_model_config_file_to_archive(archive, model, plate_data_list, objects_data, export_plate_idx, m_save_gcode)) { + if (!_add_model_config_file_to_archive(archive, model, plate_data_list, objects_data, export_plate_idx, m_save_gcode, m_use_loaded_id)) { BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << ":" << __LINE__ << boost::format(", _add_model_config_file_to_archive failed\n"); return false; } @@ -5295,14 +5389,14 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) return true; } - bool _BBS_3MF_Exporter::_add_thumbnail_file_to_archive(mz_zip_archive& archive, const ThumbnailData& thumbnail_data, int index) + bool _BBS_3MF_Exporter::_add_thumbnail_file_to_archive(mz_zip_archive& archive, const ThumbnailData& thumbnail_data, const char* local_path, int index) { bool res = false; size_t png_size = 0; void* png_data = tdefl_write_image_to_png_file_in_memory_ex((const void*)thumbnail_data.pixels.data(), thumbnail_data.width, thumbnail_data.height, 4, &png_size, MZ_DEFAULT_COMPRESSION, 1); if (png_data != nullptr) { - std::string thumbnail_name = (boost::format("Metadata/plate_%1%.png") % (index + 1)).str(); + std::string thumbnail_name = (boost::format("%1%_%2%.png")%local_path % (index + 1)).str(); res = mz_zip_writer_add_mem(&archive, thumbnail_name.c_str(), (const void*)png_data, png_size, MZ_NO_COMPRESSION); mz_free(png_data); } @@ -5319,7 +5413,7 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) { bool res = false; - size_t png_size = 0; + /*size_t png_size = 0; void* png_data = tdefl_write_image_to_png_file_in_memory_ex((const void*)thumbnail_data.pixels.data(), thumbnail_data.width, thumbnail_data.height, 4, &png_size, MZ_DEFAULT_COMPRESSION, 1); if (png_data != nullptr) { std::string thumbnail_name = (boost::format(PATTERN_FILE_FORMAT) % (index + 1)).str(); @@ -5330,7 +5424,7 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) if (!res) { add_error("Unable to add thumbnail file to archive"); BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << ":" << __LINE__ << boost::format(", Unable to add thumbnail file to archive\n"); - } + }*/ return res; } @@ -6332,7 +6426,7 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) return true; } - bool _BBS_3MF_Exporter::_add_model_config_file_to_archive(mz_zip_archive& archive, const Model& model, PlateDataPtrs& plate_data_list, const IdToObjectDataMap &objects_data, int export_plate_idx, bool save_gcode) + bool _BBS_3MF_Exporter::_add_model_config_file_to_archive(mz_zip_archive& archive, const Model& model, PlateDataPtrs& plate_data_list, const IdToObjectDataMap &objects_data, int export_plate_idx, bool save_gcode, bool use_loaded_id) { std::stringstream stream; std::map shared_meshes; @@ -6493,10 +6587,20 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) stream << " <" << METADATA_TAG << " " << KEY_ATTR << "=\"" << THUMBNAIL_FILE_ATTR << "\" " << VALUE_ATTR << "=\"" << std::boolalpha << thumbnail_file_in_3mf << "\"/>\n"; } - if (!plate_data->pattern_file.empty()) { + if (!plate_data->top_file.empty()) { + std::string top_file_in_3mf = (boost::format(TOP_FILE_FORMAT) % (plate_data->plate_index + 1)).str(); + stream << " <" << METADATA_TAG << " " << KEY_ATTR << "=\"" << TOP_FILE_ATTR << "\" " << VALUE_ATTR << "=\"" << std::boolalpha << top_file_in_3mf << "\"/>\n"; + } + + if (!plate_data->pick_file.empty()) { + std::string pick_file_in_3mf = (boost::format(PICK_FILE_FORMAT) % (plate_data->plate_index + 1)).str(); + stream << " <" << METADATA_TAG << " " << KEY_ATTR << "=\"" << PICK_FILE_ATTR << "\" " << VALUE_ATTR << "=\"" << std::boolalpha << pick_file_in_3mf << "\"/>\n"; + } + + /*if (!plate_data->pattern_file.empty()) { std::string pattern_file_in_3mf = (boost::format(PATTERN_FILE_FORMAT) % (plate_data->plate_index + 1)).str(); stream << " <" << METADATA_TAG << " " << KEY_ATTR << "=\"" << PATTERN_FILE_ATTR << "\" " << VALUE_ATTR << "=\"" << std::boolalpha << pattern_file_in_3mf << "\"/>\n"; - } + }*/ if (!plate_data->pattern_bbox_file.empty()) { std::string pattern_bbox_file_in_3mf = (boost::format(PATTERN_CONFIG_FILE_FORMAT) % (plate_data->plate_index + 1)).str(); stream << " <" << METADATA_TAG << " " << KEY_ATTR << "=\"" << PATTERN_BBOX_FILE_ATTR << "\" " << VALUE_ATTR << "=\"" << std::boolalpha << pattern_bbox_file_in_3mf << "\"/>\n"; @@ -6509,7 +6613,7 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) stream << " <" << INSTANCE_TAG << ">\n"; int obj_id = plate_data->objects_and_instances[j].first; int inst_id = plate_data->objects_and_instances[j].second; - int arrange_o = 0; + int identify_id = 0; ModelObject* obj = NULL; ModelInstance* inst = NULL; if (obj_id >= model.objects.size()) { @@ -6523,7 +6627,10 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) } else if (obj){ inst = obj->instances[inst_id]; - arrange_o = inst->arrange_order; + if (use_loaded_id && (inst->loaded_id > 0)) + identify_id = inst->loaded_id; + else + identify_id = inst->id().id; } if (m_skip_static && obj) { obj_id = obj->get_backup_id(); @@ -6534,7 +6641,7 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) stream << " <" << METADATA_TAG << " " << KEY_ATTR << "=\"" << OBJECT_ID_ATTR << "\" " << VALUE_ATTR << "=\"" << obj_id << "\"/>\n"; stream << " <" << METADATA_TAG << " " << KEY_ATTR << "=\"" << INSTANCEID_ATTR << "\" " << VALUE_ATTR << "=\"" << inst_id << "\"/>\n"; - stream << " <" << METADATA_TAG << " " << KEY_ATTR << "=\"" << ARRANGE_ORDER_ATTR << "\" " << VALUE_ATTR << "=\"" << arrange_o << "\"/>\n"; + stream << " <" << METADATA_TAG << " " << KEY_ATTR << "=\"" << IDENTIFYID_ATTR << "\" " << VALUE_ATTR << "=\"" << identify_id << "\"/>\n"; stream << " \n"; } } diff --git a/src/libslic3r/Format/bbs_3mf.hpp b/src/libslic3r/Format/bbs_3mf.hpp index e0914f677..4989b5a89 100644 --- a/src/libslic3r/Format/bbs_3mf.hpp +++ b/src/libslic3r/Format/bbs_3mf.hpp @@ -16,7 +16,9 @@ struct ThumbnailData; #define GCODE_FILE_FORMAT "Metadata/plate_%1%.gcode" #define THUMBNAIL_FILE_FORMAT "Metadata/plate_%1%.png" -#define PATTERN_FILE_FORMAT "Metadata/plate_%1%_pattern_layer_0.png" +#define TOP_FILE_FORMAT "Metadata/top_%1%.png" +#define PICK_FILE_FORMAT "Metadata/pick_%1%.png" +//#define PATTERN_FILE_FORMAT "Metadata/plate_%1%_pattern_layer_0.png" #define PATTERN_CONFIG_FILE_FORMAT "Metadata/plate_%1%.json" #define EMBEDDED_PRINT_FILE_FORMAT "Metadata/process_settings_%1%.config" #define EMBEDDED_FILAMENT_FILE_FORMAT "Metadata/filament_settings_%1%.config" @@ -65,8 +67,10 @@ struct PlateData std::string gcode_file_md5; std::string thumbnail_file; ThumbnailData plate_thumbnail; - ThumbnailData pattern_thumbnail; - std::string pattern_file; + std::string top_file; + std::string pick_file; + //ThumbnailData pattern_thumbnail; + //std::string pattern_file; std::string pattern_bbox_file; std::string gcode_prediction; std::string gcode_weight; @@ -102,6 +106,7 @@ enum class SaveStrategy SkipModel = 1 << 7, WithSliceInfo = 1 << 8, SkipAuxiliary = 1 << 9, + UseLoadedId = 1 << 10, SplitModel = 0x1000 | ProductionExt, Encrypted = SecureContentExt | SplitModel, @@ -194,6 +199,8 @@ struct StoreParams std::vector project_presets; DynamicPrintConfig* config; std::vector thumbnail_data; + std::vector top_thumbnail_data; + std::vector pick_thumbnail_data; std::vector calibration_thumbnail_data; SaveStrategy strategy = SaveStrategy::Zip64; Export3mfProgressFn proFn = nullptr; diff --git a/src/libslic3r/Model.hpp b/src/libslic3r/Model.hpp index 0560840a0..e260c200f 100644 --- a/src/libslic3r/Model.hpp +++ b/src/libslic3r/Model.hpp @@ -1070,6 +1070,7 @@ public: // Whether or not this instance is printable bool printable; int arrange_order = 0; // BBS + size_t loaded_id = 0; // BBS ModelObject* get_object() const { return this->object; } @@ -1262,7 +1263,7 @@ class ModelProfileInfo { public: std::string ProfileTile; - std::string ProfileCover; + std::string ProfileCover; std::string ProfileDescription; std::string ProfileUserId; std::string ProfileUserName; diff --git a/src/libslic3r/Print.cpp b/src/libslic3r/Print.cpp index 394e73574..daf6b08e6 100644 --- a/src/libslic3r/Print.cpp +++ b/src/libslic3r/Print.cpp @@ -1442,14 +1442,20 @@ void Print::process(bool use_cache) for (int index = 0; index < object_count; index++) { PrintObject *obj = m_objects[index]; + bool found_shared = false; if (need_slicing_objects.find(obj) == need_slicing_objects.end()) { for (PrintObject *slicing_obj : need_slicing_objects) { if (is_print_object_the_same(obj, slicing_obj)) { obj->set_shared_object(slicing_obj); + found_shared = true; break; } } + if (!found_shared) { + BOOST_LOG_TRIVIAL(error) << boost::format("Also can not find the shared object, identify_id %1%")%obj->model_object()->instances[0]->loaded_id; + throw Slic3r::SlicingError("Can not find the cached data."); + } } } } @@ -2207,7 +2213,7 @@ std::string PrintStatistics::finalize_output_path(const std::string &path_in) co #define JSON_EXPOLYGON "expolygon" #define JSON_ARC_FITTING "arc_fitting" #define JSON_OBJECT_NAME "name" -#define JSON_ARRANGE_ORDER "arrange_order" +#define JSON_IDENTIFY_ID "identify_id" #define JSON_LAYERS "layers" @@ -2943,18 +2949,19 @@ int Print::export_cached_data(const std::string& directory, bool with_space) BOOST_LOG_TRIVIAL(info) << boost::format("shared object %1%, skip directly")%model_obj->name; continue; } - BOOST_LOG_TRIVIAL(info) << boost::format("begin to dump object %1%")%model_obj->name; const PrintInstance &print_instance = obj->instances()[0]; const ModelInstance *model_instance = print_instance.model_instance; - int arrange_order = model_instance->arrange_order; - std::string file_name = directory +"/obj_"+std::to_string(arrange_order)+".json"; + size_t identify_id = (model_instance->loaded_id > 0)?model_instance->loaded_id: model_instance->id().id; + std::string file_name = directory +"/obj_"+std::to_string(identify_id)+".json"; + + BOOST_LOG_TRIVIAL(info) << boost::format("begin to dump object %1%, identify_id %2% to %3%")%model_obj->name %identify_id %file_name; try { json root_json, layers_json = json::array(), support_layers_json = json::array(); root_json[JSON_OBJECT_NAME] = model_obj->name; - root_json[JSON_ARRANGE_ORDER] = arrange_order; + root_json[JSON_IDENTIFY_ID] = identify_id; //export the layers std::vector layers_json_vector(obj->layer_count()); @@ -3139,12 +3146,14 @@ int Print::load_cached_data(const std::string& directory) obj->clear_layers(); obj->clear_support_layers(); - int arrange_order = model_instance->arrange_order; - if (arrange_order <= 0) { - BOOST_LOG_TRIVIAL(info) << __FUNCTION__<< boost::format(": object %1% has invalid arrange_order %2%, can not load cached_data")%model_obj->name %arrange_order; - continue; + int identify_id = model_instance->loaded_id; + if (identify_id <= 0) { + //for old 3mf + identify_id = model_instance->id().id; + BOOST_LOG_TRIVIAL(info) << __FUNCTION__<< boost::format(": object %1%'s loaded_id is 0, need to use the instance_id %2%")%model_obj->name %identify_id; + //continue; } - std::string file_name = directory +"/obj_"+std::to_string(arrange_order)+".json"; + std::string file_name = directory +"/obj_"+std::to_string(identify_id)+".json"; if (!fs::exists(file_name)) { BOOST_LOG_TRIVIAL(info) << __FUNCTION__<> root_json; std::string name = root_json.at(JSON_OBJECT_NAME); - int order = root_json.at(JSON_ARRANGE_ORDER); + int identify_id = root_json.at(JSON_IDENTIFY_ID); int layer_count = 0, support_layer_count = 0; layer_count = root_json[JSON_LAYERS].size(); support_layer_count = root_json[JSON_SUPPORT_LAYERS].size(); - BOOST_LOG_TRIVIAL(info) << __FUNCTION__<cli_params = "\"filament1.json;filament2.json;...\""; def->set_default_value(new ConfigOptionStrings()); + def = this->add("skip_objects", coStrings); + def->label = L("Skip Objects"); + def->tooltip = L("Skip some objects in this print"); + def->cli_params = "\"3;5;10;77\""; + def->set_default_value(new ConfigOptionInts()); + /*def = this->add("output", coString); def->label = L("Output File"); def->tooltip = L("The file where the output will be written (if not specified, it will be based on the input file)."); diff --git a/src/libslic3r/Utils.hpp b/src/libslic3r/Utils.hpp index 71dacf6d2..b04628e65 100644 --- a/src/libslic3r/Utils.hpp +++ b/src/libslic3r/Utils.hpp @@ -47,6 +47,7 @@ #define CLI_IMPORT_CACHE_LOAD_FAILED -57 #define CLI_SLICING_TIME_EXCEEDS_LIMIT -58 #define CLI_TRIANGLE_COUNT_EXCEEDS_LIMIT -59 +#define CLI_NO_SUITABLE_OBJECTS_AFTER_SKIP -60 #define CLI_SLICING_ERROR -100 diff --git a/src/slic3r/GUI/3DScene.cpp b/src/slic3r/GUI/3DScene.cpp index 3494b94cc..d13cbefb2 100644 --- a/src/slic3r/GUI/3DScene.cpp +++ b/src/slic3r/GUI/3DScene.cpp @@ -1044,7 +1044,8 @@ int GLVolumeCollection::load_object_volume( int instance_idx, const std::string &color_by, bool opengl_initialized, - bool in_assemble_view) + bool in_assemble_view, + bool use_loaded_id) { const ModelVolume *model_volume = model_object->volumes[volume_idx]; const int extruder_id = model_volume->extruder_id(); @@ -1079,6 +1080,11 @@ int GLVolumeCollection::load_object_volume( else v.set_instance_transformation(instance->get_transformation()); v.set_volume_transformation(model_volume->get_transformation()); + //use object's instance id + if (use_loaded_id && (instance->loaded_id > 0)) + v.model_object_ID = instance->loaded_id; + else + v.model_object_ID = instance->id().id; return int(this->volumes.size() - 1); } diff --git a/src/slic3r/GUI/3DScene.hpp b/src/slic3r/GUI/3DScene.hpp index bf6af2ee3..c61a4eb28 100644 --- a/src/slic3r/GUI/3DScene.hpp +++ b/src/slic3r/GUI/3DScene.hpp @@ -357,6 +357,8 @@ public: // An ID containing the extruder ID (used to select color). int extruder_id; + size_t model_object_ID{0}; + // Various boolean flags. struct { // Is this object selected? @@ -634,7 +636,8 @@ public: int instance_idx, const std::string &color_by, bool opengl_initialized, - bool in_assemble_view = false); + bool in_assemble_view = false, + bool use_loaded_id = false); // Load SLA auxiliary GLVolumes (for support trees or pad). void load_object_auxiliary( diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index d8b8a7526..85094b689 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -1971,12 +1971,13 @@ void GLCanvas3D::render(bool only_init) m_render_stats.increment_fps_counter(); } -void GLCanvas3D::render_thumbnail(ThumbnailData& thumbnail_data, unsigned int w, unsigned int h, const ThumbnailsParams& thumbnail_params, Camera::EType camera_type) +void GLCanvas3D::render_thumbnail(ThumbnailData& thumbnail_data, unsigned int w, unsigned int h, const ThumbnailsParams& thumbnail_params, Camera::EType camera_type, bool use_top_view, bool for_picking) { - render_thumbnail(thumbnail_data, w, h, thumbnail_params, m_volumes, camera_type); + render_thumbnail(thumbnail_data, w, h, thumbnail_params, m_volumes, camera_type, use_top_view, for_picking); } -void GLCanvas3D::render_thumbnail(ThumbnailData& thumbnail_data, unsigned int w, unsigned int h, const ThumbnailsParams& thumbnail_params, const GLVolumeCollection& volumes, Camera::EType 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, bool use_top_view, bool for_picking) { GLShaderProgram* shader = wxGetApp().get_shader("gouraud_light"); ModelObjectPtrs& model_objects = GUI::wxGetApp().model().objects; @@ -1985,10 +1986,10 @@ void GLCanvas3D::render_thumbnail(ThumbnailData& thumbnail_data, unsigned int w, { case OpenGLManager::EFramebufferType::Arb: { render_thumbnail_framebuffer(thumbnail_data, w, h, thumbnail_params, - wxGetApp().plater()->get_partplate_list(), model_objects, volumes, colors, shader, camera_type); break; } + wxGetApp().plater()->get_partplate_list(), model_objects, volumes, colors, shader, camera_type, use_top_view, for_picking); break; } case OpenGLManager::EFramebufferType::Ext: { render_thumbnail_framebuffer_ext(thumbnail_data, w, h, thumbnail_params, - wxGetApp().plater()->get_partplate_list(), model_objects, volumes, colors, shader, camera_type); break; } + wxGetApp().plater()->get_partplate_list(), model_objects, volumes, colors, shader, camera_type, use_top_view, for_picking); break; } default: { render_thumbnail_legacy(thumbnail_data, w, h, thumbnail_params, wxGetApp().plater()->get_partplate_list(), model_objects, volumes, colors, shader, camera_type); break; } @@ -5375,7 +5376,9 @@ static void debug_output_thumbnail(const ThumbnailData& thumbnail_data) } #endif // ENABLE_THUMBNAIL_GENERATOR_DEBUG_OUTPUT -void GLCanvas3D::render_thumbnail_internal(ThumbnailData& thumbnail_data, const ThumbnailsParams& thumbnail_params, PartPlateList& partplate_list, ModelObjectPtrs& model_objects, const GLVolumeCollection& volumes, std::vector>& extruder_colors, GLShaderProgram* shader, Camera::EType camera_type) +void GLCanvas3D::render_thumbnail_internal(ThumbnailData& thumbnail_data, const ThumbnailsParams& thumbnail_params, + PartPlateList& partplate_list, ModelObjectPtrs& model_objects, const GLVolumeCollection& volumes, std::vector>& extruder_colors, + GLShaderProgram* shader, Camera::EType camera_type, bool use_top_view, bool for_picking) { //BBS modify visible calc function int plate_idx = thumbnail_params.plate_id; @@ -5418,7 +5421,7 @@ void GLCanvas3D::render_thumbnail_internal(ThumbnailData& thumbnail_data, const } } - BOOST_LOG_TRIVIAL(info) << boost::format("render_thumbnail: plate_idx %1% volumes size %2%, shader %3%") % plate_idx % visible_volumes.size() %shader; + BOOST_LOG_TRIVIAL(info) << boost::format("render_thumbnail: plate_idx %1% volumes size %2%, shader %3%, use_top_view=%4%, for_picking=%5%") % plate_idx % visible_volumes.size() %shader %use_top_view %for_picking; //BoundingBoxf3 volumes_box = plate_build_volume; BoundingBoxf3 volumes_box; volumes_box.min.z() = 0; @@ -5448,11 +5451,29 @@ void GLCanvas3D::render_thumbnail_internal(ThumbnailData& thumbnail_data, const //BoundingBoxf3 plate_box = plate->get_bounding_box(false); //plate_box.min.z() = 0.0; //plate_box.max.z() = 0.0; - camera.zoom_to_box(volumes_box); - const Vec3d& target = camera.get_target(); - double distance = camera.get_distance(); - //camera.select_view("topfront"); - camera.look_at(target - 0.707 * distance * Vec3d::UnitY() + 0.3 * distance * Vec3d::UnitZ(), target, Vec3d::UnitY() + Vec3d::UnitZ()); + + if (use_top_view) { + float center_x = (plate_build_volume.max(0) + plate_build_volume.min(0))/2; + float center_y = (plate_build_volume.max(1) + plate_build_volume.min(1))/2; + float distance_z = plate_build_volume.max(2) - plate_build_volume.min(2); + Vec3d center(center_x, center_y, 0.f); + double zoom_ratio, scale_x, scale_y; + + scale_x = ((double)thumbnail_data.width)/(plate_build_volume.max(0) - plate_build_volume.min(0)); + scale_y = ((double)thumbnail_data.height)/(plate_build_volume.max(1) - plate_build_volume.min(1)); + zoom_ratio = (scale_x <= scale_y)?scale_x:scale_y; + camera.look_at(center + distance_z * Vec3d::UnitZ(), center, Vec3d::UnitY()); + camera.set_zoom(zoom_ratio); + //camera.select_view("top"); + } + else { + camera.zoom_to_box(volumes_box); + + const Vec3d& target = camera.get_target(); + double distance = camera.get_distance(); + camera.look_at(target - 0.707 * distance * Vec3d::UnitY() + 0.3 * distance * Vec3d::UnitZ(), target, Vec3d::UnitY() + Vec3d::UnitZ()); + } + camera.apply_view_matrix(); camera.apply_projection(plate_build_volume); @@ -5462,44 +5483,94 @@ void GLCanvas3D::render_thumbnail_internal(ThumbnailData& thumbnail_data, const //camera.apply_projection(volumes_box, near_z, far_z); //GLShaderProgram* shader = wxGetApp().get_shader("gouraud_light"); - if (shader == nullptr) { - BOOST_LOG_TRIVIAL(info) << boost::format("render_thumbnail: shader is null, return directly"); + if (!for_picking && (shader == nullptr)) { + BOOST_LOG_TRIVIAL(info) << boost::format("render_thumbnail with no picking: shader is null, return directly"); return; } //if (thumbnail_params.transparent_background) - glsafe(::glClearColor(0.906f, 0.906f, 0.906f, 1.0f)); + if (for_picking) + glsafe(::glClearColor(0.f, 0.f, 0.f, 0.f)); + else + glsafe(::glClearColor(0.906f, 0.906f, 0.906f, 1.0f)); glsafe(::glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)); glsafe(::glEnable(GL_DEPTH_TEST)); - shader->start_using(); - shader->set_uniform("emission_factor", 0.0f); + if (for_picking) { + //if (OpenGLManager::can_multisample()) + // This flag is often ignored by NVIDIA drivers if rendering into a screen buffer. + // glsafe(::glDisable(GL_MULTISAMPLE)); - for (GLVolume* vol : visible_volumes) { - //BBS set render color for thumbnails - curr_color[0] = vol->color[0]; - curr_color[1] = vol->color[1]; - curr_color[2] = vol->color[2]; - curr_color[3] = vol->color[3]; + glsafe(::glDisable(GL_BLEND)); - shader->set_uniform("uniform_color", curr_color); - //BBS set all volume to orange - //shader->set_uniform("uniform_color", orange); - /*if (plate_idx > 0) { - shader->set_uniform("uniform_color", orange); + static const GLfloat INV_255 = 1.0f / 255.0f; + + // do not cull backfaces to show broken geometry, if any + glsafe(::glDisable(GL_CULL_FACE)); + + //glsafe(::glEnableClientState(GL_VERTEX_ARRAY)); + //glsafe(::glEnableClientState(GL_NORMAL_ARRAY)); + + for (GLVolume* vol : visible_volumes) { + // Object picking mode. Render the object with a color encoding the object index. + // we reserve color = (0,0,0) for occluders (as the printbed) + // so we shift volumes' id by 1 to get the proper color + //BBS: remove the bed picking logic + unsigned int id = vol->model_object_ID; + //unsigned int id = 1 + volume.second.first; + unsigned int r = (id & (0x000000FF << 0)) >> 0; + unsigned int g = (id & (0x000000FF << 8)) >> 8; + unsigned int b = (id & (0x000000FF << 16)) >> 16; + unsigned int a = 0xFF; + glsafe(::glColor4f((GLfloat)r * INV_255, (GLfloat)g * INV_255, (GLfloat)b * INV_255, (GLfloat)a * INV_255)); + /*curr_color[0] = (GLfloat)r * INV_255; + curr_color[1] = (GLfloat)g * INV_255; + curr_color[2] = (GLfloat)b * INV_255; + curr_color[3] = (GLfloat)a * INV_255; + shader->set_uniform("uniform_color", curr_color);*/ + + bool is_active = vol->is_active; + vol->is_active = true; + vol->simple_render(nullptr, model_objects, extruder_colors); + vol->is_active = is_active; } - else { - shader->set_uniform("uniform_color", (vol->printable && !vol->is_outside) ? orange : gray); - }*/ - // the volume may have been deactivated by an active gizmo - bool is_active = vol->is_active; - vol->is_active = true; - vol->simple_render(shader, model_objects, extruder_colors); - vol->is_active = is_active; - } - shader->stop_using(); + //glsafe(::glDisableClientState(GL_NORMAL_ARRAY)); + //glsafe(::glDisableClientState(GL_VERTEX_ARRAY)); + + glsafe(::glEnable(GL_CULL_FACE)); + + //if (OpenGLManager::can_multisample()) + // glsafe(::glEnable(GL_MULTISAMPLE)); + } + else { + shader->start_using(); + shader->set_uniform("emission_factor", 0.0f); + for (GLVolume* vol : visible_volumes) { + //BBS set render color for thumbnails + curr_color[0] = vol->color[0]; + curr_color[1] = vol->color[1]; + curr_color[2] = vol->color[2]; + curr_color[3] = vol->color[3]; + + shader->set_uniform("uniform_color", curr_color); + //BBS set all volume to orange + //shader->set_uniform("uniform_color", orange); + /*if (plate_idx > 0) { + shader->set_uniform("uniform_color", orange); + } + else { + shader->set_uniform("uniform_color", (vol->printable && !vol->is_outside) ? orange : gray); + }*/ + // the volume may have been deactivated by an active gizmo + bool is_active = vol->is_active; + vol->is_active = true; + vol->simple_render(shader, model_objects, extruder_colors); + vol->is_active = is_active; + } + shader->stop_using(); + } glsafe(::glDisable(GL_DEPTH_TEST)); @@ -5512,7 +5583,9 @@ void GLCanvas3D::render_thumbnail_internal(ThumbnailData& thumbnail_data, const BOOST_LOG_TRIVIAL(info) << boost::format("render_thumbnail: finished"); } -void GLCanvas3D::render_thumbnail_framebuffer(ThumbnailData& thumbnail_data, unsigned int w, unsigned int h, const ThumbnailsParams& thumbnail_params, PartPlateList& partplate_list, ModelObjectPtrs& model_objects, const GLVolumeCollection& volumes, std::vector>& extruder_colors, GLShaderProgram* shader, Camera::EType camera_type) +void GLCanvas3D::render_thumbnail_framebuffer(ThumbnailData& thumbnail_data, unsigned int w, unsigned int h, const ThumbnailsParams& thumbnail_params, + PartPlateList& partplate_list, ModelObjectPtrs& model_objects, const GLVolumeCollection& volumes, std::vector>& extruder_colors, + GLShaderProgram* shader, Camera::EType camera_type, bool use_top_view, bool for_picking) { thumbnail_data.set(w, h); if (!thumbnail_data.is_valid()) @@ -5563,7 +5636,7 @@ void GLCanvas3D::render_thumbnail_framebuffer(ThumbnailData& thumbnail_data, uns glsafe(::glDrawBuffers(1, drawBufs)); if (::glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE) { - render_thumbnail_internal(thumbnail_data, thumbnail_params, partplate_list, model_objects, volumes, extruder_colors, shader, camera_type); + render_thumbnail_internal(thumbnail_data, thumbnail_params, partplate_list, model_objects, volumes, extruder_colors, shader, camera_type, use_top_view, for_picking); if (multisample) { GLuint resolve_fbo; @@ -5616,7 +5689,9 @@ void GLCanvas3D::render_thumbnail_framebuffer(ThumbnailData& thumbnail_data, uns BOOST_LOG_TRIVIAL(info) << boost::format("render_thumbnail prepare: finished"); } -void GLCanvas3D::render_thumbnail_framebuffer_ext(ThumbnailData& thumbnail_data, unsigned int w, unsigned int h, const ThumbnailsParams& thumbnail_params, PartPlateList& partplate_list, ModelObjectPtrs& model_objects, const GLVolumeCollection& volumes, std::vector>& extruder_colors, GLShaderProgram* shader, Camera::EType camera_type) +void GLCanvas3D::render_thumbnail_framebuffer_ext(ThumbnailData& thumbnail_data, unsigned int w, unsigned int h, const ThumbnailsParams& thumbnail_params, + PartPlateList& partplate_list, ModelObjectPtrs& model_objects, const GLVolumeCollection& volumes, std::vector>& extruder_colors, + GLShaderProgram* shader, Camera::EType camera_type, bool use_top_view, bool for_picking) { thumbnail_data.set(w, h); if (!thumbnail_data.is_valid()) @@ -5666,7 +5741,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, thumbnail_params, partplate_list, model_objects, volumes, extruder_colors, shader, camera_type); + render_thumbnail_internal(thumbnail_data, thumbnail_params, partplate_list, model_objects, volumes, extruder_colors, shader, camera_type, use_top_view, for_picking); if (multisample) { GLuint resolve_fbo; @@ -7339,7 +7414,7 @@ void GLCanvas3D::_render_imgui_select_plate_toolbar() if (item->selected) { ImGui::PushStyleColor(ImGuiCol_Button, button_active); ImGui::PushStyleColor(ImGuiCol_ButtonHovered, button_active); - } + } else { ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(128.0f, 128.0f, 128.0f, 0.0f)); ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(0.42f, 0.42f, 0.42f, 1.0f)); @@ -7615,7 +7690,7 @@ void GLCanvas3D::_render_paint_toolbar() const Slic3r::GUI::BitmapCache::parse_color(colors[i], rgb); float gray = 0.299 * rgb[0] + 0.587 * rgb[1] + 0.114 * rgb[2]; ImVec4 text_color = gray < 80 ? ImVec4(255, 255, 255, 255) : ImVec4(0, 0, 0, 255); - + ImVec2 number_label_size = ImGui::CalcTextSize(std::to_string(i + 1).c_str()); ImGui::SetCursorPosY(cursor_y + text_offset_y); ImGui::SetCursorPosX(item_spacing + i * (item_spacing + button_size) + (button_size - number_label_size.x) / 2); diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp index e1b0787e3..601f801ec 100644 --- a/src/slic3r/GUI/GLCanvas3D.hpp +++ b/src/slic3r/GUI/GLCanvas3D.hpp @@ -832,13 +832,21 @@ public: // 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, 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); - static void render_thumbnail_internal(ThumbnailData& thumbnail_data, const ThumbnailsParams& thumbnail_params, PartPlateList& partplate_list, ModelObjectPtrs& model_objects, const GLVolumeCollection& volumes, std::vector>& extruder_colors, GLShaderProgram* shader, Camera::EType camera_type); + void render_thumbnail(ThumbnailData& thumbnail_data, unsigned int w, unsigned int h, const ThumbnailsParams& thumbnail_params, + Camera::EType camera_type, bool use_top_view = false, bool for_picking = false); + void render_thumbnail(ThumbnailData& thumbnail_data, unsigned int w, unsigned int h, const ThumbnailsParams& thumbnail_params, + const GLVolumeCollection& volumes, Camera::EType camera_type, bool use_top_view = false, bool for_picking = false); + static void render_thumbnail_internal(ThumbnailData& thumbnail_data, const ThumbnailsParams& thumbnail_params, PartPlateList& partplate_list, ModelObjectPtrs& model_objects, + const GLVolumeCollection& volumes, std::vector>& extruder_colors, + GLShaderProgram* shader, Camera::EType camera_type, bool use_top_view = false, bool for_picking = false); // render thumbnail using an off-screen framebuffer - static void render_thumbnail_framebuffer(ThumbnailData& thumbnail_data, unsigned int w, unsigned int h, const ThumbnailsParams& thumbnail_params, PartPlateList& partplate_list, ModelObjectPtrs& model_objects, const GLVolumeCollection& volumes, std::vector>& extruder_colors, GLShaderProgram* shader, Camera::EType camera_type); + static void render_thumbnail_framebuffer(ThumbnailData& thumbnail_data, unsigned int w, unsigned int h, const ThumbnailsParams& thumbnail_params, + PartPlateList& partplate_list, ModelObjectPtrs& model_objects, const GLVolumeCollection& volumes, std::vector>& extruder_colors, + GLShaderProgram* shader, Camera::EType camera_type, bool use_top_view = false, bool for_picking = false); // render thumbnail using an off-screen framebuffer when GLEW_EXT_framebuffer_object is supported - static void render_thumbnail_framebuffer_ext(ThumbnailData& thumbnail_data, unsigned int w, unsigned int h, const ThumbnailsParams& thumbnail_params, PartPlateList& partplate_list, ModelObjectPtrs& model_objects, const GLVolumeCollection& volumes, std::vector>& extruder_colors, GLShaderProgram* shader, Camera::EType camera_type); + static void render_thumbnail_framebuffer_ext(ThumbnailData& thumbnail_data, unsigned int w, unsigned int h, const ThumbnailsParams& thumbnail_params, + PartPlateList& partplate_list, ModelObjectPtrs& model_objects, const GLVolumeCollection& volumes, std::vector>& extruder_colors, + GLShaderProgram* shader, Camera::EType camera_type, bool use_top_view = false, bool for_picking = false); //BBS use gcoder viewer render calibration thumbnails void render_calibration_thumbnail(ThumbnailData& thumbnail_data, unsigned int w, unsigned int h, const ThumbnailsParams& thumbnail_params); diff --git a/src/slic3r/GUI/PartPlate.cpp b/src/slic3r/GUI/PartPlate.cpp index 57b24fea8..aa83adfbd 100644 --- a/src/slic3r/GUI/PartPlate.cpp +++ b/src/slic3r/GUI/PartPlate.cpp @@ -2348,7 +2348,7 @@ int PartPlate::load_gcode_from_file(const std::string& filename) return ret; } -int PartPlate::load_thumbnail_data(std::string filename) +int PartPlate::load_thumbnail_data(std::string filename, ThumbnailData& thumb_data) { bool result = true; wxImage img; @@ -2357,11 +2357,11 @@ int PartPlate::load_thumbnail_data(std::string filename) img = img.Mirror(false); } if (result) { - thumbnail_data.set(img.GetWidth(), img.GetHeight()); + thumb_data.set(img.GetWidth(), img.GetHeight()); for (int i = 0; i < img.GetWidth() * img.GetHeight(); i++) { - memcpy(&thumbnail_data.pixels[4 * i], (unsigned char*)(img.GetData() + 3 * i), 3); + memcpy(&thumb_data.pixels[4 * i], (unsigned char*)(img.GetData() + 3 * i), 3); if (img.HasAlpha()) { - thumbnail_data.pixels[4 * i + 3] = *(unsigned char*)(img.GetAlpha() + i); + thumb_data.pixels[4 * i + 3] = *(unsigned char*)(img.GetAlpha() + i); } } } else { @@ -2372,7 +2372,7 @@ int PartPlate::load_thumbnail_data(std::string filename) int PartPlate::load_pattern_thumbnail_data(std::string filename) { - bool result = true; + /*bool result = true; wxImage img; result = load_image(filename, img); if (result) { @@ -2386,7 +2386,7 @@ int PartPlate::load_pattern_thumbnail_data(std::string filename) } else { return -1; - } + }*/ return 0; } @@ -3428,6 +3428,8 @@ int PartPlateList::notify_instance_update(int obj_id, int instance_id) PartPlate* plate = m_plate_list[obj_id - 1000]; plate->update_slice_result_valid_state( false ); plate->thumbnail_data.reset(); + plate->top_thumbnail_data.reset(); + plate->pick_thumbnail_data.reset(); return 0; } @@ -3456,10 +3458,14 @@ int PartPlateList::notify_instance_update(int obj_id, int instance_id) plate->update_states(); plate->update_slice_result_valid_state(); plate->thumbnail_data.reset(); + plate->top_thumbnail_data.reset(); + plate->pick_thumbnail_data.reset(); return 0; } plate->update_slice_result_valid_state(); plate->thumbnail_data.reset(); + plate->top_thumbnail_data.reset(); + plate->pick_thumbnail_data.reset(); } else if (unprintable_plate.contain_instance(obj_id, instance_id)) { @@ -3490,6 +3496,8 @@ int PartPlateList::notify_instance_update(int obj_id, int instance_id) plate->add_instance(obj_id, instance_id, false, &boundingbox); plate->update_slice_result_valid_state(); plate->thumbnail_data.reset(); + plate->top_thumbnail_data.reset(); + plate->pick_thumbnail_data.reset(); BOOST_LOG_TRIVIAL(debug) << __FUNCTION__ << boost::format(": add it to new plate %1%") % i; return 0; } @@ -3525,6 +3533,8 @@ int PartPlateList::notify_instance_removed(int obj_id, int instance_id) plate->remove_instance(obj_id, instance_to_delete); plate->update_slice_result_valid_state(); plate->thumbnail_data.reset(); + plate->top_thumbnail_data.reset(); + plate->pick_thumbnail_data.reset(); } if (unprintable_plate.contain_instance(obj_id, instance_to_delete)) @@ -4416,6 +4426,11 @@ int PartPlateList::store_to_3mf_structure(PlateDataPtrs& plate_data_list, bool w %(i+1) %plate_data_item->plate_thumbnail.width %plate_data_item->plate_thumbnail.height %plate_data_item->plate_thumbnail.pixels.size(); plate_data_item->config.apply(*m_plate_list[i]->config()); + if (m_plate_list[i]->top_thumbnail_data.is_valid()) + plate_data_item->top_file = "valid_top"; + if (m_plate_list[i]->pick_thumbnail_data.is_valid()) + plate_data_item->pick_file = "valid_pick"; + if (m_plate_list[i]->obj_to_instance_set.size() > 0) { for (std::set>::iterator it = m_plate_list[i]->obj_to_instance_set.begin(); it != m_plate_list[i]->obj_to_instance_set.end(); ++it) @@ -4430,8 +4445,8 @@ int PartPlateList::store_to_3mf_structure(PlateDataPtrs& plate_data_list, bool w // BBS only include current palte_idx if (plate_idx == i || plate_idx == PLATE_CURRENT_IDX || plate_idx == PLATE_ALL_IDX) { //load calibration thumbnail - if (m_plate_list[i]->cali_thumbnail_data.is_valid()) - plate_data_item->pattern_file = "valid_pattern"; + //if (m_plate_list[i]->cali_thumbnail_data.is_valid()) + // plate_data_item->pattern_file = "valid_pattern"; if (m_plate_list[i]->cali_bboxes_data.is_valid()) plate_data_item->pattern_bbox_file = "valid_pattern_bbox"; plate_data_item->gcode_file = m_plate_list[i]->m_gcode_result->filename; @@ -4513,17 +4528,29 @@ int PartPlateList::load_from_3mf_structure(PlateDataPtrs& plate_data_list) if (m_plater && !plate_data_list[i]->thumbnail_file.empty()) { BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(": plate %1%, load thumbnail from %2%.")%(i+1) %plate_data_list[i]->thumbnail_file; if (boost::filesystem::exists(plate_data_list[i]->thumbnail_file)) { - m_plate_list[index]->load_thumbnail_data(plate_data_list[i]->thumbnail_file); + m_plate_list[index]->load_thumbnail_data(plate_data_list[i]->thumbnail_file, m_plate_list[index]->thumbnail_data); BOOST_LOG_TRIVIAL(info) << __FUNCTION__ <thumbnail_data.width %m_plate_list[index]->thumbnail_data.height %m_plate_list[index]->thumbnail_data.pixels.size(); } } - if (m_plater && !plate_data_list[i]->pattern_file.empty()) { + /*if (m_plater && !plate_data_list[i]->pattern_file.empty()) { if (boost::filesystem::exists(plate_data_list[i]->pattern_file)) { //no need to load pattern data currently //m_plate_list[index]->load_pattern_thumbnail_data(plate_data_list[i]->pattern_file); } + }*/ + if (m_plater && !plate_data_list[i]->top_file.empty()) { + if (boost::filesystem::exists(plate_data_list[i]->top_file)) { + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(": plate %1%, load top_thumbnail from %2%.")%(i+1) %plate_data_list[i]->top_file; + m_plate_list[index]->load_thumbnail_data(plate_data_list[i]->top_file, m_plate_list[index]->top_thumbnail_data); + } + } + if (m_plater && !plate_data_list[i]->pick_file.empty()) { + if (boost::filesystem::exists(plate_data_list[i]->pick_file)) { + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(": plate %1%, load pick_thumbnail from %2%.")%(i+1) %plate_data_list[i]->pick_file; + m_plate_list[index]->load_thumbnail_data(plate_data_list[i]->pick_file, m_plate_list[index]->pick_thumbnail_data); + } } if (m_plater && !plate_data_list[i]->pattern_bbox_file.empty()) { if (boost::filesystem::exists(plate_data_list[i]->pattern_bbox_file)) { diff --git a/src/slic3r/GUI/PartPlate.hpp b/src/slic3r/GUI/PartPlate.hpp index 0a188a346..4076df6fa 100644 --- a/src/slic3r/GUI/PartPlate.hpp +++ b/src/slic3r/GUI/PartPlate.hpp @@ -231,10 +231,13 @@ public: static const int plate_thumbnail_width = 512; static const int plate_thumbnail_height = 512; - ThumbnailData cali_thumbnail_data; + ThumbnailData top_thumbnail_data; + ThumbnailData pick_thumbnail_data; + + //ThumbnailData cali_thumbnail_data; PlateBBoxData cali_bboxes_data; - static const int cali_thumbnail_width = 2560; - static const int cali_thumbnail_height = 2560; + //static const int cali_thumbnail_width = 2560; + //static const int cali_thumbnail_height = 2560; //set the plate's index void set_index(int index); @@ -410,7 +413,7 @@ public: //load gcode from file int load_gcode_from_file(const std::string& filename); //load thumbnail data from file - int load_thumbnail_data(std::string filename); + int load_thumbnail_data(std::string filename, ThumbnailData& thumb_data); //load pattern thumbnail data from file int load_pattern_thumbnail_data(std::string filename); //load pattern box data from file diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 0d9ee3c2c..13e12f090 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -2109,7 +2109,8 @@ struct Plater::priv #endif // ENABLE_ENHANCED_PRINT_VOLUME_FIT //BBS: add plate_id for thumbnail - void generate_thumbnail(ThumbnailData& data, unsigned int w, unsigned int h, const ThumbnailsParams& thumbnail_params, Camera::EType camera_type); + void generate_thumbnail(ThumbnailData& data, unsigned int w, unsigned int h, const ThumbnailsParams& thumbnail_params, + Camera::EType camera_type, bool use_top_view = false, bool for_picking = false); ThumbnailsList generate_thumbnails(const ThumbnailsParams& params, Camera::EType camera_type); //BBS void generate_calibration_thumbnail(ThumbnailData& data, unsigned int w, unsigned int h, const ThumbnailsParams& thumbnail_params); @@ -6440,9 +6441,10 @@ void Plater::priv::on_3dcanvas_mouse_dragging_finished(SimpleEvent&) } //BBS: add plate id for thumbnail generate param -void Plater::priv::generate_thumbnail(ThumbnailData& data, unsigned int w, unsigned int h, const ThumbnailsParams& thumbnail_params, Camera::EType camera_type) +void Plater::priv::generate_thumbnail(ThumbnailData& data, unsigned int w, unsigned int h, const ThumbnailsParams& thumbnail_params, + Camera::EType camera_type, bool use_top_view, bool for_picking) { - view3D->get_canvas3d()->render_thumbnail(data, w, h, thumbnail_params, camera_type); + view3D->get_canvas3d()->render_thumbnail(data, w, h, thumbnail_params, camera_type, use_top_view, for_picking); } //BBS: add plate id for thumbnail generate param @@ -9523,6 +9525,7 @@ void Plater::export_stl(bool extended, bool selection_only) // BBS: backup int Plater::export_3mf(const boost::filesystem::path& output_path, SaveStrategy strategy, int export_plate_idx, Export3mfProgressFn proFn) { + int ret = 0; //if (p->model.objects.empty()) { // MessageDialog dialog(nullptr, _L("No objects to export."), _L("Save project"), wxYES); // if (dialog.ShowModal() == wxYES) @@ -9548,6 +9551,8 @@ int Plater::export_3mf(const boost::filesystem::path& output_path, SaveStrategy //BBS: add plate logic for thumbnail generate std::vector thumbnails; std::vector calibration_thumbnails; + std::vector top_thumbnails; + std::vector picking_thumbnails; std::vector plate_bboxes; // BBS: backup if (!(strategy & SaveStrategy::Backup)) { @@ -9560,22 +9565,50 @@ int Plater::export_3mf(const boost::filesystem::path& output_path, SaveStrategy else { BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(": re-generate thumbnail for plate %1%") % i; const ThumbnailsParams thumbnail_params = { {}, false, true, true, true, i }; - p->generate_thumbnail(p->partplate_list.get_plate(i)->thumbnail_data, THUMBNAIL_SIZE_3MF.first, THUMBNAIL_SIZE_3MF.second, thumbnail_params, Camera::EType::Ortho); + p->generate_thumbnail(p->partplate_list.get_plate(i)->thumbnail_data, THUMBNAIL_SIZE_3MF.first, THUMBNAIL_SIZE_3MF.second, + thumbnail_params, Camera::EType::Ortho); } thumbnails.push_back(thumbnail_data); - ThumbnailData* calibration_data = &p->partplate_list.get_plate(i)->cali_thumbnail_data; - calibration_thumbnails.push_back(calibration_data); + //ThumbnailData* calibration_data = &p->partplate_list.get_plate(i)->cali_thumbnail_data; + //calibration_thumbnails.push_back(calibration_data); PlateBBoxData* plate_bbox_data = &p->partplate_list.get_plate(i)->cali_bboxes_data; plate_bboxes.push_back(plate_bbox_data); + + //generate top and picking thumbnails + ThumbnailData* top_thumbnail = &p->partplate_list.get_plate(i)->top_thumbnail_data; + if (top_thumbnail->is_valid() && using_exported_file()) { + //no need to generate thumbnail + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(": non need to re-generate top_thumbnail for gcode/exported mode of plate %1%")%i; + } + else { + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(": re-generate top_thumbnail for plate %1%") % i; + const ThumbnailsParams thumbnail_params = { {}, false, true, false, true, i }; + p->generate_thumbnail(p->partplate_list.get_plate(i)->top_thumbnail_data, THUMBNAIL_SIZE_3MF.first, THUMBNAIL_SIZE_3MF.second, + thumbnail_params, Camera::EType::Ortho, true, false); + } + top_thumbnails.push_back(top_thumbnail); + + ThumbnailData* picking_thumbnail = &p->partplate_list.get_plate(i)->pick_thumbnail_data; + if (picking_thumbnail->is_valid() && using_exported_file()) { + //no need to generate thumbnail + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(": non need to re-generate pick_thumbnail for gcode/exported mode of plate %1%")%i; + } + else { + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(": re-generate pick_thumbnail for plate %1%") % i; + const ThumbnailsParams thumbnail_params = { {}, false, true, false, true, i }; + p->generate_thumbnail(p->partplate_list.get_plate(i)->pick_thumbnail_data, THUMBNAIL_SIZE_3MF.first, THUMBNAIL_SIZE_3MF.second, + thumbnail_params, Camera::EType::Ortho, true, true); + } + picking_thumbnails.push_back(picking_thumbnail); } if (p->partplate_list.get_curr_plate()->is_slice_result_valid()) { //BBS generate BBS calibration thumbnails int index = p->partplate_list.get_curr_plate_index(); - ThumbnailData* calibration_data = calibration_thumbnails[index]; - const ThumbnailsParams calibration_params = { {}, false, true, true, true, p->partplate_list.get_curr_plate_index() }; - p->generate_calibration_thumbnail(*calibration_data, PartPlate::cali_thumbnail_width, PartPlate::cali_thumbnail_height, calibration_params); + //ThumbnailData* calibration_data = calibration_thumbnails[index]; + //const ThumbnailsParams calibration_params = { {}, false, true, true, true, p->partplate_list.get_curr_plate_index() }; + //p->generate_calibration_thumbnail(*calibration_data, PartPlate::cali_thumbnail_width, PartPlate::cali_thumbnail_height, calibration_params); if (using_exported_file()) { //do nothing } @@ -9600,6 +9633,8 @@ int Plater::export_3mf(const boost::filesystem::path& output_path, SaveStrategy store_params.project_presets = project_presets; store_params.config = export_config ? &cfg : nullptr; store_params.thumbnail_data = thumbnails; + store_params.top_thumbnail_data = top_thumbnails; + store_params.pick_thumbnail_data = picking_thumbnails; store_params.calibration_thumbnail_data = calibration_thumbnails; store_params.proFn = proFn; store_params.id_bboxes = plate_bboxes;//BBS @@ -9661,7 +9696,7 @@ int Plater::export_3mf(const boost::filesystem::path& output_path, SaveStrategy } } else { - return -1; + ret = -1; } if (project_presets.size() > 0) @@ -9680,8 +9715,20 @@ int Plater::export_3mf(const boost::filesystem::path& output_path, SaveStrategy //release the data here, as it will always be generated when export calibration_thumbnails[i]->reset(); } + for (unsigned int i = 0; i < top_thumbnails.size(); i++) + { + //release the data here, as it will always be generated when export + top_thumbnails[i]->reset(); + } + top_thumbnails.clear(); + for (unsigned int i = 0; i < picking_thumbnails.size(); i++) + { + //release the data here, as it will always be generated when export + picking_thumbnails[i]->reset();; + } + picking_thumbnails.clear(); - return 0; + return ret; } void Plater::publish_project()