mirror of
https://git.mirrors.martin98.com/https://github.com/slic3r/Slic3r.git
synced 2025-08-03 04:00:40 +08:00
Merge remote-tracking branch 'remotes/prusa/version_2.3.1' into merill-merge
This commit is contained in:
commit
81f78cc993
@ -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)
|
||||
|
@ -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
89
cmake/modules/bin2h.cmake
Normal 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()
|
@ -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.
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
|
||||
|
@ -158,6 +158,8 @@ add_library(libslic3r STATIC
|
||||
PerimeterGenerator.hpp
|
||||
PlaceholderParser.cpp
|
||||
PlaceholderParser.hpp
|
||||
Platform.cpp
|
||||
Platform.hpp
|
||||
Point.cpp
|
||||
Point.hpp
|
||||
Polygon.cpp
|
||||
|
@ -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]);
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
71
src/libslic3r/Platform.cpp
Normal file
71
src/libslic3r/Platform.cpp
Normal 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
|
41
src/libslic3r/Platform.hpp
Normal file
41
src/libslic3r/Platform.hpp
Normal 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
|
@ -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_
|
||||
|
@ -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;
|
||||
|
@ -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 &)
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
@ -43,6 +43,7 @@ private:
|
||||
|
||||
void on_reply(BonjourReplyEvent &);
|
||||
void on_timer(wxTimerEvent &);
|
||||
void on_timer_process();
|
||||
};
|
||||
|
||||
|
||||
|
@ -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++;
|
||||
}
|
||||
|
@ -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
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
};
|
||||
|
@ -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));
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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;
|
||||
|
@ -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."));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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");
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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)
|
||||
|
@ -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];
|
||||
|
@ -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;
|
||||
|
@ -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) {
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
||||
|
@ -75,6 +75,7 @@
|
||||
#undef times
|
||||
#undef accept
|
||||
#undef wait
|
||||
#undef abort
|
||||
|
||||
// Breaks compilation with Eigen matrices embedded into Slic3r::Point.
|
||||
#undef malloc
|
||||
|
Loading…
x
Reference in New Issue
Block a user