Fixed conflicts after merge with master

This commit is contained in:
enricoturri1966 2021-11-30 12:13:51 +01:00
commit 18cb91a982
53 changed files with 741 additions and 839 deletions

View File

@ -13,7 +13,7 @@ prusaslicer_add_cmake_project(wxWidgets
# GIT_REPOSITORY "https://github.com/prusa3d/wxWidgets"
# GIT_TAG tm_cross_compile #${_wx_git_tag}
URL https://github.com/prusa3d/wxWidgets/archive/refs/heads/v3.1.4-patched.zip
URL_HASH SHA256=21ed12eb5c215b00999f0374af652be0a6f785df10d18d0dfec8d81ed4abaea3
URL_HASH SHA256=ed36a2159c781cce07b06378664e683ebd8cb2f51914aba9acd3bfca3d63d7d3
DEPENDS ${PNG_PKG} ${ZLIB_PKG} ${EXPAT_PKG} dep_TIFF dep_JPEG
CMAKE_ARGS
-DwxBUILD_PRECOMP=ON

View File

@ -740,11 +740,7 @@ ConfigSubstitutions ConfigBase::load(const boost::property_tree::ptree &tree, Fo
}
// Load the config keys from the given string.
#if ENABLE_FIX_SUPERSLICER_GCODE_IMPORT
size_t ConfigBase::load_from_gcode_string_legacy(ConfigBase& config, const char* str, ConfigSubstitutionContext& substitutions)
#else
static inline size_t load_from_gcode_string_legacy(ConfigBase& config, const char* str, ConfigSubstitutionContext& substitutions)
#endif // ENABLE_FIX_SUPERSLICER_GCODE_IMPORT
{
if (str == nullptr)
return 0;

View File

@ -2017,9 +2017,7 @@ public:
// Set all the nullable values to nils.
void null_nullables();
#if ENABLE_FIX_SUPERSLICER_GCODE_IMPORT
static size_t load_from_gcode_string_legacy(ConfigBase& config, const char* str, ConfigSubstitutionContext& substitutions);
#endif // ENABLE_FIX_SUPERSLICER_GCODE_IMPORT
private:
// Set a configuration value from a string.

View File

@ -2710,16 +2710,10 @@ namespace Slic3r {
bool _3MF_Exporter::_add_build_to_model_stream(std::stringstream& stream, const BuildItemsList& build_items)
{
#if ENABLE_SAVE_COMMANDS_ALWAYS_ENABLED
// This happens for empty projects
#endif // ENABLE_SAVE_COMMANDS_ALWAYS_ENABLED
if (build_items.size() == 0) {
add_error("No build item found");
#if ENABLE_SAVE_COMMANDS_ALWAYS_ENABLED
return true;
#else
return false;
#endif // ENABLE_SAVE_COMMANDS_ALWAYS_ENABLED
}
stream << " <" << BUILD_TAG << ">\n";

View File

@ -759,9 +759,7 @@ const std::vector<std::pair<GCodeProcessor::EProducer, std::string>> GCodeProces
{ EProducer::PrusaSlicer, "generated by PrusaSlicer" },
{ EProducer::Slic3rPE, "generated by Slic3r Prusa Edition" },
{ EProducer::Slic3r, "generated by Slic3r" },
#if ENABLE_FIX_SUPERSLICER_GCODE_IMPORT
{ EProducer::SuperSlicer, "generated by SuperSlicer" },
#endif // ENABLE_FIX_SUPERSLICER_GCODE_IMPORT
{ EProducer::Cura, "Cura_SteamEngine" },
{ EProducer::Simplify3D, "G-Code generated by Simplify3D(R)" },
{ EProducer::CraftWare, "CraftWare" },
@ -824,9 +822,7 @@ 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";
@ -1190,9 +1186,7 @@ void GCodeProcessor::reset()
m_use_volumetric_e = false;
m_last_default_color_id = 0;
#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();
@ -1249,10 +1243,8 @@ void GCodeProcessor::process_file(const std::string& filename, std::function<voi
}
else if (m_producer == EProducer::Simplify3D)
apply_config_simplify3d(filename);
#if ENABLE_FIX_SUPERSLICER_GCODE_IMPORT
else if (m_producer == EProducer::SuperSlicer)
apply_config_superslicer(filename);
#endif // ENABLE_FIX_SUPERSLICER_GCODE_IMPORT
}
// process gcode
@ -1398,7 +1390,6 @@ std::vector<std::pair<ExtrusionRole, float>> GCodeProcessor::get_roles_time(Prin
return ret;
}
#if ENABLE_FIX_SUPERSLICER_GCODE_IMPORT
ConfigSubstitutions load_from_superslicer_gcode_file(const std::string& filename, DynamicPrintConfig& config, ForwardCompatibilitySubstitutionRule compatibility_rule)
{
// for reference, see: ConfigBase::load_from_gcode_file()
@ -1431,7 +1422,6 @@ void GCodeProcessor::apply_config_superslicer(const std::string& filename)
load_from_superslicer_gcode_file(filename, config, ForwardCompatibilitySubstitutionRule::EnableSilent);
apply_config(config);
}
#endif // ENABLE_FIX_SUPERSLICER_GCODE_IMPORT
std::vector<float> GCodeProcessor::get_layers_time(PrintEstimatedStatistics::ETimeMode mode) const
{
@ -1868,9 +1858,7 @@ void GCodeProcessor::process_tags(const std::string_view comment, bool producers
store_move_vertex(EMoveType::Color_change);
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);
}
@ -1883,9 +1871,7 @@ void GCodeProcessor::process_tags(const std::string_view comment, bool producers
store_move_vertex(EMoveType::Pause_Print);
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
process_custom_gcode_time(CustomGCode::PausePrint);
return;
}
@ -1895,9 +1881,7 @@ void GCodeProcessor::process_tags(const std::string_view comment, bool producers
store_move_vertex(EMoveType::Custom_GCode);
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
return;
}
@ -1923,9 +1907,7 @@ bool GCodeProcessor::process_producers_tags(const std::string_view comment)
{
case EProducer::Slic3rPE:
case EProducer::Slic3r:
#if ENABLE_FIX_SUPERSLICER_GCODE_IMPORT
case EProducer::SuperSlicer:
#endif // ENABLE_FIX_SUPERSLICER_GCODE_IMPORT
case EProducer::PrusaSlicer: { return process_prusaslicer_tags(comment); }
case EProducer::Cura: { return process_cura_tags(comment); }
case EProducer::Simplify3D: { return process_simplify3d_tags(comment); }
@ -2478,12 +2460,8 @@ void GCodeProcessor::process_G1(const GCodeReader::GCodeLine& line)
if (m_forced_height > 0.0f)
m_height = m_forced_height;
else {
if (m_end_position[Z] > m_extruded_last_z + EPSILON) {
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)
@ -2492,10 +2470,8 @@ void GCodeProcessor::process_G1(const GCodeReader::GCodeLine& line)
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);

View File

@ -398,7 +398,6 @@ 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
@ -435,7 +434,6 @@ namespace Slic3r {
m_custom_gcode_per_print_z_id.reset();
}
};
#endif // ENABLE_FIX_PREVIEW_OPTIONS_Z
#if ENABLE_GCODE_VIEWER_DATA_CHECKING
struct DataChecker
@ -541,9 +539,7 @@ 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
size_t m_last_default_color_id;
#if ENABLE_GCODE_VIEWER_STATISTICS
std::chrono::time_point<std::chrono::high_resolution_clock> m_start_time;
@ -555,9 +551,7 @@ namespace Slic3r {
PrusaSlicer,
Slic3rPE,
Slic3r,
#if ENABLE_FIX_SUPERSLICER_GCODE_IMPORT
SuperSlicer,
#endif // ENABLE_FIX_SUPERSLICER_GCODE_IMPORT
Cura,
Simplify3D,
CraftWare,
@ -618,9 +612,7 @@ namespace Slic3r {
private:
void apply_config(const DynamicPrintConfig& config);
void apply_config_simplify3d(const std::string& filename);
#if ENABLE_FIX_SUPERSLICER_GCODE_IMPORT
void apply_config_superslicer(const std::string& filename);
#endif // ENABLE_FIX_SUPERSLICER_GCODE_IMPORT
void process_gcode_line(const GCodeReader::GCodeLine& line, bool producers_enabled);
// Process tags embedded into comments

View File

@ -160,13 +160,7 @@ Model Model::read_from_archive(const std::string& input_file, DynamicPrintConfig
if (!result)
throw Slic3r::RuntimeError("Loading of a model file failed.");
#if !ENABLE_SAVE_COMMANDS_ALWAYS_ENABLED
if (model.objects.empty())
throw Slic3r::RuntimeError("The supplied file couldn't be read because it's empty");
#endif // !ENABLE_SAVE_COMMANDS_ALWAYS_ENABLED
for (ModelObject *o : model.objects)
{
for (ModelObject *o : model.objects) {
// if (boost::algorithm::iends_with(input_file, ".zip.amf"))
// {
// // we remove the .zip part of the extension to avoid it be added to filenames when exporting

View File

@ -920,7 +920,7 @@ static PrintObjectRegions* generate_print_object_regions(
const PrintObjectRegions::VolumeRegion &parent_region = layer_range.volume_regions[parent_region_id];
const ModelVolume &parent_volume = *parent_region.model_volume;
if (parent_volume.is_model_part() || parent_volume.is_modifier())
if (PrintObjectRegions::BoundingBox parent_bbox = find_modifier_volume_extents(layer_range, parent_region_id); parent_bbox.intersects(*bbox))
if (PrintObjectRegions::BoundingBox parent_bbox = find_modifier_volume_extents(layer_range, parent_region_id); parent_bbox.intersects(*bbox)) {
// Only create new region for a modifier, which actually modifies config of it's parent.
if (PrintRegionConfig config = region_config_from_model_volume(parent_region.region->config(), nullptr, volume, num_extruders);
config != parent_region.region->config()) {
@ -928,6 +928,7 @@ static PrintObjectRegions* generate_print_object_regions(
layer_range.volume_regions.push_back({ &volume, parent_region_id, get_create_region(std::move(config)), bbox });
} else if (parent_model_part_id == -1 && parent_volume.is_model_part())
parent_model_part_id = parent_region_id;
}
}
if (! added && parent_model_part_id >= 0)
// This modifier does not override any printable volume's configuration, however it may in the future.

View File

@ -72,7 +72,8 @@ static t_config_enum_values s_keys_map_PrintHostType {
{ "duet", htDuet },
{ "flashair", htFlashAir },
{ "astrobox", htAstroBox },
{ "repetier", htRepetier }
{ "repetier", htRepetier },
{ "mks", htMKS }
};
CONFIG_OPTION_ENUM_DEFINE_STATIC_MAPS(PrintHostType)
@ -1854,12 +1855,14 @@ void PrintConfigDef::init_fff_params()
def->enum_values.push_back("flashair");
def->enum_values.push_back("astrobox");
def->enum_values.push_back("repetier");
def->enum_values.push_back("mks");
def->enum_labels.push_back("PrusaLink");
def->enum_labels.push_back("OctoPrint");
def->enum_labels.push_back("Duet");
def->enum_labels.push_back("FlashAir");
def->enum_labels.push_back("AstroBox");
def->enum_labels.push_back("Repetier");
def->enum_labels.push_back("MKS");
def->mode = comAdvanced;
def->cli = ConfigOptionDef::nocli;
def->set_default_value(new ConfigOptionEnum<PrintHostType>(htOctoPrint));

View File

@ -44,7 +44,7 @@ enum class MachineLimitsUsage {
};
enum PrintHostType {
htPrusaLink, htOctoPrint, htDuet, htFlashAir, htAstroBox, htRepetier
htPrusaLink, htOctoPrint, htDuet, htFlashAir, htAstroBox, htRepetier, htMKS
};
enum AuthorizationType {

View File

@ -379,11 +379,7 @@ static std::vector<std::vector<ExPolygons>> slices_to_regions(
int j = i;
bool merged = false;
ExPolygons &expolygons = temp_slices[i].expolygons;
for (++ j;
j < int(temp_slices.size()) &&
temp_slices[i].region_id == temp_slices[j].region_id &&
(clip_multipart_objects || temp_slices[i].volume_id == temp_slices[j].volume_id);
++ j)
for (++ j; j < int(temp_slices.size()) && temp_slices[i].region_id == temp_slices[j].region_id; ++ j)
if (ExPolygons &expolygons2 = temp_slices[j].expolygons; ! expolygons2.empty()) {
if (expolygons.empty()) {
expolygons = std::move(expolygons2);
@ -392,7 +388,10 @@ static std::vector<std::vector<ExPolygons>> slices_to_regions(
merged = true;
}
}
if (merged)
// Don't unite the regions if ! clip_multipart_objects. In that case it is user's responsibility
// to handle region overlaps. Indeed, one may intentionally let the regions overlap to produce crossing perimeters
// for example.
if (merged && clip_multipart_objects)
expolygons = closing_ex(expolygons, float(scale_(EPSILON)));
slices_by_region[temp_slices[i].region_id][z_idx] = std::move(expolygons);
i = j;

View File

@ -2354,8 +2354,8 @@ PrintObjectSupportMaterial::MyLayersPtr PrintObjectSupportMaterial::bottom_conta
Polygons &layer_support_area = layer_support_areas[layer_id];
Polygons *layer_buildplate_covered = buildplate_covered.empty() ? nullptr : &buildplate_covered[layer_id];
// Filtering the propagated support columns to two extrusions, overlapping by maximum 20%.
float column_propagation_filtering_radius = scaled<float>(0.8 * 0.5 * (m_support_params.support_material_flow.spacing() + m_support_params.support_material_flow.width()));
task_group.run([&grid_params, &overhangs_projection, &overhangs_projection_raw, &layer, &layer_support_area, layer_buildplate_covered, column_propagation_filtering_radius
// float column_propagation_filtering_radius = scaled<float>(0.8 * 0.5 * (m_support_params.support_material_flow.spacing() + m_support_params.support_material_flow.width()));
task_group.run([&grid_params, &overhangs_projection, &overhangs_projection_raw, &layer, &layer_support_area, layer_buildplate_covered /* , column_propagation_filtering_radius */
#ifdef SLIC3R_DEBUG
, iRun, layer_id
#endif /* SLIC3R_DEBUG */

View File

@ -36,43 +36,6 @@
#define ENABLE_FIXED_SCREEN_SIZE_POINT_MARKERS 1
//====================
// 2.4.0.alpha1 techs
//====================
#define ENABLE_2_4_0_ALPHA1 1
// Enable implementation of retract acceleration in gcode processor
#define ENABLE_RETRACT_ACCELERATION (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_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_ALPHA1)
//====================
// 2.4.0.alpha2 techs
//====================
#define ENABLE_2_4_0_ALPHA2 1
// 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_2_4_0_ALPHA2)
// Enable replacing a missing file during reload from disk command
#define ENABLE_RELOAD_FROM_DISK_REPLACE_FILE (1 && ENABLE_2_4_0_ALPHA2)
// Enable fixing the synchronization of seams with the horizontal slider in preview
#define ENABLE_FIX_SEAMS_SYNCH (1 && ENABLE_2_4_0_ALPHA2)
//====================
// 2.4.0.alpha3 techs
//====================
#define ENABLE_2_4_0_ALPHA3 1
// Enable fixing loading of gcode files generated with SuperSlicer in GCodeViewer
#define ENABLE_FIX_SUPERSLICER_GCODE_IMPORT (1 && ENABLE_2_4_0_ALPHA3)
//====================
// 2.4.0.beta1 techs
//====================
@ -109,4 +72,5 @@
// Enable showing time estimate for travel moves in legend
#define ENABLE_TRAVEL_TIME (1 && ENABLE_2_4_0_RC)
#endif // _prusaslicer_technologies_h_

View File

@ -1090,7 +1090,7 @@ indexed_triangle_set its_convex_hull(const std::vector<Vec3f> &pts)
centroid += pt;
centroid /= float(pts.size());
#endif // NDEBUG
for (const orgQhull::QhullFacet facet : qhull.facetList()) {
for (const orgQhull::QhullFacet &facet : qhull.facetList()) {
// Collect face vertices first, allocate unique vertices in dst_vertices based on QHull's vertex ID.
Vec3i indices;
int cnt = 0;

View File

@ -560,9 +560,9 @@ void slice_facet_with_slabs(
// Save the open edge for sure.
type = FacetSliceType::Slicing;
} else {
#ifndef NDEBUG
const stl_triangle_vertex_indices &neighbor = mesh_triangles[neighbor_idx];
float z = *it;
#ifndef NDEBUG
int num_on_plane = (mesh_vertices[neighbor(0)].z() == z) + (mesh_vertices[neighbor(1)].z() == z) + (mesh_vertices[neighbor(2)].z() == z);
assert(num_on_plane == 2 || num_on_plane == 3);
#endif // NDEBUG

View File

@ -237,6 +237,10 @@ set(SLIC3R_GUI_SOURCES
Utils/UndoRedo.hpp
Utils/HexFile.cpp
Utils/HexFile.hpp
Utils/TCPConsole.cpp
Utils/TCPConsole.hpp
Utils/MKS.cpp
Utils/MKS.hpp
)
if (APPLE)
@ -250,7 +254,6 @@ if (APPLE)
GUI/InstanceCheckMac.h
)
FIND_LIBRARY(DISKARBITRATION_LIBRARY DiskArbitration)
endif ()
add_library(libslic3r_gui STATIC ${SLIC3R_GUI_SOURCES})
@ -259,8 +262,12 @@ encoding_check(libslic3r_gui)
target_link_libraries(libslic3r_gui libslic3r avrdude cereal imgui GLEW::GLEW OpenGL::GL hidapi libcurl ${wxWidgets_LIBRARIES})
if (CMAKE_SYSTEM_NAME STREQUAL "Linux")
if (MSVC)
target_link_libraries(libslic3r_gui Setupapi.lib)
elseif (CMAKE_SYSTEM_NAME STREQUAL "Linux")
target_link_libraries(libslic3r_gui ${DBUS_LIBRARIES})
elseif (APPLE)
target_link_libraries(libslic3r_gui ${DISKARBITRATION_LIBRARY})
endif()
if (SLIC3R_STATIC)
@ -269,10 +276,6 @@ if (SLIC3R_STATIC)
target_compile_definitions(libslic3r_gui PUBLIC -DwxDEBUG_LEVEL=0)
endif()
if(APPLE)
target_link_libraries(libslic3r_gui ${DISKARBITRATION_LIBRARY})
endif()
if (SLIC3R_STATIC AND NOT SLIC3R_STATIC_EXCLUDE_CURL AND UNIX AND NOT APPLE)
target_compile_definitions(libslic3r_gui PRIVATE OPENSSL_CERT_OVERRIDE)
endif ()

View File

@ -115,7 +115,7 @@ class TickCodeInfo
bool m_suppress_plus = false;
bool m_suppress_minus = false;
bool m_use_default_colors= false;
int m_default_color_idx = 0;
// int m_default_color_idx = 0;
std::vector<std::string>* m_colors {nullptr};

View File

@ -223,7 +223,8 @@ bool BitmapTextRenderer::GetValueFromEditorCtrl(wxWindow* ctrl, wxVariant& value
if (!text_editor || text_editor->GetValue().IsEmpty())
return false;
if (m_was_unusable_symbol = Slic3r::GUI::Plater::has_illegal_filename_characters(text_editor->GetValue()))
m_was_unusable_symbol = Slic3r::GUI::Plater::has_illegal_filename_characters(text_editor->GetValue());
if (m_was_unusable_symbol)
return false;
// The icon can't be edited so get its old value and reuse it.

View File

@ -89,7 +89,6 @@ void GCodeViewer::VBuffer::reset()
count = 0;
}
#if ENABLE_SEAMS_USING_MODELS
void GCodeViewer::InstanceVBuffer::Ranges::reset()
{
for (Range& range : ranges) {
@ -107,7 +106,6 @@ void GCodeViewer::InstanceVBuffer::reset()
buffer.clear();
render_ranges.reset();
}
#endif // ENABLE_SEAMS_USING_MODELS
void GCodeViewer::IBuffer::reset()
{
@ -150,12 +148,10 @@ bool GCodeViewer::Path::matches(const GCodeProcessorResult::MoveVertex& move) co
}
}
#if ENABLE_SEAMS_USING_MODELS
void GCodeViewer::TBuffer::Model::reset()
{
instances.reset();
}
#endif // ENABLE_SEAMS_USING_MODELS
void GCodeViewer::TBuffer::reset()
{
@ -167,9 +163,7 @@ void GCodeViewer::TBuffer::reset()
indices.clear();
paths.clear();
render_paths.clear();
#if ENABLE_SEAMS_USING_MODELS
model.reset();
#endif // ENABLE_SEAMS_USING_MODELS
}
void GCodeViewer::TBuffer::add_path(const GCodeProcessorResult::MoveVertex& move, unsigned int b_id, size_t i_id, size_t s_id)
@ -297,12 +291,8 @@ void GCodeViewer::SequentialView::Marker::render() const
imgui.text_colored(ImGuiWrapper::COL_ORANGE_LIGHT, _u8L("Tool position") + ":");
ImGui::SameLine();
char buf[1024];
#if ENABLE_FIX_SEAMS_SYNCH
const Vec3f position = m_world_position + m_world_offset;
sprintf(buf, "X: %.3f, Y: %.3f, Z: %.3f", position.x(), position.y(), position.z());
#else
sprintf(buf, "X: %.3f, Y: %.3f, Z: %.3f", m_world_position.x(), m_world_position.y(), m_world_position.z());
#endif // ENABLE_FIX_SEAMS_SYNCH
imgui.text(std::string(buf));
// force extra frame to automatically update window size
@ -594,48 +584,11 @@ const GCodeViewer::Color GCodeViewer::Neutral_Color = { 0.25f, 0.25f, 0.25f, 1.0
GCodeViewer::GCodeViewer()
{
#if !ENABLE_SEAMS_USING_MODELS
// initializes non OpenGL data of TBuffers
// OpenGL data are initialized into render().init_gl_data()
for (size_t i = 0; i < m_buffers.size(); ++i) {
TBuffer& buffer = m_buffers[i];
switch (buffer_type(i))
{
default: { break; }
case EMoveType::Tool_change:
case EMoveType::Color_change:
case EMoveType::Pause_Print:
case EMoveType::Custom_GCode:
case EMoveType::Retract:
case EMoveType::Unretract:
case EMoveType::Seam: {
buffer.render_primitive_type = TBuffer::ERenderPrimitiveType::Point;
buffer.vertices.format = VBuffer::EFormat::Position;
break;
}
case EMoveType::Wipe:
case EMoveType::Extrude: {
buffer.render_primitive_type = TBuffer::ERenderPrimitiveType::Triangle;
buffer.vertices.format = VBuffer::EFormat::PositionNormal3;
break;
}
case EMoveType::Travel: {
buffer.render_primitive_type = TBuffer::ERenderPrimitiveType::Line;
buffer.vertices.format = VBuffer::EFormat::PositionNormal1;
break;
}
}
}
set_toolpath_move_type_visible(EMoveType::Extrude, true);
#endif // !ENABLE_SEAMS_USING_MODELS
m_extrusions.reset_role_visibility_flags();
// m_sequential_view.skip_invisible_moves = true;
}
#if ENABLE_SEAMS_USING_MODELS
void GCodeViewer::init()
{
if (m_gl_data_initialized)
@ -655,7 +608,6 @@ void GCodeViewer::init()
case EMoveType::Retract:
case EMoveType::Unretract:
case EMoveType::Seam: {
#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";
@ -673,20 +625,6 @@ void GCodeViewer::init()
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";
buffer.model.model.init_from(diamond(16));
buffer.model.color = option_color(type);
}
else {
buffer.render_primitive_type = TBuffer::ERenderPrimitiveType::Point;
buffer.vertices.format = VBuffer::EFormat::Position;
buffer.shader = wxGetApp().is_glsl_version_greater_or_equal_to(1, 20) ? "options_120" : "options_110";
}
break;
#endif // ENABLE_SEAMS_USING_BATCHED_MODELS
}
case EMoveType::Wipe:
case EMoveType::Extrude: {
@ -716,7 +654,6 @@ void GCodeViewer::init()
m_gl_data_initialized = true;
}
#endif // ENABLE_SEAMS_USING_MODELS
void GCodeViewer::load(const GCodeProcessorResult& gcode_result, const Print& print, bool initialized)
{
@ -932,72 +869,11 @@ void GCodeViewer::reset()
void GCodeViewer::render()
{
#if !ENABLE_SEAMS_USING_MODELS
auto init_gl_data = [this]() {
// initializes opengl data of TBuffers
for (size_t i = 0; i < m_buffers.size(); ++i) {
TBuffer& buffer = m_buffers[i];
EMoveType type = buffer_type(i);
switch (type)
{
default: { break; }
case EMoveType::Tool_change:
case EMoveType::Color_change:
case EMoveType::Pause_Print:
case EMoveType::Custom_GCode:
case EMoveType::Retract:
case EMoveType::Unretract:
case EMoveType::Seam: {
if (wxGetApp().is_gl_version_greater_or_equal_to(3, 3)) {
buffer.render_primitive_type = TBuffer::ERenderPrimitiveType::Model;
buffer.shader = "gouraud_light_instanced";
buffer.model.model.init_from(diamond(16));
buffer.model.color = option_color(type);
}
else {
buffer.render_primitive_type = TBuffer::ERenderPrimitiveType::Point;
buffer.vertices.format = VBuffer::EFormat::Position;
buffer.shader = wxGetApp().is_glsl_version_greater_or_equal_to(1, 20) ? "options_120" : "options_110";
}
break;
}
case EMoveType::Wipe:
case EMoveType::Extrude: {
buffer.shader = "gouraud_light";
break;
}
case EMoveType::Travel: {
buffer.shader = "toolpaths_lines";
break;
}
}
}
// initializes tool marker
m_sequential_view.marker.init();
// initializes point sizes
std::array<int, 2> point_sizes;
::glGetIntegerv(GL_ALIASED_POINT_SIZE_RANGE, point_sizes.data());
m_detected_point_sizes = { static_cast<float>(point_sizes[0]), static_cast<float>(point_sizes[1]) };
m_gl_data_initialized = true;
};
#endif // !ENABLE_SEAMS_USING_MODELS
#if ENABLE_GCODE_VIEWER_STATISTICS
m_statistics.reset_opengl();
#if ENABLE_SEAMS_USING_MODELS
m_statistics.total_instances_gpu_size = 0;
#endif // ENABLE_SEAMS_USING_MODELS
#endif // ENABLE_GCODE_VIEWER_STATISTICS
#if !ENABLE_SEAMS_USING_MODELS
// OpenGL data must be initialized after the glContext has been created.
// This is ensured when this method is called by GLCanvas3D::_render_gcode().
if (!m_gl_data_initialized)
init_gl_data();
#endif // !ENABLE_SEAMS_USING_MODELS
if (m_roles.empty())
return;
@ -1008,9 +884,7 @@ void GCodeViewer::render()
render_legend(legend_height);
if (m_sequential_view.current.last != m_sequential_view.endpoints.last) {
m_sequential_view.marker.set_world_position(m_sequential_view.current_position);
#if ENABLE_FIX_SEAMS_SYNCH
m_sequential_view.marker.set_world_offset(m_sequential_view.current_offset);
#endif // ENABLE_FIX_SEAMS_SYNCH
m_sequential_view.render(legend_height);
}
#if ENABLE_GCODE_VIEWER_STATISTICS
@ -1558,7 +1432,6 @@ void GCodeViewer::load_toolpaths(const GCodeProcessorResult& gcode_result)
sq_prev_length = sq_length;
};
#if ENABLE_SEAMS_USING_MODELS
// format data into the buffers to be rendered as instanced model
auto add_model_instance = [](const GCodeProcessorResult::MoveVertex& curr, InstanceBuffer& instances, InstanceIdBuffer& instances_ids, size_t move_id) {
// append position
@ -1574,7 +1447,6 @@ void GCodeViewer::load_toolpaths(const GCodeProcessorResult& gcode_result)
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 GCodeProcessorResult::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);
@ -1615,8 +1487,6 @@ void GCodeViewer::load_toolpaths(const GCodeProcessorResult& gcode_result)
}
}
};
#endif // ENABLE_SEAMS_USING_BATCHED_MODELS
#endif // ENABLE_SEAMS_USING_MODELS
#if ENABLE_GCODE_VIEWER_STATISTICS
auto start_time = std::chrono::high_resolution_clock::now();
@ -1656,46 +1526,32 @@ void GCodeViewer::load_toolpaths(const GCodeProcessorResult& gcode_result)
if (wxGetApp().is_editor())
m_contained_in_bed = wxGetApp().plater()->build_volume().all_paths_inside(gcode_result, m_paths_bounding_box);
#if ENABLE_FIX_SEAMS_SYNCH
m_sequential_view.gcode_ids.clear();
for (size_t i = 0; i < gcode_result.moves.size(); ++i) {
const GCodeProcessorResult::MoveVertex& move = gcode_result.moves[i];
if (move.type != EMoveType::Seam)
m_sequential_view.gcode_ids.push_back(move.gcode_id);
}
#else
for (const GCodeProcessorResult::MoveVertex& move : gcode_result.moves) {
m_sequential_view.gcode_ids.push_back(move.gcode_id);
}
#endif // ENABLE_FIX_SEAMS_SYNCH
std::vector<MultiVertexBuffer> vertices(m_buffers.size());
std::vector<MultiIndexBuffer> indices(m_buffers.size());
#if ENABLE_SEAMS_USING_MODELS
std::vector<InstanceBuffer> instances(m_buffers.size());
std::vector<InstanceIdBuffer> instances_ids(m_buffers.size());
#endif // ENABLE_SEAMS_USING_MODELS
#if ENABLE_FIX_SEAMS_SYNCH
std::vector<InstancesOffsets> instances_offsets(m_buffers.size());
#endif // ENABLE_FIX_SEAMS_SYNCH
std::vector<float> options_zs;
#if ENABLE_FIX_SEAMS_SYNCH
size_t seams_count = 0;
std::vector<size_t> seams_ids;
#endif // ENABLE_FIX_SEAMS_SYNCH
// toolpaths data -> extract vertices from result
for (size_t i = 0; i < m_moves_count; ++i) {
const GCodeProcessorResult::MoveVertex& curr = gcode_result.moves[i];
#if ENABLE_FIX_SEAMS_SYNCH
if (curr.type == EMoveType::Seam) {
++seams_count;
seams_ids.push_back(i);
}
size_t move_id = i - seams_count;
#endif // ENABLE_FIX_SEAMS_SYNCH
// skip first vertex
if (i == 0)
@ -1715,13 +1571,9 @@ void GCodeViewer::load_toolpaths(const GCodeProcessorResult& gcode_result)
const unsigned char id = buffer_id(curr.type);
TBuffer& t_buffer = m_buffers[id];
MultiVertexBuffer& v_multibuffer = vertices[id];
#if ENABLE_SEAMS_USING_MODELS
InstanceBuffer& inst_buffer = instances[id];
InstanceIdBuffer& inst_id_buffer = instances_ids[id];
#if ENABLE_FIX_SEAMS_SYNCH
InstancesOffsets& inst_offsets = instances_offsets[id];
#endif // ENABLE_FIX_SEAMS_SYNCH
#endif // ENABLE_SEAMS_USING_MODELS
// ensure there is at least one vertex buffer
if (v_multibuffer.empty())
@ -1729,21 +1581,13 @@ void GCodeViewer::load_toolpaths(const GCodeProcessorResult& 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();
if (prev.type == curr.type && last_path.matches(curr))
#if ENABLE_FIX_SEAMS_SYNCH
last_path.add_sub_path(prev, static_cast<unsigned int>(v_multibuffer.size()) - 1, 0, move_id - 1);
#else
last_path.add_sub_path(prev, static_cast<unsigned int>(v_multibuffer.size()) - 1, 0, i - 1);
#endif // ENABLE_FIX_SEAMS_SYNCH
}
}
@ -1753,21 +1597,11 @@ void GCodeViewer::load_toolpaths(const GCodeProcessorResult& gcode_result)
{
case TBuffer::ERenderPrimitiveType::Point: { add_vertices_as_point(curr, v_buffer); break; }
case TBuffer::ERenderPrimitiveType::Line: { add_vertices_as_line(prev, curr, v_buffer); break; }
#if ENABLE_FIX_SEAMS_SYNCH
case TBuffer::ERenderPrimitiveType::Triangle: { add_vertices_as_solid(prev, curr, t_buffer, static_cast<unsigned int>(v_multibuffer.size()) - 1, v_buffer, move_id); break; }
#else
case TBuffer::ERenderPrimitiveType::Triangle: { add_vertices_as_solid(prev, curr, t_buffer, static_cast<unsigned int>(v_multibuffer.size()) - 1, v_buffer, i); break; }
#endif // ENABLE_FIX_SEAMS_SYNCH
#if ENABLE_SEAMS_USING_MODELS
#if ENABLE_SEAMS_USING_BATCHED_MODELS
case TBuffer::ERenderPrimitiveType::InstancedModel:
{
#if ENABLE_FIX_SEAMS_SYNCH
add_model_instance(curr, inst_buffer, inst_id_buffer, move_id);
inst_offsets.push_back(prev.position - curr.position);
#else
add_model_instance(curr, inst_buffer, inst_id_buffer, i);
#endif // ENABLE_FIX_SEAMS_SYNCH
#if ENABLE_GCODE_VIEWER_STATISTICS
++m_statistics.instances_count;
#endif // ENABLE_GCODE_VIEWER_STATISTICS
@ -1775,32 +1609,13 @@ void GCodeViewer::load_toolpaths(const GCodeProcessorResult& gcode_result)
}
case TBuffer::ERenderPrimitiveType::BatchedModel:
{
#if ENABLE_FIX_SEAMS_SYNCH
add_vertices_as_model_batch(curr, t_buffer.model.data, v_buffer, inst_buffer, inst_id_buffer, move_id);
inst_offsets.push_back(prev.position - curr.position);
#else
add_vertices_as_model_batch(curr, t_buffer.model.data, v_buffer, inst_buffer, inst_id_buffer, i);
#endif // ENABLE_FIX_SEAMS_SYNCH
#if ENABLE_GCODE_VIEWER_STATISTICS
++m_statistics.batched_count;
#endif // ENABLE_GCODE_VIEWER_STATISTICS
break;
}
#else
case TBuffer::ERenderPrimitiveType::Model:
{
#if ENABLE_FIX_SEAMS_SYNCH
add_model_instance(curr, inst_buffer, inst_id_buffer, move_id);
#else
add_model_instance(curr, inst_buffer, inst_id_buffer, i);
#endif // ENABLE_FIX_SEAMS_SYNCH
#if ENABLE_GCODE_VIEWER_STATISTICS
++m_statistics.instances_count;
#endif // ENABLE_GCODE_VIEWER_STATISTICS
break;
}
#endif // ENABLE_SEAMS_USING_MODELS
#endif // ENABLE_SEAMS_USING_BATCHED_MODELS
}
// collect options zs for later use
@ -1812,11 +1627,7 @@ void GCodeViewer::load_toolpaths(const GCodeProcessorResult& gcode_result)
}
// smooth toolpaths corners for the given TBuffer using triangles
#if ENABLE_FIX_SEAMS_SYNCH
auto smooth_triangle_toolpaths_corners = [&gcode_result, &seams_ids](const TBuffer& t_buffer, MultiVertexBuffer& v_multibuffer) {
#else
auto smooth_triangle_toolpaths_corners = [&gcode_result](const TBuffer& t_buffer, MultiVertexBuffer& v_multibuffer) {
#endif // ENABLE_FIX_SEAMS_SYNCH
auto extract_position_at = [](const VertexBuffer& vertices, size_t offset) {
return Vec3f(vertices[offset + 0], vertices[offset + 1], vertices[offset + 2]);
};
@ -1890,7 +1701,6 @@ void GCodeViewer::load_toolpaths(const GCodeProcessorResult& gcode_result)
}
};
#if ENABLE_FIX_SEAMS_SYNCH
auto extract_move_id = [&seams_ids](size_t id) {
for (int i = seams_ids.size() - 1; i >= 0; --i) {
if (seams_ids[i] < id + i + 1)
@ -1898,7 +1708,6 @@ void GCodeViewer::load_toolpaths(const GCodeProcessorResult& gcode_result)
}
return id;
};
#endif // ENABLE_FIX_SEAMS_SYNCH
size_t vertex_size_floats = t_buffer.vertices.vertex_size_floats();
for (const Path& path : t_buffer.paths) {
@ -1910,16 +1719,10 @@ void GCodeViewer::load_toolpaths(const GCodeProcessorResult& gcode_result)
const float half_width = 0.5f * path.width;
for (size_t j = 1; j < path_vertices_count - 1; ++j) {
size_t curr_s_id = path.sub_paths.front().first.s_id + j;
#if ENABLE_FIX_SEAMS_SYNCH
size_t move_id = extract_move_id(curr_s_id);
const Vec3f& prev = gcode_result.moves[move_id - 1].position;
const Vec3f& curr = gcode_result.moves[move_id].position;
const Vec3f& next = gcode_result.moves[move_id + 1].position;
#else
const Vec3f& prev = gcode_result.moves[curr_s_id - 1].position;
const Vec3f& curr = gcode_result.moves[curr_s_id].position;
const Vec3f& next = gcode_result.moves[curr_s_id + 1].position;
#endif // ENABLE_FIX_SEAMS_SYNCH
// select the subpaths which contains the previous/next segments
if (!path.sub_paths[prev_sub_path_id].contains(curr_s_id))
@ -1986,10 +1789,8 @@ void GCodeViewer::load_toolpaths(const GCodeProcessorResult& gcode_result)
}
}
#if ENABLE_FIX_SEAMS_SYNCH
// dismiss, no more needed
std::vector<size_t>().swap(seams_ids);
#endif // ENABLE_FIX_SEAMS_SYNCH
for (MultiVertexBuffer& v_multibuffer : vertices) {
for (VertexBuffer& v_buffer : v_multibuffer) {
@ -2008,16 +1809,12 @@ void GCodeViewer::load_toolpaths(const GCodeProcessorResult& gcode_result)
// send vertices data to gpu, where needed
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];
#if ENABLE_FIX_SEAMS_SYNCH
t_buffer.model.instances.offsets = instances_offsets[i];
#endif // ENABLE_FIX_SEAMS_SYNCH
}
}
else {
@ -2026,25 +1823,9 @@ void GCodeViewer::load_toolpaths(const GCodeProcessorResult& gcode_result)
if (!inst_buffer.empty()) {
t_buffer.model.instances.buffer = inst_buffer;
t_buffer.model.instances.s_ids = instances_ids[i];
#if ENABLE_FIX_SEAMS_SYNCH
t_buffer.model.instances.offsets = instances_offsets[i];
#endif // ENABLE_FIX_SEAMS_SYNCH
}
}
#else
if (t_buffer.render_primitive_type == TBuffer::ERenderPrimitiveType::Model) {
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];
#if ENABLE_FIX_SEAMS_SYNCH
t_buffer.model.instances.offsets = instances_offsets[i];
#endif // ENABLE_FIX_SEAMS_SYNCH
}
}
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) {
const size_t size_elements = v_buffer.size();
@ -2067,9 +1848,7 @@ void GCodeViewer::load_toolpaths(const GCodeProcessorResult& gcode_result)
t_buffer.vertices.vbos.push_back(static_cast<unsigned int>(id));
t_buffer.vertices.sizes.push_back(size_bytes);
}
#if ENABLE_SEAMS_USING_MODELS
}
#endif // ENABLE_SEAMS_USING_MODELS
}
#if ENABLE_GCODE_VIEWER_STATISTICS
@ -2080,10 +1859,8 @@ void GCodeViewer::load_toolpaths(const GCodeProcessorResult& gcode_result)
// dismiss vertices data, no more needed
std::vector<MultiVertexBuffer>().swap(vertices);
#if ENABLE_SEAMS_USING_MODELS
std::vector<InstanceBuffer>().swap(instances);
std::vector<InstanceIdBuffer>().swap(instances_ids);
#endif // ENABLE_SEAMS_USING_MODELS
// toolpaths data -> extract indices from result
// paths may have been filled while extracting vertices,
@ -2100,18 +1877,14 @@ void GCodeViewer::load_toolpaths(const GCodeProcessorResult& gcode_result)
using VboIndexList = std::vector<unsigned int>;
std::vector<VboIndexList> vbo_indices(m_buffers.size());
#if ENABLE_FIX_SEAMS_SYNCH
seams_count = 0;
#endif // ENABLE_FIX_SEAMS_SYNCH
for (size_t i = 0; i < m_moves_count; ++i) {
const GCodeProcessorResult::MoveVertex& curr = gcode_result.moves[i];
#if ENABLE_FIX_SEAMS_SYNCH
if (curr.type == EMoveType::Seam)
++seams_count;
size_t move_id = i - seams_count;
#endif // ENABLE_FIX_SEAMS_SYNCH
// skip first vertex
if (i == 0)
@ -2139,63 +1912,37 @@ void GCodeViewer::load_toolpaths(const GCodeProcessorResult& gcode_result)
// ensure there is at least one index buffer
if (i_multibuffer.empty()) {
i_multibuffer.push_back(IndexBuffer());
#if ENABLE_SEAMS_USING_MODELS
if (!t_buffer.vertices.vbos.empty())
#endif // ENABLE_SEAMS_USING_MODELS
vbo_index_list.push_back(t_buffer.vertices.vbos[curr_vertex_buffer.first]);
}
// 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();
#if ENABLE_FIX_SEAMS_SYNCH
last_path.add_sub_path(prev, static_cast<unsigned int>(i_multibuffer.size()) - 1, 0, move_id - 1);
#else
last_path.add_sub_path(prev, static_cast<unsigned int>(i_multibuffer.size()) - 1, 0, i - 1);
#endif // ENABLE_FIX_SEAMS_SYNCH
}
}
// 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();
#if ENABLE_FIX_SEAMS_SYNCH
last_path.add_sub_path(prev, static_cast<unsigned int>(i_multibuffer.size()) - 1, 0, move_id - 1);
#else
last_path.add_sub_path(prev, static_cast<unsigned int>(i_multibuffer.size()) - 1, 0, i - 1);
#endif // ENABLE_FIX_SEAMS_SYNCH
}
}
@ -2204,38 +1951,24 @@ void GCodeViewer::load_toolpaths(const GCodeProcessorResult& gcode_result)
switch (t_buffer.render_primitive_type)
{
case TBuffer::ERenderPrimitiveType::Point: {
#if ENABLE_FIX_SEAMS_SYNCH
add_indices_as_point(curr, t_buffer, static_cast<unsigned int>(i_multibuffer.size()) - 1, i_buffer, move_id);
#else
add_indices_as_point(curr, t_buffer, static_cast<unsigned int>(i_multibuffer.size()) - 1, i_buffer, i);
#endif // ENABLE_FIX_SEAMS_SYNCH
curr_vertex_buffer.second += t_buffer.max_vertices_per_segment();
break;
}
case TBuffer::ERenderPrimitiveType::Line: {
#if ENABLE_FIX_SEAMS_SYNCH
add_indices_as_line(prev, curr, t_buffer, static_cast<unsigned int>(i_multibuffer.size()) - 1, i_buffer, move_id);
#else
add_indices_as_line(prev, curr, t_buffer, static_cast<unsigned int>(i_multibuffer.size()) - 1, i_buffer, i);
#endif // ENABLE_FIX_SEAMS_SYNCH
curr_vertex_buffer.second += t_buffer.max_vertices_per_segment();
break;
}
case TBuffer::ERenderPrimitiveType::Triangle: {
#if ENABLE_FIX_SEAMS_SYNCH
add_indices_as_solid(prev, curr, next, t_buffer, curr_vertex_buffer.second, static_cast<unsigned int>(i_multibuffer.size()) - 1, i_buffer, move_id);
#else
add_indices_as_solid(prev, curr, next, t_buffer, curr_vertex_buffer.second, static_cast<unsigned int>(i_multibuffer.size()) - 1, i_buffer, i);
#endif // ENABLE_FIX_SEAMS_SYNCH
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; }
}
}
@ -2249,13 +1982,7 @@ void GCodeViewer::load_toolpaths(const GCodeProcessorResult& gcode_result)
// toolpaths data -> send indices data to gpu
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) {
const size_t size_elements = i_buffer.size();
@ -2278,9 +2005,7 @@ void GCodeViewer::load_toolpaths(const GCodeProcessorResult& gcode_result)
glsafe(::glBufferData(GL_ELEMENT_ARRAY_BUFFER, size_bytes, i_buffer.data(), GL_STATIC_DRAW));
glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0));
}
#if ENABLE_SEAMS_USING_MODELS
}
#endif // ENABLE_SEAMS_USING_MODELS
}
if (progress_dialog != nullptr) {
@ -2321,34 +2046,22 @@ void GCodeViewer::load_toolpaths(const GCodeProcessorResult& gcode_result)
// layers zs / roles / extruder ids -> extract from result
size_t last_travel_s_id = 0;
#if ENABLE_FIX_SEAMS_SYNCH
seams_count = 0;
#endif // ENABLE_FIX_SEAMS_SYNCH
for (size_t i = 0; i < m_moves_count; ++i) {
const GCodeProcessorResult::MoveVertex& move = gcode_result.moves[i];
#if ENABLE_FIX_SEAMS_SYNCH
if (move.type == EMoveType::Seam)
++seams_count;
size_t move_id = i - seams_count;
#endif // ENABLE_FIX_SEAMS_SYNCH
if (move.type == EMoveType::Extrude) {
// layers zs
const double* const last_z = m_layers.empty() ? nullptr : &m_layers.get_zs().back();
const double z = static_cast<double>(move.position.z());
if (last_z == nullptr || z < *last_z - EPSILON || *last_z + EPSILON < z)
#if ENABLE_FIX_SEAMS_SYNCH
m_layers.append(z, { last_travel_s_id, move_id });
#else
m_layers.append(z, { last_travel_s_id, i });
#endif // ENABLE_FIX_SEAMS_SYNCH
else
#if ENABLE_FIX_SEAMS_SYNCH
m_layers.get_ranges().back().last = move_id;
#else
m_layers.get_ranges().back().last = i;
#endif // ENABLE_FIX_SEAMS_SYNCH
// extruder ids
m_extruder_ids.emplace_back(move.extruder_id);
// roles
@ -2356,17 +2069,10 @@ void GCodeViewer::load_toolpaths(const GCodeProcessorResult& gcode_result)
m_roles.emplace_back(move.extrusion_role);
}
else if (move.type == EMoveType::Travel) {
#if ENABLE_FIX_SEAMS_SYNCH
if (move_id - last_travel_s_id > 1 && !m_layers.empty())
m_layers.get_ranges().back().last = move_id;
last_travel_s_id = move_id;
#else
if (i - last_travel_s_id > 1 && !m_layers.empty())
m_layers.get_ranges().back().last = i;
last_travel_s_id = i;
#endif // ENABLE_FIX_SEAMS_SYNCH
}
}
@ -2551,9 +2257,7 @@ void GCodeViewer::refresh_render_paths(bool keep_sequential_current_first, bool
#if ENABLE_GCODE_VIEWER_STATISTICS
Statistics* statistics = const_cast<Statistics*>(&m_statistics);
statistics->render_paths_size = 0;
#if ENABLE_SEAMS_USING_MODELS
statistics->models_instances_size = 0;
#endif // ENABLE_SEAMS_USING_MODELS
#endif // ENABLE_GCODE_VIEWER_STATISTICS
const bool top_layer_only = get_app_config()->get("seq_top_layer_only") == "1";
@ -2574,13 +2278,8 @@ void GCodeViewer::refresh_render_paths(bool keep_sequential_current_first, bool
if (!buffer.visible)
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;
@ -2598,7 +2297,6 @@ void GCodeViewer::refresh_render_paths(bool keep_sequential_current_first, bool
}
}
else {
#endif // ENABLE_SEAMS_USING_MODELS
for (size_t i = 0; i < buffer.paths.size(); ++i) {
const Path& path = buffer.paths[i];
if (path.type == EMoveType::Travel) {
@ -2632,9 +2330,7 @@ void GCodeViewer::refresh_render_paths(bool keep_sequential_current_first, bool
}
}
}
#if ENABLE_SEAMS_USING_MODELS
}
#endif // ENABLE_SEAMS_USING_MODELS
}
// update current sequential position
@ -2644,30 +2340,21 @@ void GCodeViewer::refresh_render_paths(bool keep_sequential_current_first, bool
// get the world position from the vertex buffer
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();
sequential_view->current_position.x() = buffer.model.instances.buffer[offset + 0];
sequential_view->current_position.y() = buffer.model.instances.buffer[offset + 1];
sequential_view->current_position.z() = buffer.model.instances.buffer[offset + 2];
#if ENABLE_FIX_SEAMS_SYNCH
sequential_view->current_offset = buffer.model.instances.offsets[i];
#endif // ENABLE_FIX_SEAMS_SYNCH
found = true;
break;
}
}
}
else {
#endif // ENABLE_SEAMS_USING_MODELS
// searches the path containing the current position
for (const Path& path : buffer.paths) {
if (path.contains(m_sequential_view.current.last)) {
@ -2699,18 +2386,13 @@ void GCodeViewer::refresh_render_paths(bool keep_sequential_current_first, bool
glsafe(::glGetBufferSubData(GL_ARRAY_BUFFER, static_cast<GLintptr>(index * buffer.vertices.vertex_size_bytes()), static_cast<GLsizeiptr>(3 * sizeof(float)), static_cast<void*>(sequential_view->current_position.data())));
glsafe(::glBindBuffer(GL_ARRAY_BUFFER, 0));
#if ENABLE_FIX_SEAMS_SYNCH
sequential_view->current_offset = Vec3f::Zero();
#endif // ENABLE_FIX_SEAMS_SYNCH
found = true;
break;
}
}
}
#if ENABLE_SEAMS_USING_MODELS
}
#endif // ENABLE_SEAMS_USING_MODELS
if (found)
break;
@ -2817,20 +2499,11 @@ void GCodeViewer::refresh_render_paths(bool keep_sequential_current_first, bool
#endif
}
#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();
@ -2846,11 +2519,7 @@ 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;
@ -2873,14 +2542,11 @@ void GCodeViewer::refresh_render_paths(bool keep_sequential_current_first, bool
}
}
}
#endif // ENABLE_SEAMS_USING_MODELS
// set sequential data to their final value
sequential_view->endpoints = top_layer_only ? top_layer_endpoints : global_endpoints;
sequential_view->current.first = !top_layer_only && keep_sequential_current_first ? std::clamp(sequential_view->current.first, sequential_view->endpoints.first, sequential_view->endpoints.last) : sequential_view->endpoints.first;
#if ENABLE_SEAMS_USING_MODELS
sequential_view->global = global_endpoints;
#endif // ENABLE_SEAMS_USING_MODELS
// updates sequential range caps
std::array<SequentialRangeCap, 2>* sequential_range_caps = const_cast<std::array<SequentialRangeCap, 2>*>(&m_sequential_range_caps);
@ -3002,11 +2668,9 @@ void GCodeViewer::refresh_render_paths(bool keep_sequential_current_first, bool
statistics->render_paths_size += SLIC3R_STDVEC_MEMSIZE(path.sizes, unsigned int);
statistics->render_paths_size += SLIC3R_STDVEC_MEMSIZE(path.offsets, size_t);
}
#if ENABLE_SEAMS_USING_MODELS
statistics->models_instances_size += SLIC3R_STDVEC_MEMSIZE(buffer.model.instances.buffer, float);
statistics->models_instances_size += SLIC3R_STDVEC_MEMSIZE(buffer.model.instances.s_ids, size_t);
statistics->models_instances_size += SLIC3R_STDVEC_MEMSIZE(buffer.model.instances.render_ranges.ranges, InstanceVBuffer::Ranges::Range);
#endif // ENABLE_SEAMS_USING_MODELS
}
statistics->refresh_paths_time = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::high_resolution_clock::now() - start_time).count();
#endif // ENABLE_GCODE_VIEWER_STATISTICS
@ -3095,7 +2759,6 @@ void GCodeViewer::render_toolpaths()
}
};
#if ENABLE_SEAMS_USING_MODELS
#if ENABLE_GCODE_VIEWER_STATISTICS
auto render_as_instanced_model = [this]
#else
@ -3121,7 +2784,6 @@ 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
@ -3179,8 +2841,6 @@ void GCodeViewer::render_toolpaths()
buffer_range.first = buffer_range.last;
}
};
#endif // ENABLE_SEAMS_USING_BATCHED_MODELS
#endif // ENABLE_SEAMS_USING_MODELS
auto line_width = [](double zoom) {
return (zoom < 5.0) ? 1.0 : (1.0 + 5.0 * (zoom - 5.0) / (100.0 - 5.0));
@ -3190,11 +2850,7 @@ void GCodeViewer::render_toolpaths()
unsigned char end_id = buffer_id(EMoveType::Count);
for (unsigned char i = begin_id; i < end_id; ++i) {
#if ENABLE_SEAMS_USING_MODELS
TBuffer& buffer = m_buffers[i];
#else
const TBuffer& buffer = m_buffers[i];
#endif // ENABLE_SEAMS_USING_MODELS
if (!buffer.visible || !buffer.has_data())
continue;
@ -3202,25 +2858,17 @@ void GCodeViewer::render_toolpaths()
if (shader != nullptr) {
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) {
const IBuffer& i_buffer = buffer.indices[j];
@ -3261,9 +2909,7 @@ void GCodeViewer::render_toolpaths()
glsafe(::glDisableClientState(GL_VERTEX_ARRAY));
glsafe(::glBindBuffer(GL_ARRAY_BUFFER, 0));
}
#if ENABLE_SEAMS_USING_MODELS
}
#endif // ENABLE_SEAMS_USING_MODELS
shader->stop_using();
}
@ -3384,11 +3030,7 @@ void GCodeViewer::render_legend(float& legend_height)
bool imperial_units = wxGetApp().app_config->get("use_inches") == "1";
#if ENABLE_SEAMS_USING_BATCHED_MODELS
auto append_item = [icon_size, percent_bar_size, &imgui, imperial_units](EItemType type, const Color& color, const std::string& label,
#else
auto append_item = [this, icon_size, percent_bar_size, &imgui, imperial_units](EItemType type, const Color& color, const std::string& label,
#endif // ENABLE_SEAMS_USING_BATCHED_MODELS
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) {
@ -3406,19 +3048,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);
float radius = 0.5f * icon_size;
draw_list->AddCircleFilled(center, radius, ImGui::GetColorU32({ color[0], color[1], color[2], 1.0f }), 16);
radius = 0.5f * icon_size * 0.01f * 33.0f;
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);
draw_list->AddCircleFilled(center, 0.5f * icon_size, ImGui::GetColorU32({ color[0], color[1], color[2], 1.0f }), 16);
break;
}
case EItemType::Hexagon: {
@ -4178,11 +3808,7 @@ 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
@ -4608,13 +4234,9 @@ void GCodeViewer::render_statistics()
add_counter(std::string("Multi GL_LINES:"), m_statistics.gl_multi_lines_calls_count);
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
}
if (ImGui::CollapsingHeader("CPU memory")) {
@ -4623,17 +4245,13 @@ void GCodeViewer::render_statistics()
ImGui::Separator();
add_memory(std::string("Paths:"), m_statistics.paths_size);
add_memory(std::string("Render paths:"), m_statistics.render_paths_size);
#if ENABLE_SEAMS_USING_MODELS
add_memory(std::string("Models instances:"), m_statistics.models_instances_size);
#endif // ENABLE_SEAMS_USING_MODELS
}
if (ImGui::CollapsingHeader("GPU memory")) {
add_memory(std::string("Vertices:"), m_statistics.total_vertices_gpu_size);
add_memory(std::string("Indices:"), m_statistics.total_indices_gpu_size);
#if ENABLE_SEAMS_USING_MODELS
add_memory(std::string("Instances:"), m_statistics.total_instances_gpu_size);
#endif // ENABLE_SEAMS_USING_MODELS
ImGui::Separator();
add_memory(std::string("Max VBuffer:"), m_statistics.max_vbuffer_gpu_size);
add_memory(std::string("Max IBuffer:"), m_statistics.max_ibuffer_gpu_size);
@ -4643,12 +4261,8 @@ void GCodeViewer::render_statistics()
add_counter(std::string("Travel segments count:"), m_statistics.travel_segments_count);
add_counter(std::string("Wipe segments count:"), m_statistics.wipe_segments_count);
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);
add_counter(std::string("IBuffers count:"), m_statistics.ibuffers_count);

