Fixed conflicts after merge with master

This commit is contained in:
enricoturri1966 2021-09-09 11:27:35 +02:00
commit 17f665f8d6
29 changed files with 978 additions and 397 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

View File

@ -34,7 +34,9 @@ void main()
float NdotL = max(dot(eye_normal, LIGHT_TOP_DIR), 0.0);
intensity.x = INTENSITY_AMBIENT + NdotL * LIGHT_TOP_DIFFUSE;
vec4 world_position = vec4(v_position * vec3(vec2(i_scales.x), i_scales.y) + i_offset, 1.0);
float width = 1.5 * i_scales.x;
float height = 1.5 * i_scales.y;
vec4 world_position = vec4(v_position * vec3(vec2(width), height) + i_offset - vec3(0.0, 0.0, 0.5 * i_scales.y), 1.0);
vec3 eye_position = (gl_ModelViewMatrix * world_position).xyz;
intensity.y = LIGHT_TOP_SPECULAR * pow(max(dot(-normalize(eye_position), reflect(-LIGHT_TOP_DIR, eye_normal)), 0.0), LIGHT_TOP_SHININESS);

View File

@ -33,22 +33,20 @@ std::wstring BlacklistedLibraryCheck::get_blacklisted_string()
bool BlacklistedLibraryCheck::perform_check()
{
// Get a handle to the process.
HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, GetCurrentProcessId());
if (NULL == hProcess)
return false;
// Get the pseudo-handle for the current process.
HANDLE hCurrentProcess = GetCurrentProcess();
// Get a list of all the modules in this process.
HMODULE hMods[1024];
DWORD cbNeeded;
if (EnumProcessModulesEx(hProcess, hMods, sizeof(hMods), &cbNeeded, LIST_MODULES_ALL))
if (EnumProcessModulesEx(hCurrentProcess, hMods, sizeof(hMods), &cbNeeded, LIST_MODULES_ALL))
{
//printf("Total Dlls: %d\n", cbNeeded / sizeof(HMODULE));
for (unsigned int i = 0; i < cbNeeded / sizeof(HMODULE); ++ i)
{
wchar_t szModName[MAX_PATH];
// Get the full path to the module's file.
if (GetModuleFileNameExW(hProcess, hMods[i], szModName, MAX_PATH))
if (GetModuleFileNameExW(hCurrentProcess, hMods[i], szModName, MAX_PATH))
{
// Add to list if blacklisted
if (BlacklistedLibraryCheck::is_blacklisted(szModName)) {
@ -61,7 +59,6 @@ bool BlacklistedLibraryCheck::perform_check()
}
}
CloseHandle(hProcess);
//printf("\n");
return !m_found.empty();
}

View File

@ -744,27 +744,28 @@ void GCode::do_export(Print* print, const char* path, GCodeProcessor::Result* re
std::string path_tmp(path);
path_tmp += ".tmp";
FILE *file = boost::nowide::fopen(path_tmp.c_str(), "wb");
if (file == nullptr)
m_processor.initialize(path_tmp);
GCodeOutputStream file(boost::nowide::fopen(path_tmp.c_str(), "wb"), m_processor);
if (! file.is_open())
throw Slic3r::RuntimeError(std::string("G-code export to ") + path + " failed.\nCannot open the file for writing.\n");
try {
m_placeholder_parser_failed_templates.clear();
this->_do_export(*print, file, thumbnail_cb);
fflush(file);
if (ferror(file)) {
fclose(file);
file.flush();
if (file.is_error()) {
file.close();
boost::nowide::remove(path_tmp.c_str());
throw Slic3r::RuntimeError(std::string("G-code export to ") + path + " failed\nIs the disk full?\n");
}
} catch (std::exception & /* ex */) {
// Rethrow on any exception. std::runtime_exception and CanceledException are expected to be thrown.
// Close and remove the file.
fclose(file);
file.close();
boost::nowide::remove(path_tmp.c_str());
throw;
}
fclose(file);
file.close();
if (! m_placeholder_parser_failed_templates.empty()) {
// G-code export proceeded, but some of the PlaceholderParser substitutions failed.
@ -782,7 +783,7 @@ void GCode::do_export(Print* print, const char* path, GCodeProcessor::Result* re
}
BOOST_LOG_TRIVIAL(debug) << "Start processing gcode, " << log_memory_info();
m_processor.process_file(path_tmp, true, [print]() { print->throw_if_canceled(); });
m_processor.finalize();
// DoExport::update_print_estimated_times_stats(m_processor, print->m_print_statistics);
DoExport::update_print_estimated_stats(m_processor, m_writer.extruders(), print->m_print_statistics);
if (result != nullptr) {
@ -1046,7 +1047,7 @@ std::vector<const PrintInstance*> sort_object_instances_by_model_order(const Pri
return instances;
}
void GCode::_do_export(Print& print, FILE* file, ThumbnailsGeneratorCallback thumbnail_cb)
void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGeneratorCallback thumbnail_cb)
{
PROFILE_FUNC();
@ -1111,10 +1112,10 @@ void GCode::_do_export(Print& print, FILE* file, ThumbnailsGeneratorCallback thu
#endif /* HAS_PRESSURE_EQUALIZER */
// Write information on the generator.
_write_format(file, "; %s\n\n", Slic3r::header_slic3r_generated().c_str());
file.write_format("; %s\n\n", Slic3r::header_slic3r_generated().c_str());
DoExport::export_thumbnails_to_file(thumbnail_cb, print.full_print_config().option<ConfigOptionPoints>("thumbnails")->values,
[this, file](const char* sz) { this->_write(file, sz); },
[&file](const char* sz) { file.write(sz); },
[&print]() { print.throw_if_canceled(); });
// Write notes (content of the Print Settings tab -> Notes)
@ -1125,10 +1126,10 @@ void GCode::_do_export(Print& print, FILE* file, ThumbnailsGeneratorCallback thu
// Remove the trailing '\r' from the '\r\n' sequence.
if (! line.empty() && line.back() == '\r')
line.pop_back();
_write_format(file, "; %s\n", line.c_str());
file.write_format("; %s\n", line.c_str());
}
if (! lines.empty())
_write(file, "\n");
file.write("\n");
}
print.throw_if_canceled();
@ -1139,22 +1140,22 @@ void GCode::_do_export(Print& print, FILE* file, ThumbnailsGeneratorCallback thu
const double first_layer_height = print.config().first_layer_height.value;
for (size_t region_id = 0; region_id < print.num_print_regions(); ++ region_id) {
const PrintRegion &region = print.get_print_region(region_id);
_write_format(file, "; external perimeters extrusion width = %.2fmm\n", region.flow(*first_object, frExternalPerimeter, layer_height).width());
_write_format(file, "; perimeters extrusion width = %.2fmm\n", region.flow(*first_object, frPerimeter, layer_height).width());
_write_format(file, "; infill extrusion width = %.2fmm\n", region.flow(*first_object, frInfill, layer_height).width());
_write_format(file, "; solid infill extrusion width = %.2fmm\n", region.flow(*first_object, frSolidInfill, layer_height).width());
_write_format(file, "; top infill extrusion width = %.2fmm\n", region.flow(*first_object, frTopSolidInfill, layer_height).width());
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())
_write_format(file, "; support material extrusion width = %.2fmm\n", support_material_flow(first_object).width());
file.write_format("; support material extrusion width = %.2fmm\n", support_material_flow(first_object).width());
if (print.config().first_layer_extrusion_width.value > 0)
_write_format(file, "; first layer extrusion width = %.2fmm\n", region.flow(*first_object, frPerimeter, first_layer_height, true).width());
_write_format(file, "\n");
file.write_format("; first layer extrusion width = %.2fmm\n", region.flow(*first_object, frPerimeter, first_layer_height, true).width());
file.write_format("\n");
}
print.throw_if_canceled();
// adds tags for time estimators
if (print.config().remaining_times.value)
_write_format(file, ";%s\n", GCodeProcessor::reserved_tag(GCodeProcessor::ETags::First_Line_M73_Placeholder).c_str());
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 = print.placeholder_parser();
@ -1218,7 +1219,7 @@ void GCode::_do_export(Print& print, FILE* file, ThumbnailsGeneratorCallback thu
// Disable fan.
if (! print.config().cooling.get_at(initial_extruder_id) || print.config().disable_fan_first_layers.get_at(initial_extruder_id))
_write(file, m_writer.set_fan(0, true));
file.write(m_writer.set_fan(0, true));
// Let the start-up script prime the 1st printing tool.
m_placeholder_parser.set("initial_tool", initial_extruder_id);
@ -1261,10 +1262,10 @@ void GCode::_do_export(Print& print, FILE* file, ThumbnailsGeneratorCallback thu
this->_print_first_layer_extruder_temperatures(file, print, start_gcode, initial_extruder_id, false);
// adds tag for processor
_write_format(file, ";%s%s\n", GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Role).c_str(), ExtrusionEntity::role_to_string(erCustom).c_str());
file.write_format(";%s%s\n", GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Role).c_str(), ExtrusionEntity::role_to_string(erCustom).c_str());
// Write the custom start G-code
_writeln(file, start_gcode);
file.writeln(start_gcode);
// Process filament-specific gcode.
/* if (has_wipe_tower) {
@ -1272,14 +1273,14 @@ void GCode::_do_export(Print& print, FILE* file, ThumbnailsGeneratorCallback thu
} else {
DynamicConfig config;
config.set_key_value("filament_extruder_id", new ConfigOptionInt(int(initial_extruder_id)));
_writeln(file, this->placeholder_parser_process("start_filament_gcode", print.config().start_filament_gcode.values[initial_extruder_id], initial_extruder_id, &config));
file.writeln(this->placeholder_parser_process("start_filament_gcode", print.config().start_filament_gcode.values[initial_extruder_id], initial_extruder_id, &config));
}
*/
this->_print_first_layer_extruder_temperatures(file, print, start_gcode, initial_extruder_id, true);
print.throw_if_canceled();
// Set other general things.
_write(file, this->preamble());
file.write(this->preamble());
// Calculate wiping points if needed
DoExport::init_ooze_prevention(print, m_ooze_prevention);
@ -1291,7 +1292,7 @@ void GCode::_do_export(Print& print, FILE* file, ThumbnailsGeneratorCallback thu
if (! (has_wipe_tower && print.config().single_extruder_multi_material_priming)) {
// Set initial extruder only after custom start G-code.
// Ugly hack: Do not set the initial extruder if the extruder is primed using the MMU priming towers at the edge of the print bed.
_write(file, this->set_extruder(initial_extruder_id, 0.));
file.write(this->set_extruder(initial_extruder_id, 0.));
}
// Do all objects for each layer.
@ -1317,8 +1318,8 @@ void GCode::_do_export(Print& print, FILE* file, ThumbnailsGeneratorCallback thu
// This happens before Z goes down to layer 0 again, so that no collision happens hopefully.
m_enable_cooling_markers = false; // we're not filtering these moves through CoolingBuffer
m_avoid_crossing_perimeters.use_external_mp_once();
_write(file, this->retract());
_write(file, this->travel_to(Point(0, 0), erNone, "move to origin position for next object"));
file.write(this->retract());
file.write(this->travel_to(Point(0, 0), erNone, "move to origin position for next object"));
m_enable_cooling_markers = true;
// Disable motion planner when traveling to first object point.
m_avoid_crossing_perimeters.disable_once();
@ -1330,7 +1331,7 @@ void GCode::_do_export(Print& print, FILE* file, ThumbnailsGeneratorCallback thu
// Set first layer bed and extruder temperatures, don't wait for it to reach the temperature.
this->_print_first_layer_bed_temperature(file, print, between_objects_gcode, initial_extruder_id, false);
this->_print_first_layer_extruder_temperatures(file, print, between_objects_gcode, initial_extruder_id, false);
_writeln(file, between_objects_gcode);
file.writeln(between_objects_gcode);
}
// Reset the cooling buffer internal state (the current position, feed rate, accelerations).
m_cooling_buffer->reset();
@ -1346,7 +1347,7 @@ void GCode::_do_export(Print& print, FILE* file, ThumbnailsGeneratorCallback thu
}
#ifdef HAS_PRESSURE_EQUALIZER
if (m_pressure_equalizer)
_write(file, m_pressure_equalizer->process("", true));
file.write(m_pressure_equalizer->process("", true));
#endif /* HAS_PRESSURE_EQUALIZER */
++ finished_objects;
// Flag indicating whether the nozzle temperature changes from 1st to 2nd layer were performed.
@ -1361,9 +1362,9 @@ void GCode::_do_export(Print& print, FILE* file, ThumbnailsGeneratorCallback thu
// Prusa Multi-Material wipe tower.
if (has_wipe_tower && ! layers_to_print.empty()) {
m_wipe_tower.reset(new WipeTowerIntegration(print.config(), *print.wipe_tower_data().priming.get(), print.wipe_tower_data().tool_changes, *print.wipe_tower_data().final_purge.get()));
_write(file, m_writer.travel_to_z(first_layer_height + m_config.z_offset.value, "Move to the first layer height"));
file.write(m_writer.travel_to_z(first_layer_height + m_config.z_offset.value, "Move to the first layer height"));
if (print.config().single_extruder_multi_material_priming) {
_write(file, m_wipe_tower->prime(*this));
file.write(m_wipe_tower->prime(*this));
// Verify, whether the print overaps the priming extrusions.
BoundingBoxf bbox_print(get_print_extrusions_extents(print));
coordf_t twolayers_printz = ((layers_to_print.size() == 1) ? layers_to_print.front() : layers_to_print[1]).first + EPSILON;
@ -1375,15 +1376,15 @@ void GCode::_do_export(Print& print, FILE* file, ThumbnailsGeneratorCallback thu
bool overlap = bbox_prime.overlap(bbox_print);
if (print.config().gcode_flavor == gcfMarlinLegacy || print.config().gcode_flavor == gcfMarlinFirmware) {
_write(file, this->retract());
_write(file, "M300 S800 P500\n"); // Beep for 500ms, tone 800Hz.
file.write(this->retract());
file.write("M300 S800 P500\n"); // Beep for 500ms, tone 800Hz.
if (overlap) {
// Wait for the user to remove the priming extrusions.
_write(file, "M1 Remove priming towers and click button.\n");
file.write("M1 Remove priming towers and click button.\n");
} else {
// Just wait for a bit to let the user check, that the priming succeeded.
//TODO Add a message explaining what the printer is waiting for. This needs a firmware fix.
_write(file, "M1 S10\n");
file.write("M1 S10\n");
}
} else {
// This is not Marlin, M1 command is probably not supported.
@ -1410,19 +1411,19 @@ void GCode::_do_export(Print& print, FILE* file, ThumbnailsGeneratorCallback thu
}
#ifdef HAS_PRESSURE_EQUALIZER
if (m_pressure_equalizer)
_write(file, m_pressure_equalizer->process("", true));
file.write(m_pressure_equalizer->process("", true));
#endif /* HAS_PRESSURE_EQUALIZER */
if (m_wipe_tower)
// Purge the extruder, pull out the active filament.
_write(file, m_wipe_tower->finalize(*this));
file.write(m_wipe_tower->finalize(*this));
}
// Write end commands to file.
_write(file, this->retract());
_write(file, m_writer.set_fan(false));
file.write(this->retract());
file.write(m_writer.set_fan(false));
// adds tag for processor
_write_format(file, ";%s%s\n", GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Role).c_str(), ExtrusionEntity::role_to_string(erCustom).c_str());
file.write_format(";%s%s\n", GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Role).c_str(), ExtrusionEntity::role_to_string(erCustom).c_str());
// Process filament-specific gcode in extruder order.
{
@ -1434,48 +1435,48 @@ void GCode::_do_export(Print& print, FILE* file, ThumbnailsGeneratorCallback thu
// Process the end_filament_gcode for the active filament only.
int extruder_id = m_writer.extruder()->id();
config.set_key_value("filament_extruder_id", new ConfigOptionInt(extruder_id));
_writeln(file, this->placeholder_parser_process("end_filament_gcode", print.config().end_filament_gcode.get_at(extruder_id), extruder_id, &config));
file.writeln(this->placeholder_parser_process("end_filament_gcode", print.config().end_filament_gcode.get_at(extruder_id), extruder_id, &config));
} else {
for (const std::string &end_gcode : print.config().end_filament_gcode.values) {
int extruder_id = (unsigned int)(&end_gcode - &print.config().end_filament_gcode.values.front());
config.set_key_value("filament_extruder_id", new ConfigOptionInt(extruder_id));
_writeln(file, this->placeholder_parser_process("end_filament_gcode", end_gcode, extruder_id, &config));
file.writeln(this->placeholder_parser_process("end_filament_gcode", end_gcode, extruder_id, &config));
}
}
_writeln(file, this->placeholder_parser_process("end_gcode", print.config().end_gcode, m_writer.extruder()->id(), &config));
file.writeln(this->placeholder_parser_process("end_gcode", print.config().end_gcode, m_writer.extruder()->id(), &config));
}
_write(file, m_writer.update_progress(m_layer_count, m_layer_count, true)); // 100%
_write(file, m_writer.postamble());
file.write(m_writer.update_progress(m_layer_count, m_layer_count, true)); // 100%
file.write(m_writer.postamble());
// adds tags for time estimators
if (print.config().remaining_times.value)
_write_format(file, ";%s\n", GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Last_Line_M73_Placeholder).c_str());
file.write_format(";%s\n", GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Last_Line_M73_Placeholder).c_str());
print.throw_if_canceled();
// Get filament stats.
_write(file, DoExport::update_print_stats_and_format_filament_stats(
file.write(DoExport::update_print_stats_and_format_filament_stats(
// Const inputs
has_wipe_tower, print.wipe_tower_data(),
m_writer.extruders(),
// Modifies
print.m_print_statistics));
_write(file, "\n");
_write_format(file, "; total filament used [g] = %.2lf\n", print.m_print_statistics.total_weight);
_write_format(file, "; total filament cost = %.2lf\n", print.m_print_statistics.total_cost);
file.write("\n");
file.write_format("; total filament used [g] = %.2lf\n", print.m_print_statistics.total_weight);
file.write_format("; total filament cost = %.2lf\n", print.m_print_statistics.total_cost);
if (print.m_print_statistics.total_toolchanges > 0)
_write_format(file, "; total toolchanges = %i\n", print.m_print_statistics.total_toolchanges);
_write_format(file, ";%s\n", GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Estimated_Printing_Time_Placeholder).c_str());
file.write_format("; total toolchanges = %i\n", print.m_print_statistics.total_toolchanges);
file.write_format(";%s\n", GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Estimated_Printing_Time_Placeholder).c_str());
// Append full config, delimited by two 'phony' configuration keys prusaslicer_config = begin and prusaslicer_config = end.
// The delimiters are structured as configuration key / value pairs to be parsable by older versions of PrusaSlicer G-code viewer.
{
_write(file, "\n; prusaslicer_config = begin\n");
file.write("\n; prusaslicer_config = begin\n");
std::string full_config;
append_full_config(print, full_config);
if (!full_config.empty())
_write(file, full_config);
_write(file, "; prusaslicer_config = end\n");
file.write(full_config);
file.write("; prusaslicer_config = end\n");
}
print.throw_if_canceled();
}
@ -1565,16 +1566,16 @@ static bool custom_gcode_sets_temperature(const std::string &gcode, const int mc
// Print the machine envelope G-code for the Marlin firmware based on the "machine_max_xxx" parameters.
// Do not process this piece of G-code by the time estimator, it already knows the values through another sources.
void GCode::print_machine_envelope(FILE *file, Print &print)
void GCode::print_machine_envelope(GCodeOutputStream &file, Print &print)
{
if ((print.config().gcode_flavor.value == gcfMarlinLegacy || print.config().gcode_flavor.value == gcfMarlinFirmware)
&& print.config().machine_limits_usage.value == MachineLimitsUsage::EmitToGCode) {
fprintf(file, "M201 X%d Y%d Z%d E%d ; sets maximum accelerations, mm/sec^2\n",
file.write_format("M201 X%d Y%d Z%d E%d ; sets maximum accelerations, mm/sec^2\n",
int(print.config().machine_max_acceleration_x.values.front() + 0.5),
int(print.config().machine_max_acceleration_y.values.front() + 0.5),
int(print.config().machine_max_acceleration_z.values.front() + 0.5),
int(print.config().machine_max_acceleration_e.values.front() + 0.5));
fprintf(file, "M203 X%d Y%d Z%d E%d ; sets maximum feedrates, mm/sec\n",
file.write_format("M203 X%d Y%d Z%d E%d ; sets maximum feedrates, mm/sec\n",
int(print.config().machine_max_feedrate_x.values.front() + 0.5),
int(print.config().machine_max_feedrate_y.values.front() + 0.5),
int(print.config().machine_max_feedrate_z.values.front() + 0.5),
@ -1587,18 +1588,18 @@ void GCode::print_machine_envelope(FILE *file, Print &print)
int travel_acc = print.config().gcode_flavor == gcfMarlinLegacy
? int(print.config().machine_max_acceleration_extruding.values.front() + 0.5)
: int(print.config().machine_max_acceleration_travel.values.front() + 0.5);
fprintf(file, "M204 P%d R%d T%d ; sets acceleration (P, T) and retract acceleration (R), mm/sec^2\n",
file.write_format("M204 P%d R%d T%d ; sets acceleration (P, T) and retract acceleration (R), mm/sec^2\n",
int(print.config().machine_max_acceleration_extruding.values.front() + 0.5),
int(print.config().machine_max_acceleration_retracting.values.front() + 0.5),
travel_acc);
assert(is_decimal_separator_point());
fprintf(file, "M205 X%.2lf Y%.2lf Z%.2lf E%.2lf ; sets the jerk limits, mm/sec\n",
file.write_format("M205 X%.2lf Y%.2lf Z%.2lf E%.2lf ; sets the jerk limits, mm/sec\n",
print.config().machine_max_jerk_x.values.front(),
print.config().machine_max_jerk_y.values.front(),
print.config().machine_max_jerk_z.values.front(),
print.config().machine_max_jerk_e.values.front());
fprintf(file, "M205 S%d T%d ; sets the minimum extruding and travel feed rate, mm/sec\n",
file.write_format("M205 S%d T%d ; sets the minimum extruding and travel feed rate, mm/sec\n",
int(print.config().machine_min_extruding_rate.values.front() + 0.5),
int(print.config().machine_min_travel_rate.values.front() + 0.5));
}
@ -1608,7 +1609,7 @@ void GCode::print_machine_envelope(FILE *file, Print &print)
// Only do that if the start G-code does not already contain any M-code controlling an extruder temperature.
// M140 - Set Extruder Temperature
// M190 - Set Extruder Temperature and Wait
void GCode::_print_first_layer_bed_temperature(FILE *file, Print &print, const std::string &gcode, unsigned int first_printing_extruder_id, bool wait)
void GCode::_print_first_layer_bed_temperature(GCodeOutputStream &file, Print &print, const std::string &gcode, unsigned int first_printing_extruder_id, bool wait)
{
// Initial bed temperature based on the first extruder.
int temp = print.config().first_layer_bed_temperature.get_at(first_printing_extruder_id);
@ -1621,7 +1622,7 @@ void GCode::_print_first_layer_bed_temperature(FILE *file, Print &print, const s
// the custom start G-code emited these.
std::string set_temp_gcode = m_writer.set_bed_temperature(temp, wait);
if (! temp_set_by_gcode)
_write(file, set_temp_gcode);
file.write(set_temp_gcode);
}
// Write 1st layer extruder temperatures into the G-code.
@ -1629,7 +1630,7 @@ void GCode::_print_first_layer_bed_temperature(FILE *file, Print &print, const s
// M104 - Set Extruder Temperature
// M109 - Set Extruder Temperature and Wait
// RepRapFirmware: G10 Sxx
void GCode::_print_first_layer_extruder_temperatures(FILE *file, Print &print, const std::string &gcode, unsigned int first_printing_extruder_id, bool wait)
void GCode::_print_first_layer_extruder_temperatures(GCodeOutputStream &file, Print &print, const std::string &gcode, unsigned int first_printing_extruder_id, bool wait)
{
// Is the bed temperature set by the provided custom G-code?
int temp_by_gcode = -1;
@ -1646,7 +1647,7 @@ void GCode::_print_first_layer_extruder_temperatures(FILE *file, Print &print, c
// Set temperature of the first printing extruder only.
int temp = print.config().first_layer_temperature.get_at(first_printing_extruder_id);
if (temp > 0)
_write(file, m_writer.set_temperature(temp, wait, first_printing_extruder_id));
file.write(m_writer.set_temperature(temp, wait, first_printing_extruder_id));
} else {
// Set temperatures of all the printing extruders.
for (unsigned int tool_id : print.extruders()) {
@ -1654,7 +1655,7 @@ void GCode::_print_first_layer_extruder_temperatures(FILE *file, Print &print, c
if (print.config().ooze_prevention.value)
temp += print.config().standby_temperature_delta.value;
if (temp > 0)
_write(file, m_writer.set_temperature(temp, wait, tool_id));
file.write(m_writer.set_temperature(temp, wait, tool_id));
}
}
}
@ -1891,7 +1892,7 @@ namespace Skirt {
// and performing the extruder specific extrusions together.
void GCode::process_layer(
// Write into the output file.
FILE *file,
GCodeOutputStream &file,
const Print &print,
// Set of object & print layers of the same PrintObject and with the same print_z.
const std::vector<LayerToPrint> &layers,
@ -2306,7 +2307,7 @@ void GCode::process_layer(
// printf("G-code after filter:\n%s\n", out.c_str());
#endif /* HAS_PRESSURE_EQUALIZER */
_write(file, gcode);
file.write(gcode);
BOOST_LOG_TRIVIAL(trace) << "Exported layer " << layer.id() << " print_z " << print_z <<
log_memory_info();
}
@ -2642,22 +2643,42 @@ std::string GCode::extrude_support(const ExtrusionEntityCollection &support_fill
return gcode;
}
void GCode::_write(FILE* file, const char *what)
bool GCode::GCodeOutputStream::is_error() const
{
return ::ferror(this->f);
}
void GCode::GCodeOutputStream::flush()
{
::fflush(this->f);
}
void GCode::GCodeOutputStream::close()
{
if (this->f) {
::fclose(this->f);
this->f = nullptr;
}
}
void GCode::GCodeOutputStream::write(const char *what)
{
if (what != nullptr) {
const char* gcode = what;
// writes string to file
fwrite(gcode, 1, ::strlen(gcode), file);
fwrite(gcode, 1, ::strlen(gcode), this->f);
//FIXME don't allocate a string, maybe process a batch of lines?
m_processor.process_buffer(std::string(gcode));
}
}
void GCode::_writeln(FILE* file, const std::string &what)
void GCode::GCodeOutputStream::writeln(const std::string &what)
{
if (! what.empty())
_write(file, (what.back() == '\n') ? what : (what + '\n'));
this->write(what.back() == '\n' ? what : what + '\n');
}
void GCode::_write_format(FILE* file, const char* format, ...)
void GCode::GCodeOutputStream::write_format(const char* format, ...)
{
va_list args;
va_start(args, format);
@ -2681,7 +2702,7 @@ void GCode::_write_format(FILE* file, const char* format, ...)
char *bufptr = buffer_dynamic ? (char*)malloc(buflen) : buffer;
int res = ::vsnprintf(bufptr, buflen, format, args);
if (res > 0)
_write(file, bufptr);
this->write(bufptr);
if (buffer_dynamic)
free(bufptr);

View File

@ -184,13 +184,40 @@ public:
};
private:
void _do_export(Print &print, FILE *file, ThumbnailsGeneratorCallback thumbnail_cb);
class GCodeOutputStream {
public:
GCodeOutputStream(FILE *f, GCodeProcessor &processor) : f(f), m_processor(processor) {}
~GCodeOutputStream() { this->close(); }
bool is_open() const { return f; }
bool is_error() const;
void flush();
void close();
// Write a string into a file.
void write(const std::string& what) { this->write(what.c_str()); }
void write(const char* what);
// Write a string into a file.
// Add a newline, if the string does not end with a newline already.
// Used to export a custom G-code section processed by the PlaceholderParser.
void writeln(const std::string& what);
// Formats and write into a file the given data.
void write_format(const char* format, ...);
private:
FILE *f = nullptr;
GCodeProcessor &m_processor;
};
void _do_export(Print &print, GCodeOutputStream &file, ThumbnailsGeneratorCallback thumbnail_cb);
static std::vector<LayerToPrint> collect_layers_to_print(const PrintObject &object);
static std::vector<std::pair<coordf_t, std::vector<LayerToPrint>>> collect_layers_to_print(const Print &print);
void process_layer(
// Write into the output file.
FILE *file,
GCodeOutputStream &file,
const Print &print,
// Set of object & print layers of the same PrintObject and with the same print_z.
const std::vector<LayerToPrint> &layers,
@ -358,22 +385,10 @@ private:
// Processor
GCodeProcessor m_processor;
// Write a string into a file.
void _write(FILE* file, const std::string& what) { this->_write(file, what.c_str()); }
void _write(FILE* file, const char *what);
// Write a string into a file.
// Add a newline, if the string does not end with a newline already.
// Used to export a custom G-code section processed by the PlaceholderParser.
void _writeln(FILE* file, const std::string& what);
// Formats and write into a file the given data.
void _write_format(FILE* file, const char* format, ...);
std::string _extrude(const ExtrusionPath &path, std::string description = "", double speed = -1);
void print_machine_envelope(FILE *file, Print &print);
void _print_first_layer_bed_temperature(FILE *file, Print &print, const std::string &gcode, unsigned int first_printing_extruder_id, bool wait);
void _print_first_layer_extruder_temperatures(FILE *file, Print &print, const std::string &gcode, unsigned int first_printing_extruder_id, bool wait);
void print_machine_envelope(GCodeOutputStream &file, Print &print);
void _print_first_layer_bed_temperature(GCodeOutputStream &file, Print &print, const std::string &gcode, unsigned int first_printing_extruder_id, bool wait);
void _print_first_layer_extruder_temperatures(GCodeOutputStream &file, Print &print, const std::string &gcode, unsigned int first_printing_extruder_id, bool wait);
// On the first printing layer. This flag triggers first layer speeds.
bool on_first_layer() const { return m_layer != nullptr && m_layer->id() == 0; }
// To control print speed of 1st object layer over raft interface.

View File

@ -21,6 +21,9 @@
#include <chrono>
static const float DEFAULT_TOOLPATH_WIDTH = 0.4f;
static const float DEFAULT_TOOLPATH_HEIGHT = 0.2f;
static const float INCHES_TO_MM = 25.4f;
static const float MMMIN_TO_MMSEC = 1.0f / 60.0f;
static const float DEFAULT_ACCELERATION = 1500.0f; // Prusa Firmware 1_75mm_MK2
@ -344,20 +347,34 @@ void GCodeProcessor::TimeProcessor::reset()
machines[static_cast<size_t>(PrintEstimatedStatistics::ETimeMode::Normal)].enabled = true;
}
void GCodeProcessor::TimeProcessor::post_process(const std::string& filename, std::vector<MoveVertex>& moves)
struct FilePtr {
FilePtr(FILE *f) : f(f) {}
~FilePtr() { this->close(); }
void close() {
if (this->f) {
::fclose(this->f);
this->f = nullptr;
}
}
FILE* f = nullptr;
};
void GCodeProcessor::TimeProcessor::post_process(const std::string& filename, std::vector<MoveVertex>& moves, std::vector<size_t>& lines_ends)
{
boost::nowide::ifstream in(filename);
if (!in.good())
FilePtr in{ boost::nowide::fopen(filename.c_str(), "rb") };
if (in.f == nullptr)
throw Slic3r::RuntimeError(std::string("Time estimator post process export failed.\nCannot open file for reading.\n"));
// temporary file to contain modified gcode
std::string out_path = filename + ".postprocess";
FILE* out = boost::nowide::fopen(out_path.c_str(), "wb");
if (out == nullptr)
FilePtr out{ boost::nowide::fopen(out_path.c_str(), "wb") };
if (out.f == nullptr) {
throw Slic3r::RuntimeError(std::string("Time estimator post process export failed.\nCannot open file for writing.\n"));
}
auto time_in_minutes = [](float time_in_seconds) {
return int(::roundf(time_in_seconds / 60.0f));
assert(time_in_seconds >= 0.f);
return int((time_in_seconds + 0.5f) / 60.0f);
};
auto time_in_last_minute = [](float time_in_seconds) {
@ -389,7 +406,6 @@ void GCodeProcessor::TimeProcessor::post_process(const std::string& filename, st
return std::string(line_M73);
};
GCodeReader parser;
std::string gcode_line;
size_t g1_lines_counter = 0;
// keeps track of last exported pair <percent, remaining time>
@ -408,11 +424,12 @@ void GCodeProcessor::TimeProcessor::post_process(const std::string& filename, st
std::string export_line;
// replace placeholder lines with the proper final value
auto process_placeholders = [&](const std::string& gcode_line) {
// gcode_line is in/out parameter, to reduce expensive memory allocation
auto process_placeholders = [&](std::string& gcode_line) {
unsigned int extra_lines_count = 0;
// remove trailing '\n'
std::string line = gcode_line.substr(0, gcode_line.length() - 1);
auto line = std::string_view(gcode_line).substr(0, gcode_line.length() - 1);
std::string ret;
if (line.length() > 1) {
@ -453,7 +470,10 @@ void GCodeProcessor::TimeProcessor::post_process(const std::string& filename, st
}
}
return std::tuple(!ret.empty(), ret.empty() ? gcode_line : ret, (extra_lines_count == 0) ? extra_lines_count : extra_lines_count - 1);
if (! ret.empty())
// Not moving the move operator on purpose, so that the gcode_line allocation will grow and it will not be reallocated after handful of lines are processed.
gcode_line = ret;
return std::tuple(!ret.empty(), (extra_lines_count == 0) ? extra_lines_count : extra_lines_count - 1);
};
// check for temporary lines
@ -476,11 +496,19 @@ void GCodeProcessor::TimeProcessor::post_process(const std::string& filename, st
g1_times_cache_it.emplace_back(machine.g1_times_cache.begin());
// add lines M73 to exported gcode
auto process_line_G1 = [&]() {
auto process_line_G1 = [
// Lambdas, mostly for string formatting, all with an empty capture block.
time_in_minutes, format_time_float, format_line_M73_main, format_line_M73_stop_int, format_line_M73_stop_float, time_in_last_minute,
&self = std::as_const(*this),
// Caches, to be modified
&g1_times_cache_it, &last_exported_main, &last_exported_stop,
// String output
&export_line]
(const size_t g1_lines_counter) {
unsigned int exported_lines_count = 0;
if (export_remaining_time_enabled) {
if (self.export_remaining_time_enabled) {
for (size_t i = 0; i < static_cast<size_t>(PrintEstimatedStatistics::ETimeMode::Count); ++i) {
const TimeMachine& machine = machines[i];
const TimeMachine& machine = self.machines[i];
if (machine.enabled) {
// export pair <percent, remaining time>
// Skip all machine.g1_times_cache below g1_lines_counter.
@ -544,60 +572,81 @@ void GCodeProcessor::TimeProcessor::post_process(const std::string& filename, st
};
// helper function to write to disk
auto write_string = [&](const std::string& str) {
fwrite((const void*)export_line.c_str(), 1, export_line.length(), out);
if (ferror(out)) {
in.close();
fclose(out);
size_t out_file_pos = 0;
lines_ends.clear();
auto write_string = [&export_line, &out, &out_path, &out_file_pos, &lines_ends](const std::string& str) {
fwrite((const void*)export_line.c_str(), 1, export_line.length(), out.f);
if (ferror(out.f)) {
out.close();
boost::nowide::remove(out_path.c_str());
throw Slic3r::RuntimeError(std::string("Time estimator post process export failed.\nIs the disk full?\n"));
}
for (size_t i = 0; i < export_line.size(); ++ i)
if (export_line[i] == '\n')
lines_ends.emplace_back(out_file_pos + i + 1);
out_file_pos += export_line.size();
export_line.clear();
};
unsigned int line_id = 0;
std::vector<std::pair<unsigned int, unsigned int>> offsets;
while (std::getline(in, gcode_line)) {
if (!in.good()) {
fclose(out);
throw Slic3r::RuntimeError(std::string("Time estimator post process export failed.\nError while reading from file.\n"));
}
{
// Read the input stream 64kB at a time, extract lines and process them.
std::vector<char> buffer(65536 * 10, 0);
// Line buffer.
assert(gcode_line.empty());
for (;;) {
size_t cnt_read = ::fread(buffer.data(), 1, buffer.size(), in.f);
if (::ferror(in.f))
throw Slic3r::RuntimeError(std::string("Time estimator post process export failed.\nError while reading from file.\n"));
bool eof = cnt_read == 0;
auto it = buffer.begin();
auto it_bufend = buffer.begin() + cnt_read;
while (it != it_bufend || (eof && ! gcode_line.empty())) {
// Find end of line.
bool eol = false;
auto it_end = it;
for (; it_end != it_bufend && ! (eol = *it_end == '\r' || *it_end == '\n'); ++ it_end) ;
// End of line is indicated also if end of file was reached.
eol |= eof && it_end == it_bufend;
gcode_line.insert(gcode_line.end(), it, it_end);
if (eol) {
++line_id;
++line_id;
gcode_line += "\n";
// replace placeholder lines
auto [processed, result, lines_added_count] = process_placeholders(gcode_line);
if (processed && lines_added_count > 0)
offsets.push_back({ line_id, lines_added_count });
gcode_line = result;
if (!processed) {
// remove temporary lines
if (is_temporary_decoration(gcode_line))
continue;
// add lines M73 where needed
parser.parse_line(gcode_line,
[&](GCodeReader& reader, const GCodeReader::GCodeLine& line) {
if (line.cmd_is("G1")) {
unsigned int extra_lines_count = process_line_G1();
++g1_lines_counter;
gcode_line += "\n";
// replace placeholder lines
auto [processed, lines_added_count] = process_placeholders(gcode_line);
if (processed && lines_added_count > 0)
offsets.push_back({ line_id, lines_added_count });
if (! processed && ! is_temporary_decoration(gcode_line) && GCodeReader::GCodeLine::cmd_is(gcode_line, "G1")) {
// remove temporary lines, add lines M73 where needed
unsigned int extra_lines_count = process_line_G1(g1_lines_counter ++);
if (extra_lines_count > 0)
offsets.push_back({ line_id, extra_lines_count });
}
});
}
export_line += gcode_line;
if (export_line.length() > 65535)
write_string(export_line);
export_line += gcode_line;
if (export_line.length() > 65535)
write_string(export_line);
gcode_line.clear();
}
// Skip EOL.
it = it_end;
if (it != it_bufend && *it == '\r')
++ it;
if (it != it_bufend && *it == '\n')
++ it;
}
if (eof)
break;
}
}
if (!export_line.empty())
write_string(export_line);
fclose(out);
out.close();
in.close();
// updates moves' gcode ids which have been modified by the insertion of the M73 lines
@ -698,7 +747,9 @@ void GCodeProcessor::Result::reset() {
}
#else
void GCodeProcessor::Result::reset() {
moves = std::vector<GCodeProcessor::MoveVertex>();
moves.clear();
lines_ends.clear();
bed_shape = Pointfs();
settings_ids.reset();
extruders_count = 0;
@ -777,6 +828,9 @@ bool GCodeProcessor::contains_reserved_tags(const std::string& gcode, unsigned i
}
GCodeProcessor::GCodeProcessor()
#if ENABLE_FIX_PREVIEW_OPTIONS_Z
: m_options_z_corrector(m_result)
#endif // ENABLE_FIX_PREVIEW_OPTIONS_Z
{
reset();
m_time_processor.machines[static_cast<size_t>(PrintEstimatedStatistics::ETimeMode::Normal)].line_m73_main_mask = "M73 P%s R%s\n";
@ -951,10 +1005,9 @@ void GCodeProcessor::apply_config(const DynamicPrintConfig& config)
}
// replace missing values with default
std::string default_color = "#FF8000";
for (size_t i = 0; i < m_result.extruder_colors.size(); ++i) {
if (m_result.extruder_colors[i].empty())
m_result.extruder_colors[i] = default_color;
m_result.extruder_colors[i] = "#FF8000";
}
m_extruder_colors.resize(m_result.extruder_colors.size());
@ -1139,7 +1192,6 @@ void GCodeProcessor::reset()
m_cp_color.reset();
m_producer = EProducer::Unknown;
m_producers_enabled = false;
m_time_processor.reset();
m_used_filaments.reset();
@ -1152,6 +1204,10 @@ void GCodeProcessor::reset()
m_last_default_color_id = 0;
#endif // ENABLE_FIX_IMPORTING_COLOR_PRINT_VIEW_INTO_GCODEVIEWER
#if ENABLE_FIX_PREVIEW_OPTIONS_Z
m_options_z_corrector.reset();
#endif // ENABLE_FIX_PREVIEW_OPTIONS_Z
#if ENABLE_GCODE_VIEWER_DATA_CHECKING
m_mm3_per_mm_compare.reset();
m_height_compare.reset();
@ -1159,27 +1215,26 @@ void GCodeProcessor::reset()
#endif // ENABLE_GCODE_VIEWER_DATA_CHECKING
}
void GCodeProcessor::process_file(const std::string& filename, bool apply_postprocess, std::function<void()> cancel_callback)
void GCodeProcessor::process_file(const std::string& filename, std::function<void()> cancel_callback)
{
auto last_cancel_callback_time = std::chrono::high_resolution_clock::now();
CNumericLocalesSetter locales_setter;
#if ENABLE_GCODE_VIEWER_STATISTICS
auto start_time = std::chrono::high_resolution_clock::now();
m_start_time = std::chrono::high_resolution_clock::now();
#endif // ENABLE_GCODE_VIEWER_STATISTICS
// pre-processing
// parse the gcode file to detect its producer
if (m_producers_enabled) {
{
m_parser.parse_file(filename, [this](GCodeReader& reader, const GCodeReader::GCodeLine& line) {
const std::string_view cmd = line.cmd();
if (cmd.length() == 0) {
if (cmd.empty()) {
const std::string_view comment = line.comment();
if (comment.length() > 1 && detect_producer(comment))
m_parser.quit_parsing();
}
});
m_parser.reset();
// if the gcode was produced by PrusaSlicer,
// extract the config from it
@ -1201,18 +1256,45 @@ void GCodeProcessor::process_file(const std::string& filename, bool apply_postpr
m_result.id = ++s_result_id;
// 1st move must be a dummy move
m_result.moves.emplace_back(MoveVertex());
m_parser.parse_file(filename, [this, cancel_callback, &last_cancel_callback_time](GCodeReader& reader, const GCodeReader::GCodeLine& line) {
if (cancel_callback != nullptr) {
// call the cancel callback every 100 ms
auto curr_time = std::chrono::high_resolution_clock::now();
if (std::chrono::duration_cast<std::chrono::milliseconds>(curr_time - last_cancel_callback_time).count() > 100) {
size_t parse_line_callback_cntr = 10000;
m_parser.parse_file(filename, [this, cancel_callback, &parse_line_callback_cntr](GCodeReader& reader, const GCodeReader::GCodeLine& line) {
if (-- parse_line_callback_cntr == 0) {
// Don't call the cancel_callback() too often, do it every at every 10000'th line.
parse_line_callback_cntr = 10000;
if (cancel_callback)
cancel_callback();
last_cancel_callback_time = curr_time;
}
}
process_gcode_line(line);
});
this->process_gcode_line(line, true);
});
this->finalize();
}
void GCodeProcessor::initialize(const std::string& filename)
{
assert(is_decimal_separator_point());
#if ENABLE_GCODE_VIEWER_STATISTICS
m_start_time = std::chrono::high_resolution_clock::now();
#endif // ENABLE_GCODE_VIEWER_STATISTICS
// process gcode
m_result.filename = filename;
m_result.id = ++s_result_id;
// 1st move must be a dummy move
m_result.moves.emplace_back(MoveVertex());
}
void GCodeProcessor::process_buffer(const std::string &buffer)
{
//FIXME maybe cache GCodeLine gline to be over multiple parse_buffer() invocations.
m_parser.parse_buffer(buffer, [this](GCodeReader&, const GCodeReader::GCodeLine& line) {
this->process_gcode_line(line, false);
});
}
void GCodeProcessor::finalize()
{
// update width/height of wipe moves
for (MoveVertex& move : m_result.moves) {
if (move.type == EMoveType::Wipe) {
@ -1234,10 +1316,6 @@ void GCodeProcessor::process_file(const std::string& filename, bool apply_postpr
update_estimated_times_stats();
// post-process to add M73 lines into the gcode
if (apply_postprocess)
m_time_processor.post_process(filename, m_result.moves);
#if ENABLE_GCODE_VIEWER_DATA_CHECKING
std::cout << "\n";
m_mm3_per_mm_compare.output();
@ -1245,8 +1323,9 @@ void GCodeProcessor::process_file(const std::string& filename, bool apply_postpr
m_width_compare.output();
#endif // ENABLE_GCODE_VIEWER_DATA_CHECKING
m_time_processor.post_process(m_result.filename, m_result.moves, m_result.lines_ends);
#if ENABLE_GCODE_VIEWER_STATISTICS
m_result.time = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::high_resolution_clock::now() - start_time).count();
m_result.time = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::high_resolution_clock::now() - m_start_time).count();
#endif // ENABLE_GCODE_VIEWER_STATISTICS
}
@ -1340,7 +1419,7 @@ void GCodeProcessor::apply_config_simplify3d(const std::string& filename)
if (pos != cmt.npos) {
std::string data_str = cmt.substr(pos + 1);
std::vector<std::string> values_str;
boost::split(values_str, data_str, boost::is_any_of("|"), boost::token_compress_on);
boost::split(values_str, data_str, boost::is_any_of("|,"), boost::token_compress_on);
for (const std::string& s : values_str) {
out.emplace_back(static_cast<float>(string_to_double_decimal_point(s)));
}
@ -1364,10 +1443,16 @@ void GCodeProcessor::apply_config_simplify3d(const std::string& filename)
m_result.filament_densities.clear();
extract_floats(comment, "filamentDensities", m_result.filament_densities);
}
else if (comment.find("extruderDiameter") != comment.npos) {
std::vector<float> extruder_diameters;
extract_floats(comment, "extruderDiameter", extruder_diameters);
m_result.extruders_count = extruder_diameters.size();
}
}
});
m_result.extruders_count = std::max<size_t>(1, std::min(m_result.filament_diameters.size(), m_result.filament_densities.size()));
if (m_result.extruders_count == 0)
m_result.extruders_count = std::max<size_t>(1, std::min(m_result.filament_diameters.size(), m_result.filament_densities.size()));
if (bed_size.is_defined()) {
m_result.bed_shape = {
@ -1379,7 +1464,7 @@ void GCodeProcessor::apply_config_simplify3d(const std::string& filename)
}
}
void GCodeProcessor::process_gcode_line(const GCodeReader::GCodeLine& line)
void GCodeProcessor::process_gcode_line(const GCodeReader::GCodeLine& line, bool producers_enabled)
{
/* std::cout << line.raw() << std::endl; */
@ -1391,61 +1476,170 @@ void GCodeProcessor::process_gcode_line(const GCodeReader::GCodeLine& line)
const std::string_view cmd = line.cmd();
if (cmd.length() > 1) {
// process command lines
switch (::toupper(cmd[0]))
switch (cmd[0])
{
case 'g':
case 'G':
{
switch (::atoi(&cmd[1]))
{
case 0: { process_G0(line); break; } // Move
case 1: { process_G1(line); break; } // Move
case 10: { process_G10(line); break; } // Retract
case 11: { process_G11(line); break; } // Unretract
case 20: { process_G20(line); break; } // Set Units to Inches
case 21: { process_G21(line); break; } // Set Units to Millimeters
case 22: { process_G22(line); break; } // Firmware controlled retract
case 23: { process_G23(line); break; } // Firmware controlled unretract
case 28: { process_G28(line); break; } // Move to origin
case 90: { process_G90(line); break; } // Set to Absolute Positioning
case 91: { process_G91(line); break; } // Set to Relative Positioning
case 92: { process_G92(line); break; } // Set Position
default: { break; }
switch (cmd.size()) {
case 2:
switch (cmd[1]) {
case '0': { process_G0(line); break; } // Move
case '1': { process_G1(line); break; } // Move
default: break;
}
break;
case 3:
switch (cmd[1]) {
case '1':
switch (cmd[2]) {
case '0': { process_G10(line); break; } // Retract
case '1': { process_G11(line); break; } // Unretract
default: break;
}
break;
case '2':
switch (cmd[2]) {
case '0': { process_G20(line); break; } // Set Units to Inches
case '1': { process_G21(line); break; } // Set Units to Millimeters
case '2': { process_G22(line); break; } // Firmware controlled retract
case '3': { process_G23(line); break; } // Firmware controlled unretract
case '8': { process_G28(line); break; } // Move to origin
default: break;
}
break;
case '9':
switch (cmd[2]) {
case '0': { process_G90(line); break; } // Set to Absolute Positioning
case '1': { process_G91(line); break; } // Set to Relative Positioning
case '2': { process_G92(line); break; } // Set Position
default: break;
}
break;
}
break;
default:
break;
}
break;
case 'm':
case 'M':
{
switch (::atoi(&cmd[1]))
{
case 1: { process_M1(line); break; } // Sleep or Conditional stop
case 82: { process_M82(line); break; } // Set extruder to absolute mode
case 83: { process_M83(line); break; } // Set extruder to relative mode
case 104: { process_M104(line); break; } // Set extruder temperature
case 106: { process_M106(line); break; } // Set fan speed
case 107: { process_M107(line); break; } // Disable fan
case 108: { process_M108(line); break; } // Set tool (Sailfish)
case 109: { process_M109(line); break; } // Set extruder temperature and wait
case 132: { process_M132(line); break; } // Recall stored home offsets
case 135: { process_M135(line); break; } // Set tool (MakerWare)
case 201: { process_M201(line); break; } // Set max printing acceleration
case 203: { process_M203(line); break; } // Set maximum feedrate
case 204: { process_M204(line); break; } // Set default acceleration
case 205: { process_M205(line); break; } // Advanced settings
case 221: { process_M221(line); break; } // Set extrude factor override percentage
case 401: { process_M401(line); break; } // Repetier: Store x, y and z position
case 402: { process_M402(line); break; } // Repetier: Go to stored position
case 566: { process_M566(line); break; } // Set allowable instantaneous speed change
case 702: { process_M702(line); break; } // Unload the current filament into the MK3 MMU2 unit at the end of print.
default: { break; }
switch (cmd.size()) {
case 2:
switch (cmd[1]) {
case '1': { process_M1(line); break; } // Sleep or Conditional stop
default: break;
}
break;
}
case 'T':
{
process_T(line); // Select Tool
case 3:
switch (cmd[1]) {
case '8':
switch (cmd[2]) {
case '2': { process_M82(line); break; } // Set extruder to absolute mode
case '3': { process_M83(line); break; } // Set extruder to relative mode
default: break;
}
break;
default:
break;
}
break;
case 4:
switch (cmd[1]) {
case '1':
switch (cmd[2]) {
case '0':
switch (cmd[3]) {
case '4': { process_M104(line); break; } // Set extruder temperature
case '6': { process_M106(line); break; } // Set fan speed
case '7': { process_M107(line); break; } // Disable fan
case '8': { process_M108(line); break; } // Set tool (Sailfish)
case '9': { process_M109(line); break; } // Set extruder temperature and wait
default: break;
}
break;
case '3':
switch (cmd[3]) {
case '2': { process_M132(line); break; } // Recall stored home offsets
case '5': { process_M135(line); break; } // Set tool (MakerWare)
default: break;
}
break;
default:
break;
}
break;
case '2':
switch (cmd[2]) {
case '0':
switch (cmd[3]) {
case '1': { process_M201(line); break; } // Set max printing acceleration
case '3': { process_M203(line); break; } // Set maximum feedrate
case '4': { process_M204(line); break; } // Set default acceleration
case '5': { process_M205(line); break; } // Advanced settings
default: break;
}
break;
case '2':
switch (cmd[3]) {
case '1': { process_M221(line); break; } // Set extrude factor override percentage
default: break;
}
break;
default:
break;
}
break;
case '4':
switch (cmd[2]) {
case '0':
switch (cmd[3]) {
case '1': { process_M401(line); break; } // Repetier: Store x, y and z position
case '2': { process_M402(line); break; } // Repetier: Go to stored position
default: break;
}
break;
default:
break;
}
break;
case '5':
switch (cmd[2]) {
case '6':
switch (cmd[3]) {
case '6': { process_M566(line); break; } // Set allowable instantaneous speed change
default: break;
}
break;
default:
break;
}
break;
case '7':
switch (cmd[2]) {
case '0':
switch (cmd[3]) {
case '2': { process_M702(line); break; } // Unload the current filament into the MK3 MMU2 unit at the end of print.
default: break;
}
break;
default:
break;
}
break;
default:
break;
}
break;
default:
break;
}
default: { break; }
break;
case 't':
case 'T':
process_T(line); // Select Tool
break;
default:
break;
}
}
else {
@ -1453,7 +1647,7 @@ void GCodeProcessor::process_gcode_line(const GCodeReader::GCodeLine& line)
if (comment.length() > 2 && comment.front() == ';')
// Process tags embedded into comments. Tag comments always start at the start of a line
// with a comment and continue with a tag without any whitespace separator.
process_tags(comment.substr(1));
process_tags(comment.substr(1), producers_enabled);
}
}
@ -1502,10 +1696,10 @@ template<typename T>
}
}
void GCodeProcessor::process_tags(const std::string_view comment)
void GCodeProcessor::process_tags(const std::string_view comment, bool producers_enabled)
{
// producers tags
if (m_producers_enabled && process_producers_tags(comment))
if (producers_enabled && process_producers_tags(comment))
return;
// extrusion role tag
@ -1529,7 +1723,7 @@ void GCodeProcessor::process_tags(const std::string_view comment)
return;
}
if (!m_producers_enabled || m_producer == EProducer::PrusaSlicer) {
if (!producers_enabled || m_producer == EProducer::PrusaSlicer) {
// height tag
if (boost::starts_with(comment, reserved_tag(ETags::Height))) {
if (!parse_number(comment.substr(reserved_tag(ETags::Height).size()), m_forced_height))
@ -1619,6 +1813,9 @@ void GCodeProcessor::process_tags(const std::string_view comment)
#if ENABLE_FIX_IMPORTING_COLOR_PRINT_VIEW_INTO_GCODEVIEWER
CustomGCode::Item item = { static_cast<double>(m_end_position[2]), CustomGCode::ColorChange, extruder_id + 1, color, "" };
m_result.custom_gcode_per_print_z.emplace_back(item);
#if ENABLE_FIX_PREVIEW_OPTIONS_Z
m_options_z_corrector.set();
#endif // ENABLE_FIX_PREVIEW_OPTIONS_Z
process_custom_gcode_time(CustomGCode::ColorChange);
process_filaments(CustomGCode::ColorChange);
#endif // ENABLE_FIX_IMPORTING_COLOR_PRINT_VIEW_INTO_GCODEVIEWER
@ -1638,6 +1835,9 @@ void GCodeProcessor::process_tags(const std::string_view comment)
#if ENABLE_FIX_IMPORTING_COLOR_PRINT_VIEW_INTO_GCODEVIEWER
CustomGCode::Item item = { static_cast<double>(m_end_position[2]), CustomGCode::PausePrint, m_extruder_id + 1, "", "" };
m_result.custom_gcode_per_print_z.emplace_back(item);
#if ENABLE_FIX_PREVIEW_OPTIONS_Z
m_options_z_corrector.set();
#endif // ENABLE_FIX_PREVIEW_OPTIONS_Z
#endif // ENABLE_FIX_IMPORTING_COLOR_PRINT_VIEW_INTO_GCODEVIEWER
process_custom_gcode_time(CustomGCode::PausePrint);
return;
@ -1649,6 +1849,9 @@ void GCodeProcessor::process_tags(const std::string_view comment)
#if ENABLE_FIX_IMPORTING_COLOR_PRINT_VIEW_INTO_GCODEVIEWER
CustomGCode::Item item = { static_cast<double>(m_end_position[2]), CustomGCode::Custom, m_extruder_id + 1, "", "" };
m_result.custom_gcode_per_print_z.emplace_back(item);
#if ENABLE_FIX_PREVIEW_OPTIONS_Z
m_options_z_corrector.set();
#endif // ENABLE_FIX_PREVIEW_OPTIONS_Z
#endif // ENABLE_FIX_IMPORTING_COLOR_PRINT_VIEW_INTO_GCODEVIEWER
return;
}
@ -2210,9 +2413,6 @@ void GCodeProcessor::process_G1(const GCodeReader::GCodeLine& line)
return;
EMoveType type = move_type(delta_pos);
if (type == EMoveType::Extrude && m_end_position[Z] == 0.0f)
type = EMoveType::Travel;
if (type == EMoveType::Extrude) {
float delta_xyz = std::sqrt(sqr(delta_pos[X]) + sqr(delta_pos[Y]) + sqr(delta_pos[Z]));
float volume_extruded_filament = area_filament_cross_section * delta_pos[E];
@ -2232,10 +2432,23 @@ void GCodeProcessor::process_G1(const GCodeReader::GCodeLine& line)
else {
if (m_end_position[Z] > m_extruded_last_z + EPSILON) {
m_height = m_end_position[Z] - m_extruded_last_z;
#if !ENABLE_FIX_PREVIEW_OPTIONS_Z
m_extruded_last_z = m_end_position[Z];
#endif // !ENABLE_FIX_PREVIEW_OPTIONS_Z
}
}
if (m_height == 0.0f)
m_height = DEFAULT_TOOLPATH_HEIGHT;
if (m_end_position[Z] == 0.0f)
m_end_position[Z] = m_height;
#if ENABLE_FIX_PREVIEW_OPTIONS_Z
m_extruded_last_z = m_end_position[Z];
m_options_z_corrector.update(m_height);
#endif // ENABLE_FIX_PREVIEW_OPTIONS_Z
#if ENABLE_GCODE_VIEWER_DATA_CHECKING
m_height_compare.update(m_height, m_extrusion_role);
#endif // ENABLE_GCODE_VIEWER_DATA_CHECKING
@ -2252,23 +2465,17 @@ void GCodeProcessor::process_G1(const GCodeReader::GCodeLine& line)
// cross section: rectangle + 2 semicircles
m_width = delta_pos[E] * static_cast<float>(M_PI * sqr(filament_radius)) / (delta_xyz * m_height) + static_cast<float>(1.0 - 0.25 * M_PI) * m_height;
#if ENABLE_CLAMP_TOOLPATHS_WIDTH
if (m_producers_enabled && m_producer != EProducer::PrusaSlicer)
// clamp width to avoid artifacts which may arise from wrong values of m_height
m_width = std::min(m_width, std::max(1.0f, 4.0f * m_height));
#else
if (m_width == 0.0f)
m_width = DEFAULT_TOOLPATH_WIDTH;
// clamp width to avoid artifacts which may arise from wrong values of m_height
m_width = std::min(m_width, std::max(1.0f, 4.0f * m_height));
#endif // ENABLE_CLAMP_TOOLPATHS_WIDTH
m_width = std::min(m_width, std::max(2.0f, 4.0f * m_height));
#if ENABLE_GCODE_VIEWER_DATA_CHECKING
m_width_compare.update(m_width, m_extrusion_role);
#endif // ENABLE_GCODE_VIEWER_DATA_CHECKING
}
if (type == EMoveType::Extrude && (m_width == 0.0f || m_height == 0.0f))
type = EMoveType::Travel;
// time estimate section
auto move_length = [](const AxisCoords& delta_pos) {
float sq_xyz_length = sqr(delta_pos[X]) + sqr(delta_pos[Y]) + sqr(delta_pos[Z]);

View File

@ -306,7 +306,7 @@ namespace Slic3r {
// post process the file with the given filename to add remaining time lines M73
// and updates moves' gcode ids accordingly
void post_process(const std::string& filename, std::vector<MoveVertex>& moves);
void post_process(const std::string& filename, std::vector<MoveVertex>& moves, std::vector<size_t>& lines_ends);
};
struct UsedFilaments // filaments per ColorChange
@ -350,6 +350,8 @@ namespace Slic3r {
std::string filename;
unsigned int id;
std::vector<MoveVertex> moves;
// Positions of ends of lines of the final G-code this->filename after TimeProcessor::post_process() finalizes the G-code.
std::vector<size_t> lines_ends;
Pointfs bed_shape;
SettingsIds settings_ids;
size_t extruders_count;
@ -388,6 +390,45 @@ namespace Slic3r {
bool has_first_vertex() const { return m_first_vertex.has_value(); }
};
#if ENABLE_FIX_PREVIEW_OPTIONS_Z
// Helper class used to fix the z for color change, pause print and
// custom gcode markes
class OptionsZCorrector
{
Result& m_result;
std::optional<size_t> m_move_id;
std::optional<size_t> m_custom_gcode_per_print_z_id;
public:
explicit OptionsZCorrector(Result& result) : m_result(result) {
}
void set() {
m_move_id = m_result.moves.size() - 1;
m_custom_gcode_per_print_z_id = m_result.custom_gcode_per_print_z.size() - 1;
}
void update(float height) {
if (!m_move_id.has_value() || !m_custom_gcode_per_print_z_id.has_value())
return;
const Vec3f position = m_result.moves.back().position;
MoveVertex& move = m_result.moves.emplace_back(m_result.moves[*m_move_id]);
move.position = position;
move.height = height;
m_result.moves.erase(m_result.moves.begin() + *m_move_id);
m_result.custom_gcode_per_print_z[*m_custom_gcode_per_print_z_id].print_z = position.z();
reset();
}
void reset() {
m_move_id.reset();
m_custom_gcode_per_print_z_id.reset();
}
};
#endif // ENABLE_FIX_PREVIEW_OPTIONS_Z
#if ENABLE_GCODE_VIEWER_DATA_CHECKING
struct DataChecker
{
@ -492,9 +533,15 @@ namespace Slic3r {
CpColor m_cp_color;
bool m_use_volumetric_e;
SeamsDetector m_seams_detector;
#if ENABLE_FIX_PREVIEW_OPTIONS_Z
OptionsZCorrector m_options_z_corrector;
#endif // ENABLE_FIX_PREVIEW_OPTIONS_Z
#if ENABLE_FIX_IMPORTING_COLOR_PRINT_VIEW_INTO_GCODEVIEWER
size_t m_last_default_color_id;
#endif // ENABLE_FIX_IMPORTING_COLOR_PRINT_VIEW_INTO_GCODEVIEWER
#if ENABLE_GCODE_VIEWER_STATISTICS
std::chrono::time_point<std::chrono::high_resolution_clock> m_start_time;
#endif // ENABLE_GCODE_VIEWER_STATISTICS
enum class EProducer
{
@ -511,7 +558,6 @@ namespace Slic3r {
static const std::vector<std::pair<GCodeProcessor::EProducer, std::string>> Producers;
EProducer m_producer;
bool m_producers_enabled;
TimeProcessor m_time_processor;
UsedFilaments m_used_filaments;
@ -534,7 +580,6 @@ namespace Slic3r {
return m_time_processor.machines[static_cast<size_t>(PrintEstimatedStatistics::ETimeMode::Stealth)].enabled;
}
void enable_machine_envelope_processing(bool enabled) { m_time_processor.machine_envelope_processing_enabled = enabled; }
void enable_producers(bool enabled) { m_producers_enabled = enabled; }
void reset();
const Result& get_result() const { return m_result; }
@ -542,7 +587,12 @@ namespace Slic3r {
// Process the gcode contained in the file with the given filename
// throws CanceledException through print->throw_if_canceled() (sent by the caller as callback).
void process_file(const std::string& filename, bool apply_postprocess, std::function<void()> cancel_callback = nullptr);
void process_file(const std::string& filename, std::function<void()> cancel_callback = nullptr);
// Streaming interface, for processing G-codes just generated by PrusaSlicer in a pipelined fashion.
void initialize(const std::string& filename);
void process_buffer(const std::string& buffer);
void finalize();
float get_time(PrintEstimatedStatistics::ETimeMode mode) const;
std::string get_time_dhm(PrintEstimatedStatistics::ETimeMode mode) const;
@ -555,10 +605,10 @@ namespace Slic3r {
private:
void apply_config(const DynamicPrintConfig& config);
void apply_config_simplify3d(const std::string& filename);
void process_gcode_line(const GCodeReader::GCodeLine& line);
void process_gcode_line(const GCodeReader::GCodeLine& line, bool producers_enabled);
// Process tags embedded into comments
void process_tags(const std::string_view comment);
void process_tags(const std::string_view comment, bool producers_enabled);
bool process_producers_tags(const std::string_view comment);
bool process_prusaslicer_tags(const std::string_view comment);
bool process_cura_tags(const std::string_view comment);

View File

@ -71,9 +71,16 @@ const char* GCodeReader::parse_line_internal(const char *ptr, const char *end, G
}
if (axis != NUM_AXES_WITH_UNKNOWN) {
// Try to parse the numeric value.
#ifdef WIN32
double v;
auto [pend, ec] = std::from_chars(++ c, end, v);
if (pend != c && is_end_of_word(*pend)) {
#else
// The older version of GCC and Clang support std::from_chars just for integers, so strtod we used it instead.
char *pend = nullptr;
double v = strtod(++ c, &pend);
if (pend != nullptr && is_end_of_word(*pend)) {
#endif
// The axis value has been parsed correctly.
if (axis != UNKNOWN_AXIS)
gline.m_axis[int(axis)] = float(v);
@ -126,7 +133,7 @@ void GCodeReader::update_coordinates(GCodeLine &gline, std::pair<const char*, co
}
}
void GCodeReader::parse_file(const std::string &file, callback_t callback)
bool GCodeReader::parse_file(const std::string &file, callback_t callback)
{
boost::nowide::ifstream f(file);
f.sync_with_stdio(false);
@ -134,17 +141,18 @@ void GCodeReader::parse_file(const std::string &file, callback_t callback)
std::string line;
m_parsing = true;
GCodeLine gline;
bool eof = false;
while (m_parsing && ! eof) {
while (m_parsing && ! f.eof()) {
f.read(buffer.data(), buffer.size());
if (! f.eof() && ! f.good())
// Reading the input file failed.
return false;
auto it = buffer.begin();
auto it_bufend = buffer.begin() + f.gcount();
eof = ! f.good();
while (it != it_bufend) {
bool eol = false;
auto it_end = it;
for (; it_end != it_bufend && ! (eol = *it_end == '\r' || *it_end == '\n'); ++ it_end) ;
eol |= eof && it_end == it_bufend;
eol |= f.eof() && it_end == it_bufend;
if (eol) {
gline.reset();
if (line.empty())
@ -160,6 +168,7 @@ void GCodeReader::parse_file(const std::string &file, callback_t callback)
for (it = it_end; it != it_bufend && (*it == '\r' || *it == '\n'); ++ it) ;
}
}
return true;
}
bool GCodeReader::GCodeLine::has(char axis) const

View File

@ -44,11 +44,7 @@ public:
float y = this->has(Y) ? (this->y() - reader.y()) : 0;
return sqrt(x*x + y*y);
}
bool cmd_is(const char *cmd_test) const {
const char *cmd = GCodeReader::skip_whitespaces(m_raw.c_str());
size_t len = strlen(cmd_test);
return strncmp(cmd, cmd_test, len) == 0 && GCodeReader::is_end_of_word(cmd[len]);
}
bool cmd_is(const char *cmd_test) const { return cmd_is(m_raw, cmd_test); }
bool extruding(const GCodeReader &reader) const { return this->cmd_is("G1") && this->dist_E(reader) > 0; }
bool retracting(const GCodeReader &reader) const { return this->cmd_is("G1") && this->dist_E(reader) < 0; }
bool travel() const { return this->cmd_is("G1") && ! this->has(E); }
@ -66,6 +62,12 @@ public:
float e() const { return m_axis[E]; }
float f() const { return m_axis[F]; }
static bool cmd_is(const std::string &gcode_line, const char *cmd_test) {
const char *cmd = GCodeReader::skip_whitespaces(gcode_line.c_str());
size_t len = strlen(cmd_test);
return strncmp(cmd, cmd_test, len) == 0 && GCodeReader::is_end_of_word(cmd[len]);
}
private:
std::string m_raw;
float m_axis[NUM_AXES];
@ -75,7 +77,8 @@ public:
typedef std::function<void(GCodeReader&, const GCodeLine&)> callback_t;
GCodeReader() : m_verbose(false), m_extrusion_axis('E') { memset(m_position, 0, sizeof(m_position)); }
GCodeReader() : m_verbose(false), m_extrusion_axis('E') { this->reset(); }
void reset() { memset(m_position, 0, sizeof(m_position)); }
void apply_config(const GCodeConfig &config);
void apply_config(const DynamicPrintConfig &config);
@ -109,7 +112,8 @@ public:
void parse_line(const std::string &line, Callback callback)
{ GCodeLine gline; this->parse_line(line.c_str(), line.c_str() + line.size(), gline, callback); }
void parse_file(const std::string &file, callback_t callback);
// Returns false if reading the file failed.
bool parse_file(const std::string &file, callback_t callback);
void quit_parsing() { m_parsing = false; }
float& x() { return m_position[X]; }

View File

@ -309,7 +309,16 @@ public:
void emit_axis(const char axis, const double v, size_t digits) {
*ptr_err.ptr ++ = ' '; *ptr_err.ptr ++ = axis;
#ifdef WIN32
this->ptr_err = std::to_chars(this->ptr_err.ptr, this->buf_end, v, std::chars_format::fixed, digits);
#else
int buf_capacity = int(this->buf_end - this->ptr_err.ptr);
int ret = snprintf(this->ptr_err.ptr, buf_capacity, "%.*lf", int(digits), v);
if (ret <= 0 || ret > buf_capacity)
ptr_err.ec = std::errc::value_too_large;
else
this->ptr_err.ptr = this->ptr_err.ptr + ret;
#endif
}
void emit_xy(const Vec2d &point) {

View File

@ -37,24 +37,24 @@
//====================
// 2.4.0.alpha0 techs
// 2.4.0.alpha1 techs
//====================
#define ENABLE_2_4_0_ALPHA0 1
#define ENABLE_2_4_0_ALPHA1 1
// Enable delayed rendering of transparent volumes
#define ENABLE_DELAYED_TRANSPARENT_VOLUMES_RENDERING (1 && ENABLE_2_4_0_ALPHA0)
#define ENABLE_DELAYED_TRANSPARENT_VOLUMES_RENDERING (1 && ENABLE_2_4_0_ALPHA1)
// Enable the fix of importing color print view from gcode files into GCodeViewer
#define ENABLE_FIX_IMPORTING_COLOR_PRINT_VIEW_INTO_GCODEVIEWER (1 && ENABLE_2_4_0_ALPHA0)
#define ENABLE_FIX_IMPORTING_COLOR_PRINT_VIEW_INTO_GCODEVIEWER (1 && ENABLE_2_4_0_ALPHA1)
// Enable drawing contours, at cut level, for sinking volumes
#define ENABLE_SINKING_CONTOURS (1 && ENABLE_2_4_0_ALPHA0)
#define ENABLE_SINKING_CONTOURS (1 && ENABLE_2_4_0_ALPHA1)
// Enable implementation of retract acceleration in gcode processor
#define ENABLE_RETRACT_ACCELERATION (1 && ENABLE_2_4_0_ALPHA0)
#define ENABLE_RETRACT_ACCELERATION (1 && ENABLE_2_4_0_ALPHA1)
// Enable the fix for exporting and importing to/from 3mf file of mirrored volumes
#define ENABLE_FIX_MIRRORED_VOLUMES_3MF_IMPORT_EXPORT (1 && ENABLE_2_4_0_ALPHA0)
#define ENABLE_FIX_MIRRORED_VOLUMES_3MF_IMPORT_EXPORT (1 && ENABLE_2_4_0_ALPHA1)
// Enable rendering seams (and other options) in preview using models
#define ENABLE_SEAMS_USING_MODELS (1 && ENABLE_2_4_0_ALPHA0)
#define ENABLE_SEAMS_USING_MODELS (1 && ENABLE_2_4_0_ALPHA1)
// Enable save and save as commands to be enabled also when the plater is empty and allow to load empty projects
#define ENABLE_SAVE_COMMANDS_ALWAYS_ENABLED (1 && ENABLE_2_4_0_ALPHA0)
#define ENABLE_SAVE_COMMANDS_ALWAYS_ENABLED (1 && ENABLE_2_4_0_ALPHA1)
//====================
@ -62,8 +62,10 @@
//====================
#define ENABLE_2_4_0_ALPHA2 1
// Enable clamping toolpaths width only for gcodes files produced by 3rd part softwares
#define ENABLE_CLAMP_TOOLPATHS_WIDTH (1 && ENABLE_2_4_0_ALPHA2)
// Enable rendering seams (and other options) in preview using batched models on systems not supporting OpenGL 3.3
#define ENABLE_SEAMS_USING_BATCHED_MODELS (1 && ENABLE_SEAMS_USING_MODELS && ENABLE_2_4_0_ALPHA2)
// Enable fixing the z position of color change, pause print and custom gcode markers in preview
#define ENABLE_FIX_PREVIEW_OPTIONS_Z (1 && ENABLE_SEAMS_USING_MODELS && ENABLE_FIX_IMPORTING_COLOR_PRINT_VIEW_INTO_GCODEVIEWER && ENABLE_2_4_0_ALPHA2)
// Enable coloring of toolpaths in preview by layer time
#define ENABLE_PREVIEW_LAYER_TIME (1 && ENABLE_2_4_0_ALPHA2)

View File

@ -984,16 +984,11 @@ std::string log_memory_info(bool ignore_loglevel)
} PROCESS_MEMORY_COUNTERS_EX, *PPROCESS_MEMORY_COUNTERS_EX;
#endif /* PROCESS_MEMORY_COUNTERS_EX */
HANDLE hProcess = ::OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, ::GetCurrentProcessId());
if (hProcess != nullptr) {
PROCESS_MEMORY_COUNTERS_EX pmc;
if (GetProcessMemoryInfo(hProcess, (PROCESS_MEMORY_COUNTERS*)&pmc, sizeof(pmc)))
out = " WorkingSet: " + format_memsize_MB(pmc.WorkingSetSize) + "; PrivateBytes: " + format_memsize_MB(pmc.PrivateUsage) + "; Pagefile(peak): " + format_memsize_MB(pmc.PagefileUsage) + "(" + format_memsize_MB(pmc.PeakPagefileUsage) + ")";
else
out += " Used memory: N/A";
CloseHandle(hProcess);
}
PROCESS_MEMORY_COUNTERS_EX pmc;
if (GetProcessMemoryInfo(GetCurrentProcess(), (PROCESS_MEMORY_COUNTERS*)&pmc, sizeof(pmc)))
out = " WorkingSet: " + format_memsize_MB(pmc.WorkingSetSize) + "; PrivateBytes: " + format_memsize_MB(pmc.PrivateUsage) + "; Pagefile(peak): " + format_memsize_MB(pmc.PagefileUsage) + "(" + format_memsize_MB(pmc.PeakPagefileUsage) + ")";
else
out += " Used memory: N/A";
#elif defined(__linux__) or defined(__APPLE__)
// Get current memory usage.
#ifdef __APPLE__

View File

@ -574,11 +574,8 @@ Print::ApplyStatus BackgroundSlicingProcess::apply(const Model &model, const Dyn
// Some FFF status was invalidated, and the G-code was not exported yet.
// Let the G-code preview UI know that the final G-code preview is not valid.
// In addition, this early memory deallocation reduces memory footprint.
if (m_gcode_result != nullptr) {
//FIXME calling platter from here is not a staple of a good architecture.
GUI::wxGetApp().plater()->stop_mapping_gcode_window();
if (m_gcode_result != nullptr)
m_gcode_result->reset();
}
}
return invalidated;
}

View File

@ -230,18 +230,21 @@ void Field::get_value_by_opt_type(wxString& str, const bool check_value/* = true
}
double val;
bool is_na_value = m_opt.nullable && str == na_value();
const char dec_sep = is_decimal_separator_point() ? '.' : ',';
const char dec_sep_alt = dec_sep == '.' ? ',' : '.';
// Replace the first incorrect separator in decimal number.
if (str.Replace(dec_sep_alt, dec_sep, false) != 0)
// Replace the first incorrect separator in decimal number,
// if this value doesn't "N/A" value in some language
// see https://github.com/prusa3d/PrusaSlicer/issues/6921
if (!is_na_value && str.Replace(dec_sep_alt, dec_sep, false) != 0)
set_value(str, false);
if (str == dec_sep)
val = 0.0;
else
{
if (m_opt.nullable && str == na_value())
if (is_na_value)
val = ConfigOptionFloatsNullable::nil_value();
else if (!str.ToDouble(&val))
{

View File

@ -284,45 +284,14 @@ void GCodeViewer::SequentialView::Marker::render() const
ImGui::PopStyleVar();
}
void GCodeViewer::SequentialView::GCodeWindow::load_gcode()
void GCodeViewer::SequentialView::GCodeWindow::load_gcode(const std::string& filename, const std::vector<size_t> &lines_ends)
{
if (m_filename.empty())
return;
assert(! m_file.is_open());
if (m_file.is_open())
return;
try
{
// generate mapping for accessing data in file by line number
boost::nowide::ifstream f(m_filename);
f.seekg(0, f.end);
uint64_t file_length = static_cast<uint64_t>(f.tellg());
f.seekg(0, f.beg);
std::string line;
uint64_t offset = 0;
while (std::getline(f, line)) {
uint64_t line_length = static_cast<uint64_t>(line.length());
m_lines_map.push_back({ offset, line_length });
offset += static_cast<uint64_t>(line_length) + 1;
}
if (offset != file_length) {
// if the final offset does not match with file length, lines are terminated with CR+LF
// so update all offsets accordingly
for (size_t i = 0; i < m_lines_map.size(); ++i) {
m_lines_map[i].first += static_cast<uint64_t>(i);
}
}
}
catch (...)
{
BOOST_LOG_TRIVIAL(error) << "Unable to load data from " << m_filename << ". Cannot show G-code window.";
reset();
return;
}
m_filename = filename;
m_lines_ends = std::move(lines_ends);
m_selected_line_id = 0;
m_last_lines_size = 0;
@ -345,7 +314,9 @@ void GCodeViewer::SequentialView::GCodeWindow::render(float top, float bottom, u
ret.reserve(end_id - start_id + 1);
for (uint64_t id = start_id; id <= end_id; ++id) {
// read line from file
std::string gline(m_file.data() + m_lines_map[id - 1].first, m_lines_map[id - 1].second);
const size_t start = id == 1 ? 0 : m_lines_ends[id - 2];
const size_t len = m_lines_ends[id - 1] - start;
std::string gline(m_file.data() + start, len);
std::string command;
std::string parameters;
@ -379,7 +350,7 @@ void GCodeViewer::SequentialView::GCodeWindow::render(float top, float bottom, u
static const ImVec4 PARAMETERS_COLOR = { 1.0f, 1.0f, 1.0f, 1.0f };
static const ImVec4 COMMENT_COLOR = { 0.7f, 0.7f, 0.7f, 1.0f };
if (!m_visible || m_filename.empty() || m_lines_map.empty() || curr_line_id == 0)
if (!m_visible || m_filename.empty() || m_lines_ends.empty() || curr_line_id == 0)
return;
// window height
@ -397,8 +368,8 @@ void GCodeViewer::SequentialView::GCodeWindow::render(float top, float bottom, u
const uint64_t half_lines_count = lines_count / 2;
uint64_t start_id = (curr_line_id >= half_lines_count) ? curr_line_id - half_lines_count : 0;
uint64_t end_id = start_id + lines_count - 1;
if (end_id >= static_cast<uint64_t>(m_lines_map.size())) {
end_id = static_cast<uint64_t>(m_lines_map.size()) - 1;
if (end_id >= static_cast<uint64_t>(m_lines_ends.size())) {
end_id = static_cast<uint64_t>(m_lines_ends.size()) - 1;
start_id = end_id - lines_count + 1;
}
@ -503,7 +474,7 @@ void GCodeViewer::SequentialView::render(float legend_height) const
}
const std::vector<GCodeViewer::Color> GCodeViewer::Extrusion_Role_Colors {{
{ 0.75f, 0.75f, 0.75f, 1.0f }, // erNone
{ 0.90f, 0.70f, 0.70f, 1.0f }, // erNone
{ 1.00f, 0.90f, 0.30f, 1.0f }, // erPerimeter
{ 1.00f, 0.49f, 0.22f, 1.0f }, // erExternalPerimeter
{ 0.12f, 0.12f, 1.00f, 1.0f }, // erOverhangPerimeter
@ -606,8 +577,7 @@ void GCodeViewer::load(const GCodeProcessor::Result& gcode_result, const Print&
// release gpu memory, if used
reset();
m_sequential_view.gcode_window.set_filename(gcode_result.filename);
m_sequential_view.gcode_window.load_gcode();
m_sequential_view.gcode_window.load_gcode(gcode_result.filename, gcode_result.lines_ends);
#if ENABLE_FIX_IMPORTING_COLOR_PRINT_VIEW_INTO_GCODEVIEWER
if (wxGetApp().is_gcode_viewer())
@ -695,8 +665,8 @@ void GCodeViewer::refresh(const GCodeProcessor::Result& gcode_result, const std:
// update tool colors
m_tool_colors = decode_colors(str_tool_colors);
// ensure at least one (default) color is defined
if (m_tool_colors.empty())
// ensure there are enough colors defined
while (m_tool_colors.size() < std::max(size_t(1), gcode_result.extruders_count))
m_tool_colors.push_back(decode_color("#FF8000"));
// update ranges for coloring / legend
@ -815,6 +785,25 @@ void GCodeViewer::render()
case EMoveType::Unretract:
case EMoveType::Seam: {
#if ENABLE_SEAMS_USING_MODELS
#if ENABLE_SEAMS_USING_BATCHED_MODELS
if (wxGetApp().is_gl_version_greater_or_equal_to(3, 3)) {
buffer.render_primitive_type = TBuffer::ERenderPrimitiveType::InstancedModel;
buffer.shader = "gouraud_light_instanced";
buffer.model.model.init_from(diamond(16));
buffer.model.color = option_color(type);
buffer.model.instances.format = InstanceVBuffer::EFormat::InstancedModel;
}
else {
buffer.render_primitive_type = TBuffer::ERenderPrimitiveType::BatchedModel;
buffer.vertices.format = VBuffer::EFormat::PositionNormal3;
buffer.shader = "gouraud_light";
buffer.model.data = diamond(16);
buffer.model.color = option_color(type);
buffer.model.instances.format = InstanceVBuffer::EFormat::BatchedModel;
}
break;
#else
if (wxGetApp().is_gl_version_greater_or_equal_to(3, 3)) {
buffer.render_primitive_type = TBuffer::ERenderPrimitiveType::Model;
buffer.shader = "gouraud_light_instanced";
@ -827,6 +816,7 @@ void GCodeViewer::render()
buffer.shader = wxGetApp().is_glsl_version_greater_or_equal_to(1, 20) ? "options_120" : "options_110";
}
break;
#endif // ENABLE_SEAMS_USING_BATCHED_MODELS
#else
buffer.render_primitive_type = TBuffer::ERenderPrimitiveType::Point;
buffer.vertices.format = VBuffer::EFormat::Position;
@ -1163,16 +1153,6 @@ void GCodeViewer::export_toolpaths_to_obj(const char* filename) const
fclose(fp);
}
void GCodeViewer::start_mapping_gcode_window()
{
m_sequential_view.gcode_window.load_gcode();
}
void GCodeViewer::stop_mapping_gcode_window()
{
m_sequential_view.gcode_window.stop_mapping_file();
}
void GCodeViewer::load_toolpaths(const GCodeProcessor::Result& gcode_result)
{
// max index buffer size, in bytes
@ -1227,9 +1207,9 @@ void GCodeViewer::load_toolpaths(const GCodeProcessor::Result& gcode_result)
};
auto add_indices_as_line = [](const GCodeProcessor::MoveVertex& prev, const GCodeProcessor::MoveVertex& curr, TBuffer& buffer,
unsigned int ibuffer_id, IndexBuffer& indices, size_t move_id) {
if (prev.type != curr.type || !buffer.paths.back().matches(curr)) {
if (buffer.paths.empty() || prev.type != curr.type || !buffer.paths.back().matches(curr)) {
// add starting index
indices.push_back(static_cast<unsigned int>(indices.size()));
indices.push_back(static_cast<IBufferType>(indices.size()));
buffer.add_path(curr, ibuffer_id, indices.size() - 1, move_id - 1);
buffer.paths.back().sub_paths.front().first.position = prev.position;
}
@ -1237,11 +1217,11 @@ void GCodeViewer::load_toolpaths(const GCodeProcessor::Result& gcode_result)
Path& last_path = buffer.paths.back();
if (last_path.sub_paths.front().first.i_id != last_path.sub_paths.back().last.i_id) {
// add previous index
indices.push_back(static_cast<unsigned int>(indices.size()));
indices.push_back(static_cast<IBufferType>(indices.size()));
}
// add current index
indices.push_back(static_cast<unsigned int>(indices.size()));
indices.push_back(static_cast<IBufferType>(indices.size()));
last_path.sub_paths.back().last = { ibuffer_id, indices.size() - 1, move_id, curr.position };
};
@ -1444,20 +1424,63 @@ void GCodeViewer::load_toolpaths(const GCodeProcessor::Result& gcode_result)
};
#if ENABLE_SEAMS_USING_MODELS
// format data into the buffers to be rendered as model
// format data into the buffers to be rendered as instanced model
auto add_model_instance = [](const GCodeProcessor::MoveVertex& curr, InstanceBuffer& instances, InstanceIdBuffer& instances_ids, size_t move_id) {
// append position
instances.push_back(curr.position.x());
instances.push_back(curr.position.y());
instances.push_back(curr.position.z());
// append width
instances.push_back(1.5f * curr.width);
instances.push_back(curr.width);
// append height
instances.push_back(1.5f * curr.height);
instances.push_back(curr.height);
// append id
instances_ids.push_back(move_id);
};
#if ENABLE_SEAMS_USING_BATCHED_MODELS
// format data into the buffers to be rendered as batched model
auto add_vertices_as_model_batch = [](const GCodeProcessor::MoveVertex& curr, const GLModel::InitializationData& data, VertexBuffer& vertices, InstanceBuffer& instances, InstanceIdBuffer& instances_ids, size_t move_id) {
const double width = static_cast<double>(1.5f * curr.width);
const double height = static_cast<double>(1.5f * curr.height);
const Transform3d trafo = Geometry::assemble_transform((curr.position - 0.5f * curr.height * Vec3f::UnitZ()).cast<double>(), Vec3d::Zero(), { width, width, height });
const Eigen::Matrix<double, 3, 3, Eigen::DontAlign> normal_matrix = trafo.matrix().template block<3, 3>(0, 0).inverse().transpose();
for (const auto& entity : data.entities) {
// append vertices
for (size_t i = 0; i < entity.positions.size(); ++i) {
// append position
const Vec3d position = trafo * entity.positions[i].cast<double>();
vertices.push_back(static_cast<float>(position.x()));
vertices.push_back(static_cast<float>(position.y()));
vertices.push_back(static_cast<float>(position.z()));
// append normal
const Vec3d normal = normal_matrix * entity.normals[i].cast<double>();
vertices.push_back(static_cast<float>(normal.x()));
vertices.push_back(static_cast<float>(normal.y()));
vertices.push_back(static_cast<float>(normal.z()));
}
}
// append instance position
instances.push_back(curr.position.x());
instances.push_back(curr.position.y());
instances.push_back(curr.position.z());
// append instance id
instances_ids.push_back(move_id);
};
auto add_indices_as_model_batch = [](const GLModel::InitializationData& data, IndexBuffer& indices, IBufferType base_index) {
for (const auto& entity : data.entities) {
for (size_t i = 0; i < entity.indices.size(); ++i) {
indices.push_back(static_cast<IBufferType>(entity.indices[i] + base_index));
}
}
};
#endif // ENABLE_SEAMS_USING_BATCHED_MODELS
#endif // ENABLE_SEAMS_USING_MODELS
#if ENABLE_GCODE_VIEWER_STATISTICS
@ -1541,7 +1564,12 @@ void GCodeViewer::load_toolpaths(const GCodeProcessor::Result& gcode_result)
// if adding the vertices for the current segment exceeds the threshold size of the current vertex buffer
// add another vertex buffer
#if ENABLE_SEAMS_USING_BATCHED_MODELS
size_t vertices_size_to_add = (t_buffer.render_primitive_type == TBuffer::ERenderPrimitiveType::BatchedModel) ? t_buffer.model.data.vertices_size_bytes() : t_buffer.max_vertices_per_segment_size_bytes();
if (v_multibuffer.back().size() * sizeof(float) > t_buffer.vertices.max_size_bytes() - vertices_size_to_add) {
#else
if (v_multibuffer.back().size() * sizeof(float) > t_buffer.vertices.max_size_bytes() - t_buffer.max_vertices_per_segment_size_bytes()) {
#endif // ENABLE_SEAMS_USING_BATCHED_MODELS
v_multibuffer.push_back(VertexBuffer());
if (t_buffer.render_primitive_type == TBuffer::ERenderPrimitiveType::Triangle) {
Path& last_path = t_buffer.paths.back();
@ -1558,6 +1586,24 @@ void GCodeViewer::load_toolpaths(const GCodeProcessor::Result& gcode_result)
case TBuffer::ERenderPrimitiveType::Line: { add_vertices_as_line(prev, curr, v_buffer); break; }
case TBuffer::ERenderPrimitiveType::Triangle: { add_vertices_as_solid(prev, curr, t_buffer, static_cast<unsigned int>(v_multibuffer.size()) - 1, v_buffer, i); break; }
#if ENABLE_SEAMS_USING_MODELS
#if ENABLE_SEAMS_USING_BATCHED_MODELS
case TBuffer::ERenderPrimitiveType::InstancedModel:
{
add_model_instance(curr, inst_buffer, inst_id_buffer, i);
#if ENABLE_GCODE_VIEWER_STATISTICS
++m_statistics.instances_count;
#endif // ENABLE_GCODE_VIEWER_STATISTICS
break;
}
case TBuffer::ERenderPrimitiveType::BatchedModel:
{
add_vertices_as_model_batch(curr, t_buffer.model.data, v_buffer, inst_buffer, inst_id_buffer, i);
#if ENABLE_GCODE_VIEWER_STATISTICS
++m_statistics.batched_count;
#endif // ENABLE_GCODE_VIEWER_STATISTICS
break;
}
#else
case TBuffer::ERenderPrimitiveType::Model:
{
add_model_instance(curr, inst_buffer, inst_id_buffer, i);
@ -1567,6 +1613,7 @@ void GCodeViewer::load_toolpaths(const GCodeProcessor::Result& gcode_result)
break;
}
#endif // ENABLE_SEAMS_USING_MODELS
#endif // ENABLE_SEAMS_USING_BATCHED_MODELS
}
// collect options zs for later use
@ -1749,6 +1796,23 @@ void GCodeViewer::load_toolpaths(const GCodeProcessor::Result& gcode_result)
for (size_t i = 0; i < m_buffers.size(); ++i) {
TBuffer& t_buffer = m_buffers[i];
#if ENABLE_SEAMS_USING_MODELS
#if ENABLE_SEAMS_USING_BATCHED_MODELS
if (t_buffer.render_primitive_type == TBuffer::ERenderPrimitiveType::InstancedModel) {
const InstanceBuffer& inst_buffer = instances[i];
if (!inst_buffer.empty()) {
t_buffer.model.instances.buffer = inst_buffer;
t_buffer.model.instances.s_ids = instances_ids[i];
}
}
else {
if (t_buffer.render_primitive_type == TBuffer::ERenderPrimitiveType::BatchedModel) {
const InstanceBuffer& inst_buffer = instances[i];
if (!inst_buffer.empty()) {
t_buffer.model.instances.buffer = inst_buffer;
t_buffer.model.instances.s_ids = instances_ids[i];
}
}
#else
if (t_buffer.render_primitive_type == TBuffer::ERenderPrimitiveType::Model) {
const InstanceBuffer& inst_buffer = instances[i];
if (!inst_buffer.empty()) {
@ -1757,6 +1821,7 @@ void GCodeViewer::load_toolpaths(const GCodeProcessor::Result& gcode_result)
}
}
else {
#endif // ENABLE_SEAMS_USING_BATCHED_MODELS
#endif // ENABLE_SEAMS_USING_MODELS
const MultiVertexBuffer& v_multibuffer = vertices[i];
for (const VertexBuffer& v_buffer : v_multibuffer) {
@ -1850,10 +1915,20 @@ void GCodeViewer::load_toolpaths(const GCodeProcessor::Result& gcode_result)
// if adding the indices for the current segment exceeds the threshold size of the current index buffer
// create another index buffer
#if ENABLE_SEAMS_USING_BATCHED_MODELS
size_t indiced_size_to_add = (t_buffer.render_primitive_type == TBuffer::ERenderPrimitiveType::BatchedModel) ? t_buffer.model.data.indices_size_bytes() : t_buffer.max_indices_per_segment_size_bytes();
if (i_multibuffer.back().size() * sizeof(IBufferType) >= IBUFFER_THRESHOLD_BYTES - indiced_size_to_add) {
#else
if (i_multibuffer.back().size() * sizeof(IBufferType) >= IBUFFER_THRESHOLD_BYTES - t_buffer.max_indices_per_segment_size_bytes()) {
#endif // ENABLE_SEAMS_USING_BATCHED_MODELS
i_multibuffer.push_back(IndexBuffer());
vbo_index_list.push_back(t_buffer.vertices.vbos[curr_vertex_buffer.first]);
#if ENABLE_SEAMS_USING_BATCHED_MODELS
if (t_buffer.render_primitive_type != TBuffer::ERenderPrimitiveType::Point &&
t_buffer.render_primitive_type != TBuffer::ERenderPrimitiveType::BatchedModel) {
#else
if (t_buffer.render_primitive_type != TBuffer::ERenderPrimitiveType::Point) {
#endif // ENABLE_SEAMS_USING_BATCHED_MODELS
Path& last_path = t_buffer.paths.back();
last_path.add_sub_path(prev, static_cast<unsigned int>(i_multibuffer.size()) - 1, 0, i - 1);
}
@ -1861,14 +1936,24 @@ void GCodeViewer::load_toolpaths(const GCodeProcessor::Result& gcode_result)
// if adding the vertices for the current segment exceeds the threshold size of the current vertex buffer
// create another index buffer
#if ENABLE_SEAMS_USING_BATCHED_MODELS
size_t vertices_size_to_add = (t_buffer.render_primitive_type == TBuffer::ERenderPrimitiveType::BatchedModel) ? t_buffer.model.data.vertices_size_bytes() : t_buffer.max_vertices_per_segment_size_bytes();
if (curr_vertex_buffer.second * t_buffer.vertices.vertex_size_bytes() > t_buffer.vertices.max_size_bytes() - vertices_size_to_add) {
#else
if (curr_vertex_buffer.second * t_buffer.vertices.vertex_size_bytes() > t_buffer.vertices.max_size_bytes() - t_buffer.max_vertices_per_segment_size_bytes()) {
#endif // ENABLE_SEAMS_USING_BATCHED_MODELS
i_multibuffer.push_back(IndexBuffer());
++curr_vertex_buffer.first;
curr_vertex_buffer.second = 0;
vbo_index_list.push_back(t_buffer.vertices.vbos[curr_vertex_buffer.first]);
#if ENABLE_SEAMS_USING_BATCHED_MODELS
if (t_buffer.render_primitive_type != TBuffer::ERenderPrimitiveType::Point &&
t_buffer.render_primitive_type != TBuffer::ERenderPrimitiveType::BatchedModel) {
#else
if (t_buffer.render_primitive_type != TBuffer::ERenderPrimitiveType::Point) {
#endif // ENABLE_SEAMS_USING_BATCHED_MODELS
Path& last_path = t_buffer.paths.back();
last_path.add_sub_path(prev, static_cast<unsigned int>(i_multibuffer.size()) - 1, 0, i - 1);
}
@ -1892,6 +1977,13 @@ void GCodeViewer::load_toolpaths(const GCodeProcessor::Result& gcode_result)
add_indices_as_solid(prev, curr, next, t_buffer, curr_vertex_buffer.second, static_cast<unsigned int>(i_multibuffer.size()) - 1, i_buffer, i);
break;
}
#if ENABLE_SEAMS_USING_BATCHED_MODELS
case TBuffer::ERenderPrimitiveType::BatchedModel: {
add_indices_as_model_batch(t_buffer.model.data, i_buffer, curr_vertex_buffer.second);
curr_vertex_buffer.second += t_buffer.model.data.vertices_count();
break;
}
#endif // ENABLE_SEAMS_USING_BATCHED_MODELS
default: { break; }
}
}
@ -1906,7 +1998,11 @@ void GCodeViewer::load_toolpaths(const GCodeProcessor::Result& gcode_result)
for (size_t i = 0; i < m_buffers.size(); ++i) {
TBuffer& t_buffer = m_buffers[i];
#if ENABLE_SEAMS_USING_MODELS
#if ENABLE_SEAMS_USING_BATCHED_MODELS
if (t_buffer.render_primitive_type != TBuffer::ERenderPrimitiveType::InstancedModel) {
#else
if (t_buffer.render_primitive_type != TBuffer::ERenderPrimitiveType::Model) {
#endif // ENABLE_SEAMS_USING_BATCHED_MODELS
#endif // ENABLE_SEAMS_USING_MODELS
const MultiIndexBuffer& i_multibuffer = indices[i];
for (const IndexBuffer& i_buffer : i_multibuffer) {
@ -2200,7 +2296,12 @@ void GCodeViewer::refresh_render_paths(bool keep_sequential_current_first, bool
continue;
#if ENABLE_SEAMS_USING_MODELS
#if ENABLE_SEAMS_USING_BATCHED_MODELS
if (buffer.render_primitive_type == TBuffer::ERenderPrimitiveType::InstancedModel ||
buffer.render_primitive_type == TBuffer::ERenderPrimitiveType::BatchedModel) {
#else
if (buffer.render_primitive_type == TBuffer::ERenderPrimitiveType::Model) {
#endif // ENABLE_SEAMS_USING_BATCHED_MODELS
for (size_t id : buffer.model.instances.s_ids) {
if (id < m_layers.get_range_at(m_layers_z_range[0]).first || m_layers.get_range_at(m_layers_z_range[1]).last < id)
continue;
@ -2265,7 +2366,12 @@ void GCodeViewer::refresh_render_paths(bool keep_sequential_current_first, bool
bool found = false;
for (const TBuffer& buffer : m_buffers) {
#if ENABLE_SEAMS_USING_MODELS
#if ENABLE_SEAMS_USING_BATCHED_MODELS
if (buffer.render_primitive_type == TBuffer::ERenderPrimitiveType::InstancedModel ||
buffer.render_primitive_type == TBuffer::ERenderPrimitiveType::BatchedModel) {
#else
if (buffer.render_primitive_type == TBuffer::ERenderPrimitiveType::Model) {
#endif // ENABLE_SEAMS_USING_BATCHED_MODELS
for (size_t i = 0; i < buffer.model.instances.s_ids.size(); ++i) {
if (buffer.model.instances.s_ids[i] == m_sequential_view.current.last) {
size_t offset = i * buffer.model.instances.instance_size_floats();
@ -2426,10 +2532,19 @@ void GCodeViewer::refresh_render_paths(bool keep_sequential_current_first, bool
}
#if ENABLE_SEAMS_USING_MODELS
#if ENABLE_SEAMS_USING_BATCHED_MODELS
// second pass: for buffers using instanced and batched models, update the instances render ranges
#else
// second pass: for buffers using instanced models, update the instances render ranges
#endif // ENABLE_SEAMS_USING_BATCHED_MODELS
for (size_t b = 0; b < m_buffers.size(); ++b) {
TBuffer& buffer = const_cast<TBuffer&>(m_buffers[b]);
#if ENABLE_SEAMS_USING_BATCHED_MODELS
if (buffer.render_primitive_type != TBuffer::ERenderPrimitiveType::InstancedModel &&
buffer.render_primitive_type != TBuffer::ERenderPrimitiveType::BatchedModel)
#else
if (buffer.render_primitive_type != TBuffer::ERenderPrimitiveType::Model)
#endif // ENABLE_SEAMS_USING_BATCHED_MODELS
continue;
buffer.model.instances.render_ranges.reset();
@ -2445,7 +2560,11 @@ void GCodeViewer::refresh_render_paths(bool keep_sequential_current_first, bool
if (m_sequential_view.current.first <= buffer.model.instances.s_ids.back() && buffer.model.instances.s_ids.front() <= m_sequential_view.current.last) {
for (size_t id : buffer.model.instances.s_ids) {
if (has_second_range) {
#if ENABLE_FIX_PREVIEW_OPTIONS_Z
if (id < m_sequential_view.endpoints.first) {
#else
if (id <= m_sequential_view.endpoints.first) {
#endif // ENABLE_FIX_PREVIEW_OPTIONS_Z
++buffer.model.instances.render_ranges.ranges.front().offset;
if (id <= m_sequential_view.current.first)
++buffer.model.instances.render_ranges.ranges.back().offset;
@ -2715,6 +2834,66 @@ void GCodeViewer::render_toolpaths()
}
}
};
#if ENABLE_SEAMS_USING_BATCHED_MODELS
#if ENABLE_GCODE_VIEWER_STATISTICS
auto render_as_batched_model = [this](TBuffer& buffer, GLShaderProgram& shader) {
#else
auto render_as_batched_model = [](TBuffer& buffer, GLShaderProgram& shader) {
#endif // ENABLE_GCODE_VIEWER_STATISTICS
struct Range
{
unsigned int first;
unsigned int last;
bool intersects(const Range& other) const { return (other.last < first || other.first > last) ? false : true; }
};
Range buffer_range = { 0, 0 };
size_t indices_per_instance = buffer.model.data.indices_count();
for (size_t j = 0; j < buffer.indices.size(); ++j) {
const IBuffer& i_buffer = buffer.indices[j];
buffer_range.last = buffer_range.first + i_buffer.count / indices_per_instance;
glsafe(::glBindBuffer(GL_ARRAY_BUFFER, i_buffer.vbo));
glsafe(::glVertexPointer(buffer.vertices.position_size_floats(), GL_FLOAT, buffer.vertices.vertex_size_bytes(), (const void*)buffer.vertices.position_offset_bytes()));
glsafe(::glEnableClientState(GL_VERTEX_ARRAY));
bool has_normals = buffer.vertices.normal_size_floats() > 0;
if (has_normals) {
glsafe(::glNormalPointer(GL_FLOAT, buffer.vertices.vertex_size_bytes(), (const void*)buffer.vertices.normal_offset_bytes()));
glsafe(::glEnableClientState(GL_NORMAL_ARRAY));
}
glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, i_buffer.ibo));
for (auto& range : buffer.model.instances.render_ranges.ranges) {
Range range_range = { range.offset, range.offset + range.count };
if (range_range.intersects(buffer_range)) {
shader.set_uniform("uniform_color", range.color);
unsigned int offset = (range_range.first > buffer_range.first) ? range_range.first - buffer_range.first : 0;
size_t offset_bytes = static_cast<size_t>(offset) * indices_per_instance * sizeof(IBufferType);
Range render_range = { std::max(range_range.first, buffer_range.first), std::min(range_range.last, buffer_range.last) };
size_t count = static_cast<size_t>(render_range.last - render_range.first) * indices_per_instance;
if (count > 0) {
glsafe(::glDrawElements(GL_TRIANGLES, (GLsizei)count, GL_UNSIGNED_SHORT, (const void*)offset_bytes));
#if ENABLE_GCODE_VIEWER_STATISTICS
++m_statistics.gl_batched_models_calls_count;
#endif // ENABLE_GCODE_VIEWER_STATISTICS
}
}
}
glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0));
if (has_normals)
glsafe(::glDisableClientState(GL_NORMAL_ARRAY));
glsafe(::glDisableClientState(GL_VERTEX_ARRAY));
glsafe(::glBindBuffer(GL_ARRAY_BUFFER, 0));
buffer_range.first = buffer_range.last;
}
};
#endif // ENABLE_SEAMS_USING_BATCHED_MODELS
#endif // ENABLE_SEAMS_USING_MODELS
auto line_width = [](double zoom) {
@ -2738,11 +2917,22 @@ void GCodeViewer::render_toolpaths()
shader->start_using();
#if ENABLE_SEAMS_USING_MODELS
#if ENABLE_SEAMS_USING_BATCHED_MODELS
if (buffer.render_primitive_type == TBuffer::ERenderPrimitiveType::InstancedModel) {
#else
if (buffer.render_primitive_type == TBuffer::ERenderPrimitiveType::Model) {
#endif // ENABLE_SEAMS_USING_BATCHED_MODELS
shader->set_uniform("emission_factor", 0.25f);
render_as_instanced_model(buffer, *shader);
shader->set_uniform("emission_factor", 0.0f);
}
#if ENABLE_SEAMS_USING_BATCHED_MODELS
else if (buffer.render_primitive_type == TBuffer::ERenderPrimitiveType::BatchedModel) {
shader->set_uniform("emission_factor", 0.25f);
render_as_batched_model(buffer, *shader);
shader->set_uniform("emission_factor", 0.0f);
}
#endif // ENABLE_SEAMS_USING_BATCHED_MODELS
else {
#endif // ENABLE_SEAMS_USING_MODELS
for (size_t j = 0; j < buffer.indices.size(); ++j) {
@ -2895,7 +3085,7 @@ void GCodeViewer::render_legend(float& legend_height)
bool imperial_units = wxGetApp().app_config->get("use_inches") == "1";
auto append_item = [this, icon_size, percent_bar_size, &imgui, imperial_units](EItemType type, const Color& color, const std::string& label,
auto append_item = [icon_size, percent_bar_size, &imgui, imperial_units](EItemType type, const Color& color, const std::string& label,
bool visible = true, const std::string& time = "", float percent = 0.0f, float max_percent = 0.0f, const std::array<float, 4>& offsets = { 0.0f, 0.0f, 0.0f, 0.0f },
double used_filament_m = 0.0, double used_filament_g = 0.0,
std::function<void()> callback = nullptr) {
@ -2913,6 +3103,7 @@ void GCodeViewer::render_legend(float& legend_height)
}
case EItemType::Circle: {
ImVec2 center(0.5f * (pos.x + pos.x + icon_size), 0.5f * (pos.y + pos.y + icon_size));
#if !ENABLE_SEAMS_USING_BATCHED_MODELS
if (m_buffers[buffer_id(EMoveType::Retract)].shader == "options_120") {
draw_list->AddCircleFilled(center, 0.5f * icon_size,
ImGui::GetColorU32({ 0.5f * color[0], 0.5f * color[1], 0.5f * color[2], 1.0f }), 16);
@ -2922,6 +3113,7 @@ void GCodeViewer::render_legend(float& legend_height)
draw_list->AddCircleFilled(center, radius, ImGui::GetColorU32({ 0.5f * color[0], 0.5f * color[1], 0.5f * color[2], 1.0f }), 16);
}
else
#endif // !ENABLE_SEAMS_USING_BATCHED_MODELS
draw_list->AddCircleFilled(center, 0.5f * icon_size, ImGui::GetColorU32({ color[0], color[1], color[2], 1.0f }), 16);
break;
@ -3597,7 +3789,11 @@ void GCodeViewer::render_legend(float& legend_height)
auto add_option = [this, append_item](EMoveType move_type, EOptionsColors color, const std::string& text) {
const TBuffer& buffer = m_buffers[buffer_id(move_type)];
if (buffer.visible && buffer.has_data())
#if ENABLE_SEAMS_USING_BATCHED_MODELS
append_item(EItemType::Circle, Options_Colors[static_cast<unsigned int>(color)], text);
#else
append_item((buffer.shader == "options_110") ? EItemType::Rect : EItemType::Circle, Options_Colors[static_cast<unsigned int>(color)], text);
#endif // ENABLE_SEAMS_USING_BATCHED_MODELS
};
// options section
@ -3821,7 +4017,11 @@ void GCodeViewer::render_statistics()
add_counter(std::string("Multi GL_TRIANGLES:"), m_statistics.gl_multi_triangles_calls_count);
add_counter(std::string("GL_TRIANGLES:"), m_statistics.gl_triangles_calls_count);
#if ENABLE_SEAMS_USING_MODELS
ImGui::Separator();
add_counter(std::string("Instanced models:"), m_statistics.gl_instanced_models_calls_count);
#if ENABLE_SEAMS_USING_BATCHED_MODELS
add_counter(std::string("Batched models:"), m_statistics.gl_batched_models_calls_count);
#endif // ENABLE_SEAMS_USING_BATCHED_MODELS
#endif // ENABLE_SEAMS_USING_MODELS
}
@ -3853,6 +4053,9 @@ void GCodeViewer::render_statistics()
add_counter(std::string("Extrude segments count:"), m_statistics.extrude_segments_count);
#if ENABLE_SEAMS_USING_MODELS
add_counter(std::string("Instances count:"), m_statistics.instances_count);
#if ENABLE_SEAMS_USING_BATCHED_MODELS
add_counter(std::string("Batched count:"), m_statistics.batched_count);
#endif // ENABLE_SEAMS_USING_BATCHED_MODELS
#endif // ENABLE_SEAMS_USING_MODELS
ImGui::Separator();
add_counter(std::string("VBuffers count:"), m_statistics.vbuffers_count);

View File

@ -105,9 +105,16 @@ class GCodeViewer
};
#if ENABLE_SEAMS_USING_MODELS
#if ENABLE_SEAMS_USING_BATCHED_MODELS
// buffer containing instances data used to render a toolpaths using instanced or batched models
// instance record format:
// instanced models: 5 floats -> position.x|position.y|position.z|width|height (which are sent to the shader as -> vec3 (offset) + vec2 (scales) in GLModel::render_instanced())
// batched models: 3 floats -> position.x|position.y|position.z
#else
// buffer containing instances data used to render a toolpaths using instanced models
// instance record format: 5 floats -> position.x|position.y|position.z|width|height
// which is sent to the shader as -> vec3 (offset) + vec2 (scales) in GLModel::render_instanced()
#endif // ENABLE_SEAMS_USING_BATCHED_MODELS
struct InstanceVBuffer
{
// ranges used to render only subparts of the intances
@ -130,6 +137,16 @@ class GCodeViewer
void reset();
};
#if ENABLE_SEAMS_USING_BATCHED_MODELS
enum class EFormat : unsigned char
{
InstancedModel,
BatchedModel
};
EFormat format;
#endif // ENABLE_SEAMS_USING_BATCHED_MODELS
// cpu-side buffer containing all instances data
InstanceBuffer buffer;
// indices of the moves for all instances
@ -138,7 +155,18 @@ class GCodeViewer
size_t data_size_bytes() const { return s_ids.size() * instance_size_bytes(); }
#if ENABLE_SEAMS_USING_BATCHED_MODELS
size_t instance_size_floats() const {
switch (format)
{
case EFormat::InstancedModel: { return 5; }
case EFormat::BatchedModel: { return 3; }
default: { return 0; }
}
}
#else
size_t instance_size_floats() const { return 5; }
#endif // ENABLE_SEAMS_USING_BATCHED_MODELS
size_t instance_size_bytes() const { return instance_size_floats() * sizeof(float); }
void reset();
@ -280,7 +308,12 @@ class GCodeViewer
Line,
#if ENABLE_SEAMS_USING_MODELS
Triangle,
#if ENABLE_SEAMS_USING_BATCHED_MODELS
InstancedModel,
BatchedModel
#else
Model
#endif // ENABLE_SEAMS_USING_BATCHED_MODELS
#else
Triangle
#endif // ENABLE_SEAMS_USING_MODELS
@ -298,6 +331,9 @@ class GCodeViewer
GLModel model;
Color color;
InstanceVBuffer instances;
#if ENABLE_SEAMS_USING_BATCHED_MODELS
GLModel::InitializationData data;
#endif // ENABLE_SEAMS_USING_BATCHED_MODELS
void reset();
};
@ -362,7 +398,15 @@ class GCodeViewer
case ERenderPrimitiveType::Triangle: {
return !vertices.vbos.empty() && vertices.vbos.front() != 0 && !indices.empty() && indices.front().ibo != 0;
}
#if ENABLE_SEAMS_USING_BATCHED_MODELS
case ERenderPrimitiveType::InstancedModel: { return model.model.is_initialized() && !model.instances.buffer.empty(); }
case ERenderPrimitiveType::BatchedModel: {
return model.data.vertices_count() > 0 && model.data.indices_count() &&
!vertices.vbos.empty() && vertices.vbos.front() != 0 && !indices.empty() && indices.front().ibo != 0;
}
#else
case ERenderPrimitiveType::Model: { return model.model.is_initialized() && !model.instances.buffer.empty(); }
#endif // ENABLE_SEAMS_USING_BATCHED_MODELS
default: { return false; }
}
}
@ -528,6 +572,9 @@ class GCodeViewer
int64_t gl_triangles_calls_count{ 0 };
#if ENABLE_SEAMS_USING_MODELS
int64_t gl_instanced_models_calls_count{ 0 };
#if ENABLE_SEAMS_USING_BATCHED_MODELS
int64_t gl_batched_models_calls_count{ 0 };
#endif // ENABLE_SEAMS_USING_BATCHED_MODELS
#endif // ENABLE_SEAMS_USING_MODELS
// memory
int64_t results_size{ 0 };
@ -549,6 +596,9 @@ class GCodeViewer
int64_t extrude_segments_count{ 0 };
#if ENABLE_SEAMS_USING_MODELS
int64_t instances_count{ 0 };
#if ENABLE_SEAMS_USING_BATCHED_MODELS
int64_t batched_count{ 0 };
#endif // ENABLE_SEAMS_USING_BATCHED_MODELS
#endif // ENABLE_SEAMS_USING_MODELS
int64_t vbuffers_count{ 0 };
int64_t ibuffers_count{ 0 };
@ -577,6 +627,9 @@ class GCodeViewer
gl_triangles_calls_count = 0;
#if ENABLE_SEAMS_USING_MODELS
gl_instanced_models_calls_count = 0;
#if ENABLE_SEAMS_USING_BATCHED_MODELS
gl_batched_models_calls_count = 0;
#endif // ENABLE_SEAMS_USING_BATCHED_MODELS
#endif // ENABLE_SEAMS_USING_MODELS
}
@ -602,6 +655,9 @@ class GCodeViewer
extrude_segments_count = 0;
#if ENABLE_SEAMS_USING_MODELS
instances_count = 0;
#if ENABLE_SEAMS_USING_BATCHED_MODELS
batched_count = 0;
#endif // ENABLE_SEAMS_USING_BATCHED_MODELS
#endif // ENABLE_SEAMS_USING_MODELS
vbuffers_count = 0;
ibuffers_count = 0;
@ -647,18 +703,17 @@ public:
std::string m_filename;
boost::iostreams::mapped_file_source m_file;
// map for accessing data in file by line number
std::vector<std::pair<uint64_t, uint64_t>> m_lines_map;
std::vector<size_t> m_lines_ends;
// current visible lines
std::vector<Line> m_lines;
public:
GCodeWindow() = default;
~GCodeWindow() { stop_mapping_file(); }
void set_filename(const std::string& filename) { m_filename = filename; }
void load_gcode();
void load_gcode(const std::string& filename, const std::vector<size_t> &lines_ends);
void reset() {
stop_mapping_file();
m_lines_map.clear();
m_lines_ends.clear();
m_lines.clear();
m_filename.clear();
}
@ -791,8 +846,6 @@ public:
void export_toolpaths_to_obj(const char* filename) const;
void start_mapping_gcode_window();
void stop_mapping_gcode_window();
void toggle_gcode_window_visibility() { m_sequential_view.gcode_window.toggle_visibility(); }
#if ENABLE_FIX_IMPORTING_COLOR_PRINT_VIEW_INTO_GCODEVIEWER

View File

@ -1114,16 +1114,6 @@ int GLCanvas3D::check_volumes_outside_state() const
return (int)state;
}
void GLCanvas3D::start_mapping_gcode_window()
{
m_gcode_viewer.start_mapping_gcode_window();
}
void GLCanvas3D::stop_mapping_gcode_window()
{
m_gcode_viewer.stop_mapping_gcode_window();
}
void GLCanvas3D::toggle_sla_auxiliaries_visibility(bool visible, const ModelObject* mo, int instance_idx)
{
m_render_sla_auxiliaries = visible;

View File

@ -621,9 +621,6 @@ public:
const GCodeViewer::SequentialView& get_gcode_sequential_view() const { return m_gcode_viewer.get_sequential_view(); }
void update_gcode_sequential_view_current(unsigned int first, unsigned int last) { m_gcode_viewer.update_sequential_view_current(first, last); }
void start_mapping_gcode_window();
void stop_mapping_gcode_window();
void toggle_sla_auxiliaries_visibility(bool visible, const ModelObject* mo = nullptr, int instance_idx = -1);
void toggle_model_objects_visibility(bool visible, const ModelObject* mo = nullptr, int instance_idx = -1);
void update_instance_printable_state_for_object(size_t obj_idx);

View File

@ -19,6 +19,26 @@
namespace Slic3r {
namespace GUI {
#if ENABLE_SEAMS_USING_BATCHED_MODELS
size_t GLModel::InitializationData::vertices_count() const
{
size_t ret = 0;
for (const Entity& entity : entities) {
ret += entity.positions.size();
}
return ret;
}
size_t GLModel::InitializationData::indices_count() const
{
size_t ret = 0;
for (const Entity& entity : entities) {
ret += entity.indices.size();
}
return ret;
}
#endif // ENABLE_SEAMS_USING_BATCHED_MODELS
void GLModel::init_from(const InitializationData& data)
{
if (!m_render_data.empty()) // call reset() if you want to reuse this model

View File

@ -48,6 +48,15 @@ namespace GUI {
};
std::vector<Entity> entities;
#if ENABLE_SEAMS_USING_BATCHED_MODELS
size_t vertices_count() const;
size_t vertices_size_floats() const { return vertices_count() * 6; }
size_t vertices_size_bytes() const { return vertices_size_floats() * sizeof(float); }
size_t indices_count() const;
size_t indices_size_bytes() const { return indices_count() * sizeof(unsigned int); }
#endif // ENABLE_SEAMS_USING_BATCHED_MODELS
};
private:

View File

@ -33,11 +33,19 @@ std::pair<bool, std::string> GLShadersManager::init()
bool valid = true;
#if ENABLE_SEAMS_USING_BATCHED_MODELS
// used to render bed axes and model, selection hints, gcode sequential view marker model, preview shells, options in gcode preview
#else
// used to render bed axes and model, selection hints, gcode sequential view marker model, preview shells
#endif // ENABLE_SEAMS_USING_BATCHED_MODELS
valid &= append_shader("gouraud_light", { "gouraud_light.vs", "gouraud_light.fs" });
// used to render printbed
valid &= append_shader("printbed", { "printbed.vs", "printbed.fs" });
// used to render options in gcode preview
#if ENABLE_SEAMS_USING_BATCHED_MODELS
if (GUI::wxGetApp().is_gl_version_greater_or_equal_to(3, 3))
valid &= append_shader("gouraud_light_instanced", { "gouraud_light_instanced.vs", "gouraud_light_instanced.fs" });
#else
#if ENABLE_SEAMS_USING_MODELS
if (GUI::wxGetApp().is_gl_version_greater_or_equal_to(3, 3))
valid &= append_shader("gouraud_light_instanced", { "gouraud_light_instanced.vs", "gouraud_light_instanced.fs" });
@ -49,6 +57,7 @@ std::pair<bool, std::string> GLShadersManager::init()
#if ENABLE_SEAMS_USING_MODELS
}
#endif // ENABLE_SEAMS_USING_MODELS
#endif // ENABLE_SEAMS_USING_BATCHED_MODELS
// used to render extrusion and travel paths as lines in gcode preview
valid &= append_shader("toolpaths_lines", { "toolpaths_lines.vs", "toolpaths_lines.fs" });
// used to render objects in 3d editor

View File

@ -1044,13 +1044,8 @@ void ObjectList::key_event(wxKeyEvent& event)
{
if (event.GetKeyCode() == WXK_TAB)
Navigate(event.ShiftDown() ? wxNavigationKeyEvent::IsBackward : wxNavigationKeyEvent::IsForward);
else if (event.GetKeyCode() == WXK_DELETE
#ifdef __WXOSX__
|| event.GetKeyCode() == WXK_BACK
#endif //__WXOSX__
) {
else if (event.GetKeyCode() == WXK_DELETE || event.GetKeyCode() == WXK_BACK )
remove();
}
else if (event.GetKeyCode() == WXK_F5)
wxGetApp().plater()->reload_all_from_disk();
else if (wxGetKeyState(wxKeyCode('A')) && wxGetKeyState(WXK_CONTROL/*WXK_SHIFT*/))

View File

@ -142,11 +142,11 @@ DPIFrame(NULL, wxID_ANY, "", wxDefaultPosition, wxDefaultSize, wxDEFAULT_FRAME_S
default:
case GUI_App::EAppMode::Editor:
m_taskbar_icon = std::make_unique<PrusaSlicerTaskBarIcon>(wxTBI_DOCK);
m_taskbar_icon->SetIcon(wxIcon(Slic3r::var("PrusaSlicer_128px.png"), wxBITMAP_TYPE_PNG), "PrusaSlicer");
m_taskbar_icon->SetIcon(wxIcon(Slic3r::var("PrusaSlicer-mac_128px.png"), wxBITMAP_TYPE_PNG), "PrusaSlicer");
break;
case GUI_App::EAppMode::GCodeViewer:
m_taskbar_icon = std::make_unique<GCodeViewerTaskBarIcon>(wxTBI_DOCK);
m_taskbar_icon->SetIcon(wxIcon(Slic3r::var("PrusaSlicer-gcodeviewer_128px.png"), wxBITMAP_TYPE_PNG), "G-code Viewer");
m_taskbar_icon->SetIcon(wxIcon(Slic3r::var("PrusaSlicer-gcodeviewer-mac_128px.png"), wxBITMAP_TYPE_PNG), "G-code Viewer");
break;
}
#endif // __APPLE__

View File

@ -1361,7 +1361,8 @@ wxDataViewItem ObjectDataViewModel::ReorganizeChildren( const int current_volume
if (!node_parent) // happens if item.IsOk()==false
return ret_item;
const size_t shift = node_parent->GetChildren().Item(0)->m_type == itSettings ? 1 : 0;
size_t shift;
for (shift = 0; shift < node_parent->GetChildCount() && node_parent->GetNthChild(shift)->GetType() != itVolume; shift ++);
ObjectDataViewModelNode *deleted_node = node_parent->GetNthChild(current_volume_id+shift);
node_parent->GetChildren().Remove(deleted_node);

View File

@ -4871,10 +4871,9 @@ void Plater::load_gcode(const wxString& filename)
// process gcode
GCodeProcessor processor;
processor.enable_producers(true);
try
{
processor.process_file(filename.ToUTF8().data(), false);
processor.process_file(filename.ToUTF8().data());
}
catch (const std::exception& ex)
{
@ -6143,16 +6142,6 @@ BoundingBoxf Plater::bed_shape_bb() const
return p->bed_shape_bb();
}
void Plater::start_mapping_gcode_window()
{
p->preview->get_canvas3d()->start_mapping_gcode_window();
}
void Plater::stop_mapping_gcode_window()
{
p->preview->get_canvas3d()->stop_mapping_gcode_window();
}
void Plater::arrange()
{
p->m_ui_jobs.arrange();

View File

@ -282,9 +282,6 @@ public:
GLCanvas3D* get_current_canvas3D();
BoundingBoxf bed_shape_bb() const;
void start_mapping_gcode_window();
void stop_mapping_gcode_window();
void arrange();
void find_new_position(const ModelInstancePtrs &instances);

View File

@ -696,7 +696,12 @@ void DiffViewCtrl::context_menu(wxDataViewEvent& event)
auto it = m_items_map.find(item);
if (it == m_items_map.end() || !it->second.is_long)
return;
FullCompareDialog(it->second.opt_name, it->second.old_val, it->second.new_val).ShowModal();
size_t column_cnt = this->GetColumnCount();
const wxString old_value_header = this->GetColumn(column_cnt - 2)->GetTitle();
const wxString new_value_header = this->GetColumn(column_cnt - 1)->GetTitle();
FullCompareDialog(it->second.opt_name, it->second.old_val, it->second.new_val,
old_value_header, new_value_header).ShowModal();
#ifdef __WXOSX__
wxWindow* parent = this->GetParent();
@ -1281,7 +1286,8 @@ void UnsavedChangesDialog::on_sys_color_changed()
// FullCompareDialog
//------------------------------------------
FullCompareDialog::FullCompareDialog(const wxString& option_name, const wxString& old_value, const wxString& new_value)
FullCompareDialog::FullCompareDialog(const wxString& option_name, const wxString& old_value, const wxString& new_value,
const wxString& old_value_header, const wxString& new_value_header)
: wxDialog(nullptr, wxID_ANY, option_name, wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER)
{
wxGetApp().UpdateDarkUI(this);
@ -1302,8 +1308,8 @@ FullCompareDialog::FullCompareDialog(const wxString& option_name, const wxString
grid_sizer->Add(text, 0, wxALL, border);
};
add_header(_L("Old value"));
add_header(_L("New value"));
add_header(old_value_header);
add_header(new_value_header);
auto get_set_from_val = [](wxString str) {
if (str.Find("\n") == wxNOT_FOUND)
@ -1327,7 +1333,7 @@ FullCompareDialog::FullCompareDialog(const wxString& option_name, const wxString
std::set_difference(new_set.begin(), new_set.end(), old_set.begin(), old_set.end(), std::inserter(new_old_diff_set, new_old_diff_set.begin()));
auto add_value = [grid_sizer, border, this](wxString label, const std::set<wxString>& diff_set, bool is_colored = false) {
wxTextCtrl* text = new wxTextCtrl(this, wxID_ANY, label, wxDefaultPosition, wxSize(400, 400), wxTE_MULTILINE | wxTE_READONLY | wxBORDER_SIMPLE | wxTE_RICH);
wxTextCtrl* text = new wxTextCtrl(this, wxID_ANY, label, wxDefaultPosition, wxSize(400, 400), wxTE_MULTILINE | wxTE_READONLY | wxBORDER_DEFAULT | wxTE_RICH);
wxGetApp().UpdateDarkUI(text);
text->SetStyle(0, label.Len(), wxTextAttr(is_colored ? wxColour(orange) : wxNullColour, wxNullColour, this->GetFont()));

View File

@ -299,7 +299,8 @@ protected:
class FullCompareDialog : public wxDialog
{
public:
FullCompareDialog(const wxString& option_name, const wxString& old_value, const wxString& new_value);
FullCompareDialog(const wxString& option_name, const wxString& old_value, const wxString& new_value,
const wxString& old_value_header, const wxString& new_value_header);
~FullCompareDialog() {}
};