Merge remote-tracking branch 'remotes/prusa/version_2.3.1' into merill-merge

This commit is contained in:
remi durand 2021-06-04 21:40:49 +02:00
commit 81f78cc993
39 changed files with 2827 additions and 490 deletions

View File

@ -45,15 +45,27 @@ option(SLIC3R_ALPHA "Development/Experimental version; use separate
set(SLIC3R_GTK "2" CACHE STRING "GTK version to use with wxWidgets on Linux")
set(IS_CROSS_COMPILE FALSE)
if (APPLE)
set(CMAKE_FIND_FRAMEWORK LAST)
set(CMAKE_FIND_APPBUNDLE LAST)
list(FIND CMAKE_OSX_ARCHITECTURES ${CMAKE_SYSTEM_PROCESSOR} _arch_idx)
if (CMAKE_OSX_ARCHITECTURES AND _arch_idx LESS 0)
set(IS_CROSS_COMPILE TRUE)
endif ()
endif ()
# Proposal for C++ unit tests and sandboxes
option(SLIC3R_BUILD_SANDBOXES "Build development sandboxes" OFF)
option(SLIC3R_BUILD_TESTS "Build unit tests" OFF)
if (IS_CROSS_COMPILE)
message("Detected cross compilation setup. Tests and encoding checks will be forcedly disabled!")
set(SLIC3R_PERL_XS OFF CACHE BOOL "" FORCE)
set(SLIC3R_BUILD_TESTS OFF CACHE BOOL "" FORCE)
endif ()
# Print out the SLIC3R_* cache options
get_cmake_property(_cache_vars CACHE_VARIABLES)
list (SORT _cache_vars)

View File

@ -157,7 +157,9 @@ function(OPENVDB_ABI_VERSION_FROM_PRINT OPENVDB_PRINT)
endif()
set(_OpenVDB_ABI)
if (_VDB_PRINT_VERSION_STRING)
string(REGEX REPLACE ".*abi([0-9]*).*" "\\1" _OpenVDB_ABI ${_VDB_PRINT_VERSION_STRING})
endif ()
if(${_OpenVDB_ABI} STREQUAL ${_VDB_PRINT_VERSION_STRING})
set(_OpenVDB_ABI "")
endif()

89
cmake/modules/bin2h.cmake Normal file
View File

@ -0,0 +1,89 @@
# Source: https://gist.github.com/sivachandran/3a0de157dccef822a230#file-bin2h-cmake
# Added modifications to suit prusaslicer
include(CMakeParseArguments)
# Function to wrap a given string into multiple lines at the given column position.
# Parameters:
# VARIABLE - The name of the CMake variable holding the string.
# AT_COLUMN - The column position at which string will be wrapped.
function(WRAP_STRING)
set(oneValueArgs VARIABLE AT_COLUMN)
cmake_parse_arguments(WRAP_STRING "${options}" "${oneValueArgs}" "" ${ARGN})
string(LENGTH ${${WRAP_STRING_VARIABLE}} stringLength)
math(EXPR offset "0")
while(stringLength GREATER 0)
if(stringLength GREATER ${WRAP_STRING_AT_COLUMN})
math(EXPR length "${WRAP_STRING_AT_COLUMN}")
else()
math(EXPR length "${stringLength}")
endif()
string(SUBSTRING ${${WRAP_STRING_VARIABLE}} ${offset} ${length} line)
set(lines "${lines}\n${line}")
math(EXPR stringLength "${stringLength} - ${length}")
math(EXPR offset "${offset} + ${length}")
endwhile()
set(${WRAP_STRING_VARIABLE} "${lines}" PARENT_SCOPE)
endfunction()
# Function to embed contents of a file as byte array in C/C++ header file(.h). The header file
# will contain a byte array and integer variable holding the size of the array.
# Parameters
# SOURCE_FILE - The path of source file whose contents will be embedded in the header file.
# VARIABLE_NAME - The name of the variable for the byte array. The string "_SIZE" will be append
# to this name and will be used a variable name for size variable.
# HEADER_FILE - The path of header file.
# APPEND - If specified appends to the header file instead of overwriting it
# NULL_TERMINATE - If specified a null byte(zero) will be append to the byte array. This will be
# useful if the source file is a text file and we want to use the file contents
# as string. But the size variable holds size of the byte array without this
# null byte.
# Usage:
# bin2h(SOURCE_FILE "Logo.png" HEADER_FILE "Logo.h" VARIABLE_NAME "LOGO_PNG")
function(BIN2H)
set(options APPEND NULL_TERMINATE ADD_WARNING_TEXT)
set(oneValueArgs SOURCE_FILE VARIABLE_NAME HEADER_FILE)
cmake_parse_arguments(BIN2H "${options}" "${oneValueArgs}" "" ${ARGN})
# reads source file contents as hex string
file(READ ${BIN2H_SOURCE_FILE} hexString HEX)
string(LENGTH ${hexString} hexStringLength)
# appends null byte if asked
if(BIN2H_NULL_TERMINATE)
set(hexString "${hexString}00")
endif()
# wraps the hex string into multiple lines at column 32(i.e. 16 bytes per line)
wrap_string(VARIABLE hexString AT_COLUMN 32)
math(EXPR arraySize "${hexStringLength} / 2")
# adds '0x' prefix and comma suffix before and after every byte respectively
string(REGEX REPLACE "([0-9a-f][0-9a-f])" "0x\\1, " arrayValues ${hexString})
# removes trailing comma
string(REGEX REPLACE ", $" "" arrayValues ${arrayValues})
# converts the variable name into proper C identifier
string(MAKE_C_IDENTIFIER "${BIN2H_VARIABLE_NAME}" BIN2H_VARIABLE_NAME)
# string(TOUPPER "${BIN2H_VARIABLE_NAME}" BIN2H_VARIABLE_NAME)
# declares byte array and the length variables
set(arrayDefinition "const unsigned char ${BIN2H_VARIABLE_NAME}[] = { ${arrayValues} };")
set(arraySizeDefinition "const size_t ${BIN2H_VARIABLE_NAME}_SIZE = ${arraySize};")
set(warnTxt "")
if (BIN2H_ADD_WARNING_TEXT)
set(warnTxt "/* WARN: This file is auto-generated from ${BIN2H_SOURCE_FILE} */\n")
endif ()
set(declarations "${warnTxt}${arrayDefinition}\n\n${arraySizeDefinition}\n\n")
if(BIN2H_APPEND)
file(APPEND ${BIN2H_HEADER_FILE} "${declarations}")
else()
file(WRITE ${BIN2H_HEADER_FILE} "${declarations}")
endif()
endfunction()

View File

@ -32,6 +32,7 @@
#include "libslic3r/GCode/PostProcessor.hpp"
#include "libslic3r/Model.hpp"
#include "libslic3r/ModelArrange.hpp"
#include "libslic3r/Platform.hpp"
#include "libslic3r/Print.hpp"
#include "libslic3r/SLAPrint.hpp"
#include "libslic3r/TriangleMesh.hpp"
@ -597,6 +598,9 @@ bool CLI::setup(int argc, char **argv)
}
}
// Detect the operating system flavor after SLIC3R_LOGLEVEL is set.
detect_platform();
boost::filesystem::path path_to_binary = boost::filesystem::system_complete(argv[0]);
// Path from the Slic3r binary to its resources.

View File