View File

@ -27,13 +27,9 @@ class GCodeViewer
using MultiVertexBuffer = std::vector<VertexBuffer>;
using IndexBuffer = std::vector<IBufferType>;
using MultiIndexBuffer = std::vector<IndexBuffer>;
#if ENABLE_SEAMS_USING_MODELS
using InstanceBuffer = std::vector<float>;
using InstanceIdBuffer = std::vector<size_t>;
#endif // ENABLE_SEAMS_USING_MODELS
#if ENABLE_FIX_SEAMS_SYNCH
using InstancesOffsets = std::vector<Vec3f>;
#endif // ENABLE_FIX_SEAMS_SYNCH
static const std::vector<Color> Extrusion_Role_Colors;
static const std::vector<Color> Options_Colors;
@ -107,17 +103,10 @@ class GCodeViewer
void reset();
};
#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
@ -140,7 +129,6 @@ class GCodeViewer
void reset();
};
#if ENABLE_SEAMS_USING_BATCHED_MODELS
enum class EFormat : unsigned char
{
InstancedModel,
@ -148,21 +136,17 @@ class GCodeViewer
};
EFormat format;
#endif // ENABLE_SEAMS_USING_BATCHED_MODELS
// cpu-side buffer containing all instances data
InstanceBuffer buffer;
// indices of the moves for all instances
std::vector<size_t> s_ids;
#if ENABLE_FIX_SEAMS_SYNCH
// position offsets, used to show the correct value of the tool position
InstancesOffsets offsets;
#endif // ENABLE_FIX_SEAMS_SYNCH
Ranges render_ranges;
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)
{
@ -171,14 +155,10 @@ class GCodeViewer
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();
};
#endif // ENABLE_SEAMS_USING_MODELS
// ibo buffer containing indices data (for lines/triangles) used to render a specific toolpath type
struct IBuffer
@ -313,17 +293,9 @@ class GCodeViewer
{
Point,
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
};
ERenderPrimitiveType render_primitive_type;
@ -332,22 +304,18 @@ class GCodeViewer
VBuffer vertices;
std::vector<IBuffer> indices;
#if ENABLE_SEAMS_USING_MODELS
struct Model
{
GLModel model;
Color color;
InstanceVBuffer instances;
#if ENABLE_SEAMS_USING_BATCHED_MODELS
GLModel::InitializationData data;
#endif // ENABLE_SEAMS_USING_BATCHED_MODELS
void reset();
};
// contain the buffer for model primitive types
Model model;
#endif // ENABLE_SEAMS_USING_MODELS
std::string shader;
std::vector<Path> paths;
@ -396,7 +364,6 @@ class GCodeViewer
}
size_t max_indices_per_segment_size_bytes() const { return max_indices_per_segment() * sizeof(IBufferType); }
#if ENABLE_SEAMS_USING_MODELS
bool has_data() const {
switch (render_primitive_type)
{
@ -405,23 +372,14 @@ 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; }
}
}
#else
bool has_data() const {
return !vertices.vbos.empty() && vertices.vbos.front() != 0 && !indices.empty() && indices.front().ibo != 0;
}
#endif // ENABLE_SEAMS_USING_MODELS
};
// helper to render shells
@ -590,36 +548,24 @@ class GCodeViewer
int64_t gl_multi_lines_calls_count{ 0 };
int64_t gl_multi_triangles_calls_count{ 0 };
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 };
int64_t total_vertices_gpu_size{ 0 };
int64_t total_indices_gpu_size{ 0 };
#if ENABLE_SEAMS_USING_MODELS
int64_t total_instances_gpu_size{ 0 };
#endif // ENABLE_SEAMS_USING_MODELS
int64_t max_vbuffer_gpu_size{ 0 };
int64_t max_ibuffer_gpu_size{ 0 };
int64_t paths_size{ 0 };
int64_t render_paths_size{ 0 };
#if ENABLE_SEAMS_USING_MODELS
int64_t models_instances_size{ 0 };
#endif // ENABLE_SEAMS_USING_MODELS
// other
int64_t travel_segments_count{ 0 };
int64_t wipe_segments_count{ 0 };
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 };
@ -645,40 +591,28 @@ class GCodeViewer
gl_multi_lines_calls_count = 0;
gl_multi_triangles_calls_count = 0;
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
}
void reset_sizes() {
results_size = 0;
total_vertices_gpu_size = 0;
total_indices_gpu_size = 0;
#if ENABLE_SEAMS_USING_MODELS
total_instances_gpu_size = 0;
#endif // ENABLE_SEAMS_USING_MODELS
max_vbuffer_gpu_size = 0;
max_ibuffer_gpu_size = 0;
paths_size = 0;
render_paths_size = 0;
#if ENABLE_SEAMS_USING_MODELS
models_instances_size = 0;
#endif // ENABLE_SEAMS_USING_MODELS
}
void reset_others() {
travel_segments_count = 0;
wipe_segments_count = 0;
extrude_segments_count = 0;
#if ENABLE_SEAMS_USING_MODELS
extrude_segments_count = 0;
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;
}
@ -693,12 +627,10 @@ public:
GLModel m_model;
Vec3f m_world_position;
Transform3f m_world_transform;
#if ENABLE_FIX_SEAMS_SYNCH
// for seams, the position of the marker is on the last endpoint of the toolpath containing it
// the offset is used to show the correct value of tool position in the "ToolPosition" window
// see implementation of render() method
Vec3f m_world_offset;
#endif // ENABLE_FIX_SEAMS_SYNCH
float m_z_offset{ 0.5f };
bool m_visible{ true };
@ -708,9 +640,7 @@ public:
const BoundingBoxf3& get_bounding_box() const { return m_model.get_bounding_box(); }
void set_world_position(const Vec3f& position);
#if ENABLE_FIX_SEAMS_SYNCH
void set_world_offset(const Vec3f& offset) { m_world_offset = offset; }
#endif // ENABLE_FIX_SEAMS_SYNCH
bool is_visible() const { return m_visible; }
void set_visible(bool visible) { m_visible = visible; }
@ -764,13 +694,9 @@ public:
Endpoints endpoints;
Endpoints current;
Endpoints last_current;
#if ENABLE_SEAMS_USING_MODELS
Endpoints global;
#endif // ENABLE_SEAMS_USING_MODELS
Vec3f current_position{ Vec3f::Zero() };
#if ENABLE_FIX_SEAMS_SYNCH
Vec3f current_offset{ Vec3f::Zero() };
#endif // ENABLE_FIX_SEAMS_SYNCH
Marker marker;
GCodeWindow gcode_window;
std::vector<unsigned int> gcode_ids;
@ -847,9 +773,7 @@ public:
GCodeViewer();
~GCodeViewer() { reset(); }
#if ENABLE_SEAMS_USING_MODELS
void init();
#endif // ENABLE_SEAMS_USING_MODELS
// extract rendering data from the given parameters
void load(const GCodeProcessorResult& gcode_result, const Print& print, bool initialized);

