diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index c377b17860..1f4120a0bb 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -3095,162 +3095,6 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato if (m_config.small_area_infill_flow_compensation.value && !m_config.small_area_infill_flow_compensation_model.empty()) m_small_area_infill_flow_compensator = make_unique(print.config()); - // Process file_start_gcode - written at the very top of the file, before any header - { - std::string top_gcode_template = print.config().file_start_gcode.value; - if (!top_gcode_template.empty()) { - DynamicConfig top_config; - // file_start_gcode runs before the parser copy that normally restores these, so set them here. - PlaceholderParser::update_timestamp(top_config); - PlaceholderParser::update_user_name(top_config); - top_config.set_key_value("print_time_total_sec", new ConfigOptionString(GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Print_Time_Total_Sec_Placeholder))); - top_config.set_key_value("print_time_day", new ConfigOptionString(GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Print_Time_Day_Placeholder))); - top_config.set_key_value("print_time_hour", new ConfigOptionString(GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Print_Time_Hour_Placeholder))); - top_config.set_key_value("print_time_minute", new ConfigOptionString(GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Print_Time_Minute_Placeholder))); - top_config.set_key_value("print_time_sec", new ConfigOptionString(GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Print_Time_Sec_Placeholder))); - top_config.set_key_value("used_filament_length", new ConfigOptionString(GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Used_Filament_Length_Placeholder))); - std::string top_gcode = print.placeholder_parser().process(top_gcode_template, 0, &top_config); - if (!top_gcode.empty()) - file.writeln(top_gcode); - } - } - - // Orca: Don't output Header block if BTT thumbnail is identified in the list - // Get the thumbnails value as a string - std::string thumbnails_value = print.config().option("thumbnails")->value; - // search string for the BTT_TFT label - bool has_BTT_thumbnail = (thumbnails_value.find("BTT_TFT") != std::string::npos); - - if(!has_BTT_thumbnail){ - file.write_format("; HEADER_BLOCK_START\n"); - // Write information on the generator. - file.write_format("; generated by %s on %s\n", Slic3r::header_slic3r_generated().c_str(), Slic3r::Utils::local_timestamp().c_str()); - if (is_bbl_printers) - file.write_format(";%s\n", GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Estimated_Printing_Time_Placeholder).c_str()); - //BBS: total layer number - file.write_format(";%s\n", GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Total_Layer_Number_Placeholder).c_str()); - //Orca: extra check for bbl printer - if (is_bbl_printers) { - if (print.calib_params().mode == CalibMode::Calib_None) { // Don't support skipping in cali mode - // list all label_object_id with sorted order here - m_enable_exclude_object = true; - m_label_objects_ids.clear(); - m_label_objects_ids.reserve(print.num_object_instances()); - for (const PrintObject *print_object : print.objects()) - for (const PrintInstance &print_instance : print_object->instances()) - m_label_objects_ids.push_back(print_instance.model_instance->get_labeled_id()); - - std::sort(m_label_objects_ids.begin(), m_label_objects_ids.end()); - - std::string objects_id_list = "; model label id: "; - for (auto it = m_label_objects_ids.begin(); it != m_label_objects_ids.end(); it++) - objects_id_list += (std::to_string(*it) + (it != m_label_objects_ids.end() - 1 ? "," : "\n")); - file.writeln(objects_id_list); - } else { - m_enable_exclude_object = false; - m_label_objects_ids.clear(); - } - } - - { - std::string filament_density_list = "; filament_density: "; - (filament_density_list+=m_config.filament_density.serialize()) +='\n'; - file.writeln(filament_density_list); - - std::string filament_diameter_list = "; filament_diameter: "; - (filament_diameter_list += m_config.filament_diameter.serialize()) += '\n'; - file.writeln(filament_diameter_list); - - coordf_t max_height_z = -1; - for (const auto& object : print.objects()) - max_height_z = std::max(object->layers().back()->print_z, max_height_z); - - std::ostringstream max_height_z_tip; - max_height_z_tip<<"; max_z_height: " << std::fixed << std::setprecision(2) << max_height_z << '\n'; - file.writeln(max_height_z_tip.str()); - } - - { - auto used_filaments = print.get_slice_used_filaments(false); - std::ostringstream out; - out << "; filament: "; - for (size_t idx = 0; idx < used_filaments.size(); ++idx) { - if (idx != 0) - out << ','; - out << used_filaments[idx] + 1; - } - file.writeln(out.str()); - } - - file.write_format("; HEADER_BLOCK_END\n\n"); - } - - // BBS: write global config at the beginning of gcode file because printer - // need these config information - // Append full config, delimited by two 'phony' configuration keys - // CONFIG_BLOCK_START and CONFIG_BLOCK_END. The delimiters are structured - // as configuration key / value pairs to be parsable by older versions of - // PrusaSlicer G-code viewer. - { - if (is_bbl_printers && !skip_config_block) { - file.write("; CONFIG_BLOCK_START\n"); - std::string full_config; - append_full_config(print, full_config); - if (!full_config.empty()) - file.write(full_config); - - // SoftFever: write compatiple image - int first_layer_bed_temperature = get_bed_temperature(0, true, print.config().curr_bed_type); - file.write_format("; first_layer_bed_temperature = %d\n", - first_layer_bed_temperature); - file.write_format( - "; first_layer_temperature = %d\n", - print.config().nozzle_temperature_initial_layer.get_at(0)); - file.write("; CONFIG_BLOCK_END\n\n"); - } else if (thumbnail_cb != nullptr) { - // generate the thumbnails - auto [thumbnails, errors] = GCodeThumbnails::make_and_check_thumbnail_list(print.full_print_config()); - - if (errors != enum_bitmask()) { - std::string error_str = format("Invalid thumbnails value:"); - error_str += GCodeThumbnails::get_error_string(errors); - throw Slic3r::ExportError(error_str); - } - - if (!thumbnails.empty()) - GCodeThumbnails::export_thumbnails_to_file( - thumbnail_cb, print.get_plate_index(), thumbnails, [&file](const char* sz) { file.write(sz); }, [&print]() { print.throw_if_canceled(); }); - } - } - - - // Write some terse information on the slicing parameters. - const PrintObject *first_object = print.objects().front(); - const double layer_height = first_object->config().layer_height.value; - const double initial_layer_print_height = print.config().initial_layer_print_height.value; - for (size_t region_id = 0; region_id < print.num_print_regions(); ++ region_id) { - const PrintRegion ®ion = print.get_print_region(region_id); - file.write_format("; external perimeters extrusion width = %.2fmm\n", region.flow(*first_object, frExternalPerimeter, layer_height).width()); - file.write_format("; perimeters extrusion width = %.2fmm\n", region.flow(*first_object, frPerimeter, layer_height).width()); - file.write_format("; infill extrusion width = %.2fmm\n", region.flow(*first_object, frInfill, layer_height).width()); - file.write_format("; solid infill extrusion width = %.2fmm\n", region.flow(*first_object, frSolidInfill, layer_height).width()); - file.write_format("; top infill extrusion width = %.2fmm\n", region.flow(*first_object, frTopSolidInfill, layer_height).width()); - if (print.has_support_material()) - file.write_format("; support material extrusion width = %.2fmm\n", support_material_flow(first_object).width()); - if (print.config().initial_layer_line_width.value > 0) - file.write_format("; first layer extrusion width = %.2fmm\n", region.flow(*first_object, frPerimeter, initial_layer_print_height, true).width()); - file.write_format("\n"); - } - - file.write_format("; EXECUTABLE_BLOCK_START\n"); - - // SoftFever - if( m_enable_exclude_object) - file.write(set_object_info(&print)); - - // adds tags for time estimators - file.write_format(";%s\n", GCodeProcessor::reserved_tag(GCodeProcessor::ETags::First_Line_M73_Placeholder).c_str()); - // Prepare the helper object for replacing placeholders in custom G-code and output filename. m_placeholder_parser_integration.parser = print.placeholder_parser(); m_placeholder_parser_integration.parser.update_timestamp(); @@ -3385,16 +3229,6 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato // Orca: Initialise AdaptivePA processor filter m_pa_processor = std::make_unique(*this, tool_ordering.all_extruders()); - // Emit machine envelope limits for the Marlin firmware. - this->print_machine_envelope(file, print); - - // Disable fan. - if (m_config.auxiliary_fan.value && print.config().close_fan_the_first_x_layers.get_at(initial_extruder_id)) { - file.write(m_writer.set_fan(0)); - //BBS: disable additional fan - file.write(m_writer.set_additional_fan(0)); - } - // Update output variables after the extruders were initialized. m_placeholder_parser_integration.init(m_writer); @@ -3746,6 +3580,157 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato // Sync variant-mapped params into placeholder_parser before processing start gcode update_placeholder_parser_with_variant_params(); + // Expand the file header only after the start-up placeholders and writer state are ready. + // Use the regular custom G-code path so invalid placeholders report the template name. + if (!print.config().file_start_gcode.value.empty()) + file.writeln(this->placeholder_parser_process("file_start_gcode", print.config().file_start_gcode.value, initial_extruder_id)); + + // Orca: Don't output Header block if BTT thumbnail is identified in the list + // Get the thumbnails value as a string + std::string thumbnails_value = print.config().option("thumbnails")->value; + // search string for the BTT_TFT label + bool has_BTT_thumbnail = (thumbnails_value.find("BTT_TFT") != std::string::npos); + + if(!has_BTT_thumbnail){ + file.write_format("; HEADER_BLOCK_START\n"); + // Write information on the generator. + file.write_format("; generated by %s on %s\n", Slic3r::header_slic3r_generated().c_str(), Slic3r::Utils::local_timestamp().c_str()); + if (is_bbl_printers) + file.write_format(";%s\n", GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Estimated_Printing_Time_Placeholder).c_str()); + //BBS: total layer number + file.write_format(";%s\n", GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Total_Layer_Number_Placeholder).c_str()); + //Orca: extra check for bbl printer + if (is_bbl_printers) { + if (print.calib_params().mode == CalibMode::Calib_None) { // Don't support skipping in cali mode + // list all label_object_id with sorted order here + m_enable_exclude_object = true; + m_label_objects_ids.clear(); + m_label_objects_ids.reserve(print.num_object_instances()); + for (const PrintObject *print_object : print.objects()) + for (const PrintInstance &print_instance : print_object->instances()) + m_label_objects_ids.push_back(print_instance.model_instance->get_labeled_id()); + + std::sort(m_label_objects_ids.begin(), m_label_objects_ids.end()); + + std::string objects_id_list = "; model label id: "; + for (auto it = m_label_objects_ids.begin(); it != m_label_objects_ids.end(); it++) + objects_id_list += (std::to_string(*it) + (it != m_label_objects_ids.end() - 1 ? "," : "\n")); + file.writeln(objects_id_list); + } else { + m_enable_exclude_object = false; + m_label_objects_ids.clear(); + } + } + + { + std::string filament_density_list = "; filament_density: "; + (filament_density_list+=m_config.filament_density.serialize()) +='\n'; + file.writeln(filament_density_list); + + std::string filament_diameter_list = "; filament_diameter: "; + (filament_diameter_list += m_config.filament_diameter.serialize()) += '\n'; + file.writeln(filament_diameter_list); + + coordf_t max_height_z = -1; + for (const auto& object : print.objects()) + max_height_z = std::max(object->layers().back()->print_z, max_height_z); + + std::ostringstream max_height_z_tip; + max_height_z_tip<<"; max_z_height: " << std::fixed << std::setprecision(2) << max_height_z << '\n'; + file.writeln(max_height_z_tip.str()); + } + + { + auto used_filaments = print.get_slice_used_filaments(false); + std::ostringstream out; + out << "; filament: "; + for (size_t idx = 0; idx < used_filaments.size(); ++idx) { + if (idx != 0) + out << ','; + out << used_filaments[idx] + 1; + } + file.writeln(out.str()); + } + + file.write_format("; HEADER_BLOCK_END\n\n"); + } + + // BBS: write global config at the beginning of gcode file because printer + // need these config information + // Append full config, delimited by two 'phony' configuration keys + // CONFIG_BLOCK_START and CONFIG_BLOCK_END. The delimiters are structured + // as configuration key / value pairs to be parsable by older versions of + // PrusaSlicer G-code viewer. + { + if (is_bbl_printers && !skip_config_block) { + file.write("; CONFIG_BLOCK_START\n"); + std::string full_config; + append_full_config(print, full_config); + if (!full_config.empty()) + file.write(full_config); + + // SoftFever: write compatiple image + int first_layer_bed_temperature = get_bed_temperature(0, true, print.config().curr_bed_type); + file.write_format("; first_layer_bed_temperature = %d\n", + first_layer_bed_temperature); + file.write_format( + "; first_layer_temperature = %d\n", + print.config().nozzle_temperature_initial_layer.get_at(0)); + file.write("; CONFIG_BLOCK_END\n\n"); + } else if (thumbnail_cb != nullptr) { + // generate the thumbnails + auto [thumbnails, errors] = GCodeThumbnails::make_and_check_thumbnail_list(print.full_print_config()); + + if (errors != enum_bitmask()) { + std::string error_str = format("Invalid thumbnails value:"); + error_str += GCodeThumbnails::get_error_string(errors); + throw Slic3r::ExportError(error_str); + } + + if (!thumbnails.empty()) + GCodeThumbnails::export_thumbnails_to_file( + thumbnail_cb, print.get_plate_index(), thumbnails, [&file](const char* sz) { file.write(sz); }, [&print]() { print.throw_if_canceled(); }); + } + } + + + // Write some terse information on the slicing parameters. + const PrintObject *first_object = print.objects().front(); + const double layer_height = first_object->config().layer_height.value; + const double initial_layer_print_height = print.config().initial_layer_print_height.value; + for (size_t region_id = 0; region_id < print.num_print_regions(); ++ region_id) { + const PrintRegion ®ion = print.get_print_region(region_id); + file.write_format("; external perimeters extrusion width = %.2fmm\n", region.flow(*first_object, frExternalPerimeter, layer_height).width()); + file.write_format("; perimeters extrusion width = %.2fmm\n", region.flow(*first_object, frPerimeter, layer_height).width()); + file.write_format("; infill extrusion width = %.2fmm\n", region.flow(*first_object, frInfill, layer_height).width()); + file.write_format("; solid infill extrusion width = %.2fmm\n", region.flow(*first_object, frSolidInfill, layer_height).width()); + file.write_format("; top infill extrusion width = %.2fmm\n", region.flow(*first_object, frTopSolidInfill, layer_height).width()); + if (print.has_support_material()) + file.write_format("; support material extrusion width = %.2fmm\n", support_material_flow(first_object).width()); + if (print.config().initial_layer_line_width.value > 0) + file.write_format("; first layer extrusion width = %.2fmm\n", region.flow(*first_object, frPerimeter, initial_layer_print_height, true).width()); + file.write_format("\n"); + } + + file.write_format("; EXECUTABLE_BLOCK_START\n"); + + // SoftFever + if( m_enable_exclude_object) + file.write(set_object_info(&print)); + + // adds tags for time estimators + file.write_format(";%s\n", GCodeProcessor::reserved_tag(GCodeProcessor::ETags::First_Line_M73_Placeholder).c_str()); + + // Emit machine envelope limits for the Marlin firmware. + this->print_machine_envelope(file, print); + + // Disable fan. + if (m_config.auxiliary_fan.value && print.config().close_fan_the_first_x_layers.get_at(initial_extruder_id)) { + file.write(m_writer.set_fan(0)); + //BBS: disable additional fan + file.write(m_writer.set_additional_fan(0)); + } + std::string machine_start_gcode = this->placeholder_parser_process("machine_start_gcode", print.config().machine_start_gcode.value, initial_extruder_id); if (print.config().gcode_flavor != gcfKlipper) { // Set bed temperature if the start G-code does not contain any bed temp control G-codes.