@ -133,16 +133,16 @@ void stl_fix_normal_directions(stl_file *stl)
// Initialize list that keeps track of already fixed facets.
std::vector<char> norm_sw(stl->stats.number_of_facets, 0);
// Initialize list that keeps track of reversed facets.
std::vector<int> reversed_ids(stl->stats.number_of_facets, 0);
std::vector<int> reversed_ids;
reversed_ids.reserve(stl->stats.number_of_facets);
int facet_num = 0;
int reversed_count = 0;
// If normal vector is not within tolerance and backwards:
// Arbitrarily starts at face 0. If this one is wrong, we're screwed. Thankfully, the chances
// of it being wrong randomly are low if most of the triangles are right:
if (check_normal_vector(stl, 0, 0)) {
reverse_facet(stl, 0);
reversed_ids[reversed_count ++] = 0;
reversed_ids.emplace_back(0);
}
// Say that we've fixed this facet:
@ -159,13 +159,13 @@ void stl_fix_normal_directions(stl_file *stl)
if (stl->neighbors_start[facet_num].neighbor[j] != -1) {
if (norm_sw[stl->neighbors_start[facet_num].neighbor[j]] == 1) {
// trying to modify a facet already marked as fixed, revert all changes made until now and exit (fixes: #716, #574, #413, #269, #262, #259, #230, #228, #206)
for (int id = reversed_count - 1; id >= 0; -- id)
for (int id = int(reversed_ids.size()) - 1; id >= 0; -- id)
reverse_facet(stl, reversed_ids[id]);
force_exit = true;
break;
}
reverse_facet(stl, stl->neighbors_start[facet_num].neighbor[j]);
reversed_ids[reversed_count ++] = stl->neighbors_start[facet_num].neighbor[j];
reversed_ids.emplace_back(stl->neighbors_start[facet_num].neighbor[j]);
}
}
// If this edge of the facet is connected:
@ -188,6 +188,7 @@ void stl_fix_normal_directions(stl_file *stl)
// Get next facet to fix from top of list.
if (head->next != tail) {
facet_num = head->next->facet_num;
assert(facet_num < stl->stats.number_of_facets);
if (norm_sw[facet_num] != 1) { // If facet is in list mutiple times
norm_sw[facet_num] = 1; // Record this one as being fixed.
++ checked;
@ -207,7 +208,7 @@ void stl_fix_normal_directions(stl_file *stl)
facet_num = i;
if (check_normal_vector(stl, i, 0)) {
reverse_facet(stl, i);
reversed_ids[reversed_count++] = i;
reversed_ids.emplace_back(i);
}
norm_sw[facet_num] = 1;
++ checked;

View File

@ -77,22 +77,16 @@ elseif (MINGW)
)
endif()
add_executable(avrdude-conf-gen conf-generate.cpp)
include(bin2h)
# Config file embedding
add_custom_command(
DEPENDS avrdude-conf-gen ${CMAKE_CURRENT_SOURCE_DIR}/avrdude-slic3r.conf
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/avrdude-slic3r.conf.h
COMMAND $<TARGET_FILE:avrdude-conf-gen> avrdude-slic3r.conf avrdude_slic3r_conf ${CMAKE_CURRENT_BINARY_DIR}/avrdude-slic3r.conf.h
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
)
add_custom_target(gen_conf_h
DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/avrdude-slic3r.conf.h
bin2h(
SOURCE_FILE ${CMAKE_CURRENT_SOURCE_DIR}/avrdude-slic3r.conf
VARIABLE_NAME avrdude_slic3r_conf
HEADER_FILE ${CMAKE_CURRENT_BINARY_DIR}/avrdude-slic3r.conf.h
ADD_WARNING_TEXT
)
add_library(avrdude STATIC ${AVRDUDE_SOURCES})
add_dependencies(avrdude gen_conf_h)
add_executable(avrdude-slic3r main-standalone.cpp)
target_link_libraries(avrdude-slic3r avrdude)

View File

@ -363,6 +363,7 @@ int read_config_builtin()
// Note: Can't use yy_scan_buffer, it's buggy (?), leads to fread from a null FILE*
// and so unfortunatelly we have to use the copying variant here
// note: changed for avrdude_slic3r_conf_SIZE but i can't build with uper case... if you need it on your os, please use a #ifndef
YY_BUFFER_STATE buffer = yy_scan_bytes((const char *)avrdude_slic3r_conf, avrdude_slic3r_conf_size);
if (buffer == NULL) {
avrdude_message(MSG_INFO, "%s: read_config_builtin: Failed to initialize parsing buffer\n", progname);

View File

@ -1,6 +1,11 @@
option(SLIC3R_ENC_CHECK "Verify encoding of source files" 1)
if (IS_CROSS_COMPILE)
# Force disable due to cross compilation. This fact is already printed on cli for users
set(SLIC3R_ENC_CHECK OFF CACHE BOOL "" FORCE)
endif ()
if (SLIC3R_ENC_CHECK)
add_executable(encoding-check encoding-check.cpp)

View File

@ -158,6 +158,8 @@ add_library(libslic3r STATIC
PerimeterGenerator.hpp
PlaceholderParser.cpp
PlaceholderParser.hpp
Platform.cpp
Platform.hpp
Point.cpp
Point.hpp
Polygon.cpp

View File

@ -402,6 +402,10 @@ namespace Slic3r {
bool m_check_version;
XML_Parser m_xml_parser;
// Error code returned by the application side of the parser. In that case the expat may not reliably deliver the error state
// after returning from XML_Parse() function, thus we keep the error state here.
bool m_parse_error { false };
std::string m_parse_error_message;
Model* m_model;
float m_unit_factor;
CurrentObject m_curr_object;
@ -427,7 +431,16 @@ namespace Slic3r {
private:
void _destroy_xml_parser();
void _stop_xml_parser();
void _stop_xml_parser(const std::string& msg = std::string());
bool parse_error() const { return m_parse_error; }
const char* parse_error_message() const {
return m_parse_error ?
// The error was signalled by the user code, not the expat parser.
(m_parse_error_message.empty() ? "Invalid 3MF format" : m_parse_error_message.c_str()) :
// The error was signalled by the expat parser.
XML_ErrorString(XML_GetErrorCode(m_xml_parser));
}
bool _load_model_from_file(const std::string& filename, Model& model, DynamicPrintConfig& config);
bool _extract_model_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat);
@ -567,9 +580,13 @@ namespace Slic3r {
}
}
void _3MF_Importer::_stop_xml_parser()
void _3MF_Importer::_stop_xml_parser(const std::string &msg)
{
if (m_xml_parser != nullptr)
assert(! m_parse_error);
assert(m_parse_error_message.empty());
assert(m_xml_parser != nullptr);
m_parse_error = true;
m_parse_error_message = msg;
XML_StopParser(m_xml_parser, false);
}
@ -708,12 +725,12 @@ namespace Slic3r {
close_zip_reader(&archive);
for (const IdToModelObjectMap::value_type& object : m_objects)
{
ModelObject *model_object = m_model->objects[object.second];
ObjectMetadata::VolumeMetadataList volumes;
ObjectMetadata::VolumeMetadataList* volumes_ptr = nullptr;
for (const IdToModelObjectMap::value_type& object : m_objects) {
if (object.second >= m_model->objects.size()) {
add_error("Unable to find object");
return false;
}
ModelObject* model_object = m_model->objects[object.second];
IdToGeometryMap::const_iterator obj_geometry = m_geometries.find(object.first);
if (obj_geometry == m_geometries.end())
{
@ -743,6 +760,9 @@ namespace Slic3r {
model_object->sla_drain_holes = std::move(obj_drain_holes->second);
}
ObjectMetadata::VolumeMetadataList volumes;
ObjectMetadata::VolumeMetadataList* volumes_ptr = nullptr;
IdToMetadataMap::iterator obj_metadata = m_objects_metadata.find(object.first);
if (obj_metadata != m_objects_metadata.end())
{
@ -805,12 +825,13 @@ namespace Slic3r {
struct CallbackData
{
XML_Parser& parser;
_3MF_Importer& importer;
const mz_zip_archive_file_stat& stat;
CallbackData(XML_Parser& parser, const mz_zip_archive_file_stat& stat) : parser(parser), stat(stat) {}
CallbackData(XML_Parser& parser, _3MF_Importer& importer, const mz_zip_archive_file_stat& stat) : parser(parser), importer(importer), stat(stat) {}
};
CallbackData data(m_xml_parser, stat);
CallbackData data(m_xml_parser, *this, stat);
mz_bool res = 0;
@ -818,10 +839,9 @@ namespace Slic3r {
{
res = mz_zip_reader_extract_file_to_callback(&archive, stat.m_filename, [](void* pOpaque, mz_uint64 file_ofs, const void* pBuf, size_t n)->size_t {
CallbackData* data = (CallbackData*)pOpaque;
if (!XML_Parse(data->parser, (const char*)pBuf, (int)n, (file_ofs + n == data->stat.m_uncomp_size) ? 1 : 0))
{
if (!XML_Parse(data->parser, (const char*)pBuf, (int)n, (file_ofs + n == data->stat.m_uncomp_size) ? 1 : 0) || data->importer.parse_error()) {
char error_buf[1024];
::sprintf(error_buf, "Error (%s) while parsing '%s' at line %d", XML_ErrorString(XML_GetErrorCode(data->parser)), data->stat.m_filename, (int)XML_GetCurrentLineNumber(data->parser));
::sprintf(error_buf, "Error (%s) while parsing '%s' at line %d", data->importer.parse_error_message(), data->stat.m_filename, (int)XML_GetCurrentLineNumber(data->parser));
throw Slic3r::FileIOError(error_buf);
}
@ -1419,8 +1439,11 @@ namespace Slic3r {
bool _3MF_Importer::_handle_end_model()
{
// deletes all non-built or non-instanced objects
for (const IdToModelObjectMap::value_type& object : m_objects)
{
for (const IdToModelObjectMap::value_type& object : m_objects) {
if (object.second >= m_model->objects.size()) {
add_error("Unable to find object");
return false;
}
ModelObject *model_object = m_model->objects[object.second];
if ((model_object != nullptr) && (model_object->instances.size() == 0))
m_model->delete_object(model_object);
@ -1921,6 +1944,10 @@ namespace Slic3r {
for (unsigned int v = 0; v < 3; ++v)
{
unsigned int tri_id = geometry.triangles[src_start_id + ii + v] * 3;
if (tri_id + 2 >= geometry.vertices.size()) {
add_error("Malformed triangle mesh");
return false;
}
facet.vertex[v] = Vec3f(geometry.vertices[tri_id + 0], geometry.vertices[tri_id + 1], geometry.vertices[tri_id + 2]);
}
}

View File

@ -63,23 +63,31 @@ namespace Slic3r
struct AMFParserContext
{
AMFParserContext(XML_Parser parser, DynamicPrintConfig* config, Model* model) :
m_version(0),
m_parser(parser),
m_model(*model),
m_object(nullptr),
m_volume(nullptr),
m_material(nullptr),
m_instance(nullptr),
m_config(config)
{
m_path.reserve(12);
}
void stop()
void stop(const std::string &msg = std::string())
{
assert(! m_error);
assert(m_error_message.empty());
m_error = true;
m_error_message = msg;
XML_StopParser(m_parser, 0);
}
bool error() const { return m_error; }
const char* error_message() const {
return m_error ?
// The error was signalled by the user code, not the expat parser.
(m_error_message.empty() ? "Invalid AMF format" : m_error_message.c_str()) :
// The error was signalled by the expat parser.
XML_ErrorString(XML_GetErrorCode(m_parser));
}
void startElement(const char *name, const char **atts);
void endElement(const char *name);
void endDocument();
@ -217,33 +225,37 @@ struct AMFParserContext
};
// Version of the amf file
unsigned int m_version;
unsigned int m_version { 0 };
// Current Expat XML parser instance.
XML_Parser m_parser;
// Error code returned by the application side of the parser. In that case the expat may not reliably deliver the error state
// after returning from XML_Parse() function, thus we keep the error state here.
bool m_error { false };
std::string m_error_message;
// Model to receive objects extracted from an AMF file.
Model &m_model;
// Current parsing path in the XML file.
std::vector<AMFNodeType> m_path;
// Current object allocated for an amf/object XML subtree.
ModelObject *m_object;
ModelObject *m_object { nullptr };
// Map from obect name to object idx & instances.
std::map<std::string, Object> m_object_instances_map;
// Vertices parsed for the current m_object.
std::vector<float> m_object_vertices;
// Current volume allocated for an amf/object/mesh/volume subtree.
ModelVolume *m_volume;
ModelVolume *m_volume { nullptr };
// Faces collected for the current m_volume.
std::vector<int> m_volume_facets;
// Transformation matrix of a volume mesh from its coordinate system to Object's coordinate system.
Transform3d m_volume_transform;
// Current material allocated for an amf/metadata subtree.
ModelMaterial *m_material;
ModelMaterial *m_material { nullptr };
// Current instance allocated for an amf/constellation/instance subtree.
Instance *m_instance;
Instance *m_instance { nullptr };
// Generic string buffer for vertices, face indices, metadata etc.
std::string m_value[5];
// Pointer to config to update if config data are stored inside the amf file
DynamicPrintConfig *m_config;
DynamicPrintConfig *m_config { nullptr };
private:
AMFParserContext& operator=(AMFParserContext&);
@ -595,9 +607,9 @@ void AMFParserContext::endElement(const char * /* name */)
if (strtoul(m_value[0].c_str(), nullptr, 10) < m_object_vertices.size() &&
strtoul(m_value[1].c_str(), nullptr, 10) < m_object_vertices.size() &&
strtoul(m_value[2].c_str(), nullptr, 10) < m_object_vertices.size()) {
m_volume_facets.push_back(atoi(m_value[0].c_str()));
m_volume_facets.push_back(atoi(m_value[1].c_str()));
m_volume_facets.push_back(atoi(m_value[2].c_str()));
m_volume_facets.emplace_back(atoi(m_value[0].c_str()));
m_volume_facets.emplace_back(atoi(m_value[1].c_str()));
m_volume_facets.emplace_back(atoi(m_value[2].c_str()));
}
m_value[0].clear();
m_value[1].clear();
@ -621,6 +633,10 @@ void AMFParserContext::endElement(const char * /* name */)
for (unsigned int v = 0; v < 3; ++v)
{
unsigned int tri_id = m_volume_facets[i++] * 3;
if (tri_id < 0 || tri_id + 2 >= m_object_vertices.size()) {
this->stop("Malformed triangle mesh");
return;
}
facet.vertex[v] = Vec3f(m_object_vertices[tri_id + 0], m_object_vertices[tri_id + 1], m_object_vertices[tri_id + 2]);
}
}
@ -863,10 +879,10 @@ bool load_amf_file(const char *path, DynamicPrintConfig *config, Model *model)
break;
}
int done = feof(pFile);
if (XML_Parse(parser, buff, len, done) == XML_STATUS_ERROR) {
if (XML_Parse(parser, buff, len, done) == XML_STATUS_ERROR || ctx.error()) {
printf("AMF parser: Parse error at line %d:\n%s\n",
(int)XML_GetCurrentLineNumber(parser),
XML_ErrorString(XML_GetErrorCode(parser)));
ctx.error_message());
break;
}
if (done) {
@ -917,12 +933,13 @@ bool extract_model_from_archive(mz_zip_archive& archive, const mz_zip_archive_fi
struct CallbackData
{
XML_Parser& parser;
AMFParserContext& ctx;
const mz_zip_archive_file_stat& stat;
CallbackData(XML_Parser& parser, const mz_zip_archive_file_stat& stat) : parser(parser), stat(stat) {}
CallbackData(XML_Parser& parser, AMFParserContext& ctx, const mz_zip_archive_file_stat& stat) : parser(parser), ctx(ctx), stat(stat) {}
};
CallbackData data(parser, stat);
CallbackData data(parser, ctx, stat);
mz_bool res = 0;
@ -930,10 +947,10 @@ bool extract_model_from_archive(mz_zip_archive& archive, const mz_zip_archive_fi
{
res = mz_zip_reader_extract_file_to_callback(&archive, stat.m_filename, [](void* pOpaque, mz_uint64 file_ofs, const void* pBuf, size_t n)->size_t {
CallbackData* data = (CallbackData*)pOpaque;
if (!XML_Parse(data->parser, (const char*)pBuf, (int)n, (file_ofs + n == data->stat.m_uncomp_size) ? 1 : 0))
if (!XML_Parse(data->parser, (const char*)pBuf, (int)n, (file_ofs + n == data->stat.m_uncomp_size) ? 1 : 0) || data->ctx.error())
{
char error_buf[1024];
::sprintf(error_buf, "Error (%s) while parsing '%s' at line %d", XML_ErrorString(XML_GetErrorCode(data->parser)), data->stat.m_filename, (int)XML_GetCurrentLineNumber(data->parser));
::sprintf(error_buf, "Error (%s) while parsing '%s' at line %d", data->ctx.error_message(), data->stat.m_filename, (int)XML_GetCurrentLineNumber(data->parser));
throw Slic3r::FileIOError(error_buf);
}

View File

@ -0,0 +1,71 @@
#include "Platform.hpp"
#include <boost/log/trivial.hpp>
#include <boost/filesystem/operations.hpp>
namespace Slic3r {
static auto s_platform = Platform::Uninitialized;
static auto s_platform_flavor = PlatformFlavor::Uninitialized;
void detect_platform()
{
#if defined(_WIN32)
BOOST_LOG_TRIVIAL(info) << "Platform: Windows";
s_platform = Platform::Windows;
s_platform_flavor = PlatformFlavor::Generic;
#elif defined(__APPLE__)
BOOST_LOG_TRIVIAL(info) << "Platform: OSX";
s_platform = Platform::OSX;
s_platform_flavor = PlatformFlavor::Generic;
#elif defined(__linux__)
BOOST_LOG_TRIVIAL(info) << "Platform: Linux";
s_platform = Platform::Linux;
s_platform_flavor = PlatformFlavor::GenericLinux;
// Test for Chromium.
{
FILE *f = ::fopen("/proc/version", "rt");
if (f) {
char buf[4096];
// Read the 1st line.
if (::fgets(buf, 4096, f)) {
if (strstr(buf, "Chromium OS") != nullptr) {
s_platform_flavor = PlatformFlavor::LinuxOnChromium;
BOOST_LOG_TRIVIAL(info) << "Platform flavor: LinuxOnChromium";
} else if (strstr(buf, "microsoft") != nullptr || strstr(buf, "Microsoft") != nullptr) {
if (boost::filesystem::exists("/run/WSL") && getenv("WSL_INTEROP") != nullptr) {
BOOST_LOG_TRIVIAL(info) << "Platform flavor: WSL2";
s_platform_flavor = PlatformFlavor::WSL2;
} else {
BOOST_LOG_TRIVIAL(info) << "Platform flavor: WSL";
s_platform_flavor = PlatformFlavor::WSL;
}
}
}
::fclose(f);
}
}
#elif defined(__OpenBSD__)
BOOST_LOG_TRIVIAL(info) << "Platform: OpenBSD";
s_platform = Platform::BSDUnix;
s_platform_flavor = PlatformFlavor::OpenBSD;
#else
// This should not happen.
BOOST_LOG_TRIVIAL(info) << "Platform: Unknown";
static_assert(false, "Unknown platform detected");
s_platform = Platform::Unknown;
s_platform_flavor = PlatformFlavor::Unknown;
#endif
}
Platform platform()
{
return s_platform;
}
PlatformFlavor platform_flavor()
{
return s_platform_flavor;
}
} // namespace Slic3r

View File

@ -0,0 +1,41 @@
#ifndef SLIC3R_Platform_HPP
#define SLIC3R_Platform_HPP
namespace Slic3r {
enum class Platform
{
Uninitialized,
Unknown,
Windows,
OSX,
Linux,
BSDUnix,
};
enum class PlatformFlavor
{
Uninitialized,
Unknown,
// For Windows and OSX, until we need to be more specific.
Generic,
// For Platform::Linux
GenericLinux,
LinuxOnChromium,
// Microsoft's Windows on Linux (Linux kernel simulated on NTFS kernel)
WSL,
// Microsoft's Windows on Linux, version 2 (virtual machine)
WSL2,
// For Platform::BSDUnix
OpenBSD,
};
// To be called on program start-up.
void detect_platform();
Platform platform();
PlatformFlavor platform_flavor();
} // namespace Slic3r
#endif // SLIC3R_Platform_HPP

View File

@ -108,4 +108,14 @@
#define ENABLE_VOLUMETRIC_EXTRUSION_PROCESSING (1 && ENABLE_2_3_0_RC1)
//====================
// 2.3.1.alpha1 techs
//====================
#define ENABLE_2_3_1_ALPHA1 1
#define ENABLE_SPLITTED_VERTEX_BUFFER (1 && ENABLE_2_3_1_ALPHA1)
#define ENABLE_REDUCED_TOOLPATHS_SEGMENT_CAPS (1 && ENABLE_SPLITTED_VERTEX_BUFFER)
#endif // _prusaslicer_technologies_h_

View File

@ -6,6 +6,7 @@
#include <cstdarg>
#include <stdio.h>
#include "Platform.hpp"
#include "Time.hpp"
#ifdef WIN32
@ -22,6 +23,11 @@
#ifdef __APPLE__
#include <mach/mach.h>
#endif
#ifdef __linux__
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/sendfile.h>
#endif
#endif
#include <boost/log/core.hpp>
@ -417,6 +423,140 @@ std::error_code rename_file(const std::string &from, const std::string &to)
#endif
}
#ifdef __linux__
// Copied from boost::filesystem, to support copying a file to a weird filesystem, which does not support changing file attributes,
// for example ChromeOS Linux integration or FlashAIR WebDAV.
// Copied and simplified from boost::filesystem::detail::copy_file() with option = overwrite_if_exists and with just the Linux path kept,
// and only features supported by Linux 3.10 (on our build server with CentOS 7) are kept, namely sendfile with ranges and statx() are not supported.
bool copy_file_linux(const boost::filesystem::path &from, const boost::filesystem::path &to, boost::system::error_code &ec)
{
using namespace boost::filesystem;
struct fd_wrapper
{
int fd { -1 };
fd_wrapper() = default;
explicit fd_wrapper(int fd) throw() : fd(fd) {}
~fd_wrapper() throw() { if (fd >= 0) ::close(fd); }
};
ec.clear();
int err = 0;
// Note: Declare fd_wrappers here so that errno is not clobbered by close() that may be called in fd_wrapper destructors
fd_wrapper infile, outfile;
while (true) {
infile.fd = ::open(from.c_str(), O_RDONLY | O_CLOEXEC);
if (infile.fd < 0) {
err = errno;
if (err == EINTR)
continue;
fail:
ec.assign(err, boost::system::system_category());
return false;
}
break;
}
struct ::stat from_stat;
if (::fstat(infile.fd, &from_stat) != 0) {
fail_errno:
err = errno;
goto fail;
}
const mode_t from_mode = from_stat.st_mode;
if (!S_ISREG(from_mode)) {
err = ENOSYS;
goto fail;
}
// Enable writing for the newly created files. Having write permission set is important e.g. for NFS,
// which checks the file permission on the server, even if the client's file descriptor supports writing.
mode_t to_mode = from_mode | S_IWUSR;
int oflag = O_WRONLY | O_CLOEXEC | O_CREAT | O_TRUNC;
while (true) {
outfile.fd = ::open(to.c_str(), oflag, to_mode);
if (outfile.fd < 0) {
err = errno;
if (err == EINTR)
continue;
goto fail;
}
break;
}
struct ::stat to_stat;
if (::fstat(outfile.fd, &to_stat) != 0)
goto fail_errno;
to_mode = to_stat.st_mode;
if (!S_ISREG(to_mode)) {
err = ENOSYS;
goto fail;
}
if (from_stat.st_dev == to_stat.st_dev && from_stat.st_ino == to_stat.st_ino) {
err = EEXIST;
goto fail;
}
//! copy_file implementation that uses sendfile loop. Requires sendfile to support file descriptors.
//FIXME Vojtech: This is a copy loop valid for Linux 2.6.33 and newer.
// copy_file_data_copy_file_range() supports cross-filesystem copying since 5.3, but Vojtech did not want to polute this
// function with that, we don't think the performance gain is worth it for the types of files we are copying,
// and our build server based on CentOS 7 with Linux 3.10 does not support that anyways.
{
// sendfile will not send more than this amount of data in one call
constexpr std::size_t max_send_size = 0x7ffff000u;
uintmax_t offset = 0u;
while (off_t(offset) < from_stat.st_size) {
uintmax_t size_left = from_stat.st_size - offset;
std::size_t size_to_copy = max_send_size;
if (size_left < static_cast<uintmax_t>(max_send_size))
size_to_copy = static_cast<std::size_t>(size_left);
ssize_t sz = ::sendfile(outfile.fd, infile.fd, nullptr, size_to_copy);
if (sz < 0) {
err = errno;
if (err == EINTR)
continue;
if (err == 0)
break;
goto fail; // err already contains the error code
}
offset += sz;
}
}
// If we created a new file with an explicitly added S_IWUSR permission,
// we may need to update its mode bits to match the source file.
if (to_mode != from_mode && ::fchmod(outfile.fd, from_mode) != 0) {
if (platform_flavor() == PlatformFlavor::LinuxOnChromium) {
// Ignore that. 9p filesystem does not allow fmod().
BOOST_LOG_TRIVIAL(info) << "copy_file_linux() failed to fchmod() the output file \"" << to.string() << "\" to " << from_mode << ": " << ec.message() <<
" This may be expected when writing to a 9p filesystem.";
} else {
// Generic linux. Write out an error to console. At least we may get some feedback.
BOOST_LOG_TRIVIAL(error) << "copy_file_linux() failed to fchmod() the output file \"" << to.string() << "\" to " << from_mode << ": " << ec.message();
}
}
// Note: Use fsync/fdatasync followed by close to avoid dealing with the possibility of close failing with EINTR.
// Even if close fails, including with EINTR, most operating systems (presumably, except HP-UX) will close the
// file descriptor upon its return. This means that if an error happens later, when the OS flushes data to the
// underlying media, this error will go unnoticed and we have no way to receive it from close. Calling fsync/fdatasync
// ensures that all data have been written, and even if close fails for some unfathomable reason, we don't really
// care at that point.
err = ::fdatasync(outfile.fd);
if (err != 0)
goto fail_errno;
return true;
}
#endif // __linux__
CopyFileResult copy_file_inner(const std::string& from, const std::string& to, std::string& error_message)
{
const boost::filesystem::path source(from);
@ -434,7 +574,13 @@ CopyFileResult copy_file_inner(const std::string& from, const std::string& to, s
if (ec)
BOOST_LOG_TRIVIAL(debug) << "boost::filesystem::permisions before copy error message (this could be irrelevant message based on file system): " << ec.message();
ec.clear();
#ifdef __linux__
// We want to allow copying files on Linux to succeed even if changing the file attributes fails.
// That may happen when copying on some exotic file system, for example Linux on Chrome.
copy_file_linux(source, target, ec);
#else // __linux__
boost::filesystem::copy_file(source, target, boost::filesystem::copy_option::overwrite_if_exists, ec);
#endif // __linux__
if (ec) {
error_message = ec.message();
return FAIL_COPY_FILE;

View File

@ -108,8 +108,7 @@ bool BonjourDialog::show_and_lookup()
timer->SetOwner(this);
timer_state = 1;
timer->Start(1000);
wxTimerEvent evt_dummy;
on_timer(evt_dummy);
on_timer_process();
// The background thread needs to queue messages for this dialog
// and for that it needs a valid pointer to it (mandated by the wxWidgets API).
@ -214,6 +213,13 @@ void BonjourDialog::on_reply(BonjourReplyEvent &e)
}
void BonjourDialog::on_timer(wxTimerEvent &)
{
on_timer_process();
}
// This is here so the function can be bound to wxEVT_TIMER and also called
// explicitly (wxTimerEvent should not be created by user code).
void BonjourDialog::on_timer_process()
{
const auto search_str = _utf8(L("Searching for devices"));
@ -228,4 +234,6 @@ void BonjourDialog::on_timer(wxTimerEvent &)
}
}

View File

@ -43,6 +43,7 @@ private:
void on_reply(BonjourReplyEvent &);
void on_timer(wxTimerEvent &);
void on_timer_process();
};

View File

@ -173,6 +173,26 @@ void Control::msw_rescale()
GetParent()->Layout();
}
void Control::sys_color_changed()
{
m_bmp_add_tick_on .msw_rescale();
m_bmp_add_tick_off.msw_rescale();
m_bmp_del_tick_on .msw_rescale();
m_bmp_del_tick_off.msw_rescale();
m_tick_icon_dim = m_bmp_add_tick_on.GetBmpWidth();
m_bmp_one_layer_lock_on .msw_rescale();
m_bmp_one_layer_lock_off .msw_rescale();
m_bmp_one_layer_unlock_on .msw_rescale();
m_bmp_one_layer_unlock_off.msw_rescale();
m_lock_icon_dim = m_bmp_one_layer_lock_on.GetBmpWidth();
m_bmp_revert.msw_rescale();
m_revert_icon_dim = m_bmp_revert.GetBmpWidth();
m_bmp_cog.msw_rescale();
m_cog_icon_dim = m_bmp_cog.GetBmpWidth();
}
int Control::GetActiveValue() const
{
return m_selection == ssLower ?
@ -310,7 +330,7 @@ double Control::get_double_value(const SelectedSlider& selection)
{
if (m_values.empty() || m_lower_value<0)
return 0.0;
if (m_values.size() <= m_higher_value) {
if (m_values.size() <= size_t(m_higher_value)) {
correct_higher_value();
return m_values.back();
}
@ -614,7 +634,7 @@ static std::string short_and_splitted_time(const std::string& time)
::sprintf(buffer, "%dh%dm%ds", hours, minutes, seconds);
else if (hours > 10 && minutes > 10 && seconds > 10)
::sprintf(buffer, "%dh\n%dm\n%ds", hours, minutes, seconds);
else if (minutes < 10 && seconds > 10 || minutes > 10 && seconds < 10)
else if ((minutes < 10 && seconds > 10) || (minutes > 10 && seconds < 10))
::sprintf(buffer, "%dh\n%dm%ds", hours, minutes, seconds);
else
::sprintf(buffer, "%dh%dm\n%ds", hours, minutes, seconds);
@ -632,15 +652,15 @@ static std::string short_and_splitted_time(const std::string& time)
wxString Control::get_label(int tick, LabelType label_type/* = ltHeightWithLayer*/) const
{
const int value = tick;
const size_t value = tick;
if (m_label_koef == 1.0 && m_values.empty())
return wxString::Format("%d", value);
return wxString::Format("%lu", static_cast<unsigned long>(value));
if (value >= m_values.size())
return "ErrVal";
if (m_draw_mode == dmSequentialGCodeView)
return wxString::Format("%d", static_cast<unsigned int>(m_values[value]));
return wxString::Format("%lu", static_cast<unsigned long>(m_values[value]));
else {
if (label_type == ltEstimatedTime) {
return (value < m_layers_times.size()) ? short_and_splitted_time(get_time_dhms(m_layers_times[value])) : "";
@ -755,7 +775,7 @@ void Control::draw_ticks_pair(wxDC& dc, wxCoord pos, wxCoord mid, int tick_len)
dc.DrawLine(mid - (mid_space + tick_len), pos, mid - mid_space, pos);
is_horizontal() ? dc.DrawLine(pos, mid + (mid_space + tick_len), pos, mid + mid_space) :
dc.DrawLine(mid + (mid_space + tick_len), pos, mid + mid_space, pos);
};
}
void Control::draw_ticks(wxDC& dc)
{
@ -766,8 +786,8 @@ void Control::draw_ticks(wxDC& dc)
int height, width;
get_size(&width, &height);
const wxCoord mid = is_horizontal() ? 0.5*height : 0.5*width;
for (auto tick : m_ticks.ticks) {
if (tick.tick >= m_values.size()) {
for (const TickCode& tick : m_ticks.ticks) {
if (size_t(tick.tick) >= m_values.size()) {
// The case when OnPaint is called before m_ticks.ticks data are updated (specific for the vase mode)
break;
}
@ -920,7 +940,6 @@ void Control::Ruler::update(wxWindow* win, const std::vector<double>& values, do
auto end_it = count == 1 ? values.end() : values.begin() + lround(values.size() / count);
while (pow < 3) {
int tick = 0;
for (int istep : {1, 2, 5}) {
double val = (double)istep * std::pow(10,pow);
auto val_it = std::lower_bound(values.begin(), end_it, val - epsilon());
@ -963,7 +982,7 @@ void Control::draw_ruler(wxDC& dc)
dc.SetTextForeground(GREY_PEN.GetColour());
if (m_ruler.long_step < 0)
for (int tick = 1; tick < m_values.size(); tick++) {
for (size_t tick = 1; tick < m_values.size(); tick++) {
wxCoord pos = get_position_from_value(tick);
draw_ticks_pair(dc, pos, mid, 5);
draw_tick_text(dc, wxPoint(mid, pos), tick);
@ -979,7 +998,7 @@ void Control::draw_ruler(wxDC& dc)
}
};
double short_tick;
double short_tick = std::nan("");
int tick = 0;
double value = 0.0;
int sequence = 0;
@ -996,6 +1015,7 @@ void Control::draw_ruler(wxDC& dc)
if (m_values[tick] < value)
break;
// short ticks from the last tick to the end of current sequence
assert(! std::isnan(short_tick));
draw_short_ticks(dc, short_tick, tick);
sequence++;
}

View File

@ -192,6 +192,7 @@ public:
~Control() {}
void msw_rescale();
void sys_color_changed();
int GetMinValue() const { return m_min_value; }
int GetMaxValue() const { return m_max_value; }

File diff suppressed because it is too large Load Diff

View File

@ -19,8 +19,17 @@ namespace GUI {
class GCodeViewer
{
#if ENABLE_SPLITTED_VERTEX_BUFFER
using IBufferType = unsigned short;
#endif // ENABLE_SPLITTED_VERTEX_BUFFER
using Color = std::array<float, 3>;
using VertexBuffer = std::vector<float>;
#if ENABLE_SPLITTED_VERTEX_BUFFER
using MultiVertexBuffer = std::vector<VertexBuffer>;
using IndexBuffer = std::vector<IBufferType>;
#else
using IndexBuffer = std::vector<unsigned int>;
#endif // ENABLE_SPLITTED_VERTEX_BUFFER
using MultiIndexBuffer = std::vector<IndexBuffer>;
std::vector<Color> Extrusion_Role_Colors;
@ -39,7 +48,7 @@ class GCodeViewer
CustomGCodes
};
// vbo buffer containing vertices data used to rendder a specific toolpath type
// vbo buffer containing vertices data used to render a specific toolpath type
struct VBuffer
{
enum class EFormat : unsigned char
@ -53,20 +62,31 @@ class GCodeViewer
};
EFormat format{ EFormat::Position };
#if ENABLE_SPLITTED_VERTEX_BUFFER
// vbos id
std::vector<unsigned int> vbos;
// sizes of the buffers, in bytes, used in export to obj
std::vector<size_t> sizes;
#else
// vbo id
unsigned int id{ 0 };
#endif // ENABLE_SPLITTED_VERTEX_BUFFER
// count of vertices, updated after data are sent to gpu
size_t count{ 0 };
size_t data_size_bytes() const { return count * vertex_size_bytes(); }
#if ENABLE_SPLITTED_VERTEX_BUFFER
// We set 65536 as max count of vertices inside a vertex buffer to allow
// to use unsigned short in place of unsigned int for indices in the index buffer, to save memory
size_t max_size_bytes() const { return 65536 * vertex_size_bytes(); }
#endif // ENABLE_SPLITTED_VERTEX_BUFFER
size_t vertex_size_floats() const { return position_size_floats() + normal_size_floats(); }
size_t vertex_size_bytes() const { return vertex_size_floats() * sizeof(float); }
size_t position_offset_floats() const { return 0; }
size_t position_offset_size() const { return position_offset_floats() * sizeof(float); }
size_t position_size_floats() const
{
size_t position_size_floats() const {
switch (format)
{
case EFormat::Position:
@ -77,8 +97,7 @@ class GCodeViewer
}
size_t position_size_bytes() const { return position_size_floats() * sizeof(float); }
size_t normal_offset_floats() const
{
size_t normal_offset_floats() const {
switch (format)
{
case EFormat::Position:
@ -102,11 +121,18 @@ class GCodeViewer
void reset();
};
// ibo buffer containing indices data (lines/triangles) used to render a specific toolpath type
// ibo buffer containing indices data (for lines/triangles) used to render a specific toolpath type
struct IBuffer
{
#if ENABLE_SPLITTED_VERTEX_BUFFER
// id of the associated vertex buffer
unsigned int vbo{ 0 };
// ibo id
unsigned int ibo{ 0 };
#else
// ibo id
unsigned int id{ 0 };
#endif // ENABLE_SPLITTED_VERTEX_BUFFER
// count of indices, updated after data are sent to gpu
size_t count{ 0 };
@ -118,19 +144,36 @@ class GCodeViewer
{
struct Endpoint
{
// index of the index buffer
// index of the buffer in the multibuffer vector
// the buffer type may change:
// it is the vertex buffer while extracting vertices data,
// the index buffer while extracting indices data
unsigned int b_id{ 0 };
// index into the index buffer
// index into the buffer
size_t i_id{ 0 };
// sequential id (index into the vertex buffer)
// move id
size_t s_id{ 0 };
Vec3f position{ Vec3f::Zero() };
};
EMoveType type{ EMoveType::Noop };
ExtrusionRole role{ erNone };
#if ENABLE_SPLITTED_VERTEX_BUFFER
struct Sub_Path
{
Endpoint first;
Endpoint last;
bool contains(size_t s_id) const {
return first.s_id <= s_id && s_id <= last.s_id;
}
};
#endif // ENABLE_SPLITTED_VERTEX_BUFFER
EMoveType type{ EMoveType::Noop };
ExtrusionRole role{ erNone };
#if !ENABLE_SPLITTED_VERTEX_BUFFER
Endpoint first;
Endpoint last;
#endif // !ENABLE_SPLITTED_VERTEX_BUFFER
float delta_extruder{ 0.0f };
float height{ 0.0f };
float width{ 0.0f };
@ -139,46 +182,98 @@ class GCodeViewer
float volumetric_rate{ 0.0f };
unsigned char extruder_id{ 0 };
unsigned char cp_color_id{ 0 };
#if ENABLE_SPLITTED_VERTEX_BUFFER
std::vector<Sub_Path> sub_paths;
#endif // ENABLE_SPLITTED_VERTEX_BUFFER
float layer_time{ 0.0f };
float elapsed_time{ 0.0f };
float extruder_temp{ 0.0f };
bool matches(const GCodeProcessor::MoveVertex& move) const;
#if ENABLE_SPLITTED_VERTEX_BUFFER
size_t vertices_count() const {
return sub_paths.empty() ? 0 : sub_paths.back().last.s_id - sub_paths.front().first.s_id + 1;
}
bool contains(size_t s_id) const {
return sub_paths.empty() ? false : sub_paths.front().first.s_id <= s_id && s_id <= sub_paths.back().last.s_id;
}
int get_id_of_sub_path_containing(size_t s_id) const {
if (sub_paths.empty())
return -1;
else {
for (int i = 0; i < static_cast<int>(sub_paths.size()); ++i) {
if (sub_paths[i].contains(s_id))
return i;
}
return -1;
}
}
void add_sub_path(const GCodeProcessor::MoveVertex& move, unsigned int b_id, size_t i_id, size_t s_id) {
Endpoint endpoint = { b_id, i_id, s_id, move.position };
sub_paths.push_back({ endpoint , endpoint });
}
#else
size_t vertices_count() const { return last.s_id - first.s_id + 1; }
bool contains(size_t id) const { return first.s_id <= id && id <= last.s_id; }
#endif // ENABLE_SPLITTED_VERTEX_BUFFER
};
// Used to batch the indices needed to render paths
// Used to batch the indices needed to render the paths
struct RenderPath
{
#if ENABLE_REDUCED_TOOLPATHS_SEGMENT_CAPS
// Index of the parent tbuffer
unsigned char tbuffer_id;
#endif // ENABLE_REDUCED_TOOLPATHS_SEGMENT_CAPS
// Render path property
Color color;
unsigned int index_buffer_id;
// Index of the buffer in TBuffer::indices
unsigned int ibuffer_id;
// Render path content
// Index of the path in TBuffer::paths
unsigned int path_id;
std::vector<unsigned int> sizes;
std::vector<size_t> offsets; // use size_t because we need an unsigned int whose size matches pointer's size (used in the call glMultiDrawElements())
};
struct RenderPathPropertyHash {
size_t operator() (const RenderPath &p) const {
// Conver the RGB value to an integer hash.
// return (size_t(int(p.color[0] * 255) + 255 * int(p.color[1] * 255) + (255 * 255) * int(p.color[2] * 255)) * 7919) ^ size_t(p.index_buffer_id);
return size_t(int(p.color[0] * 255) + 255 * int(p.color[1] * 255) + (255 * 255) * int(p.color[2] * 255)) ^ size_t(p.index_buffer_id);
std::vector<size_t> offsets; // use size_t because we need an unsigned integer whose size matches pointer's size (used in the call glMultiDrawElements())
#if ENABLE_REDUCED_TOOLPATHS_SEGMENT_CAPS
bool contains(size_t offset) const {
for (size_t i = 0; i < offsets.size(); ++i) {
if (offsets[i] <= offset && offset <= offsets[i] + static_cast<size_t>(sizes[i] * sizeof(IBufferType)))
return true;
}
return false;
}
#endif // ENABLE_REDUCED_TOOLPATHS_SEGMENT_CAPS
};
// // for unordered_set implementation of render_paths
// struct RenderPathPropertyHash {
// size_t operator() (const RenderPath &p) const {
// // Convert the RGB value to an integer hash.
//// return (size_t(int(p.color[0] * 255) + 255 * int(p.color[1] * 255) + (255 * 255) * int(p.color[2] * 255)) * 7919) ^ size_t(p.ibuffer_id);
// return size_t(int(p.color[0] * 255) + 255 * int(p.color[1] * 255) + (255 * 255) * int(p.color[2] * 255)) ^ size_t(p.ibuffer_id);
// }
// };
struct RenderPathPropertyLower {
bool operator() (const RenderPath &l, const RenderPath &r) const {
for (int i = 0; i < 3; ++ i)
#if ENABLE_REDUCED_TOOLPATHS_SEGMENT_CAPS
if (l.tbuffer_id < r.tbuffer_id)
return true;
#endif // ENABLE_REDUCED_TOOLPATHS_SEGMENT_CAPS
for (int i = 0; i < 3; ++i) {
if (l.color[i] < r.color[i])
return true;
else if (l.color[i] > r.color[i])
return false;
return l.index_buffer_id < r.index_buffer_id;
}
return l.ibuffer_id < r.ibuffer_id;
}
};
struct RenderPathPropertyEqual {
bool operator() (const RenderPath &l, const RenderPath &r) const {
return l.color == r.color && l.index_buffer_id == r.index_buffer_id;
#if ENABLE_REDUCED_TOOLPATHS_SEGMENT_CAPS
return l.tbuffer_id == r.tbuffer_id && l.ibuffer_id == r.ibuffer_id && l.color == r.color;
#else
return l.color == r.color && l.ibuffer_id == r.ibuffer_id;
#endif // ENABLE_REDUCED_TOOLPATHS_SEGMENT_CAPS
}
};
@ -198,45 +293,79 @@ class GCodeViewer
std::string shader;
std::vector<Path> paths;
// std::set seems to perform singificantly better, at least on Windows.
// std::set seems to perform significantly better, at least on Windows.
// std::unordered_set<RenderPath, RenderPathPropertyHash, RenderPathPropertyEqual> render_paths;
std::set<RenderPath, RenderPathPropertyLower> render_paths;
bool visible{ false };
void reset();
// b_id index of buffer contained in this->indices
// i_id index of first index contained in this->indices[b_id]
// s_id index of first vertex contained in this->vertices
void add_path(const GCodeProcessor::MoveVertex& move, unsigned int b_id, size_t i_id, size_t s_id);
#if ENABLE_SPLITTED_VERTEX_BUFFER
unsigned int max_vertices_per_segment() const {
switch (render_primitive_type)
{
case ERenderPrimitiveType::Point: { return 1; }
case ERenderPrimitiveType::Line: { return 2; }
case ERenderPrimitiveType::Triangle: { return 8; }
default: { return 0; }
}
}
size_t max_vertices_per_segment_size_floats() const { return vertices.vertex_size_floats() * static_cast<size_t>(max_vertices_per_segment()); }
size_t max_vertices_per_segment_size_bytes() const { return max_vertices_per_segment_size_floats() * sizeof(float); }
#endif // ENABLE_SPLITTED_VERTEX_BUFFER
unsigned int indices_per_segment() const {
switch (render_primitive_type)
{
case ERenderPrimitiveType::Point: { return 1; }
case ERenderPrimitiveType::Line: { return 2; }
#if ENABLE_REDUCED_TOOLPATHS_SEGMENT_CAPS
case ERenderPrimitiveType::Triangle: { return 30; } // 3 indices x 10 triangles
#else
case ERenderPrimitiveType::Triangle: { return 42; } // 3 indices x 14 triangles
#endif // ENABLE_REDUCED_TOOLPATHS_SEGMENT_CAPS
default: { return 0; }
}
}
unsigned int start_segment_vertex_offset() const {
#if ENABLE_SPLITTED_VERTEX_BUFFER
size_t indices_per_segment_size_bytes() const { return static_cast<size_t>(indices_per_segment() * sizeof(IBufferType)); }
#endif // ENABLE_SPLITTED_VERTEX_BUFFER
#if ENABLE_REDUCED_TOOLPATHS_SEGMENT_CAPS
unsigned int max_indices_per_segment() const {
switch (render_primitive_type)
{
case ERenderPrimitiveType::Point:
case ERenderPrimitiveType::Line:
case ERenderPrimitiveType::Triangle:
case ERenderPrimitiveType::Point: { return 1; }
case ERenderPrimitiveType::Line: { return 2; }
case ERenderPrimitiveType::Triangle: { return 36; } // 3 indices x 12 triangles
default: { return 0; }
}
}
size_t max_indices_per_segment_size_bytes() const { return max_indices_per_segment() * sizeof(IBufferType); }
#endif // ENABLE_REDUCED_TOOLPATHS_SEGMENT_CAPS
#if ENABLE_SPLITTED_VERTEX_BUFFER
bool has_data() const {
return !vertices.vbos.empty() && vertices.vbos.front() != 0 && !indices.empty() && indices.front().ibo != 0;
}
#else
unsigned int start_segment_vertex_offset() const { return 0; }
unsigned int end_segment_vertex_offset() const {
switch (render_primitive_type)
{
case ERenderPrimitiveType::Point: { return 0; }
case ERenderPrimitiveType::Line: { return 1; }
case ERenderPrimitiveType::Triangle: { return 36; } // 1 vertex of 13th triangle
case ERenderPrimitiveType::Triangle: { return 36; } // 1st vertex of 13th triangle
default: { return 0; }
}
}
bool has_data() const { return vertices.id != 0 && !indices.empty() && indices.front().id != 0; }
#endif // ENABLE_SPLITTED_VERTEX_BUFFER
};
// helper to render shells
@ -322,6 +451,12 @@ class GCodeViewer
{
size_t first{ 0 };
size_t last{ 0 };
#if ENABLE_SPLITTED_VERTEX_BUFFER
bool operator == (const Endpoints& other) const {
return first == other.first && last == other.last;
}
#endif // ENABLE_SPLITTED_VERTEX_BUFFER
};
private:
@ -329,14 +464,12 @@ class GCodeViewer
std::vector<Endpoints> m_endpoints;
public:
void append(double z, Endpoints endpoints)
{
void append(double z, Endpoints endpoints) {
m_zs.emplace_back(z);
m_endpoints.emplace_back(endpoints);
}
void reset()
{
void reset() {
m_zs = std::vector<double>();
m_endpoints = std::vector<Endpoints>();
}
@ -348,20 +481,54 @@ class GCodeViewer
std::vector<Endpoints>& get_endpoints() { return m_endpoints; }
double get_z_at(unsigned int id) const { return (id < m_zs.size()) ? m_zs[id] : 0.0; }
Endpoints get_endpoints_at(unsigned int id) const { return (id < m_endpoints.size()) ? m_endpoints[id] : Endpoints(); }
#if ENABLE_SPLITTED_VERTEX_BUFFER
bool operator != (const Layers& other) const {
if (m_zs != other.m_zs)
return true;
if (!(m_endpoints == other.m_endpoints))
return true;
return false;
}
#endif // ENABLE_SPLITTED_VERTEX_BUFFER
};
#if ENABLE_REDUCED_TOOLPATHS_SEGMENT_CAPS
// used to render the toolpath caps of the current sequential range
// (i.e. when sliding on the horizontal slider)
struct SequentialRangeCap
{
TBuffer* buffer{ nullptr };
unsigned int ibo{ 0 };
unsigned int vbo{ 0 };
Color color;
~SequentialRangeCap();
bool is_renderable() const { return buffer != nullptr; }
void reset();
size_t indices_count() const { return 6; }
};
#endif // ENABLE_REDUCED_TOOLPATHS_SEGMENT_CAPS
#if ENABLE_GCODE_VIEWER_STATISTICS
struct Statistics
{
// time
int64_t results_time{ 0 };
int64_t load_time{ 0 };
int64_t load_vertices{ 0 };
int64_t smooth_vertices{ 0 };
int64_t load_indices{ 0 };
int64_t refresh_time{ 0 };
int64_t refresh_paths_time{ 0 };
// opengl calls
int64_t gl_multi_points_calls_count{ 0 };
int64_t gl_multi_lines_calls_count{ 0 };
int64_t gl_multi_triangles_calls_count{ 0 };
#if ENABLE_REDUCED_TOOLPATHS_SEGMENT_CAPS
int64_t gl_triangles_calls_count{ 0 };
#endif // ENABLE_REDUCED_TOOLPATHS_SEGMENT_CAPS
// memory
int64_t results_size{ 0 };
int64_t total_vertices_gpu_size{ 0 };
@ -376,8 +543,6 @@ class GCodeViewer
int64_t extrude_segments_count{ 0 };
int64_t vbuffers_count{ 0 };
int64_t ibuffers_count{ 0 };
int64_t max_vertices_in_vertex_buffer{ 0 };
int64_t max_indices_in_index_buffer{ 0 };
void reset_all() {
reset_times();
@ -389,6 +554,9 @@ class GCodeViewer
void reset_times() {
results_time = 0;
load_time = 0;
load_vertices = 0;
smooth_vertices = 0;
load_indices = 0;
refresh_time = 0;
refresh_paths_time = 0;
}
@ -397,6 +565,9 @@ class GCodeViewer
gl_multi_points_calls_count = 0;
gl_multi_lines_calls_count = 0;
gl_multi_triangles_calls_count = 0;
#if ENABLE_REDUCED_TOOLPATHS_SEGMENT_CAPS
gl_triangles_calls_count = 0;
#endif // ENABLE_REDUCED_TOOLPATHS_SEGMENT_CAPS
}
void reset_sizes() {
@ -415,8 +586,6 @@ class GCodeViewer
extrude_segments_count = 0;
vbuffers_count = 0;
ibuffers_count = 0;
max_vertices_in_vertex_buffer = 0;
max_indices_in_index_buffer = 0;
}
};
#endif // ENABLE_GCODE_VIEWER_STATISTICS
@ -480,11 +649,10 @@ public:
};
private:
bool m_initialized{ false };
mutable bool m_gl_data_initialized{ false };
bool m_gl_data_initialized{ false };
unsigned int m_last_result_id{ 0 };
size_t m_moves_count{ 0 };
mutable std::vector<TBuffer> m_buffers{ static_cast<size_t>(EMoveType::Extrude) };
std::vector<TBuffer> m_buffers{ static_cast<size_t>(EMoveType::Extrude) };
// bounding box of toolpaths
BoundingBoxf3 m_paths_bounding_box;
// bounding box of toolpaths + marker tools
@ -496,21 +664,24 @@ private:
std::vector<ExtrusionRole> m_roles;
size_t m_extruders_count;
std::vector<unsigned char> m_extruder_ids;
mutable Extrusions m_extrusions;
mutable SequentialView m_sequential_view;
Extrusions m_extrusions;
SequentialView m_sequential_view;
Shells m_shells;
EViewType m_view_type{ EViewType::FeatureType };
bool m_legend_enabled{ true };
PrintEstimatedTimeStatistics m_time_statistics;
mutable PrintEstimatedTimeStatistics::ETimeMode m_time_estimate_mode{ PrintEstimatedTimeStatistics::ETimeMode::Normal };
PrintEstimatedTimeStatistics::ETimeMode m_time_estimate_mode{ PrintEstimatedTimeStatistics::ETimeMode::Normal };
#if ENABLE_GCODE_VIEWER_STATISTICS
mutable Statistics m_statistics;
Statistics m_statistics;
#endif // ENABLE_GCODE_VIEWER_STATISTICS
mutable std::array<float, 2> m_detected_point_sizes = { 0.0f, 0.0f };
std::array<float, 2> m_detected_point_sizes = { 0.0f, 0.0f };
GCodeProcessor::Result::SettingsIds m_settings_ids;
#if ENABLE_REDUCED_TOOLPATHS_SEGMENT_CAPS
std::array<SequentialRangeCap, 2> m_sequential_range_caps;
#endif // ENABLE_REDUCED_TOOLPATHS_SEGMENT_CAPS
public:
GCodeViewer() = default;
GCodeViewer();
~GCodeViewer() { reset(); }
// extract rendering data from the given parameters
@ -526,10 +697,13 @@ public:
void render() const;
bool has_data() const { return !m_roles.empty(); }
#if ENABLE_SPLITTED_VERTEX_BUFFER
bool can_export_toolpaths() const;
#endif // ENABLE_SPLITTED_VERTEX_BUFFER
const BoundingBoxf3& get_paths_bounding_box() const { return m_paths_bounding_box; }
const BoundingBoxf3& get_max_bounding_box() const { return m_max_bounding_box; }
const std::vector<double>& get_layers_zs() const { return m_layers.get_zs(); };
const std::vector<double>& get_layers_zs() const { return m_layers.get_zs(); }
const SequentialView& get_sequential_view() const { return m_sequential_view; }
void update_sequential_view_current(unsigned int first, unsigned int last);
@ -556,7 +730,6 @@ public:
void export_toolpaths_to_obj(const char* filename) const;
private:
void init();
void load_toolpaths(const GCodeProcessor::Result& gcode_result);
void load_shells(const Print& print, bool initialized);
void refresh_render_paths(bool keep_sequential_current_first, bool keep_sequential_current_last) const;

View File

@ -3883,7 +3883,11 @@ void GLCanvas3D::update_tooltip_for_settings_item_in_main_toolbar()
bool GLCanvas3D::has_toolpaths_to_export() const
{
#if ENABLE_SPLITTED_VERTEX_BUFFER
return m_gcode_viewer.can_export_toolpaths();
#else
return m_gcode_viewer.has_data();
#endif // ENABLE_SPLITTED_VERTEX_BUFFER
}
void GLCanvas3D::export_toolpaths_to_obj(const char* filename) const
@ -5862,7 +5866,7 @@ void GLCanvas3D::_load_print_object_toolpaths(const PrintObject& print_object, c
int get_color_idx_for_tool_change(std::vector<CustomGCode::Item>::const_iterator it, const int extruder) const
{
const int current_extruder = it->extruder == 0 ? extruder : it->extruder;
if (number_tools() == extruders_cnt + 1) // there is no one "M600"
if (number_tools() == size_t(extruders_cnt + 1)) // there is no one "M600"
return std::min<int>(extruders_cnt - 1, std::max<int>(current_extruder - 1, 0));
auto it_n = it;

View File

@ -341,7 +341,7 @@ private:
size_t cur_len = 0;
wxString longest_sub_string;
auto get_longest_sub_string = [longest_sub_string, input](wxString &longest_sub_str, int cur_len, size_t i) {
auto get_longest_sub_string = [input](wxString &longest_sub_str, size_t cur_len, size_t i) {
if (cur_len > longest_sub_str.Len())
longest_sub_str = input.SubString(i - cur_len + 1, i);
};

View File

@ -451,6 +451,12 @@ void Preview::msw_rescale()
refresh_print();
}
void Preview::sys_color_changed()
{
if (m_layers_slider != nullptr)
m_layers_slider->sys_color_changed();
}
void Preview::jump_layers_slider(wxKeyEvent& evt)
{
if (m_layers_slider) m_layers_slider->OnChar(evt);
@ -550,13 +556,6 @@ void Preview::on_combochecklist_features(wxCommandEvent& evt)
void Preview::on_combochecklist_options(wxCommandEvent& evt)
{
auto xored = [](unsigned int flags1, unsigned int flags2, unsigned int flag) {
auto is_flag_set = [](unsigned int flags, unsigned int flag) {
return (flags & (1 << flag)) != 0;
};
return !is_flag_set(flags1, flag) != !is_flag_set(flags2, flag);
};
unsigned int curr_flags = m_canvas->get_gcode_options_visibility_flags();
unsigned int new_flags = Slic3r::GUI::combochecklist_get_flags(m_combochecklist_options);
if (curr_flags == new_flags)
@ -567,6 +566,13 @@ void Preview::on_combochecklist_options(wxCommandEvent& evt)
#if ENABLE_RENDER_PATH_REFRESH_AFTER_OPTIONS_CHANGE
m_canvas->refresh_gcode_preview_render_paths();
#else
auto xored = [](unsigned int flags1, unsigned int flags2, unsigned int flag) {
auto is_flag_set = [](unsigned int flags, unsigned int flag) {
return (flags & (1 << flag)) != 0;
};
return !is_flag_set(flags1, flag) != !is_flag_set(flags2, flag);
};
bool skip_refresh = xored(curr_flags, new_flags, static_cast<unsigned int>(OptionType::Shells)) ||
xored(curr_flags, new_flags, static_cast<unsigned int>(OptionType::ToolMarker));

View File

@ -182,6 +182,7 @@ Preview(wxWindow* parent, Model* model, DynamicPrintConfig* config, BackgroundSl
ForceState get_force_state() { return current_force_state; }
void msw_rescale();
void sys_color_changed();
void jump_layers_slider(wxKeyEvent& evt);
void move_layers_slider(wxKeyEvent& evt);
void edit_layers_slider(wxKeyEvent& evt);

View File

@ -108,6 +108,7 @@ public:
// recalc_font();
#ifndef __WXOSX__
#if wxVERSION_EQUAL_OR_GREATER_THAN(3,1,3)
this->Bind(wxEVT_DPI_CHANGED, [this](wxDPIChangedEvent& evt) {
m_scale_factor = (float)evt.GetNewDPI().x / (float)DPI_DEFAULT;
@ -128,6 +129,7 @@ public:
rescale(evt.rect);
});
#endif // wxVERSION_EQUAL_OR_GREATER_THAN
#endif // no __WXOSX__
this->Bind(wxEVT_MOVE_START, [this](wxMoveEvent& event)
{

View File

@ -41,7 +41,7 @@ namespace instance_check_internal
//if (argc < 2)
// return ret;
std::vector<std::string> arguments { argv[0] };
for (size_t i = 1; i < argc; ++i) {
for (int i = 1; i < argc; ++i) {
const std::string token = argv[i];
// Processing of boolean command line arguments shall match DynamicConfig::read_cli().
if (token == "--single-instance")
@ -180,7 +180,7 @@ namespace instance_check_internal
if ( !checker->IsAnotherRunning() ) */
{
DBusMessage* msg;
DBusMessageIter args;
// DBusMessageIter args;
DBusConnection* conn;
DBusError err;
dbus_uint32_t serial = 0;

View File

@ -394,7 +394,7 @@ void NotificationManager::PopNotification::count_spaces()
}
void NotificationManager::PopNotification::init()
{
std::string text = m_text1 + " " + m_hypertext;
std::string text = m_text1;
int last_end = 0;
m_lines_count = 0;
@ -443,6 +443,15 @@ void NotificationManager::PopNotification::init()
}
m_lines_count++;
}
// hypertext calculation
if (!m_hypertext.empty()) {
int prev_end = m_endlines.size() > 1 ? m_endlines[m_endlines.size() - 2] : 0;
if (ImGui::CalcTextSize((text.substr(prev_end, last_end - prev_end) + m_hypertext).c_str()).x > m_window_width - m_window_width_offset) {
m_endlines.push_back(last_end);
m_lines_count++;
}
}
if (m_lines_count >= 3)
m_multiline = true;
m_initialized = true;
@ -469,8 +478,9 @@ void NotificationManager::PopNotification::render_text(ImGuiWrapper& imgui, cons
int last_end = 0;
float starting_y = m_line_height/2;//10;
float shift_y = m_line_height;// -m_line_height / 20;
std::string line;
for (size_t i = 0; i < m_lines_count; i++) {
std::string line = m_text1.substr(last_end , m_endlines[i] - last_end);
line = m_text1.substr(last_end , m_endlines[i] - last_end);
if(i < m_lines_count - 1)
last_end = m_endlines[i] + (m_text1[m_endlines[i]] == '\n' || m_text1[m_endlines[i]] == ' ' ? 1 : 0);
ImGui::SetCursorPosX(x_offset);
@ -478,9 +488,8 @@ void NotificationManager::PopNotification::render_text(ImGuiWrapper& imgui, cons
imgui.text(line.c_str());
}
//hyperlink text
if (!m_hypertext.empty())
{
render_hypertext(imgui, x_offset + ImGui::CalcTextSize(m_text1.substr(m_endlines[m_lines_count - 2] + 1, m_endlines[m_lines_count - 1] - m_endlines[m_lines_count - 2] - 1).c_str()).x, starting_y + (m_lines_count - 1) * shift_y, m_hypertext);
if (!m_hypertext.empty()) {
render_hypertext(imgui, x_offset + ImGui::CalcTextSize((line + " ").c_str()).x, starting_y + (m_lines_count - 1) * shift_y, m_hypertext);
}
}
@ -840,6 +849,7 @@ void NotificationManager::ExportFinishedNotification::render_text(ImGuiWrapper&
float starting_y = m_line_height / 2;//10;
float shift_y = m_line_height;// -m_line_height / 20;
for (size_t i = 0; i < m_lines_count; i++) {
if (m_text1.size() >= m_endlines[i]) {
std::string line = m_text1.substr(last_end, m_endlines[i] - last_end);
if (i < m_lines_count - 1)
last_end = m_endlines[i] + (m_text1[m_endlines[i]] == '\n' || m_text1[m_endlines[i]] == ' ' ? 1 : 0);
@ -848,7 +858,8 @@ void NotificationManager::ExportFinishedNotification::render_text(ImGuiWrapper&
imgui.text(line.c_str());
//hyperlink text
if ( i == 0 ) {
render_hypertext(imgui, x_offset + ImGui::CalcTextSize(m_text1.substr(0, last_end).c_str()).x + ImGui::CalcTextSize(" ").x, starting_y, _u8L("Open Folder."));
render_hypertext(imgui, x_offset + ImGui::CalcTextSize(line.c_str()).x + ImGui::CalcTextSize(" ").x, starting_y, _u8L("Open Folder."));
}
}
}

View File

@ -413,6 +413,9 @@ void OG_CustomCtrl::correct_widgets_position(wxSizer* widget, const Line& line,
void OG_CustomCtrl::msw_rescale()
{
#ifdef __WXOSX__
return;
#endif
m_font = wxGetApp().normal_font();
m_em_unit = em_unit(m_parent);
m_v_gap = lround(1.0 * m_em_unit);
@ -435,7 +438,6 @@ void OG_CustomCtrl::msw_rescale()
void OG_CustomCtrl::sys_color_changed()
{
msw_rescale();
}
OG_CustomCtrl::CtrlLine::CtrlLine( wxCoord height,

View File

@ -5,6 +5,8 @@
#include "I18N.hpp"
#include "3DScene.hpp"
#include "libslic3r/Platform.hpp"
#include <GL/glew.h>
#include <boost/algorithm/string/split.hpp>
@ -333,7 +335,13 @@ void OpenGLManager::detect_multisample(int* attribList)
{
int wxVersion = wxMAJOR_VERSION * 10000 + wxMINOR_VERSION * 100 + wxRELEASE_NUMBER;
bool enable_multisample = wxVersion >= 30003;
s_multisample = (enable_multisample && wxGLCanvas::IsDisplaySupported(attribList)) ? EMultisampleState::Enabled : EMultisampleState::Disabled;
s_multisample =
enable_multisample &&
// Disable multi-sampling on ChromeOS, as the OpenGL virtualization swaps Red/Blue channels with multi-sampling enabled,
// at least on some platforms.
platform_flavor() != PlatformFlavor::LinuxOnChromium &&
wxGLCanvas::IsDisplaySupported(attribList)
? EMultisampleState::Enabled : EMultisampleState::Disabled;
// Alternative method: it was working on previous version of wxWidgets but not with the latest, at least on Windows
// s_multisample = enable_multisample && wxGLCanvas::IsExtensionSupported("WGL_ARB_multisample");
}

View File

@ -88,6 +88,7 @@
#include <wx/glcanvas.h> // Needs to be last because reasons :-/
#include "WipeTowerDialog.hpp"
#include "libslic3r/CustomGCode.hpp"
#include "libslic3r/Platform.hpp"
using boost::optional;
namespace fs = boost::filesystem;
@ -2576,7 +2577,7 @@ std::vector<size_t> Plater::priv::load_model_objects(const ModelObjectPtrs &mode
const Vec3d bed_size = Slic3r::to_3d(bed_shape.size().cast<double>(), 1.0) - 2.0 * Vec3d::Ones();
#ifndef AUTOPLACEMENT_ON_LOAD
bool need_arrange = false;
// bool need_arrange = false;
#endif /* AUTOPLACEMENT_ON_LOAD */
bool scaled_down = false;
std::vector<size_t> obj_idxs;
@ -2596,7 +2597,7 @@ std::vector<size_t> Plater::priv::load_model_objects(const ModelObjectPtrs &mode
new_instances.emplace_back(object->add_instance());
#else /* AUTOPLACEMENT_ON_LOAD */
// if object has no defined position(s) we need to rearrange everything after loading
need_arrange = true;
// need_arrange = true;
// add a default instance and center object around origin
object->center_around_origin(); // also aligns object to Z = 0
ModelInstance* instance = object->add_instance();
@ -3758,9 +3759,8 @@ bool Plater::priv::warnings_dialog()
if (current_warnings.empty())
return true;
std::string text = _u8L("There are active warnings concerning sliced models:") + "\n";
bool empt = true;
for (auto const& it : current_warnings) {
int next_n = it.first.message.find_first_of('\n', 0);
size_t next_n = it.first.message.find_first_of('\n', 0);
text += "\n";
if (next_n != std::string::npos)
text += it.first.message.substr(0, next_n);
@ -3847,7 +3847,9 @@ void Plater::priv::on_process_completed(SlicingProcessCompletedEvent &evt)
// If writing to removable drive was scheduled, show notification with eject button
if (exporting_status == ExportingStatus::EXPORTING_TO_REMOVABLE && !has_error) {
show_action_buttons(false);
notification_manager->push_exporting_finished_notification(last_output_path, last_output_dir_path, true);
notification_manager->push_exporting_finished_notification(last_output_path, last_output_dir_path,
// Don't offer the "Eject" button on ChromeOS, the Linux side has no control over it.
platform_flavor() != PlatformFlavor::LinuxOnChromium);
wxGetApp().removable_drive_manager()->set_exporting_finished(true);
} else if (exporting_status == ExportingStatus::EXPORTING_TO_LOCAL && !has_error) {
notification_manager->push_exporting_finished_notification(last_output_path, last_output_dir_path, false);
@ -5183,6 +5185,10 @@ bool Plater::load_files(const wxArrayString& filenames)
load_files(in_paths, false, true);
break;
}
case LoadType::Unknown : {
assert(false);
break;
}
}
return true;
@ -6077,7 +6083,6 @@ void Plater::force_print_bed_update()
void Plater::on_activate()
{
#if defined(__linux__) || defined(_WIN32)
wxWindow *focus_window = wxWindow::FindFocus();
// Activating the main frame, and no window has keyboard focus.
// Set the keyboard focus to the visible Canvas3D.
if (this->p->view3D->IsShown() && wxWindow::FindFocus() != this->p->view3D->get_wxglcanvas())
@ -6359,6 +6364,7 @@ void Plater::msw_rescale()
void Plater::sys_color_changed()
{
p->preview->sys_color_changed();
p->sidebar->sys_color_changed();
// msw_rescale_menu updates just icons, so use it

View File

@ -759,7 +759,7 @@ void PlaterPresetComboBox::update()
this->Clear();
invalidate_selection();
const Preset* selected_filament_preset;
const Preset* selected_filament_preset = nullptr;
std::string extruder_color;
if (m_type == Preset::TYPE_FILAMENT)
{

View File

@ -1,4 +1,5 @@
#include "RemovableDriveManager.hpp"
#include "libslic3r/Platform.hpp"
#include <libslic3r/libslic3r.h>
#include <boost/nowide/convert.hpp>
@ -185,8 +186,13 @@ namespace search_for_drives_internal
{
//confirms if the file is removable drive and adds it to vector
//if not same file system - could be removable drive
if (! compare_filesystem_id(path, parent_path)) {
if (
#ifdef __linux__
// Chromium mounts removable drives in a way that produces the same device ID.
platform_flavor() == PlatformFlavor::LinuxOnChromium ||
#endif
// If not same file system - could be removable drive.
! compare_filesystem_id(path, parent_path)) {
//free space
boost::system::error_code ec;
boost::filesystem::space_info si = boost::filesystem::space(path, ec);
@ -229,6 +235,10 @@ std::vector<DriveData> RemovableDriveManager::search_for_removable_drives() cons
#else
if (platform_flavor() == PlatformFlavor::LinuxOnChromium) {
// ChromeOS specific: search /mnt/chromeos/removable/* folder
search_for_drives_internal::search_path("/mnt/chromeos/removable/*", "/mnt/chromeos/removable", current_drives);
} else {
//search /media/* folder
search_for_drives_internal::search_path("/media/*", "/media", current_drives);
@ -245,6 +255,8 @@ std::vector<DriveData> RemovableDriveManager::search_for_removable_drives() cons
path = "/run" + path;
pp = "/run"+pp;
search_for_drives_internal::search_path(path, pp, current_drives);
}
#endif
return current_drives;
@ -441,7 +453,10 @@ RemovableDriveManager::RemovableDrivesStatus RemovableDriveManager::status()
RemovableDriveManager::RemovableDrivesStatus out;
{
tbb::mutex::scoped_lock lock(m_drives_mutex);
out.has_eject = this->find_last_save_path_drive_data() != m_current_drives.end();
out.has_eject =
// Cannot control eject on Chromium.
platform_flavor() != PlatformFlavor::LinuxOnChromium &&
this->find_last_save_path_drive_data() != m_current_drives.end();
out.has_removable_drives = ! m_current_drives.empty();
}
if (! out.has_eject)

View File

@ -81,7 +81,9 @@ static void unmount_callback(DADiskRef disk, DADissenterRef dissenter, void *con
NSLog(@"-%@",(CFStringRef)deviceModelKey);
*/
if (mediaEjectableKey != nullptr) {
BOOL op = ejectable && (CFEqual(deviceProtocolName, CFSTR("USB")) || CFEqual(deviceModelKey, CFSTR("SD Card Reader")) || CFEqual(deviceProtocolName, CFSTR("Secure Digital")));
BOOL op = ejectable &&
( (deviceProtocolName != nullptr && (CFEqual(deviceProtocolName, CFSTR("USB")) || CFEqual(deviceProtocolName, CFSTR("Secure Digital")))) ||
(deviceModelKey != nullptr && CFEqual(deviceModelKey, CFSTR("SD Card Reader"))) );
//!CFEqual(deviceModelKey, CFSTR("Disk Image"));
if (op)
[result addObject:volURL.path];

View File

@ -121,18 +121,13 @@ void OptionsSearcher::append_options(DynamicPrintConfig* config, Preset::Type ty
}
}
// Wrap a string with ColorMarkerStart and ColorMarkerEnd symbols
static wxString wrap_string(const wxString& str)
{
return wxString::Format("%c%s%c", ImGui::ColorMarkerStart, str, ImGui::ColorMarkerEnd);
}
// Mark a string using ColorMarkerStart and ColorMarkerEnd symbols
static std::wstring mark_string(const std::wstring &str, const std::vector<uint16_t> &matches)
static std::wstring mark_string(const std::wstring &str, const std::vector<uint16_t> &matches, Preset::Type type, PrinterTechnology pt)
{
std::wstring out;
out += marker_by_type(type, pt);
if (matches.empty())
out = str;
out += str;
else {
out.reserve(str.size() * 2);
if (matches.front() > 0)
@ -205,9 +200,10 @@ bool OptionsSearcher::search(const std::string& search, bool force/* = false*/)
bool full_list = search.empty();
std::wstring sep = L" : ";
auto get_label = [this, &sep](const Option& opt)
auto get_label = [this, &sep](const Option& opt, bool marked = true)
{
std::wstring out;
if (marked)
out += marker_by_type(opt.type, printer_technology);
const std::wstring* prev = nullptr;
for (const std::wstring* const s : {
@ -222,9 +218,10 @@ bool OptionsSearcher::search(const std::string& search, bool force/* = false*/)
return out;
};
auto get_label_english = [this, &sep](const Option& opt)
auto get_label_english = [this, &sep](const Option& opt, bool marked = true)
{
std::wstring out;
if (marked)
out += marker_by_type(opt.type, printer_technology);
const std::wstring* prev = nullptr;
for (const std::wstring* const s : {
@ -258,8 +255,8 @@ bool OptionsSearcher::search(const std::string& search, bool force/* = false*/)
std::wstring wsearch = boost::nowide::widen(search);
boost::trim_left(wsearch);
std::wstring label = get_label(opt);
std::wstring label_english = get_label_english(opt);
std::wstring label = get_label(opt, false);
std::wstring label_english = get_label_english(opt, false);
int score = std::numeric_limits<int>::min();
int score2;
matches.clear();
@ -280,8 +277,8 @@ bool OptionsSearcher::search(const std::string& search, bool force/* = false*/)
matches = std::move(matches2);
score = score2;
}
if (score > std::numeric_limits<int>::min()) {
label = mark_string(label, matches);
if (score > 90/*std::numeric_limits<int>::min()*/) {
label = mark_string(label, matches, opt.type, printer_technology);
label += L" [" + std::to_wstring(score) + L"]";// add score value
std::string label_u8 = into_u8(label);
std::string label_plain = label_u8;

View File

@ -2092,7 +2092,7 @@ static bool is_rotation_xy_synchronized(const Vec3d &rot_xyz_from, const Vec3d &
static void verify_instances_rotation_synchronized(const Model &model, const GLVolumePtrs &volumes)
{
for (size_t idx_object = 0; idx_object < model.objects.size(); ++idx_object) {
for (int idx_object = 0; idx_object < int(model.objects.size()); ++idx_object) {
int idx_volume_first = -1;
for (int i = 0; i < (int)volumes.size(); ++i) {
if (volumes[i]->object_idx() == idx_object) {

View File

@ -1006,7 +1006,7 @@ wxString UnsavedChangesDialog::get_short_string(wxString full_string)
{
int max_len = 30;
if (full_string.IsEmpty() || full_string.StartsWith("#") ||
(full_string.Find("\n") == wxNOT_FOUND && full_string.Length() < max_len))
(full_string.Find("\n") == wxNOT_FOUND && full_string.Length() < size_t(max_len)))
return full_string;
m_has_long_strings = true;

View File

@ -62,13 +62,13 @@ namespace fts {
}
// Public interface
static bool fuzzy_match(char_type const * pattern, char_type const * str, int & outScore) {
[[maybe_unused]] static bool fuzzy_match(char_type const * pattern, char_type const * str, int & outScore) {
pos_type matches[max_matches + 1]; // with the room for the stopper
matches[0] = stopper;
return fuzzy_match(pattern, str, outScore, matches);
}
static bool fuzzy_match(char_type const * pattern, char_type const * str, int & outScore, pos_type * matches) {
[[maybe_unused]] static bool fuzzy_match(char_type const * pattern, char_type const * str, int & outScore, pos_type * matches) {
int recursionCount = 0;
static constexpr int recursionLimit = 10;
return fuzzy_internal::fuzzy_match_recursive(pattern, str, outScore, str, nullptr, matches, 0, recursionCount, recursionLimit);
@ -113,15 +113,16 @@ namespace fts {
bool first_match = true;
while (*pattern != '\0' && *str != '\0') {
int num_matched = std::tolower(*pattern) == std::tolower(*str) ? 1 : 0;
bool folded_match = false;
int num_matched = std::towlower(*pattern) == std::towlower(*str) ? 1 : 0;
// bool folded_match = false;
if (! num_matched) {
wchar_t tmp[4];
wchar_t *end = Slic3r::fold_to_ascii(*str, tmp);
wchar_t *c = tmp;
for (const wchar_t* d = pattern; c != end && *d != 0 && std::towlower(*c) == std::towlower(*d); ++c, ++d);
if (c == end) {
folded_match = true;
// folded_match = true;
num_matched = end - tmp;
}
}
@ -168,11 +169,11 @@ namespace fts {
// Calculate score
if (matched) {
static constexpr int sequential_bonus = 15; // bonus for adjacent matches
static constexpr int separator_bonus = 30; // bonus if match occurs after a separator
static constexpr int camel_bonus = 30; // bonus if match is uppercase and prev is lower
static constexpr int separator_bonus = 10/*30*/; // bonus if match occurs after a separator
// static constexpr int camel_bonus = 30; // bonus if match is uppercase and prev is lower
static constexpr int first_letter_bonus = 15; // bonus if the first letter is matched
static constexpr int leading_letter_penalty = -5; // penalty applied for every letter in str before the first match
static constexpr int leading_letter_penalty = -1/*-5*/; // penalty applied for every letter in str before the first match
static constexpr int max_leading_letter_penalty = -15; // maximum penalty for leading letters
static constexpr int unmatched_letter_penalty = -1; // penalty for every letter that doesn't matter

View File

@ -75,6 +75,7 @@
#undef times
#undef accept
#undef wait
#undef abort
// Breaks compilation with Eigen matrices embedded into Slic3r::Point.
#undef malloc