View File

@ -1422,10 +1422,8 @@ void GLCanvas3D::render()
if (!is_initialized() && !init())
return;
#if ENABLE_SEAMS_USING_MODELS
if (!m_main_toolbar.is_enabled())
m_gcode_viewer.init();
#endif // ENABLE_SEAMS_USING_MODELS
if (! m_bed.build_volume().valid()) {
// this happens at startup when no data is still saved under <>\AppData\Roaming\Slic3rPE
@ -4148,24 +4146,15 @@ void GLCanvas3D::_render_thumbnail_internal(ThumbnailData& thumbnail_data, const
}
}
#if !ENABLE_SAVE_COMMANDS_ALWAYS_ENABLED
if (visible_volumes.empty())
return;
#endif // !ENABLE_SAVE_COMMANDS_ALWAYS_ENABLED
BoundingBoxf3 volumes_box;
#if ENABLE_SAVE_COMMANDS_ALWAYS_ENABLED
if (!visible_volumes.empty()) {
#endif // ENABLE_SAVE_COMMANDS_ALWAYS_ENABLED
for (const GLVolume* vol : visible_volumes) {
volumes_box.merge(vol->transformed_bounding_box());
}
#if ENABLE_SAVE_COMMANDS_ALWAYS_ENABLED
}
else
// This happens for empty projects
volumes_box = m_bed.extended_bounding_box();
#endif // ENABLE_SAVE_COMMANDS_ALWAYS_ENABLED
Camera camera;
camera.set_type(camera_type);

