Merge remote-tracking branch 'upstream/main' into libvgcode

# Conflicts:
#	src/libslic3r/GCode/GCodeProcessor.cpp
#	src/libslic3r/GCode/GCodeProcessor.hpp
#	src/slic3r/CMakeLists.txt
#	src/slic3r/GUI/GCodeViewer.cpp
#	src/slic3r/GUI/GCodeViewer.hpp
#	src/slic3r/GUI/GLCanvas3D.cpp
#	src/slic3r/GUI/GLCanvas3D.hpp
#	src/slic3r/GUI/GUI_Preview.cpp
This commit is contained in:
Andrew Sun
2025-11-09 18:48:04 -05:00
2978 changed files with 1208720 additions and 66304 deletions

View File

@@ -63,25 +63,6 @@ void glAssertRecentCallImpl(const char* file_name, unsigned int line, const char
}
#endif // HAS_GLSAFE
// BBS
std::vector<Slic3r::ColorRGBA> get_extruders_colors()
{
unsigned char rgba_color[4] = {};
std::vector<std::string> colors = Slic3r::GUI::wxGetApp().plater()->get_extruder_colors_from_plater_config();
std::vector<Slic3r::ColorRGBA> colors_out(colors.size());
for (const std::string &color : colors) {
Slic3r::GUI::BitmapCache::parse_color4(color, rgba_color);
size_t color_idx = &color - &colors.front();
colors_out[color_idx] = {
float(rgba_color[0]) / 255.f,
float(rgba_color[1]) / 255.f,
float(rgba_color[2]) / 255.f,
float(rgba_color[3]) / 255.f,
};
}
return colors_out;
}
float FullyTransparentMaterialThreshold = 0.1f;
float FullTransparentModdifiedToFixAlpha = 0.3f;
// Be careful changing this value because it could break thumbnail color due to rounding error!
@@ -224,6 +205,7 @@ GLVolume::GLVolume(float r, float g, float b, float a)
, partly_inside(false)
, hover(HS_None)
, is_modifier(false)
, slice_error(false)
, is_wipe_tower(false)
, is_extrusion_path(false)
, force_transparent(false)
@@ -421,7 +403,7 @@ void GLVolume::render()
return;
ModelObjectPtrs &model_objects = GUI::wxGetApp().model().objects;
std::vector<ColorRGBA> colors = get_extruders_colors();
std::vector<ColorRGBA> colors = GUI::wxGetApp().plater()->get_extruders_colors();
simple_render(shader, model_objects, colors);
}
@@ -437,7 +419,7 @@ void GLVolume::render_with_outline(const GUI::Size& cnv_size)
return;
ModelObjectPtrs &model_objects = GUI::wxGetApp().model().objects;
std::vector<ColorRGBA> colors = get_extruders_colors();
std::vector<ColorRGBA> colors = GUI::wxGetApp().plater()->get_extruders_colors();
const GUI::OpenGLManager::EFramebufferType framebuffers_type = GUI::OpenGLManager::get_framebuffers_type();
if (framebuffers_type == GUI::OpenGLManager::EFramebufferType::Unknown) {
@@ -798,7 +780,7 @@ int GLVolumeCollection::load_wipe_tower_preview(
if (height == 0.0f)
height = 0.1f;
std::vector<ColorRGBA> extruder_colors = get_extruders_colors();
std::vector<ColorRGBA> extruder_colors = GUI::wxGetApp().plater()->get_extruders_colors();
std::vector<ColorRGBA> colors;
GUI::PartPlateList& ppl = GUI::wxGetApp().plater()->get_partplate_list();
std::vector<int> plate_extruders = ppl.get_plate(plate_idx)->get_extruders(true);
@@ -834,6 +816,48 @@ int GLVolumeCollection::load_wipe_tower_preview(
return int(volumes.size() - 1);
}
int GLVolumeCollection::load_real_wipe_tower_preview(
int obj_idx, float pos_x, float pos_y, const TriangleMesh& wt_mesh,const TriangleMesh &brim_mesh,bool render_brim, float rotation_angle, bool size_unknown, bool opengl_initialized)
{
int plate_idx = obj_idx - 1000;
if (wt_mesh.its.vertices.empty()) return int(this->volumes.size() - 1);
std::vector<Slic3r::ColorRGBA> extruder_colors = GUI::wxGetApp().plater()->get_extruders_colors();
GUI::PartPlateList &ppl = GUI::wxGetApp().plater()->get_partplate_list();
std::vector<int> plate_extruders = ppl.get_plate(plate_idx)->get_extruders(true);
std::vector<Slic3r::ColorRGBA> colors;
if (!plate_extruders.empty()) {
if (plate_extruders.front() <= extruder_colors.size())
colors.push_back(extruder_colors[plate_extruders.front() - 1]);
else
colors.push_back(extruder_colors[0]);
}
if (colors.empty()) return int(this->volumes.size() - 1);
volumes.emplace_back(new GLWipeTowerVolume({colors}));
GLWipeTowerVolume &v = *dynamic_cast<GLWipeTowerVolume *>(volumes.back());
auto mesh = wt_mesh;
if (render_brim) {
mesh.merge(brim_mesh);
}
if (!colors.empty()) {
v.model_per_colors.resize(1);
v.model_per_colors[0].init_from(mesh);
}
TriangleMesh wipe_tower_shell = mesh.convex_hull_3d();
v.model.init_from(wipe_tower_shell);
v.mesh_raycaster = std::make_unique<GUI::MeshRaycaster>(std::make_shared<const TriangleMesh>(wipe_tower_shell));
v.set_convex_hull(wipe_tower_shell);
v.set_volume_offset(Vec3d(pos_x, pos_y, 0.0));
v.set_volume_rotation(Vec3d(0., 0., (M_PI / 180.) * rotation_angle));
v.composite_id = GLVolume::CompositeID(obj_idx, 0, 0);
v.geometry_id.first = 0;
v.geometry_id.second = wipe_tower_instance_id().id + (obj_idx - 1000);
v.is_wipe_tower = true;
v.shader_outside_printer_detection_enabled = !size_unknown;
return int(volumes.size() - 1);
}
GLVolume* GLVolumeCollection::new_toolpath_volume(const ColorRGBA& rgba)
{
GLVolume* out = new_nontoolpath_volume(rgba);
@@ -1003,7 +1027,8 @@ void GLVolumeCollection::render(GLVolumeCollection::ERenderType type,
#endif // ENABLE_ENVIRONMENT_MAP
glcheck();
volume.first->model.set_color(volume.first->render_color);
auto red_color = ColorRGBA{1.0f, 0.0f, 0.0f, 1.0f};//slice_error
volume.first->model.set_color(volume.first->slice_error ? red_color : volume.first->render_color);
const Transform3d model_matrix = volume.first->world_matrix();
shader->set_uniform("view_model_matrix", view_matrix * model_matrix);
shader->set_uniform("projection_matrix", projection_matrix);
@@ -1049,7 +1074,41 @@ void GLVolumeCollection::render(GLVolumeCollection::ERenderType type,
glsafe(::glDisable(GL_BLEND));
}
bool GLVolumeCollection::check_outside_state(const BuildVolume &build_volume, ModelInstanceEPrintVolumeState *out_state) const
bool GLVolumeCollection::check_wipe_tower_outside_state(const Slic3r::BuildVolume &build_volume, int plate_id) const
{
for (GLVolume *volume : this->volumes) {
if (volume->is_wipe_tower) {
int wipe_tower_plate_id = volume->composite_id.object_id - 1000;
if (wipe_tower_plate_id != plate_id)
continue;
const std::vector<Vec2d>& printable_area = build_volume.printable_area();
Polygon printable_poly = Polygon::new_scale(printable_area);
// multi-extruder
Polygons extruder_polys;
const std::vector<std::vector<Vec2d>> & extruder_areas = build_volume.extruder_areas();
if (!extruder_areas.empty()) {
for (size_t i = 0; i < extruder_areas.size(); ++i) {
extruder_polys.emplace_back(Polygon::new_scale(extruder_areas[i]));
}
extruder_polys = union_(extruder_polys);
if (extruder_polys.empty())
return false;
printable_poly = extruder_polys[0];
}
const BoundingBoxf3 &bbox = volume->transformed_convex_hull_bounding_box();
Polygon wipe_tower_polygon = bbox.polygon(true);
Polygons diff_res = diff(wipe_tower_polygon, printable_poly);
return diff_res.empty();
}
}
return true;
}
bool GLVolumeCollection::check_outside_state(const BuildVolume &build_volume, ModelInstanceEPrintVolumeState *out_state, ObjectFilamentResults* object_results) const
{
if (GUI::wxGetApp().plater() == NULL)
{
@@ -1071,19 +1130,25 @@ bool GLVolumeCollection::check_outside_state(const BuildVolume &build_volume, Mo
auto volume_convex_mesh = [volume_sinking, &model](GLVolume& volume) -> const TriangleMesh&
{ return volume_sinking(volume) ? model.objects[volume.object_idx()]->volumes[volume.volume_idx()]->mesh() : *volume.convex_hull(); };
ModelInstanceEPrintVolumeState overall_state = ModelInstancePVS_Inside;
ModelInstanceEPrintVolumeState overall_state = ModelInstancePVS_Fully_Outside;
bool contained_min_one = false;
//BBS: add instance judge logic, besides to original volume judge logic
std::map<int64_t, ModelInstanceEPrintVolumeState> model_state;
//std::map<int64_t, ModelInstanceEPrintVolumeState> model_state;
GUI::PartPlate* curr_plate = GUI::wxGetApp().plater()->get_partplate_list().get_selected_plate();
const Pointfs& pp_bed_shape = curr_plate->get_shape();
BuildVolume plate_build_volume(pp_bed_shape, build_volume.printable_height());
BuildVolume plate_build_volume(pp_bed_shape, build_volume.printable_height(), build_volume.extruder_areas(), build_volume.extruder_heights());
const std::vector<BoundingBoxf3>& exclude_areas = curr_plate->get_exclude_areas();
std::map<ModelObject*, std::map<int, std::set<int>>> objects_unprintable_filaments;
int extruder_count = build_volume.get_extruder_area_count();
std::vector<std::set<int>> unprintable_filament_ids(extruder_count, std::set<int>());
std::set<ModelObject*> partly_objects_set;
const ModelObjectPtrs &model_objects = model.objects;
for (GLVolume* volume : this->volumes)
{
std::vector<bool> inside_extruders;
if (! volume->is_modifier && (volume->shader_outside_printer_detection_enabled || (! volume->is_wipe_tower && volume->composite_id.volume_id >= 0))) {
BuildVolume::ObjectState state;
if (volume_below(*volume))
@@ -1094,38 +1159,69 @@ bool GLVolumeCollection::check_outside_state(const BuildVolume &build_volume, Mo
//FIXME this test does not evaluate collision of a build volume bounding box with non-convex objects.
const BoundingBoxf3& bb = volume_bbox(*volume);
state = plate_build_volume.volume_state_bbox(bb);
}
if ((state == BuildVolume::ObjectState::Inside) && (extruder_count > 1))
{
state = plate_build_volume.check_volume_bbox_state_with_extruder_areas(bb, inside_extruders);
}
break;
}
case BuildVolume_Type::Circle:
case BuildVolume_Type::Convex:
//FIXME doing test on convex hull until we learn to do test on non-convex polygons efficiently.
case BuildVolume_Type::Custom:
state = plate_build_volume.object_state(volume_convex_mesh(*volume).its, volume->world_matrix().cast<float>(), volume_sinking(*volume));
{
const indexed_triangle_set& convex_mesh_it = volume_convex_mesh(*volume).its;
const Transform3f trafo = volume->world_matrix().cast<float>();
state = plate_build_volume.object_state(convex_mesh_it, trafo, volume_sinking(*volume));
if ((state == BuildVolume::ObjectState::Inside) && (extruder_count > 1))
{
state = plate_build_volume.check_object_state_with_extruder_areas(convex_mesh_it, trafo, inside_extruders);
}
break;
}
default:
// Ignore, don't produce any collision.
state = BuildVolume::ObjectState::Inside;
break;
}
assert(state != BuildVolume::ObjectState::Below);
if (state == BuildVolume::ObjectState::Limited) {
//unprintable_filament_ids.resize(inside_extruders.size());
ModelObject *model_object = model_objects[volume->object_idx()];
ModelVolume *model_volume = model_object->volumes[volume->volume_idx()];
for (size_t i = 0; i < inside_extruders.size(); ++i) {
if (!inside_extruders[i]) {
std::vector<int> filaments = model_volume->get_extruders();
unprintable_filament_ids[i].insert(filaments.begin(), filaments.end());
if (object_results) {
std::map<int, std::set<int>>& obj_extruder_filament_maps = objects_unprintable_filaments[model_object];
std::set<int>& obj_extruder_filaments = obj_extruder_filament_maps[i+1];
obj_extruder_filaments.insert(filaments.begin(), filaments.end());
}
}
}
}
}
int64_t comp_id = ((int64_t)volume->composite_id.object_id << 32) | ((int64_t)volume->composite_id.instance_id);
volume->is_outside = state != BuildVolume::ObjectState::Inside;
//volume->partly_inside = (state == BuildVolume::ObjectState::Colliding);
//int64_t comp_id = ((int64_t)volume->composite_id.object_id << 32) | ((int64_t)volume->composite_id.instance_id);
volume->is_outside = (state != BuildVolume::ObjectState::Inside && state != BuildVolume::ObjectState::Limited);
volume->partly_inside = (state == BuildVolume::ObjectState::Colliding);
if (volume->printable) {
if (overall_state == ModelInstancePVS_Inside && volume->is_outside) {
overall_state = ModelInstancePVS_Fully_Outside;
}
if (overall_state == ModelInstancePVS_Fully_Outside && volume->is_outside && (state == BuildVolume::ObjectState::Colliding))
if (state == BuildVolume::ObjectState::Colliding)
{
overall_state = ModelInstancePVS_Partly_Outside;
partly_objects_set.emplace(model_objects[volume->object_idx()]);
}
else if ((state == BuildVolume::ObjectState::Limited) && (overall_state != ModelInstancePVS_Partly_Outside))
overall_state = ModelInstancePVS_Limited;
else if ((state == BuildVolume::ObjectState::Inside) && (overall_state == ModelInstancePVS_Fully_Outside)) {
overall_state = ModelInstancePVS_Fully_Outside;
}
contained_min_one |= !volume->is_outside;
}
ModelInstanceEPrintVolumeState volume_state;
/*ModelInstanceEPrintVolumeState volume_state;
//if (volume->is_outside && (plate_build_volume.bounding_volume().intersects(volume->bounding_box())))
if (volume->is_outside && (state == BuildVolume::ObjectState::Colliding))
volume_state = ModelInstancePVS_Partly_Outside;
@@ -1154,11 +1250,121 @@ bool GLVolumeCollection::check_outside_state(const BuildVolume &build_volume, Mo
if (model_state[comp_id] == ModelInstancePVS_Partly_Outside) {
overall_state = ModelInstancePVS_Partly_Outside;
BOOST_LOG_TRIVIAL(debug) << "instance includes " << volume->name << " is partially outside of bed";
}*/
}
}
std::vector<std::vector<int>> unprintable_filament_vec;
for (const std::set<int>& filamnt_ids : unprintable_filament_ids) {
unprintable_filament_vec.emplace_back(std::vector<int>(filamnt_ids.begin(), filamnt_ids.end()));
}
if (object_results && !partly_objects_set.empty()) {
object_results->partly_outside_objects = std::vector<ModelObject*>(partly_objects_set.begin(), partly_objects_set.end());
}
//check per-object error for extruder areas
if (object_results && (extruder_count > 1))
{
const auto& project_config = Slic3r::GUI::wxGetApp().preset_bundle->project_config;
object_results->mode = curr_plate->get_real_filament_map_mode(project_config);
if (object_results->mode < FilamentMapMode::fmmManual)
{
std::vector<int> conflict_filament_vector;
for (int index = 0; index < extruder_count; index++ )
{
if (!unprintable_filament_vec[index].empty())
{
std::sort (unprintable_filament_vec[index].begin(), unprintable_filament_vec[index].end());
if (index == 0)
conflict_filament_vector = unprintable_filament_vec[index];
else
{
std::vector<int> result_filaments;
//result_filaments.reserve(conflict_filaments.size());
std::set_intersection (conflict_filament_vector.begin(), conflict_filament_vector.end(), unprintable_filament_vec[index].begin(), unprintable_filament_vec[index].end(), insert_iterator<vector<int>>(result_filaments, result_filaments.begin()));
conflict_filament_vector = result_filaments;
}
}
else
{
conflict_filament_vector.clear();
break;
}
}
if (!conflict_filament_vector.empty())
{
std::set<int> conflict_filaments_set(conflict_filament_vector.begin(), conflict_filament_vector.end());
object_results->filaments = conflict_filament_vector;
for (auto& object_map: objects_unprintable_filaments)
{
ModelObject *model_object = object_map.first;
std::map<int, std::set<int>>& obj_extruder_filament_maps = object_map.second;
std::set<int> obj_filaments_set;
ObjectFilamentInfo object_filament_info;
object_filament_info.object = model_object;
for (std::map<int, std::set<int>>::iterator extruder_map_iter = obj_extruder_filament_maps.begin(); extruder_map_iter != obj_extruder_filament_maps.end(); extruder_map_iter++ )
{
int extruder_id = extruder_map_iter->first;
std::set<int>& filaments_set = extruder_map_iter->second;
for (int filament: filaments_set)
{
if (conflict_filaments_set.find(filament) != conflict_filaments_set.end())
{
obj_filaments_set.emplace(filament);
}
}
}
if (!obj_filaments_set.empty()) {
object_filament_info.auto_filaments = std::vector<int>(obj_filaments_set.begin(), obj_filaments_set.end());
object_results->object_filaments.push_back(std::move(object_filament_info));
}
}
}
}
else
{
std::set<int> conflict_filaments_set;
const auto& project_config = Slic3r::GUI::wxGetApp().preset_bundle->project_config;
std::vector<int> filament_maps = curr_plate->get_real_filament_maps(project_config);
for (auto& object_map: objects_unprintable_filaments)
{
ModelObject *model_object = object_map.first;
std::map<int, std::set<int>>& obj_extruder_filament_maps = object_map.second;
ObjectFilamentInfo object_filament_info;
object_filament_info.object = model_object;
for (std::map<int, std::set<int>>::iterator extruder_map_iter = obj_extruder_filament_maps.begin(); extruder_map_iter != obj_extruder_filament_maps.end(); extruder_map_iter++ )
{
int extruder_id = extruder_map_iter->first;
std::set<int>& filaments_set = extruder_map_iter->second;
for (int filament: filaments_set)
{
if (filament_maps[filament - 1] == extruder_id)
{
object_filament_info.manual_filaments.emplace(filament, extruder_id);
object_results->filament_maps[filament] = extruder_id;
conflict_filaments_set.emplace(filament);
}
}
}
if (!object_filament_info.manual_filaments.empty())
{
object_results->object_filaments.push_back(std::move(object_filament_info));
}
}
if (!conflict_filaments_set.empty()) {
object_results->filaments = std::vector<int>(conflict_filaments_set.begin(), conflict_filaments_set.end());
}
}
}
for (GLVolume* volume : this->volumes)
/*for (GLVolume* volume : this->volumes)
{
if (! volume->is_modifier && (volume->shader_outside_printer_detection_enabled || (! volume->is_wipe_tower && volume->composite_id.volume_id >= 0)))
{
@@ -1172,7 +1378,7 @@ bool GLVolumeCollection::check_outside_state(const BuildVolume &build_volume, Mo
volume->partly_inside = false;
}
}
}
}*/
if (out_state != nullptr)
*out_state = overall_state;