View File

@ -623,9 +623,7 @@ public:
void reset_volumes();
ModelInstanceEPrintVolumeState check_volumes_outside_state() const;
#if ENABLE_SEAMS_USING_MODELS
void init_gcode_viewer() { m_gcode_viewer.init(); }
#endif // ENABLE_SEAMS_USING_MODELS
void reset_gcode_toolpaths() { m_gcode_viewer.reset(); }
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); }

View File

@ -17,7 +17,6 @@
namespace Slic3r {
namespace GUI {
#if ENABLE_SEAMS_USING_BATCHED_MODELS
size_t GLModel::InitializationData::vertices_count() const
{
size_t ret = 0;
@ -35,7 +34,6 @@ size_t GLModel::InitializationData::indices_count() const
}
return ret;
}
#endif // ENABLE_SEAMS_USING_BATCHED_MODELS
void GLModel::init_from(const InitializationData& data)
{
@ -231,7 +229,6 @@ void GLModel::render() const
}
}
#if ENABLE_SEAMS_USING_MODELS
void GLModel::render_instanced(unsigned int instances_vbo, unsigned int instances_count) const
{
if (instances_vbo == 0)
@ -308,7 +305,6 @@ void GLModel::render_instanced(unsigned int instances_vbo, unsigned int instance
glsafe(::glBindBuffer(GL_ARRAY_BUFFER, 0));
}
#endif // ENABLE_SEAMS_USING_MODELS
void GLModel::send_to_gpu(RenderData& data, const std::vector<float>& vertices, const std::vector<unsigned int>& indices)
{

View File

@ -49,14 +49,12 @@ 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:
@ -80,9 +78,7 @@ namespace GUI {
void reset();
void render() const;
#if ENABLE_SEAMS_USING_MODELS
void render_instanced(unsigned int instances_vbo, unsigned int instances_count) const;
#endif // ENABLE_SEAMS_USING_MODELS
bool is_initialized() const { return !m_render_data.empty(); }

View File

@ -33,31 +33,13 @@ 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" });
else {
#endif // ENABLE_SEAMS_USING_MODELS
valid &= append_shader("options_110", { "options_110.vs", "options_110.fs" });
if (GUI::wxGetApp().is_glsl_version_greater_or_equal_to(1, 20))
valid &= append_shader("options_120", { "options_120.vs", "options_120.fs" });
#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

@ -12,6 +12,7 @@
#include <exception>
#include <cstdlib>
#include <regex>
#include <string_view>
#include <boost/algorithm/string/predicate.hpp>
#include <boost/algorithm/string.hpp>
#include <boost/format.hpp>
@ -97,6 +98,8 @@
#include <gtk/gtk.h>
#endif
using namespace std::literals;
namespace Slic3r {
namespace GUI {
@ -471,39 +474,86 @@ static bool run_updater_win()
}
#endif //_WIN32
struct FileWildcards {
std::string_view title;
std::vector<std::string_view> file_extensions;
};
static const FileWildcards file_wildcards_by_type[FT_SIZE] = {
/* FT_STL */ { "STL files"sv, { ".stl"sv } },
/* FT_OBJ */ { "OBJ files"sv, { ".obj"sv } },
/* FT_AMF */ { "AMF files"sv, { ".amf"sv, ".zip.amf"sv, ".xml"sv } },
/* FT_3MF */ { "3MF files"sv, { ".3mf"sv } },
/* FT_GCODE */ { "G-code files"sv, { ".gcode"sv, ".gco"sv, ".g"sv, ".ngc"sv } },
/* FT_MODEL */ { "Known files"sv, { ".stl"sv, ".obj"sv, ".3mf"sv, ".amf"sv, ".zip.amf"sv, ".xml"sv } },
/* FT_PROJECT */ { "Project files"sv, { ".3mf"sv, ".amf"sv, ".zip.amf"sv } },
/* FT_GALLERY */ { "Known files"sv, { ".stl"sv, ".obj"sv } },
/* FT_INI */ { "INI files"sv, { ".ini"sv } },
/* FT_SVG */ { "SVG files"sv, { ".svg"sv } },
/* FT_TEX */ { "Texture"sv, { ".png"sv, ".svg"sv } },
/* FT_SL1 */ { "Masked SLA files"sv, { ".sl1"sv, ".sl1s"sv } },
};
// This function produces a Win32 file dialog file template mask to be consumed by wxWidgets on all platforms.
// The function accepts a custom extension parameter. If the parameter is provided, the custom extension
// will be added as a fist to the list. This is important for a "file save" dialog on OSX, which strips
// an extension from the provided initial file name and substitutes it with the default extension (the first one in the template).
wxString file_wildcards(FileType file_type, const std::string &custom_extension)
{
static const std::string defaults[FT_SIZE] = {
/* FT_STL */ "STL files (*.stl)|*.stl;*.STL",
/* FT_OBJ */ "OBJ files (*.obj)|*.obj;*.OBJ",
/* FT_AMF */ "AMF files (*.amf)|*.zip.amf;*.amf;*.AMF;*.xml;*.XML",
/* FT_3MF */ "3MF files (*.3mf)|*.3mf;*.3MF;",
/* FT_GCODE */ "G-code files (*.gcode, *.gco, *.g, *.ngc)|*.gcode;*.GCODE;*.gco;*.GCO;*.g;*.G;*.ngc;*.NGC",
/* FT_MODEL */ "Known files (*.stl, *.obj, *.amf, *.xml, *.3mf, *.prusa)|*.stl;*.STL;*.obj;*.OBJ;*.amf;*.AMF;*.xml;*.XML;*.3mf;*.3MF",
/* FT_PROJECT */ "Project files (*.3mf, *.amf)|*.3mf;*.3MF;*.amf;*.AMF",
/* FT_GALLERY */ "Known files (*.stl, *.obj)|*.stl;*.STL;*.obj;*.OBJ",
const FileWildcards data = file_wildcards_by_type[file_type];
std::string title;
std::string mask;
std::string custom_ext_lower;
/* FT_INI */ "INI files (*.ini)|*.ini;*.INI",
/* FT_SVG */ "SVG files (*.svg)|*.svg;*.SVG",
/* FT_TEX */ "Texture (*.png, *.svg)|*.png;*.PNG;*.svg;*.SVG",
/* FT_SL1 */ "Masked SLA files (*.sl1, *.sl1s)|*.sl1;*.SL1;*.sl1s;*.SL1S",
// Workaround for OSX file picker, for some reason it always saves with the 1st extension.
/* FT_SL1S */ "Masked SLA files (*.sl1s, *.sl1)|*.sl1s;*.SL1S;*.sl1;*.SL1",
};
std::string out = defaults[file_type];
if (! custom_extension.empty()) {
// Find the custom extension in the template.
if (out.find(std::string("*") + custom_extension + ",") == std::string::npos && out.find(std::string("*") + custom_extension + ")") == std::string::npos) {
// The custom extension was not found in the template.
// Append the custom extension to the wildcards, so that the file dialog would not add the default extension to it.
boost::replace_first(out, ")|", std::string(", *") + custom_extension + ")|");
out += std::string(";*") + custom_extension;
// Generate an extension into the title mask and into the list of extensions.
custom_ext_lower = custom_extension;
boost::to_lower(custom_ext_lower);
std::string custom_ext_upper = custom_extension;
boost::to_upper(custom_ext_upper);
if (custom_ext_lower == custom_extension) {
// Add a lower case version.
title = std::string("*") + custom_ext_lower;
mask = title;
// Add an upper case version.
mask += ";*";
mask += custom_ext_upper;
} else if (custom_ext_upper == custom_extension) {
// Add an upper case version.
title = std::string("*") + custom_ext_upper;
mask = title;
// Add a lower case version.
mask += ";*";
mask += custom_ext_lower;
} else {
// Add the mixed case version only.
title = std::string("*") + custom_extension;
mask = title;
}
}
return from_u8(out);
for (const std::string_view &ext : data.file_extensions)
// Only add an extension if it was not added first as the custom extension.
if (ext != custom_ext_lower) {
if (title.empty()) {
title = "*";
title += ext;
mask = title;
} else {
title += ", *";
title += ext;
mask += ";*";
mask += ext;
}
mask += ";*";
std::string ext_upper{ ext };
boost::to_upper(ext_upper);
mask += ext_upper;
}
return GUI::format("%s (%s)|%s", data.title, title, mask);
}
static std::string libslic3r_translate_callback(const char *s) { return wxGetTranslation(wxString(s, wxConvUTF8)).utf8_str().data(); }

View File

@ -66,13 +66,11 @@ enum FileType
FT_TEX,
FT_SL1,
// Workaround for OSX file picker, for some reason it always saves with the 1st extension.
FT_SL1S,
FT_SIZE,
};
extern wxString file_wildcards(FileType file_type, const std::string &custom_extension = std::string());
extern wxString file_wildcards(FileType file_type, const std::string &custom_extension = std::string{});
enum ConfigMenuIDs {
ConfigMenuWizard,

View File

@ -484,6 +484,10 @@ void MenuFactory::append_menu_items_add_volume(wxMenu* menu)
menu->Destroy(settings_id);
}
// Update "Height range Modifier" item (delete old & create new)
if (const auto range_id = menu->FindItem(_L("Height range Modifier")); range_id != wxNOT_FOUND)
menu->Destroy(range_id);
const ConfigOptionMode mode = wxGetApp().get_mode();
if (mode == comAdvanced) {
@ -513,6 +517,8 @@ void MenuFactory::append_menu_items_add_volume(wxMenu* menu)
append_submenu(menu, sub_menu, wxID_ANY, _(item.first), "", item.second,
[]() { return obj_list()->is_instance_or_object_selected(); }, m_parent);
}
append_menu_item_layers_editing(menu);
}
wxMenuItem* MenuFactory::append_menu_item_layers_editing(wxMenu* menu)
@ -944,11 +950,7 @@ void MenuFactory::create_object_menu()
[]() { return plater()->can_split(true) && wxGetApp().get_mode() > comSimple; }, m_parent);
m_object_menu.AppendSeparator();
// Layers Editing for object
append_menu_item_layers_editing(&m_object_menu);
m_object_menu.AppendSeparator();
// "Add (volumes)" popupmenu will be added later in append_menu_items_add_volume()
// "Height range Modifier" and "Add (volumes)" menu items will be added later in append_menu_items_add_volume()
}
void MenuFactory::create_sla_object_menu()

View File

@ -97,7 +97,7 @@ public:
// will be also extended to support additional states, requiring at least one state to remain free out of 19 states.
static const constexpr size_t EXTRUDERS_LIMIT = 16;
virtual const float get_cursor_radius_min() const { return CursorRadiusMin; }
const float get_cursor_radius_min() const override { return CursorRadiusMin; }
protected:
std::array<float, 4> get_cursor_sphere_left_button_color() const override;

View File

@ -39,7 +39,7 @@ protected:
virtual void on_render() override;
virtual void on_render_for_picking() override{};
virtual CommonGizmosDataID on_get_requirements() const;
CommonGizmosDataID on_get_requirements() const override;
private:
void apply_simplify();

View File

@ -831,26 +831,15 @@ bool MainFrame::can_start_new_project() const
bool MainFrame::can_save() const
{
#if ENABLE_SAVE_COMMANDS_ALWAYS_ENABLED
return (m_plater != nullptr) &&
!m_plater->canvas3D()->get_gizmos_manager().is_in_editing_mode(false) &&
m_plater->is_project_dirty();
#else
return (m_plater != nullptr) && !m_plater->model().objects.empty() &&
!m_plater->canvas3D()->get_gizmos_manager().is_in_editing_mode(false) &&
!m_plater->get_project_filename().empty() && m_plater->is_project_dirty();
#endif // ENABLE_SAVE_COMMANDS_ALWAYS_ENABLED
}
bool MainFrame::can_save_as() const
{
#if ENABLE_SAVE_COMMANDS_ALWAYS_ENABLED
return (m_plater != nullptr) &&
!m_plater->canvas3D()->get_gizmos_manager().is_in_editing_mode(false);
#else
return (m_plater != nullptr) && !m_plater->model().objects.empty() &&
!m_plater->canvas3D()->get_gizmos_manager().is_in_editing_mode(false);
#endif // ENABLE_SAVE_COMMANDS_ALWAYS_ENABLED
}
void MainFrame::save_project()

View File

@ -1856,9 +1856,7 @@ struct Plater::priv
}
void export_gcode(fs::path output_path, bool output_path_on_removable_media, PrintHostJob upload_job);
void reload_from_disk();
#if ENABLE_RELOAD_FROM_DISK_REPLACE_FILE
bool replace_volume_with_stl(int object_idx, int volume_idx, const fs::path& new_path, const wxString& snapshot = "");
#endif // ENABLE_RELOAD_FROM_DISK_REPLACE_FILE
void replace_with_stl();
void reload_all_from_disk();
void set_current_panel(wxPanel* panel);
@ -2925,6 +2923,7 @@ void Plater::priv::remove(size_t obj_idx)
if (view3D->is_layers_editing_enabled())
view3D->enable_layers_editing(false);
m_ui_jobs.cancel_all();
model.delete_object(obj_idx);
update();
// Delete object from Sidebar list. Do it after update, so that the GLScene selection is updated with the modified model.
@ -2939,6 +2938,7 @@ void Plater::priv::delete_object_from_model(size_t obj_idx)
if (! model.objects[obj_idx]->name.empty())
snapshot_label += ": " + wxString::FromUTF8(model.objects[obj_idx]->name.c_str());
Plater::TakeSnapshot snapshot(q, snapshot_label);
m_ui_jobs.cancel_all();
model.delete_object(obj_idx);
update();
object_list_changed();
@ -2956,6 +2956,8 @@ void Plater::priv::delete_all_objects_from_model()
view3D->get_canvas3d()->reset_sequential_print_clearance();
m_ui_jobs.cancel_all();
// Stop and reset the Print content.
background_process.reset();
model.clear_objects();
@ -2986,6 +2988,8 @@ void Plater::priv::reset()
view3D->get_canvas3d()->reset_sequential_print_clearance();
m_ui_jobs.cancel_all();
// Stop and reset the Print content.
this->background_process.reset();
model.clear_objects();
@ -3371,7 +3375,6 @@ void Plater::priv::update_sla_scene()
this->update_restart_background_process(true, true);
}
#if ENABLE_RELOAD_FROM_DISK_REPLACE_FILE
bool Plater::priv::replace_volume_with_stl(int object_idx, int volume_idx, const fs::path& new_path, const wxString& snapshot)
{
const std::string path = new_path.string();
@ -3439,7 +3442,6 @@ bool Plater::priv::replace_volume_with_stl(int object_idx, int volume_idx, const
return true;
}
#endif // ENABLE_RELOAD_FROM_DISK_REPLACE_FILE
void Plater::priv::replace_with_stl()
{
@ -3477,72 +3479,8 @@ void Plater::priv::replace_with_stl()
return;
}
#if ENABLE_RELOAD_FROM_DISK_REPLACE_FILE
if (!replace_volume_with_stl(object_idx, volume_idx, out_path, _L("Replace with STL")))
return;
#else
const auto& path = out_path.string();
wxBusyCursor wait;
wxBusyInfo info(_L("Replace from:") + " " + from_u8(path), q->get_current_canvas3D()->get_wxglcanvas());
Model new_model;
try {
new_model = Model::read_from_file(path, nullptr, nullptr, Model::LoadAttribute::AddDefaultInstances);
for (ModelObject* model_object : new_model.objects) {
model_object->center_around_origin();
model_object->ensure_on_bed();
}
}
catch (std::exception&) {
// error while loading
return;
}
if (new_model.objects.size() > 1 || new_model.objects[0]->volumes.size() > 1) {
MessageDialog dlg(q, _L("Unable to replace with more than one volume"), _L("Error during replace"), wxOK | wxOK_DEFAULT | wxICON_WARNING);
dlg.ShowModal();
return;
}
Plater::TakeSnapshot snapshot(q, _L("Replace with STL"));
ModelObject* old_model_object = model.objects[object_idx];
ModelVolume* old_volume = old_model_object->volumes[volume_idx];
bool sinking = old_model_object->bounding_box().min.z() < SINKING_Z_THRESHOLD;
ModelObject* new_model_object = new_model.objects[0];
old_model_object->add_volume(*new_model_object->volumes[0]);
ModelVolume* new_volume = old_model_object->volumes.back();
new_volume->set_new_unique_id();
new_volume->config.apply(old_volume->config);
new_volume->set_type(old_volume->type());
new_volume->set_material_id(old_volume->material_id());
new_volume->set_transformation(old_volume->get_transformation());
new_volume->translate(new_volume->get_transformation().get_matrix(true) * (new_volume->source.mesh_offset - old_volume->source.mesh_offset));
assert(! old_volume->source.is_converted_from_inches || ! old_volume->source.is_converted_from_meters);
if (old_volume->source.is_converted_from_inches)
new_volume->convert_from_imperial_units();
else if (old_volume->source.is_converted_from_meters)
new_volume->convert_from_meters();
new_volume->supported_facets.assign(old_volume->supported_facets);
new_volume->seam_facets.assign(old_volume->seam_facets);
new_volume->mmu_segmentation_facets.assign(old_volume->mmu_segmentation_facets);
std::swap(old_model_object->volumes[volume_idx], old_model_object->volumes.back());
old_model_object->delete_volume(old_model_object->volumes.size() - 1);
if (!sinking)
old_model_object->ensure_on_bed();
old_model_object->sort_volumes(wxGetApp().app_config->get("order_volumes") == "1");
// if object has just one volume, rename object too
if (old_model_object->volumes.size() == 1)
old_model_object->name = old_model_object->volumes[0]->name;
// update new name in ObjectList
sidebar->obj_list()->update_name_in_list(object_idx, volume_idx);
sla::reproject_points_and_holes(old_model_object);
#endif // ENABLE_RELOAD_FROM_DISK_REPLACE_FILE
// update 3D scene
update();
@ -3591,9 +3529,7 @@ void Plater::priv::reload_from_disk()
// collects paths of files to load
std::vector<fs::path> input_paths;
std::vector<fs::path> missing_input_paths;
#if ENABLE_RELOAD_FROM_DISK_REPLACE_FILE
std::vector<fs::path> replace_paths;
#endif // ENABLE_RELOAD_FROM_DISK_REPLACE_FILE
for (const SelectedVolume& v : selected_volumes) {
const ModelObject* object = model.objects[v.object_idx];
const ModelVolume* volume = object->volumes[v.volume_idx];
@ -3601,7 +3537,6 @@ void Plater::priv::reload_from_disk()
if (!volume->source.input_file.empty()) {
if (fs::exists(volume->source.input_file))
input_paths.push_back(volume->source.input_file);
#if ENABLE_RELOAD_FROM_DISK_REPLACE_FILE
else {
// searches the source in the same folder containing the object
bool found = false;
@ -3619,10 +3554,6 @@ void Plater::priv::reload_from_disk()
if (!found)
missing_input_paths.push_back(volume->source.input_file);
}
#else
else
missing_input_paths.push_back(volume->source.input_file);
#endif // ENABLE_RELOAD_FROM_DISK_REPLACE_FILE
}
else if (!object->input_file.empty() && volume->is_model_part() && !volume->name.empty() && !volume->source.is_from_builtin_objects)
missing_input_paths.push_back(volume->name);
@ -3665,7 +3596,6 @@ void Plater::priv::reload_from_disk()
}
}
else {
#if ENABLE_RELOAD_FROM_DISK_REPLACE_FILE
wxString message = _L("The selected file") + " (" + from_u8(sel_filename) + ") " +
_L("differs from the original file") + " (" + from_u8(search.filename().string()) + ").\n" + _L("Do you want to replace it") + " ?";
//wxMessageDialog dlg(q, message, wxMessageBoxCaptionStr, wxYES_NO | wxYES_DEFAULT | wxICON_QUESTION);
@ -3673,23 +3603,14 @@ void Plater::priv::reload_from_disk()
if (dlg.ShowModal() == wxID_YES)
replace_paths.push_back(sel_filename_path);
missing_input_paths.pop_back();
#else
wxString message = _L("It is not allowed to change the file to reload") + " (" + from_u8(search.filename().string()) + ").\n" + _L("Do you want to retry") + " ?";
//wxMessageDialog dlg(q, message, wxMessageBoxCaptionStr, wxYES_NO | wxYES_DEFAULT | wxICON_QUESTION);
MessageDialog dlg(q, message, wxMessageBoxCaptionStr, wxYES_NO | wxYES_DEFAULT | wxICON_QUESTION);
if (dlg.ShowModal() != wxID_YES)
return;
#endif // ENABLE_RELOAD_FROM_DISK_REPLACE_FILE
}
}
std::sort(input_paths.begin(), input_paths.end());
input_paths.erase(std::unique(input_paths.begin(), input_paths.end()), input_paths.end());
#if ENABLE_RELOAD_FROM_DISK_REPLACE_FILE
std::sort(replace_paths.begin(), replace_paths.end());
replace_paths.erase(std::unique(replace_paths.begin(), replace_paths.end()), replace_paths.end());
#endif // ENABLE_RELOAD_FROM_DISK_REPLACE_FILE
std::vector<wxString> fail_list;
@ -3785,7 +3706,6 @@ void Plater::priv::reload_from_disk()
}
}
#if ENABLE_RELOAD_FROM_DISK_REPLACE_FILE
for (size_t i = 0; i < replace_paths.size(); ++i) {
const auto& path = replace_paths[i].string();
for (const SelectedVolume& sel_v : selected_volumes) {
@ -3797,7 +3717,6 @@ void Plater::priv::reload_from_disk()
}
}
}
#endif // ENABLE_RELOAD_FROM_DISK_REPLACE_FILE
if (!fail_list.empty()) {
wxString message = _L("Unable to reload:") + "\n";
@ -3911,9 +3830,7 @@ void Plater::priv::set_current_panel(wxPanel* panel)
bool export_in_progress = this->background_process.is_export_scheduled();
bool model_fits = view3D->get_canvas3d()->check_volumes_outside_state() != ModelInstancePVS_Partly_Outside;
if (!model.objects.empty() && !export_in_progress && model_fits) {
#if ENABLE_SEAMS_USING_MODELS
preview->get_canvas3d()->init_gcode_viewer();
#endif // ENABLE_SEAMS_USING_MODELS
q->reslice();
}
// keeps current gcode preview, if any
@ -4644,7 +4561,7 @@ void Plater::priv::set_bed_shape(const Pointfs& shape, const double max_print_he
bool Plater::priv::can_delete() const
{
return !get_selection().is_empty() && !get_selection().is_wipe_tower() && !m_ui_jobs.is_any_running();
return !get_selection().is_empty() && !get_selection().is_wipe_tower();
}
bool Plater::priv::can_delete_all() const
@ -5502,6 +5419,7 @@ void Plater::remove_selected()
return;
Plater::TakeSnapshot snapshot(this, _L("Delete Selected Objects"));
p->m_ui_jobs.cancel_all();
p->view3D->delete_selected();
}
@ -5735,7 +5653,7 @@ void Plater::export_gcode(bool prefer_removable)
wxFileDialog dlg(this, (printer_technology() == ptFFF) ? _L("Save G-code file as:") : _L("Save SL1 / SL1S file as:"),
start_dir,
from_path(default_output_file.filename()),
GUI::file_wildcards((printer_technology() == ptFFF) ? FT_GCODE : boost::iequals(ext, ".sl1s") ? FT_SL1S : FT_SL1, ext),
GUI::file_wildcards((printer_technology() == ptFFF) ? FT_GCODE : FT_SL1, ext),
wxFD_SAVE | wxFD_OVERWRITE_PROMPT
);
if (dlg.ShowModal() == wxID_OK) {
@ -5934,16 +5852,11 @@ void Plater::export_amf()
bool Plater::export_3mf(const boost::filesystem::path& output_path)
{
#if ENABLE_SAVE_COMMANDS_ALWAYS_ENABLED
if (p->model.objects.empty()) {
MessageDialog dialog(nullptr, _L("The plater is empty.\nDo you want to save the project?"), _L("Save project"), wxYES_NO);
if (dialog.ShowModal() != wxID_YES)
return false;
}
#else
if (p->model.objects.empty())
return false;
#endif // ENABLE_SAVE_COMMANDS_ALWAYS_ENABLED
wxString path;
bool export_config = true;
@ -6138,11 +6051,12 @@ void Plater::send_gcode()
upload_job.printhost->get_groups(groups);
}
PrintHostSendDialog dlg(default_output_file, upload_job.printhost->can_start_print(), groups);
PrintHostSendDialog dlg(default_output_file, upload_job.printhost->get_post_upload_actions(), groups);
if (dlg.ShowModal() == wxID_OK) {
upload_job.upload_data.upload_path = dlg.filename();
upload_job.upload_data.start_print = dlg.start_print();
upload_job.upload_data.post_action = dlg.post_action();
upload_job.upload_data.group = dlg.group();
p->export_gcode(fs::path(), false, std::move(upload_job));
}
}

View File

@ -481,14 +481,18 @@ void PreferencesDialog::build(size_t selected_tab)
option = Option(def, "dark_color_mode");
m_optgroup_dark_mode->append_single_option_line(option);
def.label = L("Use system menu for application");
def.type = coBool;
def.tooltip = L("If enabled, application will use the standart Windows system menu,\n"
"but on some combination od display scales it can look ugly. "
"If disabled, old UI will be used.");
def.set_default_value(new ConfigOptionBool{ app_config->get("sys_menu_enabled") == "1" });
option = Option(def, "sys_menu_enabled");
m_optgroup_dark_mode->append_single_option_line(option);
if (wxPlatformInfo::Get().GetOSMajorVersion() >= 10) // Use system menu just for Window newer then Windows 10
// Use menu with ownerdrawn items by default on systems older then Windows 10
{
def.label = L("Use system menu for application");
def.type = coBool;
def.tooltip = L("If enabled, application will use the standart Windows system menu,\n"
"but on some combination od display scales it can look ugly. "
"If disabled, old UI will be used.");
def.set_default_value(new ConfigOptionBool{ app_config->get("sys_menu_enabled") == "1" });
option = Option(def, "sys_menu_enabled");
m_optgroup_dark_mode->append_single_option_line(option);
}
activate_options_tab(m_optgroup_dark_mode);
}

View File

@ -23,7 +23,6 @@
#include "GUI_App.hpp"
#include "MsgDialog.hpp"
#include "I18N.hpp"
#include "../Utils/PrintHost.hpp"
#include "MainFrame.hpp"
#include "libslic3r/AppConfig.hpp"
#include "NotificationManager.hpp"
@ -35,13 +34,13 @@ namespace Slic3r {
namespace GUI {
static const char *CONFIG_KEY_PATH = "printhost_path";
static const char *CONFIG_KEY_PRINT = "printhost_print";
static const char *CONFIG_KEY_GROUP = "printhost_group";
PrintHostSendDialog::PrintHostSendDialog(const fs::path &path, bool can_start_print, const wxArrayString &groups)
PrintHostSendDialog::PrintHostSendDialog(const fs::path &path, PrintHostPostUploadActions post_actions, const wxArrayString &groups)
: MsgDialog(static_cast<wxWindow*>(wxGetApp().mainframe), _L("Send G-Code to printer host"), _L("Upload to Printer Host with the following filename:"))
, txt_filename(new wxTextCtrl(this, wxID_ANY))
, combo_groups(!groups.IsEmpty() ? new wxComboBox(this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, groups, wxCB_READONLY) : nullptr)
, post_upload_action(PrintHostPostUploadAction::None)
{
#ifdef __APPLE__
txt_filename->OSXDisableAllSmartSubstitutions();
@ -77,38 +76,47 @@ PrintHostSendDialog::PrintHostSendDialog(const fs::path &path, bool can_start_pr
txt_filename->SetValue(recent_path);
txt_filename->SetFocus();
wxString suffix = recent_path.substr(recent_path.find_last_of('.'));
m_valid_suffix = recent_path.substr(recent_path.find_last_of('.'));
// .gcode suffix control
auto validate_path = [this](const wxString &path) -> bool {
if (! path.Lower().EndsWith(m_valid_suffix.Lower())) {
MessageDialog msg_wingow(this, wxString::Format(_L("Upload filename doesn't end with \"%s\". Do you wish to continue?"), m_valid_suffix), wxString(SLIC3R_APP_NAME), wxYES | wxNO);
if (msg_wingow.ShowModal() == wxID_NO)
return false;
}
return true;
};
if (can_start_print) {
if (post_actions.has(PrintHostPostUploadAction::StartPrint)) {
auto* btn_print = add_button(wxID_YES, false, _L("Upload and Print"));
btn_print->Bind(wxEVT_BUTTON, [this, suffix](wxCommandEvent&) {
wxString path = txt_filename->GetValue();
// .gcode suffix control
if (!path.Lower().EndsWith(suffix.Lower()))
{
MessageDialog msg_wingow(this, wxString::Format(_L("Upload filename doesn't end with \"%s\". Do you wish to continue?"), suffix), wxString(SLIC3R_APP_NAME), wxYES | wxNO);
if (msg_wingow.ShowModal() == wxID_NO)
return;
btn_print->Bind(wxEVT_BUTTON, [this, validate_path](wxCommandEvent&) {
if (validate_path(txt_filename->GetValue())) {
post_upload_action = PrintHostPostUploadAction::StartPrint;
EndDialog(wxID_OK);
}
start_print_selected = true;
EndDialog(wxID_OK);
});
});
}
if (post_actions.has(PrintHostPostUploadAction::StartSimulation)) {
auto* btn_print = add_button(wxID_YES, false, _L("Upload and Simulate"));
btn_print->Bind(wxEVT_BUTTON, [this, validate_path](wxCommandEvent&) {
if (validate_path(txt_filename->GetValue())) {
post_upload_action = PrintHostPostUploadAction::StartSimulation;
EndDialog(wxID_OK);
}
});
}
add_button(wxID_CANCEL);
if (auto* btn_ok = get_button(wxID_OK); btn_ok != NULL) {
btn_ok->SetLabel(_L("Upload"));
btn_ok->Bind(wxEVT_BUTTON, [this, suffix](wxCommandEvent&) {
wxString path = txt_filename->GetValue();
// .gcode suffix control
if (!path.Lower().EndsWith(suffix.Lower()))
{
MessageDialog msg_wingow(this, wxString::Format(_L("Upload filename doesn't end with \"%s\". Do you wish to continue?"), suffix), wxString(SLIC3R_APP_NAME), wxYES | wxNO);
if (msg_wingow.ShowModal() == wxID_NO)
return;
btn_ok->Bind(wxEVT_BUTTON, [this, validate_path](wxCommandEvent&) {
if (validate_path(txt_filename->GetValue())) {
post_upload_action = PrintHostPostUploadAction::None;
EndDialog(wxID_OK);
}
EndDialog(wxID_OK);
});
});
}
finalize();
@ -137,9 +145,9 @@ fs::path PrintHostSendDialog::filename() const
return into_path(txt_filename->GetValue());
}
bool PrintHostSendDialog::start_print() const
PrintHostPostUploadAction PrintHostSendDialog::post_action() const
{
return start_print_selected;
return post_upload_action;
}
std::string PrintHostSendDialog::group() const
@ -165,8 +173,7 @@ void PrintHostSendDialog::EndModal(int ret)
AppConfig *app_config = wxGetApp().app_config;
app_config->set("recent", CONFIG_KEY_PATH, into_u8(path));
app_config->set("recent", CONFIG_KEY_PRINT, start_print() ? "1" : "0");
if (combo_groups != nullptr) {
wxString group = combo_groups->GetValue();
app_config->set("recent", CONFIG_KEY_GROUP, into_u8(group));

View File

@ -1,6 +1,7 @@
#ifndef slic3r_PrintHostSendDialog_hpp_
#define slic3r_PrintHostSendDialog_hpp_
#include <set>
#include <string>
#include <boost/filesystem/path.hpp>
@ -10,34 +11,32 @@
#include "GUI_Utils.hpp"
#include "MsgDialog.hpp"
#include "../Utils/PrintHost.hpp"
class wxButton;
class wxTextCtrl;
class wxChoice;
class wxComboBox;
class wxCheckBox;
class wxDataViewListCtrl;
namespace Slic3r {
struct PrintHostJob;
namespace GUI {
class PrintHostSendDialog : public GUI::MsgDialog
{
public:
PrintHostSendDialog(const boost::filesystem::path &path, bool can_start_print, const wxArrayString& groups);
PrintHostSendDialog(const boost::filesystem::path &path, PrintHostPostUploadActions post_actions, const wxArrayString& groups);
boost::filesystem::path filename() const;
bool start_print() const;
PrintHostPostUploadAction post_action() const;
std::string group() const;
virtual void EndModal(int ret) override;
private:
wxTextCtrl *txt_filename;
wxComboBox *combo_groups;
bool start_print_selected { false };
PrintHostPostUploadAction post_upload_action;
wxString m_valid_suffix;
};

View File

@ -115,11 +115,11 @@ bool AstroBox::upload(PrintHostUpload upload_data, ProgressFn prorgess_fn, Error
% url
% upload_filename.string()
% upload_parent_path.string()
% upload_data.start_print;
% (upload_data.post_action == PrintHostPostUploadAction::StartPrint ? "true" : "false");
auto http = Http::post(std::move(url));
set_auth(http);
http.form_add("print", upload_data.start_print ? "true" : "false")
http.form_add("print", upload_data.post_action == PrintHostPostUploadAction::StartPrint ? "true" : "false")
.form_add("path", upload_parent_path.string()) // XXX: slashes on windows ???
.form_add_file("file", upload_data.source_path.string(), upload_filename.string())
.on_complete([&](std::string body, unsigned status) {

View File

@ -26,7 +26,7 @@ public:
bool upload(PrintHostUpload upload_data, ProgressFn prorgess_fn, ErrorFn error_fn) const override;
bool has_auto_discovery() const override { return true; }
bool can_test() const override { return true; }
bool can_start_print() const override { return true; }
PrintHostPostUploadActions get_post_upload_actions() const override { return PrintHostPostUploadAction::StartPrint; }
std::string get_host() const override { return host; }
protected:

View File

@ -67,10 +67,10 @@ bool Duet::upload(PrintHostUpload upload_data, ProgressFn prorgess_fn, ErrorFn e
bool dsf = (connectionType == ConnectionType::dsf);
auto upload_cmd = get_upload_url(upload_data.upload_path.string(), connectionType);
BOOST_LOG_TRIVIAL(info) << boost::format("Duet: Uploading file %1%, filepath: %2%, print: %3%, command: %4%")
BOOST_LOG_TRIVIAL(info) << boost::format("Duet: Uploading file %1%, filepath: %2%, post_action: %3%, command: %4%")
% upload_data.source_path
% upload_data.upload_path
% upload_data.start_print
% int(upload_data.post_action)
% upload_cmd;
auto http = (dsf ? Http::put(std::move(upload_cmd)) : Http::post(std::move(upload_cmd)));
@ -87,9 +87,15 @@ bool Duet::upload(PrintHostUpload upload_data, ProgressFn prorgess_fn, ErrorFn e
BOOST_LOG_TRIVIAL(error) << boost::format("Duet: Request completed but error code was received: %1%") % err_code;
error_fn(format_error(body, L("Unknown error occured"), 0));
res = false;
} else if (upload_data.start_print) {
} else if (upload_data.post_action == PrintHostPostUploadAction::StartPrint) {
wxString errormsg;
res = start_print(errormsg, upload_data.upload_path.string(), connectionType);
res = start_print(errormsg, upload_data.upload_path.string(), connectionType, false);
if (! res) {
error_fn(std::move(errormsg));
}
} else if (upload_data.post_action == PrintHostPostUploadAction::StartSimulation) {
wxString errormsg;
res = start_print(errormsg, upload_data.upload_path.string(), connectionType, true);
if (! res) {
error_fn(std::move(errormsg));
}
@ -230,7 +236,7 @@ std::string Duet::timestamp_str() const
return std::string(buffer);
}
bool Duet::start_print(wxString &msg, const std::string &filename, ConnectionType connectionType) const
bool Duet::start_print(wxString &msg, const std::string &filename, ConnectionType connectionType, bool simulationMode) const
{
assert(connectionType != ConnectionType::error);
@ -240,14 +246,18 @@ bool Duet::start_print(wxString &msg, const std::string &filename, ConnectionTyp
auto url = dsf
? (boost::format("%1%machine/code")
% get_base_url()).str()
: (boost::format("%1%rr_gcode?gcode=M32%%20\"0:/gcodes/%2%\"")
: (boost::format(simulationMode
? "%1%rr_gcode?gcode=M37%%20P\"0:/gcodes/%2%\""
: "%1%rr_gcode?gcode=M32%%20\"0:/gcodes/%2%\"")
% get_base_url()
% Http::url_encode(filename)).str();
auto http = (dsf ? Http::post(std::move(url)) : Http::get(std::move(url)));
if (dsf) {
http.set_post_body(
(boost::format("M32 \"0:/gcodes/%1%\"")
(boost::format(simulationMode
? "M37 P\"0:/gcodes/%1%\""
: "M32 \"0:/gcodes/%1%\"")
% filename).str()
);
}

View File

@ -25,7 +25,7 @@ public:
bool upload(PrintHostUpload upload_data, ProgressFn prorgess_fn, ErrorFn error_fn) const override;
bool has_auto_discovery() const override { return false; }
bool can_test() const override { return true; }
bool can_start_print() const override { return true; }
PrintHostPostUploadActions get_post_upload_actions() const override { return PrintHostPostUploadAction::StartPrint | PrintHostPostUploadAction::StartSimulation; }
std::string get_host() const override { return host; }
private:
@ -39,7 +39,7 @@ private:
std::string timestamp_str() const;
ConnectionType connect(wxString &msg) const;
void disconnect(ConnectionType connectionType) const;
bool start_print(wxString &msg, const std::string &filename, ConnectionType connectionType) const;
bool start_print(wxString &msg, const std::string &filename, ConnectionType connectionType, bool simulationMode) const;
int get_err_code_from_body(const std::string &body) const;
};

View File

@ -26,7 +26,7 @@ public:
bool upload(PrintHostUpload upload_data, ProgressFn prorgess_fn, ErrorFn error_fn) const override;
bool has_auto_discovery() const override { return false; }
bool can_test() const override { return true; }
bool can_start_print() const override { return false; }
PrintHostPostUploadActions get_post_upload_actions() const override { return {}; }
std::string get_host() const override { return host; }
private:

150
src/slic3r/Utils/MKS.cpp Normal file
View File

@ -0,0 +1,150 @@
#include "MKS.hpp"
#include <algorithm>
#include <ctime>
#include <chrono>
#include <thread>
#include <boost/filesystem/path.hpp>
#include <boost/format.hpp>
#include <boost/log/trivial.hpp>
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/json_parser.hpp>
#include <boost/asio.hpp>
#include <boost/algorithm/string.hpp>
#include <wx/frame.h>
#include <wx/event.h>
#include <wx/progdlg.h>
#include <wx/sizer.h>
#include <wx/stattext.h>
#include <wx/textctrl.h>
#include <wx/checkbox.h>
#include "libslic3r/PrintConfig.hpp"
#include "slic3r/GUI/GUI.hpp"
#include "slic3r/GUI/I18N.hpp"
#include "slic3r/GUI/MsgDialog.hpp"
#include "Http.hpp"
namespace fs = boost::filesystem;
namespace pt = boost::property_tree;
namespace Slic3r {
MKS::MKS(DynamicPrintConfig* config) :
m_host(config->opt_string("print_host")), m_console_port("8080")
{}
const char* MKS::get_name() const { return "MKS"; }
bool MKS::test(wxString& msg) const
{
Utils::TCPConsole console(m_host, m_console_port);
console.enqueue_cmd("M105");
bool ret = console.run_queue();
if (!ret)
msg = wxString::FromUTF8(console.error_message().c_str());
return ret;
}
wxString MKS::get_test_ok_msg() const
{
return _(L("Connection to MKS works correctly."));
}
wxString MKS::get_test_failed_msg(wxString& msg) const
{
return GUI::from_u8((boost::format("%s: %s")
% _utf8(L("Could not connect to MKS"))
% std::string(msg.ToUTF8())).str());
}
bool MKS::upload(PrintHostUpload upload_data, ProgressFn prorgess_fn, ErrorFn error_fn) const
{
bool res = true;
auto upload_cmd = get_upload_url(upload_data.upload_path.string());
BOOST_LOG_TRIVIAL(info) << boost::format("MKS: Uploading file %1%, filepath: %2%, print: %3%, command: %4%")
% upload_data.source_path
% upload_data.upload_path
% (upload_data.post_action == PrintHostPostUploadAction::StartPrint)
% upload_cmd;
auto http = Http::post(std::move(upload_cmd));
http.set_post_body(upload_data.source_path);
http.on_complete([&](std::string body, unsigned status) {
BOOST_LOG_TRIVIAL(debug) << boost::format("MKS: File uploaded: HTTP %1%: %2%") % status % body;
int err_code = get_err_code_from_body(body);
if (err_code != 0) {
BOOST_LOG_TRIVIAL(error) << boost::format("MKS: Request completed but error code was received: %1%") % err_code;
error_fn(format_error(body, L("Unknown error occured"), 0));
res = false;
}
else if (upload_data.post_action == PrintHostPostUploadAction::StartPrint) {
wxString errormsg;
res = start_print(errormsg, upload_data.upload_path.string());
if (!res) {
error_fn(std::move(errormsg));
}
}
})
.on_error([&](std::string body, std::string error, unsigned status) {
BOOST_LOG_TRIVIAL(error) << boost::format("MKS: Error uploading file: %1%, HTTP %2%, body: `%3%`") % error % status % body;
error_fn(format_error(body, error, status));
res = false;
})
.on_progress([&](Http::Progress progress, bool& cancel) {
prorgess_fn(std::move(progress), cancel);
if (cancel) {
// Upload was canceled
BOOST_LOG_TRIVIAL(info) << "MKS: Upload canceled";
res = false;
}
}).perform_sync();
return res;
}
std::string MKS::get_upload_url(const std::string& filename) const
{
return (boost::format("http://%1%/upload?X-Filename=%2%")
% m_host
% Http::url_encode(filename)).str();
}
bool MKS::start_print(wxString& msg, const std::string& filename) const
{
// For some reason printer firmware does not want to respond on gcode commands immediately after file upload.
// So we just introduce artificial delay to workaround it.
// TODO: Inspect reasons
std::this_thread::sleep_for(std::chrono::milliseconds(1500));
Utils::TCPConsole console(m_host, m_console_port);
console.enqueue_cmd(std::string("M23 ") + filename);
console.enqueue_cmd("M24");
bool ret = console.run_queue();
if (!ret)
msg = wxString::FromUTF8(console.error_message().c_str());
return ret;
}
int MKS::get_err_code_from_body(const std::string& body) const
{
pt::ptree root;
std::istringstream iss(body); // wrap returned json to istringstream
pt::read_json(iss, root);
return root.get<int>("err", 0);
}
} // Slic3r

42
src/slic3r/Utils/MKS.hpp Normal file
View File

@ -0,0 +1,42 @@
#ifndef slic3r_MKS_hpp_
#define slic3r_MKS_hpp_
#include <string>
#include <wx/string.h>
#include "PrintHost.hpp"
#include "TCPConsole.hpp"
namespace Slic3r {
class DynamicPrintConfig;
class Http;
class MKS : public PrintHost
{
public:
explicit MKS(DynamicPrintConfig* config);
~MKS() override = default;
const char* get_name() const override;
bool test(wxString& curl_msg) const override;
wxString get_test_ok_msg() const override;
wxString get_test_failed_msg(wxString& msg) const override;
bool upload(PrintHostUpload upload_data, ProgressFn prorgess_fn, ErrorFn error_fn) const override;
bool has_auto_discovery() const override { return false; }
bool can_test() const override { return true; }
PrintHostPostUploadActions get_post_upload_actions() const override { return PrintHostPostUploadAction::StartPrint; }
std::string get_host() const override { return m_host; }
private:
std::string m_host;
std::string m_console_port;
std::string get_upload_url(const std::string& filename) const;
bool start_print(wxString& msg, const std::string& filename) const;
int get_err_code_from_body(const std::string& body) const;
};
}
#endif

View File

@ -137,11 +137,11 @@ bool OctoPrint::upload(PrintHostUpload upload_data, ProgressFn prorgess_fn, Erro
% url
% upload_filename.string()
% upload_parent_path.string()
% upload_data.start_print;
% (upload_data.post_action == PrintHostPostUploadAction::StartPrint ? "true" : "false");
auto http = Http::post(std::move(url));
set_auth(http);
http.form_add("print", upload_data.start_print ? "true" : "false")
http.form_add("print", upload_data.post_action == PrintHostPostUploadAction::StartPrint ? "true" : "false")
.form_add("path", upload_parent_path.string()) // XXX: slashes on windows ???
.form_add_file("file", upload_data.source_path.string(), upload_filename.string())
.on_complete([&](std::string body, unsigned status) {

View File

@ -28,7 +28,7 @@ public:
bool upload(PrintHostUpload upload_data, ProgressFn prorgess_fn, ErrorFn error_fn) const override;
bool has_auto_discovery() const override { return true; }
bool can_test() const override { return true; }
bool can_start_print() const override { return true; }
PrintHostPostUploadActions get_post_upload_actions() const override { return PrintHostPostUploadAction::StartPrint; }
std::string get_host() const override { return m_host; }
const std::string& get_apikey() const { return m_apikey; }
const std::string& get_cafile() const { return m_cafile; }
@ -57,7 +57,7 @@ public:
wxString get_test_ok_msg() const override;
wxString get_test_failed_msg(wxString &msg) const override;
bool can_start_print() const override { return false; }
PrintHostPostUploadActions get_post_upload_actions() const override { return {}; }
protected:
bool validate_version_text(const boost::optional<std::string> &version_text) const override;
@ -82,7 +82,7 @@ public:
wxString get_test_ok_msg() const override;
wxString get_test_failed_msg(wxString& msg) const override;
bool can_start_print() const override { return true; }
PrintHostPostUploadActions get_post_upload_actions() const override { return PrintHostPostUploadAction::StartPrint; }
protected:
bool validate_version_text(const boost::optional<std::string>& version_text) const override;

View File

@ -18,6 +18,7 @@
#include "FlashAir.hpp"
#include "AstroBox.hpp"
#include "Repetier.hpp"
#include "MKS.hpp"
#include "../GUI/PrintHostDialogs.hpp"
namespace fs = boost::filesystem;
@ -51,6 +52,7 @@ PrintHost* PrintHost::get_print_host(DynamicPrintConfig *config)
case htAstroBox: return new AstroBox(config);
case htRepetier: return new Repetier(config);
case htPrusaLink: return new PrusaLink(config);
case htMKS: return new MKS(config);
default: return nullptr;
}
} else {

View File

@ -2,12 +2,14 @@
#define slic3r_PrintHost_hpp_
#include <memory>
#include <set>
#include <string>
#include <functional>
#include <boost/filesystem/path.hpp>
#include <wx/string.h>
#include <libslic3r/enum_bitmask.hpp>
#include "Http.hpp"
class wxArrayString;
@ -16,6 +18,13 @@ namespace Slic3r {
class DynamicPrintConfig;
enum class PrintHostPostUploadAction {
None,
StartPrint,
StartSimulation
};
using PrintHostPostUploadActions = enum_bitmask<PrintHostPostUploadAction>;
ENABLE_ENUM_BITMASK_OPERATORS(PrintHostPostUploadAction);
struct PrintHostUpload
{
@ -24,10 +33,9 @@ struct PrintHostUpload
std::string group;
bool start_print = false;
PrintHostPostUploadAction post_action { PrintHostPostUploadAction::None };
};
class PrintHost
{
public:
@ -44,7 +52,7 @@ public:
virtual bool upload(PrintHostUpload upload_data, ProgressFn prorgess_fn, ErrorFn error_fn) const = 0;
virtual bool has_auto_discovery() const = 0;
virtual bool can_test() const = 0;
virtual bool can_start_print() const = 0;
virtual PrintHostPostUploadActions get_post_upload_actions() const = 0;
// A print host usually does not support multiple printers, with the exception of Repetier server.
virtual bool supports_multiple_printers() const { return false; }
virtual std::string get_host() const = 0;

View File

@ -107,7 +107,9 @@ bool Repetier::upload(PrintHostUpload upload_data, ProgressFn prorgess_fn, Error
bool res = true;
auto url = upload_data.start_print?make_url((boost::format("printer/job/%1%") % port).str()):make_url((boost::format("printer/model/%1%") % port).str());
auto url = upload_data.post_action == PrintHostPostUploadAction::StartPrint
? make_url((boost::format("printer/job/%1%") % port).str())
: make_url((boost::format("printer/model/%1%") % port).str());
BOOST_LOG_TRIVIAL(info) << boost::format("%1%: Uploading file %2% at %3%, filename: %4%, path: %5%, print: %6%, group: %7%")
% name
@ -115,17 +117,17 @@ bool Repetier::upload(PrintHostUpload upload_data, ProgressFn prorgess_fn, Error
% url
% upload_filename.string()
% upload_parent_path.string()
% upload_data.start_print
% (upload_data.post_action == PrintHostPostUploadAction::StartPrint ? "true" : "false")
% upload_data.group;
auto http = Http::post(std::move(url));
set_auth(http);
if (! upload_data.group.empty() && upload_data.group != _utf8(L("Default"))) {
http.form_add("group", upload_data.group);
}
if(upload_data.start_print) {
if(upload_data.post_action == PrintHostPostUploadAction::StartPrint) {
http.form_add("name", upload_filename.string());
}

View File

@ -7,7 +7,6 @@
#include "PrintHost.hpp"
namespace Slic3r {
class DynamicPrintConfig;
@ -27,7 +26,7 @@ public:
bool upload(PrintHostUpload upload_data, ProgressFn prorgess_fn, ErrorFn error_fn) const override;
bool has_auto_discovery() const override { return false; }
bool can_test() const override { return true; }
bool can_start_print() const override { return true; }
PrintHostPostUploadActions get_post_upload_actions() const override { return PrintHostPostUploadAction::StartPrint; }
bool supports_multiple_printers() const override { return true; }
std::string get_host() const override { return host; }

View File

@ -0,0 +1,205 @@
#include <boost/asio/buffer.hpp>
#include <boost/asio/io_context.hpp>
#include <boost/asio/ip/tcp.hpp>
#include <boost/asio/read_until.hpp>
#include <boost/asio/steady_timer.hpp>
#include <boost/asio/write.hpp>
#include <boost/bind.hpp>
#include <boost/format.hpp>
#include <boost/log/trivial.hpp>
#include <boost/algorithm/string.hpp>
#include <iostream>
#include <string>
#include "TCPConsole.hpp"
using boost::asio::steady_timer;
using boost::asio::ip::tcp;
namespace Slic3r {
namespace Utils {
void TCPConsole::transmit_next_command()
{
if (m_cmd_queue.empty()) {
m_io_context.stop();
return;
}
std::string cmd = m_cmd_queue.front();
m_cmd_queue.pop_front();
BOOST_LOG_TRIVIAL(debug) << boost::format("TCPConsole: transmitting '%3%' to %1%:%2%")
% m_host_name
% m_port_name
% cmd;
m_send_buffer = cmd + m_newline;
set_deadline_in(m_write_timeout);
boost::asio::async_write(
m_socket,
boost::asio::buffer(m_send_buffer),
boost::bind(&TCPConsole::handle_write, this, _1, _2)
);
}
void TCPConsole::wait_next_line()
{
set_deadline_in(m_read_timeout);
boost::asio::async_read_until(
m_socket,
m_recv_buffer,
m_newline,
boost::bind(&TCPConsole::handle_read, this, _1, _2)
);
}
// TODO: Use std::optional here
std::string TCPConsole::extract_next_line()
{
char linebuf[1024];
std::istream is(&m_recv_buffer);
is.getline(linebuf, sizeof(linebuf));
return is.good() ? linebuf : std::string{};
}
void TCPConsole::handle_read(
const boost::system::error_code& ec,
std::size_t bytes_transferred)
{
m_error_code = ec;
if (ec) {
BOOST_LOG_TRIVIAL(error) << boost::format("TCPConsole: Can't read from %1%:%2%: %3%")
% m_host_name
% m_port_name
% ec.message();
m_io_context.stop();
}
else {
std::string line = extract_next_line();
boost::trim(line);
BOOST_LOG_TRIVIAL(debug) << boost::format("TCPConsole: received '%3%' from %1%:%2%")
% m_host_name
% m_port_name
% line;
boost::to_lower(line);
if (line == m_done_string)
transmit_next_command();
else
wait_next_line();
}
}
void TCPConsole::handle_write(
const boost::system::error_code& ec,
std::size_t)
{
m_error_code = ec;
if (ec) {
BOOST_LOG_TRIVIAL(error) << boost::format("TCPConsole: Can't write to %1%:%2%: %3%")
% m_host_name
% m_port_name
% ec.message();
m_io_context.stop();
}
else {
wait_next_line();
}
}
void TCPConsole::handle_connect(const boost::system::error_code& ec)
{
m_error_code = ec;
if (ec) {
BOOST_LOG_TRIVIAL(error) << boost::format("TCPConsole: Can't connect to %1%:%2%: %3%")
% m_host_name
% m_port_name
% ec.message();
m_io_context.stop();
}
else {
m_is_connected = true;
BOOST_LOG_TRIVIAL(info) << boost::format("TCPConsole: connected to %1%:%2%")
% m_host_name
% m_port_name;
transmit_next_command();
}
}
void TCPConsole::set_deadline_in(std::chrono::steady_clock::duration d)
{
m_deadline = std::chrono::steady_clock::now() + d;
}
bool TCPConsole::is_deadline_over() const
{
return m_deadline < std::chrono::steady_clock::now();
}
bool TCPConsole::run_queue()
{
try {
// TODO: Add more resets and initializations after previous run (reset() method?..)
set_deadline_in(m_connect_timeout);
m_is_connected = false;
m_io_context.restart();
auto endpoints = m_resolver.resolve(m_host_name, m_port_name);
m_socket.async_connect(endpoints->endpoint(),
boost::bind(&TCPConsole::handle_connect, this, _1)
);
// Loop until we get any reasonable result. Negative result is also result.
// TODO: Rewrite to more graceful way using deadlime_timer
bool timeout = false;
while (!(timeout = is_deadline_over()) && !m_io_context.stopped()) {
if (m_error_code) {
m_io_context.stop();
}
m_io_context.run_for(boost::asio::chrono::milliseconds(100));
}
// Override error message if timeout is set
if (timeout)
m_error_code = make_error_code(boost::asio::error::timed_out);
// Socket is not closed automatically by boost
m_socket.close();
if (m_error_code) {
// We expect that message is logged in handler
return false;
}
// It's expected to have empty queue after successful exchange
if (!m_cmd_queue.empty()) {
BOOST_LOG_TRIVIAL(error) << "TCPConsole: command queue is not empty after end of exchange";
return false;
}
}
catch (std::exception& e)
{
BOOST_LOG_TRIVIAL(error) << boost::format("TCPConsole: Exception while talking with %1%:%2%: %3%")
% m_host_name
% m_port_name
% e.what();
return false;
}
return true;
}
} // namespace Utils
} // namespace Slic3r

View File

@ -0,0 +1,91 @@
#ifndef slic3r_Utils_TCPConsole_hpp_
#define slic3r_Utils_TCPConsole_hpp_
#include <string>
#include <deque>
#include <boost/system/error_code.hpp>
#include <boost/system/system_error.hpp>
#include <boost/asio/ip/tcp.hpp>
#include <boost/asio/streambuf.hpp>
namespace Slic3r {
namespace Utils {
using boost::asio::ip::tcp;
class TCPConsole
{
public:
TCPConsole() : m_resolver(m_io_context), m_socket(m_io_context) { set_defaults(); }
TCPConsole(const std::string& host_name, const std::string& port_name) : m_resolver(m_io_context), m_socket(m_io_context)
{ set_defaults(); set_remote(host_name, port_name); }
~TCPConsole() = default;
void set_defaults()
{
m_newline = "\n";
m_done_string = "ok";
m_connect_timeout = std::chrono::milliseconds(5000);
m_write_timeout = std::chrono::milliseconds(10000);
m_read_timeout = std::chrono::milliseconds(10000);
}
void set_line_delimiter(const std::string& newline) {
m_newline = newline;
}
void set_command_done_string(const std::string& done_string) {
m_done_string = done_string;
}
void set_remote(const std::string& host_name, const std::string& port_name)
{
m_host_name = host_name;
m_port_name = port_name;
}
bool enqueue_cmd(const std::string& cmd) {
// TODO: Add multithread protection to queue
m_cmd_queue.push_back(cmd);
return true;
}
bool run_queue();
std::string error_message() const { return m_error_code.message(); }
private:
void handle_connect(const boost::system::error_code& ec);
void handle_read(const boost::system::error_code& ec, std::size_t bytes_transferred);
void handle_write(const boost::system::error_code& ec, std::size_t bytes_transferred);
void transmit_next_command();
void wait_next_line();
std::string extract_next_line();
void set_deadline_in(std::chrono::steady_clock::duration);
bool is_deadline_over() const;
std::string m_host_name;
std::string m_port_name;
std::string m_newline;
std::string m_done_string;
std::chrono::steady_clock::duration m_connect_timeout;
std::chrono::steady_clock::duration m_write_timeout;
std::chrono::steady_clock::duration m_read_timeout;
std::deque<std::string> m_cmd_queue;
boost::asio::io_context m_io_context;
tcp::resolver m_resolver;
tcp::socket m_socket;
boost::asio::streambuf m_recv_buffer;
std::string m_send_buffer;
bool m_is_connected;
boost::system::error_code m_error_code;
std::chrono::steady_clock::time_point m_deadline;
};
} // Utils
} // Slic3r
#endif

View File

@ -220,8 +220,8 @@ SCENARIO("DynamicPrintConfig serialization", "[Config]") {
cereal::BinaryOutputArchive oarchive(ss);
oarchive(cfg);
serialized = ss.str();
} catch (std::runtime_error &e) {
e.what();
} catch (const std::runtime_error & /* e */) {
// e.what();
}
THEN("Config object contains ini file options.") {
@ -230,8 +230,8 @@ SCENARIO("DynamicPrintConfig serialization", "[Config]") {
std::stringstream ss(serialized);
cereal::BinaryInputArchive iarchive(ss);
iarchive(cfg2);
} catch (std::runtime_error &e) {
e.what();
} catch (const std::runtime_error & /* e */) {
// e.what();
}
REQUIRE(cfg == cfg2);
}

View File

@ -117,15 +117,18 @@ static float triangle_area(const Vec3crd &triangle_inices, const std::vector<Vec
vertices[triangle_inices[2]]);
}
#if 0
// clang complains about unused functions
static std::mt19937 create_random_generator() {
std::random_device rd;
std::mt19937 gen(rd());
return gen;
}
#endif
std::vector<Vec3f> its_sample_surface(const indexed_triangle_set &its,
double sample_per_mm2,
std::mt19937 random_generator = create_random_generator())
std::mt19937 random_generator) // = create_random_generator())
{
std::vector<Vec3f> samples;
std::uniform_real_distribution<float> rand01(0.f, 1.f);

View File

@ -4,7 +4,14 @@ add_executable(${_TEST_NAME}_tests
)
target_link_libraries(${_TEST_NAME}_tests test_common libslic3r_gui libslic3r)
if (MSVC)
target_link_libraries(${_TEST_NAME}_tests Setupapi.lib)
endif ()
set_property(TARGET ${_TEST_NAME}_tests PROPERTY FOLDER "tests")
if (WIN32)
prusaslicer_copy_dlls(${_TEST_NAME}_tests)
endif()
# catch_discover_tests(${_TEST_NAME}_tests TEST_PREFIX "${_TEST_NAME}: ")
add_test(${_TEST_NAME}_tests ${_TEST_NAME}_tests "${CATCH_EXTRA_ARGS} exclude:[NotWorking]")