Merge branch 'et_gcode_viewer' of https://github.com/prusa3d/PrusaSlicer into et_gcode_viewer

This commit is contained in:
Enrico Turri 2020-05-15 07:52:57 +02:00
commit 6041ec9aae
87 changed files with 2899 additions and 1761 deletions

View File

@ -234,7 +234,7 @@ foreach(COMPONENT ${OpenVDB_FIND_COMPONENTS})
if (_is_multi) if (_is_multi)
list(APPEND OpenVDB_LIB_COMPONENTS ${OpenVDB_${COMPONENT}_LIBRARY_RELEASE}) list(APPEND OpenVDB_LIB_COMPONENTS ${OpenVDB_${COMPONENT}_LIBRARY_RELEASE})
if (MSVC OR OpenVDB_${COMPONENT}_LIBRARY_DEBUG) if (OpenVDB_${COMPONENT}_LIBRARY_DEBUG)
list(APPEND OpenVDB_LIB_COMPONENTS ${OpenVDB_${COMPONENT}_LIBRARY_DEBUG}) list(APPEND OpenVDB_LIB_COMPONENTS ${OpenVDB_${COMPONENT}_LIBRARY_DEBUG})
endif () endif ()

5
deps/CMakeLists.txt vendored
View File

@ -152,6 +152,11 @@ include(MPFR/MPFR.cmake)
include(CGAL/CGAL.cmake) include(CGAL/CGAL.cmake)
include(wxWidgets/wxWidgets.cmake) include(wxWidgets/wxWidgets.cmake)
if (ZLIB_PKG)
add_dependencies(dep_blosc ${ZLIB_PKG})
add_dependencies(dep_openexr ${ZLIB_PKG})
endif ()
if (MSVC) if (MSVC)
add_custom_target(deps ALL add_custom_target(deps ALL

View File

@ -35,8 +35,6 @@ else ()
set(DEP_PLATFORM "x64") set(DEP_PLATFORM "x64")
endif () endif ()
if (${DEP_DEBUG}) if (${DEP_DEBUG})
set(DEP_BOOST_DEBUG "debug") set(DEP_BOOST_DEBUG "debug")
else () else ()
@ -217,7 +215,6 @@ ExternalProject_Add(dep_blosc
#URL_HASH SHA256=7463a1df566704f212263312717ab2c36b45d45cba6cd0dccebf91b2cc4b4da9 #URL_HASH SHA256=7463a1df566704f212263312717ab2c36b45d45cba6cd0dccebf91b2cc4b4da9
GIT_REPOSITORY https://github.com/Blosc/c-blosc.git GIT_REPOSITORY https://github.com/Blosc/c-blosc.git
GIT_TAG e63775855294b50820ef44d1b157f4de1cc38d3e #v1.17.0 GIT_TAG e63775855294b50820ef44d1b157f4de1cc38d3e #v1.17.0
DEPENDS ${ZLIB_PKG}
CMAKE_GENERATOR "${DEP_MSVC_GEN}" CMAKE_GENERATOR "${DEP_MSVC_GEN}"
CMAKE_GENERATOR_PLATFORM "${DEP_PLATFORM}" CMAKE_GENERATOR_PLATFORM "${DEP_PLATFORM}"
CMAKE_ARGS CMAKE_ARGS
@ -244,7 +241,6 @@ ExternalProject_Add(dep_openexr
EXCLUDE_FROM_ALL 1 EXCLUDE_FROM_ALL 1
GIT_REPOSITORY https://github.com/openexr/openexr.git GIT_REPOSITORY https://github.com/openexr/openexr.git
GIT_TAG eae0e337c9f5117e78114fd05f7a415819df413a #v2.4.0 GIT_TAG eae0e337c9f5117e78114fd05f7a415819df413a #v2.4.0
DEPENDS ${ZLIB_PKG}
CMAKE_GENERATOR "${DEP_MSVC_GEN}" CMAKE_GENERATOR "${DEP_MSVC_GEN}"
CMAKE_GENERATOR_PLATFORM "${DEP_PLATFORM}" CMAKE_GENERATOR_PLATFORM "${DEP_PLATFORM}"
CMAKE_ARGS CMAKE_ARGS

View File

@ -19,6 +19,7 @@ prusaslicer_add_cmake_project(wxWidgets
-DwxBUILD_PRECOMP=ON -DwxBUILD_PRECOMP=ON
${_wx_toolkit} ${_wx_toolkit}
"-DCMAKE_DEBUG_POSTFIX:STRING=" "-DCMAKE_DEBUG_POSTFIX:STRING="
-DwxBUILD_DEBUG_LEVEL=0
-DwxUSE_DETECT_SM=OFF -DwxUSE_DETECT_SM=OFF
-DwxUSE_UNICODE=ON -DwxUSE_UNICODE=ON
-DwxUSE_OPENGL=ON -DwxUSE_OPENGL=ON

View File

@ -0,0 +1,11 @@
#version 110
uniform vec4 uniform_color;
// x = tainted, y = specular;
varying vec2 intensity;
void main()
{
gl_FragColor = vec4(vec3(intensity.y, intensity.y, intensity.y) + uniform_color.rgb * intensity.x, uniform_color.a);
}

View File

@ -0,0 +1,38 @@
#version 110
#define INTENSITY_CORRECTION 0.6
// normalized values for (-0.6/1.31, 0.6/1.31, 1./1.31)
const vec3 LIGHT_TOP_DIR = vec3(-0.4574957, 0.4574957, 0.7624929);
#define LIGHT_TOP_DIFFUSE (0.8 * INTENSITY_CORRECTION)
#define LIGHT_TOP_SPECULAR (0.125 * INTENSITY_CORRECTION)
#define LIGHT_TOP_SHININESS 20.0
// normalized values for (1./1.43, 0.2/1.43, 1./1.43)
const vec3 LIGHT_FRONT_DIR = vec3(0.6985074, 0.1397015, 0.6985074);
#define LIGHT_FRONT_DIFFUSE (0.3 * INTENSITY_CORRECTION)
#define INTENSITY_AMBIENT 0.3
// x = tainted, y = specular;
varying vec2 intensity;
void main()
{
// First transform the normal into camera space and normalize the result.
vec3 normal = normalize(gl_NormalMatrix * gl_Normal);
// Compute the cos of the angle between the normal and lights direction. The light is directional so the direction is constant for every vertex.
// Since these two are normalized the cosine is the dot product. We also need to clamp the result to the [0,1] range.
float NdotL = max(dot(normal, LIGHT_TOP_DIR), 0.0);
intensity.x = INTENSITY_AMBIENT + NdotL * LIGHT_TOP_DIFFUSE;
vec3 position = (gl_ModelViewMatrix * gl_Vertex).xyz;
intensity.y = LIGHT_TOP_SPECULAR * pow(max(dot(-normalize(position), reflect(-LIGHT_TOP_DIR, normal)), 0.0), LIGHT_TOP_SHININESS);
// Perform the same lighting calculation for the 2nd light source (no specular applied).
NdotL = max(dot(normal, LIGHT_FRONT_DIR), 0.0);
intensity.x += NdotL * LIGHT_FRONT_DIFFUSE;
gl_Position = ftransform();
}

View File

@ -565,10 +565,6 @@ int CLI::run(int argc, char **argv)
gui->mainframe->load_config(m_extra_config); gui->mainframe->load_config(m_extra_config);
}); });
int result = wxEntry(argc, argv); int result = wxEntry(argc, argv);
#if !ENABLE_NON_STATIC_CANVAS_MANAGER
//FIXME this is a workaround for the PrusaSlicer 2.1 release.
_3DScene::destroy();
#endif // !ENABLE_NON_STATIC_CANVAS_MANAGER
return result; return result;
#else /* SLIC3R_GUI */ #else /* SLIC3R_GUI */
// No GUI support. Just print out a help. // No GUI support. Just print out a help.

View File

@ -3,3 +3,8 @@
For more information go to https://github.com/ocornut/imgui For more information go to https://github.com/ocornut/imgui
THIS DIRECTORY CONTAINS THE imgui-1.75 58b3e02 SOURCE DISTRIBUTION. THIS DIRECTORY CONTAINS THE imgui-1.75 58b3e02 SOURCE DISTRIBUTION.
Customized with the following commits:
042880ba2df913916b2cc77f7bb677e07bfd2c58
67c55c74901f1d337ef08f2090a87cfb4263bb0f
a94c952b40d36b1505fb77b87c0dd739e1034659

View File

@ -107,6 +107,13 @@ namespace ImGui
const char ColorMarkerStart = 0x2; // STX const char ColorMarkerStart = 0x2; // STX
const char ColorMarkerEnd = 0x3; // ETX const char ColorMarkerEnd = 0x3; // ETX
// Special ASCII characters are used here as a ikons markers
const char PrintIconMarker = 0x4;
const char PrinterIconMarker = 0x5;
const char PrinterSlaIconMarker = 0x6;
const char FilamentIconMarker = 0x7;
const char MaterialIconMarker = 0x8;
// void MyFunction(const char* name, const MyMatrix44& v); // void MyFunction(const char* name, const MyMatrix44& v);
} }

View File

@ -1,6 +1,10 @@
#include "CustomGCode.hpp" #include "CustomGCode.hpp"
#include "Config.hpp" #include "Config.hpp"
#if ENABLE_GCODE_VIEWER
#include "GCode.hpp"
#else
#include "GCode/PreviewData.hpp" #include "GCode/PreviewData.hpp"
#endif // ENABLE_GCODE_VIEWER
#include "GCodeWriter.hpp" #include "GCodeWriter.hpp"
namespace Slic3r { namespace Slic3r {
@ -17,8 +21,12 @@ extern void update_custom_gcode_per_print_z_from_config(Info& info, DynamicPrint
return; return;
if (info.gcodes.empty() && ! colorprint_heights->values.empty()) { if (info.gcodes.empty() && ! colorprint_heights->values.empty()) {
// Convert the old colorprint_heighs only if there is no equivalent data in a new format. // Convert the old colorprint_heighs only if there is no equivalent data in a new format.
const std::vector<std::string>& colors = GCodePreviewData::ColorPrintColors(); #if ENABLE_GCODE_VIEWER
const auto& colorprint_values = colorprint_heights->values; const std::vector<std::string>& colors = ColorPrintColors::get();
#else
const std::vector<std::string>& colors = GCodePreviewData::ColorPrintColors();
#endif // ENABLE_GCODE_VIEWER
const auto& colorprint_values = colorprint_heights->values;
info.gcodes.clear(); info.gcodes.clear();
info.gcodes.reserve(colorprint_values.size()); info.gcodes.reserve(colorprint_values.size());
int i = 0; int i = 0;

View File

@ -1361,7 +1361,6 @@ static void traverse_graph_generate_polylines(
continue; continue;
} }
dont_connect:
// No way to continue the current polyline. Take the rest of the line up to the outer contour. // No way to continue the current polyline. Take the rest of the line up to the outer contour.
// This will finish the polyline, starting another polyline at a new point. // This will finish the polyline, starting another polyline at a new point.
going_up ? ++ it : -- it; going_up ? ++ it : -- it;
@ -1442,6 +1441,8 @@ struct MonotonousRegionLink
AntPath *next_flipped; AntPath *next_flipped;
}; };
// Matrix of paths (AntPath) connecting ends of MontonousRegions.
// AntPath lengths and their derived visibilities refer to the length of the perimeter line if such perimeter segment exists.
class AntPathMatrix class AntPathMatrix
{ {
public: public:
@ -1456,6 +1457,12 @@ public:
// From end of one region to the start of another region, both flipped or not flipped. // From end of one region to the start of another region, both flipped or not flipped.
m_matrix(regions.size() * regions.size() * 4, AntPath{ -1., -1., initial_pheromone}) {} m_matrix(regions.size() * regions.size() * 4, AntPath{ -1., -1., initial_pheromone}) {}
void update_inital_pheromone(float initial_pheromone)
{
for (AntPath &ap : m_matrix)
ap.pheromone = initial_pheromone;
}
AntPath& operator()(const MonotonousRegion &region_from, bool flipped_from, const MonotonousRegion &region_to, bool flipped_to) AntPath& operator()(const MonotonousRegion &region_from, bool flipped_from, const MonotonousRegion &region_to, bool flipped_to)
{ {
int row = 2 * int(&region_from - m_regions.data()) + flipped_from; int row = 2 * int(&region_from - m_regions.data()) + flipped_from;
@ -1478,7 +1485,7 @@ public:
// Just apply the Eucledian distance of the end points. // Just apply the Eucledian distance of the end points.
path.length = unscale<float>(Vec2f(vline_to.pos - vline_from.pos, vline_to.intersections[i_to].pos() - vline_from.intersections[i_from].pos()).norm()); path.length = unscale<float>(Vec2f(vline_to.pos - vline_from.pos, vline_to.intersections[i_to].pos() - vline_from.intersections[i_from].pos()).norm());
} }
path.visibility = 1. / (path.length + EPSILON); path.visibility = 1.f / (path.length + float(EPSILON));
} }
return path; return path;
} }
@ -1497,7 +1504,7 @@ private:
const ExPolygonWithOffset &m_poly_with_offset; const ExPolygonWithOffset &m_poly_with_offset;
const std::vector<SegmentedIntersectionLine> &m_segs; const std::vector<SegmentedIntersectionLine> &m_segs;
// From end of one region to the start of another region, both flipped or not flipped. // From end of one region to the start of another region, both flipped or not flipped.
//FIXME one may possibly use sparse representation of the matrix. //FIXME one may possibly use sparse representation of the matrix, likely using hashing.
std::vector<AntPath> m_matrix; std::vector<AntPath> m_matrix;
}; };
@ -1724,7 +1731,98 @@ static std::vector<MonotonousRegion> generate_montonous_regions(std::vector<Segm
return monotonous_regions; return monotonous_regions;
} }
static void connect_monotonous_regions(std::vector<MonotonousRegion> &regions, std::vector<SegmentedIntersectionLine> &segs) // Traverse path, calculate length of the draw for the purpose of optimization.
// This function is very similar to polylines_from_paths() in the way how it traverses the path, but
// polylines_from_paths() emits a path, while this function just calculates the path length.
static float montonous_region_path_length(const MonotonousRegion &region, bool dir, const ExPolygonWithOffset &poly_with_offset, const std::vector<SegmentedIntersectionLine> &segs)
{
// From the initial point (i_vline, i_intersection), follow a path.
int i_intersection = region.left_intersection_point(dir);
int i_vline = region.left.vline;
float total_length = 0.;
bool no_perimeter = false;
Vec2f last_point;
for (;;) {
const SegmentedIntersectionLine &vline = segs[i_vline];
const SegmentIntersection *it = &vline.intersections[i_intersection];
const bool going_up = it->is_low();
if (no_perimeter)
total_length += (last_point - Vec2f(vline.pos, (it + (going_up ? - 1 : 1))->pos())).norm();
int iright = it->right_horizontal();
if (going_up) {
// Traverse the complete vertical segment up to the inner contour.
for (;;) {
do {
++ it;
iright = std::max(iright, it->right_horizontal());
assert(it->is_inner());
} while (it->type != SegmentIntersection::INNER_HIGH || (it + 1)->type != SegmentIntersection::OUTER_HIGH);
int inext = it->vertical_up();
if (inext == -1 || it->vertical_up_quality() != SegmentIntersection::LinkQuality::Valid)
break;
assert(it->iContour == vline.intersections[inext].iContour);
it = vline.intersections.data() + inext;
}
} else {
// Going down.
assert(it->is_high());
assert(i_intersection > 0);
for (;;) {
do {
-- it;
if (int iright_new = it->right_horizontal(); iright_new != -1)
iright = iright_new;
assert(it->is_inner());
} while (it->type != SegmentIntersection::INNER_LOW || (it - 1)->type != SegmentIntersection::OUTER_LOW);
int inext = it->vertical_down();
if (inext == -1 || it->vertical_down_quality() != SegmentIntersection::LinkQuality::Valid)
break;
assert(it->iContour == vline.intersections[inext].iContour);
it = vline.intersections.data() + inext;
}
}
if (i_vline == region.right.vline)
break;
int inext = it->right_horizontal();
if (inext != -1 && it->next_on_contour_quality == SegmentIntersection::LinkQuality::Valid) {
// Summarize length of the connection line along the perimeter.
//FIXME should it be weighted with a lower weight than non-extruding connection line? What weight?
// Taking half of the length.
total_length += 0.5f * float(measure_perimeter_horizontal_segment_length(poly_with_offset, segs, i_vline, it - vline.intersections.data(), inext));
// Don't add distance to the next vertical line start to the total length.
no_perimeter = false;
i_intersection = inext;
} else {
// Finish the current vertical line,
going_up ? ++ it : -- it;
assert(it->is_outer());
assert(it->is_high() == going_up);
// Mark the end of this vertical line.
last_point = Vec2f(vline.pos, it->pos());
// Remember to add distance to the last point.
no_perimeter = true;
if (inext == -1) {
// Find the end of the next overlapping vertical segment.
const SegmentedIntersectionLine &vline_right = segs[i_vline + 1];
const SegmentIntersection *right = going_up ?
&vertical_run_top(vline_right, vline_right.intersections[iright]) : &vertical_run_bottom(vline_right, vline_right.intersections[iright]);
i_intersection = int(right - vline_right.intersections.data());
} else
i_intersection = inext;
}
++ i_vline;
}
return unscale<float>(total_length);
}
static void connect_monotonous_regions(std::vector<MonotonousRegion> &regions, const ExPolygonWithOffset &poly_with_offset, std::vector<SegmentedIntersectionLine> &segs)
{ {
// Map from low intersection to left / right side of a monotonous region. // Map from low intersection to left / right side of a monotonous region.
using MapType = std::pair<SegmentIntersection*, MonotonousRegion*>; using MapType = std::pair<SegmentIntersection*, MonotonousRegion*>;
@ -1816,6 +1914,20 @@ static void connect_monotonous_regions(std::vector<MonotonousRegion> &regions, s
} }
} }
#endif /* NDEBUG */ #endif /* NDEBUG */
// Fill in sum length of connecting lines of a region. This length is used for optimizing the infill path for minimum length.
for (MonotonousRegion &region : regions) {
region.len1 = montonous_region_path_length(region, false, poly_with_offset, segs);
region.len2 = montonous_region_path_length(region, true, poly_with_offset, segs);
// Subtract the smaller length from the longer one, so we will optimize just with the positive difference of the two.
if (region.len1 > region.len2) {
region.len1 -= region.len2;
region.len2 = 0;
} else {
region.len2 -= region.len1;
region.len1 = 0;
}
}
} }
// Raad Salman: Algorithms for the Precedence Constrained Generalized Travelling Salesperson Problem // Raad Salman: Algorithms for the Precedence Constrained Generalized Travelling Salesperson Problem
@ -1851,6 +1963,7 @@ inline void print_ant(const std::string& fmt, TArgs&&... args) {
} }
// Find a run through monotonous infill blocks using an 'Ant colony" optimization method. // Find a run through monotonous infill blocks using an 'Ant colony" optimization method.
// http://www.scholarpedia.org/article/Ant_colony_optimization
static std::vector<MonotonousRegionLink> chain_monotonous_regions( static std::vector<MonotonousRegionLink> chain_monotonous_regions(
std::vector<MonotonousRegion> &regions, const ExPolygonWithOffset &poly_with_offset, const std::vector<SegmentedIntersectionLine> &segs, std::mt19937_64 &rng) std::vector<MonotonousRegion> &regions, const ExPolygonWithOffset &poly_with_offset, const std::vector<SegmentedIntersectionLine> &segs, std::mt19937_64 &rng)
{ {
@ -1940,14 +2053,18 @@ static std::vector<MonotonousRegionLink> chain_monotonous_regions(
}; };
#endif /* NDEBUG */ #endif /* NDEBUG */
// How many times to repeat the ant simulation. // How many times to repeat the ant simulation (number of ant generations).
constexpr int num_rounds = 10; constexpr int num_rounds = 25;
// After how many rounds without an improvement to exit?
constexpr int num_rounds_no_change_exit = 8;
// With how many ants each of the run will be performed? // With how many ants each of the run will be performed?
constexpr int num_ants = 10; const int num_ants = std::min<int>(regions.size(), 10);
// Base (initial) pheromone level. // Base (initial) pheromone level. This value will be adjusted based on the length of the first greedy path found.
constexpr float pheromone_initial_deposit = 0.5f; float pheromone_initial_deposit = 0.5f;
// Evaporation rate of pheromones. // Evaporation rate of pheromones.
constexpr float pheromone_evaporation = 0.1f; constexpr float pheromone_evaporation = 0.1f;
// Evaporation rate to diversify paths taken by individual ants.
constexpr float pheromone_diversification = 0.1f;
// Probability at which to take the next best path. Otherwise take the the path based on the cost distribution. // Probability at which to take the next best path. Otherwise take the the path based on the cost distribution.
constexpr float probability_take_best = 0.9f; constexpr float probability_take_best = 0.9f;
// Exponents of the cost function. // Exponents of the cost function.
@ -1956,6 +2073,73 @@ static std::vector<MonotonousRegionLink> chain_monotonous_regions(
AntPathMatrix path_matrix(regions, poly_with_offset, segs, pheromone_initial_deposit); AntPathMatrix path_matrix(regions, poly_with_offset, segs, pheromone_initial_deposit);
// Find an initial path in a greedy way, set the initial pheromone value to 10% of the cost of the greedy path.
{
// Construct the first path in a greedy way to calculate an initial value of the pheromone value.
queue = queue_initial;
left_neighbors_unprocessed = left_neighbors_unprocessed_initial;
assert(validate_unprocessed());
// Pick the last of the queue.
MonotonousRegionLink path_end { queue.back(), false };
queue.pop_back();
-- left_neighbors_unprocessed[path_end.region - regions.data()];
float total_length = path_end.region->length(false);
while (! queue.empty() || ! path_end.region->right_neighbors.empty()) {
// Chain.
MonotonousRegion &region = *path_end.region;
bool dir = path_end.flipped;
NextCandidate next_candidate;
next_candidate.probability = 0;
for (MonotonousRegion *next : region.right_neighbors) {
int &unprocessed = left_neighbors_unprocessed[next - regions.data()];
assert(unprocessed > 1);
if (left_neighbors_unprocessed[next - regions.data()] == 2) {
// Dependencies of the successive blocks are satisfied.
AntPath &path1 = path_matrix(region, dir, *next, false);
AntPath &path2 = path_matrix(region, dir, *next, true);
if (path1.visibility > next_candidate.probability)
next_candidate = { next, &path1, &path1, path1.visibility, false };
if (path2.visibility > next_candidate.probability)
next_candidate = { next, &path2, &path2, path2.visibility, true };
}
}
bool from_queue = next_candidate.probability == 0;
if (from_queue) {
for (MonotonousRegion *next : queue) {
AntPath &path1 = path_matrix(region, dir, *next, false);
AntPath &path2 = path_matrix(region, dir, *next, true);
if (path1.visibility > next_candidate.probability)
next_candidate = { next, &path1, &path1, path1.visibility, false };
if (path2.visibility > next_candidate.probability)
next_candidate = { next, &path2, &path2, path2.visibility, true };
}
}
// Move the other right neighbors with satisified constraints to the queue.
for (MonotonousRegion *next : region.right_neighbors)
if (-- left_neighbors_unprocessed[next - regions.data()] == 1 && next_candidate.region != next)
queue.emplace_back(next);
if (from_queue) {
// Remove the selected path from the queue.
auto it = std::find(queue.begin(), queue.end(), next_candidate.region);
assert(it != queue.end());
*it = queue.back();
queue.pop_back();
}
// Extend the path.
MonotonousRegion *next_region = next_candidate.region;
bool next_dir = next_candidate.dir;
total_length += next_region->length(next_dir) + path_matrix(*path_end.region, path_end.flipped, *next_region, next_dir).length;
path_end = { next_region, next_dir };
assert(left_neighbors_unprocessed[next_region - regions.data()] == 1);
left_neighbors_unprocessed[next_region - regions.data()] = 0;
}
// Set an initial pheromone value to 10% of the greedy path's value.
pheromone_initial_deposit = 0.1 / total_length;
path_matrix.update_inital_pheromone(pheromone_initial_deposit);
}
// Probability (unnormalized) of traversing a link between two monotonous regions. // Probability (unnormalized) of traversing a link between two monotonous regions.
auto path_probability = [pheromone_alpha, pheromone_beta](AntPath &path) { auto path_probability = [pheromone_alpha, pheromone_beta](AntPath &path) {
return pow(path.pheromone, pheromone_alpha) * pow(path.visibility, pheromone_beta); return pow(path.pheromone, pheromone_alpha) * pow(path.visibility, pheromone_beta);
@ -1966,8 +2150,10 @@ static std::vector<MonotonousRegionLink> chain_monotonous_regions(
++ irun; ++ irun;
#endif /* SLIC3R_DEBUG_ANTS */ #endif /* SLIC3R_DEBUG_ANTS */
for (int round = 0; round < num_rounds; ++ round) int num_rounds_no_change = 0;
for (int round = 0; round < num_rounds && num_rounds_no_change < num_rounds_no_change_exit; ++ round)
{ {
bool improved = false;
for (int ant = 0; ant < num_ants; ++ ant) for (int ant = 0; ant < num_ants; ++ ant)
{ {
// Find a new path following the pheromones deposited by the previous ants. // Find a new path following the pheromones deposited by the previous ants.
@ -1977,6 +2163,8 @@ static std::vector<MonotonousRegionLink> chain_monotonous_regions(
left_neighbors_unprocessed = left_neighbors_unprocessed_initial; left_neighbors_unprocessed = left_neighbors_unprocessed_initial;
assert(validate_unprocessed()); assert(validate_unprocessed());
// Pick randomly the first from the queue at random orientation. // Pick randomly the first from the queue at random orientation.
//FIXME picking the 1st monotonous region should likely be done based on accumulated pheromone level as well,
// but the inefficiency caused by the random pick of the 1st monotonous region is likely insignificant.
int first_idx = std::uniform_int_distribution<>(0, int(queue.size()) - 1)(rng); int first_idx = std::uniform_int_distribution<>(0, int(queue.size()) - 1)(rng);
path.emplace_back(MonotonousRegionLink{ queue[first_idx], rng() > rng.max() / 2 }); path.emplace_back(MonotonousRegionLink{ queue[first_idx], rng() > rng.max() / 2 });
*(queue.begin() + first_idx) = std::move(queue.back()); *(queue.begin() + first_idx) = std::move(queue.back());
@ -2051,7 +2239,7 @@ static std::vector<MonotonousRegionLink> chain_monotonous_regions(
for (std::vector<NextCandidate>::iterator it_next_candidate = next_candidates.begin(); it_next_candidate != next_candidates.begin() + num_direct_neighbors; ++ it_next_candidate) for (std::vector<NextCandidate>::iterator it_next_candidate = next_candidates.begin(); it_next_candidate != next_candidates.begin() + num_direct_neighbors; ++ it_next_candidate)
if ((queue.empty() || it_next_candidate->region != queue.back()) && it_next_candidate->region != take_path->region) if ((queue.empty() || it_next_candidate->region != queue.back()) && it_next_candidate->region != take_path->region)
queue.emplace_back(it_next_candidate->region); queue.emplace_back(it_next_candidate->region);
if (take_path - next_candidates.begin() >= num_direct_neighbors) { if (size_t(take_path - next_candidates.begin()) >= num_direct_neighbors) {
// Remove the selected path from the queue. // Remove the selected path from the queue.
auto it = std::find(queue.begin(), queue.end(), take_path->region); auto it = std::find(queue.begin(), queue.end(), take_path->region);
assert(it != queue.end()); assert(it != queue.end());
@ -2083,8 +2271,10 @@ static std::vector<MonotonousRegionLink> chain_monotonous_regions(
path.back().flipped == path.back().region->flips ? path.back().region->right.high : path.back().region->right.low, path.back().flipped == path.back().region->flips ? path.back().region->right.high : path.back().region->right.low,
path.back().flipped == path.back().region->flips ? path.back().region->right.low : path.back().region->right.high); path.back().flipped == path.back().region->flips ? path.back().region->right.low : path.back().region->right.high);
// Update pheromones along this link. // Update pheromones along this link, see Ant Colony System (ACS) update rule.
take_path->link->pheromone = (1.f - pheromone_evaporation) * take_path->link->pheromone + pheromone_evaporation * pheromone_initial_deposit; // http://www.scholarpedia.org/article/Ant_colony_optimization
// The goal here is to lower the pheromone trace for paths taken to diversify the next path picked in the same batch of ants.
take_path->link->pheromone = (1.f - pheromone_diversification) * take_path->link->pheromone + pheromone_diversification * pheromone_initial_deposit;
assert(validate_unprocessed()); assert(validate_unprocessed());
} }
@ -2104,18 +2294,33 @@ static std::vector<MonotonousRegionLink> chain_monotonous_regions(
if (path_length < best_path_length) { if (path_length < best_path_length) {
best_path_length = path_length; best_path_length = path_length;
std::swap(best_path, path); std::swap(best_path, path);
#if 0 // #if ! defined(SLIC3R_DEBUG_ANTS) && ! defined(ndebug)
if (round == 0 && ant == 0)
std::cout << std::endl;
std::cout << Slic3r::format("round %1% ant %2% path length %3%", round, ant, path_length) << std::endl;
#endif
if (path_length == 0)
// Perfect path found.
goto end;
improved = true;
} }
} }
// Reinforce the path feromones with the best path. // Reinforce the path pheromones with the best path.
float total_cost = best_path_length + EPSILON; float total_cost = best_path_length + float(EPSILON);
for (size_t i = 0; i + 1 < path.size(); ++ i) { for (size_t i = 0; i + 1 < path.size(); ++ i) {
MonotonousRegionLink &link = path[i]; MonotonousRegionLink &link = path[i];
link.next->pheromone = (1.f - pheromone_evaporation) * link.next->pheromone + pheromone_evaporation / total_cost; link.next->pheromone = (1.f - pheromone_evaporation) * link.next->pheromone + pheromone_evaporation / total_cost;
} }
if (improved)
num_rounds_no_change = 0;
else
++ num_rounds_no_change;
} }
return best_path; end:
return best_path;
} }
// Traverse path, produce polylines. // Traverse path, produce polylines.
@ -2195,7 +2400,6 @@ static void polylines_from_paths(const std::vector<MonotonousRegionLink> &path,
int inext = it->vertical_up(); int inext = it->vertical_up();
if (inext == -1 || it->vertical_up_quality() != SegmentIntersection::LinkQuality::Valid) if (inext == -1 || it->vertical_up_quality() != SegmentIntersection::LinkQuality::Valid)
break; break;
const Polygon &poly = poly_with_offset.contour(it->iContour);
assert(it->iContour == vline.intersections[inext].iContour); assert(it->iContour == vline.intersections[inext].iContour);
emit_perimeter_segment_on_vertical_line(poly_with_offset, segs, i_vline, it->iContour, it - vline.intersections.data(), inext, *polyline, it->has_left_vertical_up()); emit_perimeter_segment_on_vertical_line(poly_with_offset, segs, i_vline, it->iContour, it - vline.intersections.data(), inext, *polyline, it->has_left_vertical_up());
it = vline.intersections.data() + inext; it = vline.intersections.data() + inext;
@ -2215,7 +2419,6 @@ static void polylines_from_paths(const std::vector<MonotonousRegionLink> &path,
int inext = it->vertical_down(); int inext = it->vertical_down();
if (inext == -1 || it->vertical_down_quality() != SegmentIntersection::LinkQuality::Valid) if (inext == -1 || it->vertical_down_quality() != SegmentIntersection::LinkQuality::Valid)
break; break;
const Polygon &poly = poly_with_offset.contour(it->iContour);
assert(it->iContour == vline.intersections[inext].iContour); assert(it->iContour == vline.intersections[inext].iContour);
emit_perimeter_segment_on_vertical_line(poly_with_offset, segs, i_vline, it->iContour, it - vline.intersections.data(), inext, *polyline, it->has_right_vertical_down()); emit_perimeter_segment_on_vertical_line(poly_with_offset, segs, i_vline, it->iContour, it - vline.intersections.data(), inext, *polyline, it->has_right_vertical_down());
it = vline.intersections.data() + inext; it = vline.intersections.data() + inext;
@ -2285,8 +2488,8 @@ bool FillRectilinear2::fill_surface_by_lines(const Surface *surface, const FillP
ExPolygonWithOffset poly_with_offset( ExPolygonWithOffset poly_with_offset(
surface->expolygon, surface->expolygon,
- rotate_vector.first, - rotate_vector.first,
scale_(this->overlap - (0.5 - INFILL_OVERLAP_OVER_SPACING) * this->spacing), float(scale_(this->overlap - (0.5 - INFILL_OVERLAP_OVER_SPACING) * this->spacing)),
scale_(this->overlap - 0.5 * this->spacing)); float(scale_(this->overlap - 0.5 * this->spacing)));
if (poly_with_offset.n_contours_inner == 0) { if (poly_with_offset.n_contours_inner == 0) {
// Not a single infill line fits. // Not a single infill line fits.
//FIXME maybe one shall trigger the gap fill here? //FIXME maybe one shall trigger the gap fill here?
@ -2317,7 +2520,7 @@ bool FillRectilinear2::fill_surface_by_lines(const Surface *surface, const FillP
size_t n_vlines = (bounding_box.max(0) - bounding_box.min(0) + line_spacing - 1) / line_spacing; size_t n_vlines = (bounding_box.max(0) - bounding_box.min(0) + line_spacing - 1) / line_spacing;
coord_t x0 = bounding_box.min(0); coord_t x0 = bounding_box.min(0);
if (params.full_infill()) if (params.full_infill())
x0 += (line_spacing + SCALED_EPSILON) / 2; x0 += (line_spacing + coord_t(SCALED_EPSILON)) / 2;
#ifdef SLIC3R_DEBUG #ifdef SLIC3R_DEBUG
static int iRun = 0; static int iRun = 0;
@ -2359,7 +2562,7 @@ bool FillRectilinear2::fill_surface_by_lines(const Surface *surface, const FillP
bool monotonous_infill = params.monotonous; // || params.density > 0.99; bool monotonous_infill = params.monotonous; // || params.density > 0.99;
if (monotonous_infill) { if (monotonous_infill) {
std::vector<MonotonousRegion> regions = generate_montonous_regions(segs); std::vector<MonotonousRegion> regions = generate_montonous_regions(segs);
connect_monotonous_regions(regions, segs); connect_monotonous_regions(regions, poly_with_offset, segs);
if (! regions.empty()) { if (! regions.empty()) {
std::mt19937_64 rng; std::mt19937_64 rng;
std::vector<MonotonousRegionLink> path = chain_monotonous_regions(regions, poly_with_offset, segs, rng); std::vector<MonotonousRegionLink> path = chain_monotonous_regions(regions, poly_with_offset, segs, rng);
@ -2478,10 +2681,10 @@ Polylines FillCubic::fill_surface(const Surface *surface, const FillParams &para
params3.dont_connect = true; params3.dont_connect = true;
Polylines polylines_out; Polylines polylines_out;
coordf_t dx = sqrt(0.5) * z; coordf_t dx = sqrt(0.5) * z;
if (! fill_surface_by_lines(surface, params2, 0.f, dx, polylines_out) || if (! fill_surface_by_lines(surface, params2, 0.f, float(dx), polylines_out) ||
! fill_surface_by_lines(surface, params2, float(M_PI / 3.), - dx, polylines_out) || ! fill_surface_by_lines(surface, params2, float(M_PI / 3.), - float(dx), polylines_out) ||
// Rotated by PI*2/3 + PI to achieve reverse sloping wall. // Rotated by PI*2/3 + PI to achieve reverse sloping wall.
! fill_surface_by_lines(surface, params3, float(M_PI * 2. / 3.), dx, polylines_out)) { ! fill_surface_by_lines(surface, params3, float(M_PI * 2. / 3.), float(dx), polylines_out)) {
printf("FillCubic::fill_surface() failed to fill a region.\n"); printf("FillCubic::fill_surface() failed to fill a region.\n");
} }
return polylines_out; return polylines_out;

View File

@ -572,6 +572,10 @@ std::string WipeTowerIntegration::finalize(GCode &gcodegen)
return gcode; return gcode;
} }
#if ENABLE_GCODE_VIEWER
const std::vector<std::string> ColorPrintColors::Colors = { "#C0392B", "#E67E22", "#F1C40F", "#27AE60", "#1ABC9C", "#2980B9", "#9B59B6" };
#endif // ENABLE_GCODE_VIEWER
#define EXTRUDER_CONFIG(OPT) m_config.OPT.get_at(m_writer.extruder()->id()) #define EXTRUDER_CONFIG(OPT) m_config.OPT.get_at(m_writer.extruder()->id())
// Collect pairs of object_layer + support_layer sorted by print_z. // Collect pairs of object_layer + support_layer sorted by print_z.
@ -699,7 +703,7 @@ std::vector<std::pair<coordf_t, std::vector<GCode::LayerToPrint>>> GCode::collec
} }
#if ENABLE_GCODE_VIEWER #if ENABLE_GCODE_VIEWER
void GCode::do_export(Print* print, const char* path, GCodePreviewData* preview_data, GCodeProcessor::Result* result, ThumbnailsGeneratorCallback thumbnail_cb) void GCode::do_export(Print* print, const char* path, GCodeProcessor::Result* result, ThumbnailsGeneratorCallback thumbnail_cb)
#else #else
void GCode::do_export(Print* print, const char* path, GCodePreviewData* preview_data, ThumbnailsGeneratorCallback thumbnail_cb) void GCode::do_export(Print* print, const char* path, GCodePreviewData* preview_data, ThumbnailsGeneratorCallback thumbnail_cb)
#endif // ENABLE_GCODE_VIEWER #endif // ENABLE_GCODE_VIEWER
@ -724,7 +728,9 @@ void GCode::do_export(Print* print, const char* path, GCodePreviewData* preview_
if (file == nullptr) if (file == nullptr)
throw std::runtime_error(std::string("G-code export to ") + path + " failed.\nCannot open the file for writing.\n"); throw std::runtime_error(std::string("G-code export to ") + path + " failed.\nCannot open the file for writing.\n");
#if !ENABLE_GCODE_VIEWER
m_enable_analyzer = preview_data != nullptr; m_enable_analyzer = preview_data != nullptr;
#endif // !ENABLE_GCODE_VIEWER
try { try {
m_placeholder_parser_failed_templates.clear(); m_placeholder_parser_failed_templates.clear();
@ -778,16 +784,14 @@ void GCode::do_export(Print* print, const char* path, GCodePreviewData* preview_
m_silent_time_estimator.reset(); m_silent_time_estimator.reset();
} }
#if !ENABLE_GCODE_VIEWER
// starts analyzer calculations // starts analyzer calculations
if (m_enable_analyzer) { if (m_enable_analyzer) {
#if ENABLE_GCODE_VIEWER_DEBUG_OUTPUT
m_analyzer.close_debug_output_file();
#endif // ENABLE_GCODE_VIEWER_DEBUG_OUTPUT
BOOST_LOG_TRIVIAL(debug) << "Preparing G-code preview data" << log_memory_info(); BOOST_LOG_TRIVIAL(debug) << "Preparing G-code preview data" << log_memory_info();
m_analyzer.calc_gcode_preview_data(*preview_data, [print]() { print->throw_if_canceled(); }); m_analyzer.calc_gcode_preview_data(*preview_data, [print]() { print->throw_if_canceled(); });
m_analyzer.reset(); m_analyzer.reset();
} }
#endif // !ENABLE_GCODE_VIEWER
if (rename_file(path_tmp, path)) if (rename_file(path_tmp, path))
throw std::runtime_error( throw std::runtime_error(
@ -877,7 +881,14 @@ namespace DoExport {
} }
} }
static void init_gcode_analyzer(const PrintConfig &config, GCodeAnalyzer &analyzer) #if ENABLE_GCODE_VIEWER
static void init_gcode_processor(const PrintConfig& config, GCodeProcessor& processor)
{
processor.reset();
processor.apply_config(config);
}
#else
static void init_gcode_analyzer(const PrintConfig &config, GCodeAnalyzer &analyzer)
{ {
// resets analyzer // resets analyzer
analyzer.reset(); analyzer.reset();
@ -901,17 +912,6 @@ namespace DoExport {
// tell analyzer about the gcode flavor // tell analyzer about the gcode flavor
analyzer.set_gcode_flavor(config.gcode_flavor); analyzer.set_gcode_flavor(config.gcode_flavor);
#if ENABLE_GCODE_VIEWER_DEBUG_OUTPUT
analyzer.open_debug_output_file();
#endif // ENABLE_GCODE_VIEWER_DEBUG_OUTPUT
}
#if ENABLE_GCODE_VIEWER
static void init_gcode_processor(const PrintConfig& config, GCodeProcessor& processor)
{
processor.reset();
processor.apply_config(config);
} }
#endif // ENABLE_GCODE_VIEWER #endif // ENABLE_GCODE_VIEWER
@ -1145,15 +1145,22 @@ void GCode::_do_export(Print& print, FILE* file, ThumbnailsGeneratorCallback thu
DoExport::init_time_estimators(print.config(), DoExport::init_time_estimators(print.config(),
// modifies the following: // modifies the following:
m_normal_time_estimator, m_silent_time_estimator, m_silent_time_estimator_enabled); m_normal_time_estimator, m_silent_time_estimator, m_silent_time_estimator_enabled);
DoExport::init_gcode_analyzer(print.config(), m_analyzer);
#if ENABLE_GCODE_VIEWER #if ENABLE_GCODE_VIEWER
DoExport::init_gcode_processor(print.config(), m_processor); DoExport::init_gcode_processor(print.config(), m_processor);
#else
DoExport::init_gcode_analyzer(print.config(), m_analyzer);
#endif // ENABLE_GCODE_VIEWER #endif // ENABLE_GCODE_VIEWER
// resets analyzer's tracking data // resets analyzer's tracking data
#if ENABLE_GCODE_VIEWER
m_last_mm3_per_mm = 0.0f;
m_last_width = 0.0f;
m_last_height = 0.0f;
#else
m_last_mm3_per_mm = GCodeAnalyzer::Default_mm3_per_mm; m_last_mm3_per_mm = GCodeAnalyzer::Default_mm3_per_mm;
m_last_width = GCodeAnalyzer::Default_Width; m_last_width = GCodeAnalyzer::Default_Width;
m_last_height = GCodeAnalyzer::Default_Height; m_last_height = GCodeAnalyzer::Default_Height;
#endif // ENABLE_GCODE_VIEWER
// How many times will be change_layer() called? // How many times will be change_layer() called?
// change_layer() in turn increments the progress bar status. // change_layer() in turn increments the progress bar status.
@ -1333,13 +1340,13 @@ void GCode::_do_export(Print& print, FILE* file, ThumbnailsGeneratorCallback thu
// Set extruder(s) temperature before and after start G-code. // Set extruder(s) temperature before and after start G-code.
this->_print_first_layer_extruder_temperatures(file, print, start_gcode, initial_extruder_id, false); this->_print_first_layer_extruder_temperatures(file, print, start_gcode, initial_extruder_id, false);
if (m_enable_analyzer)
// adds tag for analyzer
_write_format(file, ";%s%d\n", GCodeAnalyzer::Extrusion_Role_Tag.c_str(), erCustom);
#if ENABLE_GCODE_VIEWER #if ENABLE_GCODE_VIEWER
// adds tag for processor // adds tag for processor
_write_format(file, ";%s%d\n", GCodeProcessor::Extrusion_Role_Tag.c_str(), erCustom); _write_format(file, ";%s%d\n", GCodeProcessor::Extrusion_Role_Tag.c_str(), erCustom);
#else
if (m_enable_analyzer)
// adds tag for analyzer
_write_format(file, ";%s%d\n", GCodeAnalyzer::Extrusion_Role_Tag.c_str(), erCustom);
#endif // ENABLE_GCODE_VIEWER #endif // ENABLE_GCODE_VIEWER
// Write the custom start G-code // Write the custom start G-code
@ -1491,13 +1498,13 @@ void GCode::_do_export(Print& print, FILE* file, ThumbnailsGeneratorCallback thu
_write(file, this->retract()); _write(file, this->retract());
_write(file, m_writer.set_fan(false)); _write(file, m_writer.set_fan(false));
if (m_enable_analyzer)
// adds tag for analyzer
_write_format(file, ";%s%d\n", GCodeAnalyzer::Extrusion_Role_Tag.c_str(), erCustom);
#if ENABLE_GCODE_VIEWER #if ENABLE_GCODE_VIEWER
// adds tag for processor // adds tag for processor
_write_format(file, ";%s%d\n", GCodeProcessor::Extrusion_Role_Tag.c_str(), erCustom); _write_format(file, ";%s%d\n", GCodeProcessor::Extrusion_Role_Tag.c_str(), erCustom);
#else
if (m_enable_analyzer)
// adds tag for analyzer
_write_format(file, ";%s%d\n", GCodeAnalyzer::Extrusion_Role_Tag.c_str(), erCustom);
#endif // ENABLE_GCODE_VIEWER #endif // ENABLE_GCODE_VIEWER
// Process filament-specific gcode in extruder order. // Process filament-specific gcode in extruder order.
@ -1821,11 +1828,12 @@ namespace ProcessLayer
{ {
assert(m600_extruder_before_layer >= 0); assert(m600_extruder_before_layer >= 0);
// Color Change or Tool Change as Color Change. // Color Change or Tool Change as Color Change.
// add tag for analyzer
gcode += "; " + GCodeAnalyzer::Color_Change_Tag + ",T" + std::to_string(m600_extruder_before_layer) + "\n";
#if ENABLE_GCODE_VIEWER #if ENABLE_GCODE_VIEWER
// add tag for processor // add tag for processor
gcode += "; " + GCodeProcessor::Color_Change_Tag + ",T" + std::to_string(m600_extruder_before_layer) + "\n"; gcode += "; " + GCodeProcessor::Color_Change_Tag + ",T" + std::to_string(m600_extruder_before_layer) + "\n";
#else
// add tag for analyzer
gcode += "; " + GCodeAnalyzer::Color_Change_Tag + ",T" + std::to_string(m600_extruder_before_layer) + "\n";
#endif // ENABLE_GCODE_VIEWER #endif // ENABLE_GCODE_VIEWER
// add tag for time estimator // add tag for time estimator
gcode += "; " + GCodeTimeEstimator::Color_Change_Tag + "\n"; gcode += "; " + GCodeTimeEstimator::Color_Change_Tag + "\n";
@ -1846,11 +1854,12 @@ namespace ProcessLayer
{ {
if (custom_code == PausePrintCode) // Pause print if (custom_code == PausePrintCode) // Pause print
{ {
// add tag for analyzer
gcode += "; " + GCodeAnalyzer::Pause_Print_Tag + "\n";
#if ENABLE_GCODE_VIEWER #if ENABLE_GCODE_VIEWER
// add tag for processor // add tag for processor
gcode += "; " + GCodeProcessor::Pause_Print_Tag + "\n"; gcode += "; " + GCodeProcessor::Pause_Print_Tag + "\n";
#else
// add tag for analyzer
gcode += "; " + GCodeAnalyzer::Pause_Print_Tag + "\n";
#endif // ENABLE_GCODE_VIEWER #endif // ENABLE_GCODE_VIEWER
//! FIXME_in_fw show message during print pause //! FIXME_in_fw show message during print pause
if (!pause_print_msg.empty()) if (!pause_print_msg.empty())
@ -1860,11 +1869,12 @@ namespace ProcessLayer
} }
else // custom Gcode else // custom Gcode
{ {
// add tag for analyzer
gcode += "; " + GCodeAnalyzer::Custom_Code_Tag + "\n";
#if ENABLE_GCODE_VIEWER #if ENABLE_GCODE_VIEWER
// add tag for processor // add tag for processor
gcode += "; " + GCodeProcessor::Custom_Code_Tag + "\n"; gcode += "; " + GCodeProcessor::Custom_Code_Tag + "\n";
#else
// add tag for analyzer
gcode += "; " + GCodeAnalyzer::Custom_Code_Tag + "\n";
#endif // ENABLE_GCODE_VIEWER #endif // ENABLE_GCODE_VIEWER
// add tag for time estimator // add tag for time estimator
//gcode += "; " + GCodeTimeEstimator::Custom_Code_Tag + "\n"; //gcode += "; " + GCodeTimeEstimator::Custom_Code_Tag + "\n";
@ -2218,9 +2228,15 @@ void GCode::process_layer(
m_wipe_tower->tool_change(*this, extruder_id, extruder_id == layer_tools.extruders.back()) : m_wipe_tower->tool_change(*this, extruder_id, extruder_id == layer_tools.extruders.back()) :
this->set_extruder(extruder_id, print_z); this->set_extruder(extruder_id, print_z);
#if ENABLE_GCODE_VIEWER
// let analyzer tag generator aware of a role type change
if (layer_tools.has_wipe_tower && m_wipe_tower)
m_last_processor_extrusion_role = erWipeTower;
#else
// let analyzer tag generator aware of a role type change // let analyzer tag generator aware of a role type change
if (m_enable_analyzer && layer_tools.has_wipe_tower && m_wipe_tower) if (m_enable_analyzer && layer_tools.has_wipe_tower && m_wipe_tower)
m_last_analyzer_extrusion_role = erWipeTower; m_last_analyzer_extrusion_role = erWipeTower;
#endif // ENABLE_GCODE_VIEWER
if (auto loops_it = skirt_loops_per_extruder.find(extruder_id); loops_it != skirt_loops_per_extruder.end()) { if (auto loops_it = skirt_loops_per_extruder.find(extruder_id); loops_it != skirt_loops_per_extruder.end()) {
const std::pair<size_t, size_t> loops = loops_it->second; const std::pair<size_t, size_t> loops = loops_it->second;
@ -2324,11 +2340,13 @@ void GCode::process_layer(
if (m_cooling_buffer) if (m_cooling_buffer)
gcode = m_cooling_buffer->process_layer(gcode, layer.id()); gcode = m_cooling_buffer->process_layer(gcode, layer.id());
#if !ENABLE_GCODE_VIEWER
// add tag for analyzer // add tag for analyzer
if (gcode.find(GCodeAnalyzer::Pause_Print_Tag) != gcode.npos) if (gcode.find(GCodeAnalyzer::Pause_Print_Tag) != gcode.npos)
gcode += "\n; " + GCodeAnalyzer::End_Pause_Print_Or_Custom_Code_Tag + "\n"; gcode += "\n; " + GCodeAnalyzer::End_Pause_Print_Or_Custom_Code_Tag + "\n";
else if (gcode.find(GCodeAnalyzer::Custom_Code_Tag) != gcode.npos) else if (gcode.find(GCodeAnalyzer::Custom_Code_Tag) != gcode.npos)
gcode += "\n; " + GCodeAnalyzer::End_Pause_Print_Or_Custom_Code_Tag + "\n"; gcode += "\n; " + GCodeAnalyzer::End_Pause_Print_Or_Custom_Code_Tag + "\n";
#endif // !ENABLE_GCODE_VIEWER
#ifdef HAS_PRESSURE_EQUALIZER #ifdef HAS_PRESSURE_EQUALIZER
// Apply pressure equalization if enabled; // Apply pressure equalization if enabled;
@ -2342,9 +2360,11 @@ void GCode::process_layer(
BOOST_LOG_TRIVIAL(trace) << "Exported layer " << layer.id() << " print_z " << print_z << BOOST_LOG_TRIVIAL(trace) << "Exported layer " << layer.id() << " print_z " << print_z <<
", time estimator memory: " << ", time estimator memory: " <<
format_memsize_MB(m_normal_time_estimator.memory_used() + (m_silent_time_estimator_enabled ? m_silent_time_estimator.memory_used() : 0)) << format_memsize_MB(m_normal_time_estimator.memory_used() + (m_silent_time_estimator_enabled ? m_silent_time_estimator.memory_used() : 0)) <<
", analyzer memory: " << #if !ENABLE_GCODE_VIEWER
", analyzer memory: " <<
format_memsize_MB(m_analyzer.memory_used()) << format_memsize_MB(m_analyzer.memory_used()) <<
log_memory_info(); #endif // !ENABLE_GCODE_VIEWER
log_memory_info();
} }
void GCode::apply_print_config(const PrintConfig &print_config) void GCode::apply_print_config(const PrintConfig &print_config)
@ -2984,8 +3004,12 @@ std::string GCode::extrude_support(const ExtrusionEntityCollection &support_fill
void GCode::_write(FILE* file, const char *what) void GCode::_write(FILE* file, const char *what)
{ {
if (what != nullptr) { if (what != nullptr) {
#if ENABLE_GCODE_VIEWER
const char* gcode = what;
#else
// apply analyzer, if enabled // apply analyzer, if enabled
const char* gcode = m_enable_analyzer ? m_analyzer.process_gcode(what).c_str() : what; const char* gcode = m_enable_analyzer ? m_analyzer.process_gcode(what).c_str() : what;
#endif // !ENABLE_GCODE_VIEWER
// writes string to file // writes string to file
fwrite(gcode, 1, ::strlen(gcode), file); fwrite(gcode, 1, ::strlen(gcode), file);
@ -3132,57 +3156,73 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description,
} }
// adds analyzer tags and updates analyzer's tracking data // adds analyzer tags and updates analyzer's tracking data
#if !ENABLE_GCODE_VIEWER
if (m_enable_analyzer) if (m_enable_analyzer)
{ {
#endif // !ENABLE_GCODE_VIEWER
// PrusaMultiMaterial::Writer may generate GCodeAnalyzer::Height_Tag and GCodeAnalyzer::Width_Tag lines without updating m_last_height and m_last_width // PrusaMultiMaterial::Writer may generate GCodeAnalyzer::Height_Tag and GCodeAnalyzer::Width_Tag lines without updating m_last_height and m_last_width
// so, if the last role was erWipeTower we force export of GCodeAnalyzer::Height_Tag and GCodeAnalyzer::Width_Tag lines // so, if the last role was erWipeTower we force export of GCodeAnalyzer::Height_Tag and GCodeAnalyzer::Width_Tag lines
#if ENABLE_GCODE_VIEWER
bool last_was_wipe_tower = (m_last_processor_extrusion_role == erWipeTower);
#else
bool last_was_wipe_tower = (m_last_analyzer_extrusion_role == erWipeTower); bool last_was_wipe_tower = (m_last_analyzer_extrusion_role == erWipeTower);
#endif // ENABLE_GCODE_VIEWER
char buf[64]; char buf[64];
#if ENABLE_GCODE_VIEWER
if (path.role() != m_last_processor_extrusion_role)
{
m_last_processor_extrusion_role = path.role();
sprintf(buf, ";%s%d\n", GCodeProcessor::Extrusion_Role_Tag.c_str(), int(m_last_processor_extrusion_role));
gcode += buf;
}
#else
if (path.role() != m_last_analyzer_extrusion_role) if (path.role() != m_last_analyzer_extrusion_role)
{ {
m_last_analyzer_extrusion_role = path.role(); m_last_analyzer_extrusion_role = path.role();
sprintf(buf, ";%s%d\n", GCodeAnalyzer::Extrusion_Role_Tag.c_str(), int(m_last_analyzer_extrusion_role)); sprintf(buf, ";%s%d\n", GCodeAnalyzer::Extrusion_Role_Tag.c_str(), int(m_last_analyzer_extrusion_role));
#if ENABLE_GCODE_VIEWER
gcode += buf;
sprintf(buf, ";%s%d\n", GCodeProcessor::Extrusion_Role_Tag.c_str(), int(m_last_analyzer_extrusion_role));
#endif // ENABLE_GCODE_VIEWER
gcode += buf; gcode += buf;
} }
#endif // ENABLE_GCODE_VIEWER
if (last_was_wipe_tower || (m_last_mm3_per_mm != path.mm3_per_mm)) if (last_was_wipe_tower || (m_last_mm3_per_mm != path.mm3_per_mm))
{ {
m_last_mm3_per_mm = path.mm3_per_mm; m_last_mm3_per_mm = path.mm3_per_mm;
sprintf(buf, ";%s%f\n", GCodeAnalyzer::Mm3_Per_Mm_Tag.c_str(), m_last_mm3_per_mm);
gcode += buf;
#if ENABLE_GCODE_VIEWER #if ENABLE_GCODE_VIEWER
sprintf(buf, ";%s%f\n", GCodeProcessor::Mm3_Per_Mm_Tag.c_str(), m_last_mm3_per_mm); sprintf(buf, ";%s%f\n", GCodeProcessor::Mm3_Per_Mm_Tag.c_str(), m_last_mm3_per_mm);
gcode += buf; gcode += buf;
#else
sprintf(buf, ";%s%f\n", GCodeAnalyzer::Mm3_Per_Mm_Tag.c_str(), m_last_mm3_per_mm);
gcode += buf;
#endif // ENABLE_GCODE_VIEWER #endif // ENABLE_GCODE_VIEWER
} }
if (last_was_wipe_tower || (m_last_width != path.width)) if (last_was_wipe_tower || (m_last_width != path.width))
{ {
m_last_width = path.width; m_last_width = path.width;
sprintf(buf, ";%s%f\n", GCodeAnalyzer::Width_Tag.c_str(), m_last_width);
gcode += buf;
#if ENABLE_GCODE_VIEWER #if ENABLE_GCODE_VIEWER
sprintf(buf, ";%s%f\n", GCodeProcessor::Width_Tag.c_str(), m_last_width); sprintf(buf, ";%s%f\n", GCodeProcessor::Width_Tag.c_str(), m_last_width);
gcode += buf; gcode += buf;
#else
sprintf(buf, ";%s%f\n", GCodeAnalyzer::Width_Tag.c_str(), m_last_width);
gcode += buf;
#endif // ENABLE_GCODE_VIEWER #endif // ENABLE_GCODE_VIEWER
} }
if (last_was_wipe_tower || (m_last_height != path.height)) if (last_was_wipe_tower || (m_last_height != path.height))
{ {
m_last_height = path.height; m_last_height = path.height;
sprintf(buf, ";%s%f\n", GCodeAnalyzer::Height_Tag.c_str(), m_last_height);
gcode += buf;
#if ENABLE_GCODE_VIEWER #if ENABLE_GCODE_VIEWER
sprintf(buf, ";%s%f\n", GCodeProcessor::Height_Tag.c_str(), m_last_height); sprintf(buf, ";%s%f\n", GCodeProcessor::Height_Tag.c_str(), m_last_height);
gcode += buf; gcode += buf;
#else
sprintf(buf, ";%s%f\n", GCodeAnalyzer::Height_Tag.c_str(), m_last_height);
gcode += buf;
#endif // ENABLE_GCODE_VIEWER #endif // ENABLE_GCODE_VIEWER
} }
#if !ENABLE_GCODE_VIEWER
} }
#endif // !ENABLE_GCODE_VIEWER
std::string comment; std::string comment;
if (m_enable_cooling_markers) { if (m_enable_cooling_markers) {

View File

@ -16,10 +16,11 @@
#include "GCode/WipeTower.hpp" #include "GCode/WipeTower.hpp"
#if ENABLE_GCODE_VIEWER #if ENABLE_GCODE_VIEWER
#include "GCode/GCodeProcessor.hpp" #include "GCode/GCodeProcessor.hpp"
#else
#include "GCode/Analyzer.hpp"
#endif // ENABLE_GCODE_VIEWER #endif // ENABLE_GCODE_VIEWER
#include "GCodeTimeEstimator.hpp" #include "GCodeTimeEstimator.hpp"
#include "EdgeGrid.hpp" #include "EdgeGrid.hpp"
#include "GCode/Analyzer.hpp"
#include "GCode/ThumbnailData.hpp" #include "GCode/ThumbnailData.hpp"
#include <memory> #include <memory>
@ -33,7 +34,9 @@ namespace Slic3r {
// Forward declarations. // Forward declarations.
class GCode; class GCode;
#if !ENABLE_GCODE_VIEWER
class GCodePreviewData; class GCodePreviewData;
#endif // !ENABLE_GCODE_VIEWER
class AvoidCrossingPerimeters { class AvoidCrossingPerimeters {
public: public:
@ -138,6 +141,15 @@ private:
double m_last_wipe_tower_print_z = 0.f; double m_last_wipe_tower_print_z = 0.f;
}; };
#if ENABLE_GCODE_VIEWER
class ColorPrintColors
{
static const std::vector<std::string> Colors;
public:
static const std::vector<std::string>& get() { return Colors; }
};
#endif // ENABLE_GCODE_VIEWER
class GCode { class GCode {
public: public:
GCode() : GCode() :
@ -145,17 +157,27 @@ public:
m_enable_loop_clipping(true), m_enable_loop_clipping(true),
m_enable_cooling_markers(false), m_enable_cooling_markers(false),
m_enable_extrusion_role_markers(false), m_enable_extrusion_role_markers(false),
#if ENABLE_GCODE_VIEWER
m_last_processor_extrusion_role(erNone),
#else
m_enable_analyzer(false), m_enable_analyzer(false),
m_last_analyzer_extrusion_role(erNone), m_last_analyzer_extrusion_role(erNone),
#endif // ENABLE_GCODE_VIEWER
m_layer_count(0), m_layer_count(0),
m_layer_index(-1), m_layer_index(-1),
m_layer(nullptr), m_layer(nullptr),
m_volumetric_speed(0), m_volumetric_speed(0),
m_last_pos_defined(false), m_last_pos_defined(false),
m_last_extrusion_role(erNone), m_last_extrusion_role(erNone),
#if ENABLE_GCODE_VIEWER
m_last_mm3_per_mm(0.0f),
m_last_width(0.0f),
m_last_height(0.0f),
#else
m_last_mm3_per_mm(GCodeAnalyzer::Default_mm3_per_mm), m_last_mm3_per_mm(GCodeAnalyzer::Default_mm3_per_mm),
m_last_width(GCodeAnalyzer::Default_Width), m_last_width(GCodeAnalyzer::Default_Width),
m_last_height(GCodeAnalyzer::Default_Height), m_last_height(GCodeAnalyzer::Default_Height),
#endif // ENABLE_GCODE_VIEWER
m_brim_done(false), m_brim_done(false),
m_second_layer_things_done(false), m_second_layer_things_done(false),
m_normal_time_estimator(GCodeTimeEstimator::Normal), m_normal_time_estimator(GCodeTimeEstimator::Normal),
@ -168,7 +190,7 @@ public:
// throws std::runtime_exception on error, // throws std::runtime_exception on error,
// throws CanceledException through print->throw_if_canceled(). // throws CanceledException through print->throw_if_canceled().
#if ENABLE_GCODE_VIEWER #if ENABLE_GCODE_VIEWER
void do_export(Print* print, const char* path, GCodePreviewData* preview_data = nullptr, GCodeProcessor::Result* result = nullptr, ThumbnailsGeneratorCallback thumbnail_cb = nullptr); void do_export(Print* print, const char* path, GCodeProcessor::Result* result = nullptr, ThumbnailsGeneratorCallback thumbnail_cb = nullptr);
#else #else
void do_export(Print* print, const char* path, GCodePreviewData* preview_data = nullptr, ThumbnailsGeneratorCallback thumbnail_cb = nullptr); void do_export(Print* print, const char* path, GCodePreviewData* preview_data = nullptr, ThumbnailsGeneratorCallback thumbnail_cb = nullptr);
#endif // ENABLE_GCODE_VIEWER #endif // ENABLE_GCODE_VIEWER
@ -331,11 +353,16 @@ private:
// Markers for the Pressure Equalizer to recognize the extrusion type. // Markers for the Pressure Equalizer to recognize the extrusion type.
// The Pressure Equalizer removes the markers from the final G-code. // The Pressure Equalizer removes the markers from the final G-code.
bool m_enable_extrusion_role_markers; bool m_enable_extrusion_role_markers;
#if ENABLE_GCODE_VIEWER
// Keeps track of the last extrusion role passed to the processor
ExtrusionRole m_last_processor_extrusion_role;
#else
// Enableds the G-code Analyzer. // Enableds the G-code Analyzer.
// Extended markers will be added during G-code generation. // Extended markers will be added during G-code generation.
// The G-code Analyzer will remove these comments from the final G-code. // The G-code Analyzer will remove these comments from the final G-code.
bool m_enable_analyzer; bool m_enable_analyzer;
ExtrusionRole m_last_analyzer_extrusion_role; ExtrusionRole m_last_analyzer_extrusion_role;
#endif // ENABLE_GCODE_VIEWER
// How many times will change_layer() be called? // How many times will change_layer() be called?
// change_layer() will update the progress bar. // change_layer() will update the progress bar.
unsigned int m_layer_count; unsigned int m_layer_count;
@ -377,12 +404,12 @@ private:
GCodeTimeEstimator m_silent_time_estimator; GCodeTimeEstimator m_silent_time_estimator;
bool m_silent_time_estimator_enabled; bool m_silent_time_estimator_enabled;
// Analyzer
GCodeAnalyzer m_analyzer;
#if ENABLE_GCODE_VIEWER #if ENABLE_GCODE_VIEWER
// Processor // Processor
GCodeProcessor m_processor; GCodeProcessor m_processor;
#else
// Analyzer
GCodeAnalyzer m_analyzer;
#endif // ENABLE_GCODE_VIEWER #endif // ENABLE_GCODE_VIEWER
// Write a string into a file. // Write a string into a file.

View File

@ -8,19 +8,11 @@
#include "Print.hpp" #include "Print.hpp"
#include <boost/log/trivial.hpp> #include <boost/log/trivial.hpp>
#if ENABLE_GCODE_VIEWER_DEBUG_OUTPUT
#include <boost/filesystem/path.hpp>
#endif // ENABLE_GCODE_VIEWER_DEBUG_OUTPUT
#include "Analyzer.hpp" #include "Analyzer.hpp"
#include "PreviewData.hpp" #include "PreviewData.hpp"
#if ENABLE_GCODE_VIEWER_DEBUG_OUTPUT #if !ENABLE_GCODE_VIEWER
#include <boost/nowide/fstream.hpp>
// don't worry, this is just temporary
static boost::nowide::ofstream g_debug_output;
#endif // ENABLE_GCODE_VIEWER_DEBUG_OUTPUT
static const std::string AXIS_STR = "XYZE"; static const std::string AXIS_STR = "XYZE";
static const float MMMIN_TO_MMSEC = 1.0f / 60.0f; static const float MMMIN_TO_MMSEC = 1.0f / 60.0f;
@ -184,19 +176,6 @@ bool GCodeAnalyzer::is_valid_extrusion_role(ExtrusionRole role)
return ((erPerimeter <= role) && (role < erMixed)); return ((erPerimeter <= role) && (role < erMixed));
} }
#if ENABLE_GCODE_VIEWER_DEBUG_OUTPUT
void GCodeAnalyzer::open_debug_output_file()
{
boost::filesystem::path path("d:/analyzer.output");
g_debug_output.open(path.string());
}
void GCodeAnalyzer::close_debug_output_file()
{
g_debug_output.close();
}
#endif // ENABLE_GCODE_VIEWER_DEBUG_OUTPUT
void GCodeAnalyzer::_process_gcode_line(GCodeReader&, const GCodeReader::GCodeLine& line) void GCodeAnalyzer::_process_gcode_line(GCodeReader&, const GCodeReader::GCodeLine& line)
{ {
// processes 'special' comments contained in line // processes 'special' comments contained in line
@ -945,23 +924,6 @@ void GCodeAnalyzer::_store_move(GCodeAnalyzer::GCodeMove::EType type)
Vec3f start_position = _get_start_position() + extruder_offset; Vec3f start_position = _get_start_position() + extruder_offset;
Vec3f end_position = _get_end_position() + extruder_offset; Vec3f end_position = _get_end_position() + extruder_offset;
it->second.emplace_back(type, _get_extrusion_role(), extruder_id, _get_mm3_per_mm(), _get_width(), _get_height(), _get_feedrate(), start_position, end_position, _get_delta_extrusion(), _get_fan_speed(), _get_cp_color_id()); it->second.emplace_back(type, _get_extrusion_role(), extruder_id, _get_mm3_per_mm(), _get_width(), _get_height(), _get_feedrate(), start_position, end_position, _get_delta_extrusion(), _get_fan_speed(), _get_cp_color_id());
#if ENABLE_GCODE_VIEWER_DEBUG_OUTPUT
if (g_debug_output.good())
{
g_debug_output << std::to_string(static_cast<int>(type));
g_debug_output << ", " << std::to_string(static_cast<int>(_get_extrusion_role()));
g_debug_output << ", " << Slic3r::to_string(static_cast<Vec3d>(end_position.cast<double>()));
g_debug_output << ", " << std::to_string(extruder_id);
g_debug_output << ", " << std::to_string(_get_cp_color_id());
g_debug_output << ", " << std::to_string(_get_feedrate());
g_debug_output << ", " << std::to_string(_get_width());
g_debug_output << ", " << std::to_string(_get_height());
g_debug_output << ", " << std::to_string(_get_mm3_per_mm());
g_debug_output << ", " << std::to_string(_get_fan_speed());
g_debug_output << "\n";
}
#endif // ENABLE_GCODE_VIEWER_DEBUG_OUTPUT
} }
bool GCodeAnalyzer::_is_valid_extrusion_role(int value) const bool GCodeAnalyzer::_is_valid_extrusion_role(int value) const
@ -1231,3 +1193,5 @@ size_t GCodeAnalyzer::memory_used() const
} }
} // namespace Slic3r } // namespace Slic3r
#endif // !ENABLE_GCODE_VIEWER

View File

@ -1,6 +1,8 @@
#ifndef slic3r_GCode_Analyzer_hpp_ #ifndef slic3r_GCode_Analyzer_hpp_
#define slic3r_GCode_Analyzer_hpp_ #define slic3r_GCode_Analyzer_hpp_
#if !ENABLE_GCODE_VIEWER
#include "../libslic3r.h" #include "../libslic3r.h"
#include "../PrintConfig.hpp" #include "../PrintConfig.hpp"
#include "../ExtrusionEntity.hpp" #include "../ExtrusionEntity.hpp"
@ -147,11 +149,6 @@ public:
static bool is_valid_extrusion_role(ExtrusionRole role); static bool is_valid_extrusion_role(ExtrusionRole role);
#if ENABLE_GCODE_VIEWER_DEBUG_OUTPUT
void open_debug_output_file();
void close_debug_output_file();
#endif // ENABLE_GCODE_VIEWER_DEBUG_OUTPUT
private: private:
// Processes the given gcode line // Processes the given gcode line
void _process_gcode_line(GCodeReader& reader, const GCodeReader::GCodeLine& line); void _process_gcode_line(GCodeReader& reader, const GCodeReader::GCodeLine& line);
@ -307,4 +304,6 @@ private:
} // namespace Slic3r } // namespace Slic3r
#endif // !ENABLE_GCODE_VIEWER
#endif /* slic3r_GCode_Analyzer_hpp_ */ #endif /* slic3r_GCode_Analyzer_hpp_ */

View File

@ -5,6 +5,8 @@
#include <boost/format.hpp> #include <boost/format.hpp>
#if !ENABLE_GCODE_VIEWER
//! macro used to mark string used at localization, //! macro used to mark string used at localization,
#define L(s) (s) #define L(s) (s)
@ -117,7 +119,8 @@ const Color GCodePreviewData::Extrusion::Default_Extrusion_Role_Colors[erCount]
Color(1.0f, 1.0f, 0.0f, 1.0f), // erInternalInfill Color(1.0f, 1.0f, 0.0f, 1.0f), // erInternalInfill
Color(1.0f, 0.0f, 1.0f, 1.0f), // erSolidInfill Color(1.0f, 0.0f, 1.0f, 1.0f), // erSolidInfill
Color(0.0f, 1.0f, 1.0f, 1.0f), // erTopSolidInfill Color(0.0f, 1.0f, 1.0f, 1.0f), // erTopSolidInfill
Color(0.0f, 1.0f, 1.0f, 1.0f), // erIroning // Color(1.0f, 0.7f, 0.61f, 1.0f), // erIroning
Color(1.0f, 0.55f, 0.41f, 1.0f), // erIroning
Color(0.5f, 0.5f, 0.5f, 1.0f), // erBridgeInfill Color(0.5f, 0.5f, 0.5f, 1.0f), // erBridgeInfill
Color(1.0f, 1.0f, 1.0f, 1.0f), // erGapFill Color(1.0f, 1.0f, 1.0f, 1.0f), // erGapFill
Color(0.5f, 0.0f, 0.0f, 1.0f), // erSkirt Color(0.5f, 0.0f, 0.0f, 1.0f), // erSkirt
@ -515,3 +518,5 @@ Color operator * (float f, const Color& color)
} }
} // namespace Slic3r } // namespace Slic3r
#endif // !ENABLE_GCODE_VIEWER

View File

@ -1,6 +1,8 @@
#ifndef slic3r_GCode_PreviewData_hpp_ #ifndef slic3r_GCode_PreviewData_hpp_
#define slic3r_GCode_PreviewData_hpp_ #define slic3r_GCode_PreviewData_hpp_
#if !ENABLE_GCODE_VIEWER
#include "../libslic3r.h" #include "../libslic3r.h"
#include "../ExtrusionEntity.hpp" #include "../ExtrusionEntity.hpp"
#include "../Point.hpp" #include "../Point.hpp"
@ -391,4 +393,6 @@ public:
} // namespace Slic3r } // namespace Slic3r
#endif // !ENABLE_GCODE_VIEWER
#endif /* slic3r_GCode_PreviewData_hpp_ */ #endif /* slic3r_GCode_PreviewData_hpp_ */

View File

@ -21,9 +21,10 @@ TODO LIST
#include <vector> #include <vector>
#include <numeric> #include <numeric>
#include "Analyzer.hpp"
#if ENABLE_GCODE_VIEWER #if ENABLE_GCODE_VIEWER
#include "GCodeProcessor.hpp" #include "GCodeProcessor.hpp"
#else
#include "Analyzer.hpp"
#endif // ENABLE_GCODE_VIEWER #endif // ENABLE_GCODE_VIEWER
#include "BoundingBox.hpp" #include "BoundingBox.hpp"
@ -56,16 +57,16 @@ public:
{ {
// adds tag for analyzer: // adds tag for analyzer:
char buf[64]; char buf[64];
sprintf(buf, ";%s%f\n", GCodeAnalyzer::Height_Tag.c_str(), m_layer_height); // don't rely on GCodeAnalyzer knowing the layer height - it knows nothing at priming
m_gcode += buf;
#if ENABLE_GCODE_VIEWER #if ENABLE_GCODE_VIEWER
sprintf(buf, ";%s%f\n", GCodeProcessor::Height_Tag.c_str(), m_layer_height); // don't rely on GCodeAnalyzer knowing the layer height - it knows nothing at priming sprintf(buf, ";%s%f\n", GCodeProcessor::Height_Tag.c_str(), m_layer_height); // don't rely on GCodeAnalyzer knowing the layer height - it knows nothing at priming
m_gcode += buf; #else
sprintf(buf, ";%s%f\n", GCodeAnalyzer::Height_Tag.c_str(), m_layer_height); // don't rely on GCodeAnalyzer knowing the layer height - it knows nothing at priming
#endif // ENABLE_GCODE_VIEWER #endif // ENABLE_GCODE_VIEWER
sprintf(buf, ";%s%d\n", GCodeAnalyzer::Extrusion_Role_Tag.c_str(), erWipeTower);
#if ENABLE_GCODE_VIEWER
m_gcode += buf; m_gcode += buf;
#if ENABLE_GCODE_VIEWER
sprintf(buf, ";%s%d\n", GCodeProcessor::Extrusion_Role_Tag.c_str(), erWipeTower); sprintf(buf, ";%s%d\n", GCodeProcessor::Extrusion_Role_Tag.c_str(), erWipeTower);
#else
sprintf(buf, ";%s%d\n", GCodeAnalyzer::Extrusion_Role_Tag.c_str(), erWipeTower);
#endif // ENABLE_GCODE_VIEWER #endif // ENABLE_GCODE_VIEWER
m_gcode += buf; m_gcode += buf;
change_analyzer_line_width(line_width); change_analyzer_line_width(line_width);
@ -74,12 +75,12 @@ public:
WipeTowerWriter& change_analyzer_line_width(float line_width) { WipeTowerWriter& change_analyzer_line_width(float line_width) {
// adds tag for analyzer: // adds tag for analyzer:
char buf[64]; char buf[64];
sprintf(buf, ";%s%f\n", GCodeAnalyzer::Width_Tag.c_str(), line_width);
m_gcode += buf;
#if ENABLE_GCODE_VIEWER #if ENABLE_GCODE_VIEWER
sprintf(buf, ";%s%f\n", GCodeProcessor::Width_Tag.c_str(), line_width); sprintf(buf, ";%s%f\n", GCodeProcessor::Width_Tag.c_str(), line_width);
m_gcode += buf; #else
sprintf(buf, ";%s%f\n", GCodeAnalyzer::Width_Tag.c_str(), line_width);
#endif // ENABLE_GCODE_VIEWER #endif // ENABLE_GCODE_VIEWER
m_gcode += buf;
return *this; return *this;
} }
@ -88,12 +89,12 @@ public:
float mm3_per_mm = (len == 0.f ? 0.f : area * e / len); float mm3_per_mm = (len == 0.f ? 0.f : area * e / len);
// adds tag for analyzer: // adds tag for analyzer:
char buf[64]; char buf[64];
sprintf(buf, ";%s%f\n", GCodeAnalyzer::Mm3_Per_Mm_Tag.c_str(), mm3_per_mm);
m_gcode += buf;
#if ENABLE_GCODE_VIEWER #if ENABLE_GCODE_VIEWER
sprintf(buf, ";%s%f\n", GCodeProcessor::Mm3_Per_Mm_Tag.c_str(), mm3_per_mm); sprintf(buf, ";%s%f\n", GCodeProcessor::Mm3_Per_Mm_Tag.c_str(), mm3_per_mm);
m_gcode += buf; #else
sprintf(buf, ";%s%f\n", GCodeAnalyzer::Mm3_Per_Mm_Tag.c_str(), mm3_per_mm);
#endif // ENABLE_GCODE_VIEWER #endif // ENABLE_GCODE_VIEWER
m_gcode += buf;
return *this; return *this;
} }

View File

@ -20,7 +20,9 @@
#include "SVG.hpp" #include "SVG.hpp"
#include <Eigen/Dense> #include <Eigen/Dense>
#include "GCodeWriter.hpp" #include "GCodeWriter.hpp"
#if !ENABLE_GCODE_VIEWER
#include "GCode/PreviewData.hpp" #include "GCode/PreviewData.hpp"
#endif // !ENABLE_GCODE_VIEWER
namespace Slic3r { namespace Slic3r {

View File

@ -411,6 +411,11 @@ public:
return timestamp == other.get_timestamp(); return timestamp == other.get_timestamp();
} }
template<class Archive> void serialize(Archive &ar)
{
ar(m_data);
}
private: private:
std::map<int, FacetSupportType> m_data; std::map<int, FacetSupportType> m_data;
@ -613,7 +618,8 @@ private:
} }
template<class Archive> void load(Archive &ar) { template<class Archive> void load(Archive &ar) {
bool has_convex_hull; bool has_convex_hull;
ar(name, source, m_mesh, m_type, m_material_id, m_transformation, m_is_splittable, has_convex_hull); ar(name, source, m_mesh, m_type, m_material_id, m_transformation,
m_is_splittable, has_convex_hull, m_supported_facets);
cereal::load_by_value(ar, config); cereal::load_by_value(ar, config);
assert(m_mesh); assert(m_mesh);
if (has_convex_hull) { if (has_convex_hull) {
@ -626,7 +632,8 @@ private:
} }
template<class Archive> void save(Archive &ar) const { template<class Archive> void save(Archive &ar) const {
bool has_convex_hull = m_convex_hull.get() != nullptr; bool has_convex_hull = m_convex_hull.get() != nullptr;
ar(name, source, m_mesh, m_type, m_material_id, m_transformation, m_is_splittable, has_convex_hull); ar(name, source, m_mesh, m_type, m_material_id, m_transformation,
m_is_splittable, has_convex_hull, m_supported_facets);
cereal::save_by_value(ar, config); cereal::save_by_value(ar, config);
if (has_convex_hull) if (has_convex_hull)
cereal::save_optional(ar, m_convex_hull); cereal::save_optional(ar, m_convex_hull);

View File

@ -1628,7 +1628,7 @@ void Print::process()
// write error into the G-code, cannot execute post-processing scripts). // write error into the G-code, cannot execute post-processing scripts).
// It is up to the caller to show an error message. // It is up to the caller to show an error message.
#if ENABLE_GCODE_VIEWER #if ENABLE_GCODE_VIEWER
std::string Print::export_gcode(const std::string& path_template, GCodePreviewData* preview_data, GCodeProcessor::Result* result, ThumbnailsGeneratorCallback thumbnail_cb) std::string Print::export_gcode(const std::string& path_template, GCodeProcessor::Result* result, ThumbnailsGeneratorCallback thumbnail_cb)
#else #else
std::string Print::export_gcode(const std::string& path_template, GCodePreviewData* preview_data, ThumbnailsGeneratorCallback thumbnail_cb) std::string Print::export_gcode(const std::string& path_template, GCodePreviewData* preview_data, ThumbnailsGeneratorCallback thumbnail_cb)
#endif // ENABLE_GCODE_VIEWER #endif // ENABLE_GCODE_VIEWER
@ -1637,7 +1637,11 @@ std::string Print::export_gcode(const std::string& path_template, GCodePreviewDa
// The following call may die if the output_filename_format template substitution fails. // The following call may die if the output_filename_format template substitution fails.
std::string path = this->output_filepath(path_template); std::string path = this->output_filepath(path_template);
std::string message; std::string message;
#if ENABLE_GCODE_VIEWER
if (!path.empty() && result == nullptr) {
#else
if (! path.empty() && preview_data == nullptr) { if (! path.empty() && preview_data == nullptr) {
#endif // ENABLE_GCODE_VIEWER
// Only show the path if preview_data is not set -> running from command line. // Only show the path if preview_data is not set -> running from command line.
message = L("Exporting G-code"); message = L("Exporting G-code");
message += " to "; message += " to ";
@ -1649,7 +1653,7 @@ std::string Print::export_gcode(const std::string& path_template, GCodePreviewDa
// The following line may die for multiple reasons. // The following line may die for multiple reasons.
GCode gcode; GCode gcode;
#if ENABLE_GCODE_VIEWER #if ENABLE_GCODE_VIEWER
gcode.do_export(this, path.c_str(), preview_data, result, thumbnail_cb); gcode.do_export(this, path.c_str(), result, thumbnail_cb);
#else #else
gcode.do_export(this, path.c_str(), preview_data, thumbnail_cb); gcode.do_export(this, path.c_str(), preview_data, thumbnail_cb);
#endif // ENABLE_GCODE_VIEWER #endif // ENABLE_GCODE_VIEWER

View File

@ -372,7 +372,7 @@ public:
// Exports G-code into a file name based on the path_template, returns the file path of the generated G-code file. // Exports G-code into a file name based on the path_template, returns the file path of the generated G-code file.
// If preview_data is not null, the preview_data is filled in for the G-code visualization (not used by the command line Slic3r). // If preview_data is not null, the preview_data is filled in for the G-code visualization (not used by the command line Slic3r).
#if ENABLE_GCODE_VIEWER #if ENABLE_GCODE_VIEWER
std::string export_gcode(const std::string& path_template, GCodePreviewData* preview_data, GCodeProcessor::Result* result, ThumbnailsGeneratorCallback thumbnail_cb = nullptr); std::string export_gcode(const std::string& path_template, GCodeProcessor::Result* result, ThumbnailsGeneratorCallback thumbnail_cb = nullptr);
#else #else
std::string export_gcode(const std::string& path_template, GCodePreviewData* preview_data, ThumbnailsGeneratorCallback thumbnail_cb = nullptr); std::string export_gcode(const std::string& path_template, GCodePreviewData* preview_data, ThumbnailsGeneratorCallback thumbnail_cb = nullptr);
#endif // ENABLE_GCODE_VIEWER #endif // ENABLE_GCODE_VIEWER

View File

@ -1292,7 +1292,7 @@ void SupportTreeBuildsteps::routing_headless()
m_thr(); m_thr();
const auto R = double(m_support_pts[i].head_front_radius); const auto R = double(m_support_pts[i].head_front_radius);
const double HWIDTH_MM = m_cfg.head_penetration_mm; const double HWIDTH_MM = std::min(R, m_cfg.head_penetration_mm);
// Exact support position // Exact support position
Vec3d sph = m_support_pts[i].pos.cast<double>(); Vec3d sph = m_support_pts[i].pos.cast<double>();

View File

@ -53,13 +53,8 @@
// Enable rendering of objects colored by facets' slope // Enable rendering of objects colored by facets' slope
#define ENABLE_SLOPE_RENDERING (1 && ENABLE_2_3_0_ALPHA1) #define ENABLE_SLOPE_RENDERING (1 && ENABLE_2_3_0_ALPHA1)
// Moves GLCanvas3DManager from being a static member of _3DScene to be a normal member of GUI_App
#define ENABLE_NON_STATIC_CANVAS_MANAGER (1 && ENABLE_2_3_0_ALPHA1)
// Enable G-Code viewer // Enable G-Code viewer
#define ENABLE_GCODE_VIEWER (1 && ENABLE_2_3_0_ALPHA1) #define ENABLE_GCODE_VIEWER (1 && ENABLE_2_3_0_ALPHA1)
#define ENABLE_GCODE_VIEWER_DEBUG_OUTPUT (0 && ENABLE_GCODE_VIEWER)
#define ENABLE_GCODE_VIEWER_STATISTICS (0 && ENABLE_GCODE_VIEWER) #define ENABLE_GCODE_VIEWER_STATISTICS (0 && ENABLE_GCODE_VIEWER)
#endif // _prusaslicer_technologies_h_ #endif // _prusaslicer_technologies_h_

View File

@ -27,8 +27,8 @@ set(SLIC3R_GUI_SOURCES
GUI/GLShader.hpp GUI/GLShader.hpp
GUI/GLCanvas3D.hpp GUI/GLCanvas3D.hpp
GUI/GLCanvas3D.cpp GUI/GLCanvas3D.cpp
GUI/GLCanvas3DManager.hpp GUI/OpenGLManager.hpp
GUI/GLCanvas3DManager.cpp GUI/OpenGLManager.cpp
GUI/Selection.hpp GUI/Selection.hpp
GUI/Selection.cpp GUI/Selection.cpp
GUI/Gizmos/GLGizmosManager.cpp GUI/Gizmos/GLGizmosManager.cpp
@ -55,6 +55,8 @@ set(SLIC3R_GUI_SOURCES
GUI/Gizmos/GLGizmoHollow.hpp GUI/Gizmos/GLGizmoHollow.hpp
GUI/GLSelectionRectangle.cpp GUI/GLSelectionRectangle.cpp
GUI/GLSelectionRectangle.hpp GUI/GLSelectionRectangle.hpp
GUI/GLModel.hpp
GUI/GLModel.cpp
GUI/GLTexture.hpp GUI/GLTexture.hpp
GUI/GLTexture.cpp GUI/GLTexture.cpp
GUI/GLToolbar.hpp GUI/GLToolbar.hpp
@ -218,6 +220,12 @@ if (CMAKE_SYSTEM_NAME STREQUAL "Linux")
target_link_libraries(libslic3r_gui ${DBUS_LIBRARIES}) target_link_libraries(libslic3r_gui ${DBUS_LIBRARIES})
endif() endif()
if (SLIC3R_STATIC)
# FIXME: This was previously exported by wx-config but the wxWidgets
# cmake build forgets this and the build fails in debug mode (or on raspberry release)
target_compile_definitions(libslic3r_gui PUBLIC -DwxDEBUG_LEVEL=0)
endif()
if(APPLE) if(APPLE)
target_link_libraries(libslic3r_gui ${DISKARBITRATION_LIBRARY}) target_link_libraries(libslic3r_gui ${DISKARBITRATION_LIBRARY})
endif() endif()

View File

@ -5,15 +5,24 @@
#include "libslic3r/Polygon.hpp" #include "libslic3r/Polygon.hpp"
#include "libslic3r/ClipperUtils.hpp" #include "libslic3r/ClipperUtils.hpp"
#include "libslic3r/BoundingBox.hpp" #include "libslic3r/BoundingBox.hpp"
#if ENABLE_GCODE_VIEWER
#include "libslic3r/Geometry.hpp"
#endif // ENABLE_GCODE_VIEWER
#include "GUI_App.hpp" #include "GUI_App.hpp"
#include "PresetBundle.hpp" #include "PresetBundle.hpp"
#include "GLCanvas3D.hpp" #include "GLCanvas3D.hpp"
#if ENABLE_GCODE_VIEWER
#include "3DScene.hpp"
#endif // ENABLE_GCODE_VIEWER
#include <GL/glew.h> #include <GL/glew.h>
#include <boost/algorithm/string/predicate.hpp> #include <boost/algorithm/string/predicate.hpp>
#include <boost/filesystem/operations.hpp> #include <boost/filesystem/operations.hpp>
#if ENABLE_GCODE_VIEWER
#include <boost/log/trivial.hpp>
#endif // ENABLE_GCODE_VIEWER
static const float GROUND_Z = -0.02f; static const float GROUND_Z = -0.02f;
@ -119,13 +128,25 @@ const float* GeometryBuffer::get_vertices_data() const
return (m_vertices.size() > 0) ? (const float*)m_vertices.data() : nullptr; return (m_vertices.size() > 0) ? (const float*)m_vertices.data() : nullptr;
} }
#if ENABLE_GCODE_VIEWER
const float Bed3D::Axes::DefaultStemRadius = 0.5f;
const float Bed3D::Axes::DefaultStemLength = 25.0f;
const float Bed3D::Axes::DefaultTipRadius = 2.5f * Bed3D::Axes::DefaultStemRadius;
const float Bed3D::Axes::DefaultTipLength = 5.0f;
#else
const double Bed3D::Axes::Radius = 0.5; const double Bed3D::Axes::Radius = 0.5;
const double Bed3D::Axes::ArrowBaseRadius = 2.5 * Bed3D::Axes::Radius; const double Bed3D::Axes::ArrowBaseRadius = 2.5 * Bed3D::Axes::Radius;
const double Bed3D::Axes::ArrowLength = 5.0; const double Bed3D::Axes::ArrowLength = 5.0;
#endif // ENABLE_GCODE_VIEWER
#if ENABLE_GCODE_VIEWER
void Bed3D::Axes::set_stem_length(float length)
{
m_stem_length = length;
m_arrow.reset();
}
#else
Bed3D::Axes::Axes() Bed3D::Axes::Axes()
: origin(Vec3d::Zero())
, length(25.0 * Vec3d::Ones())
{ {
m_quadric = ::gluNewQuadric(); m_quadric = ::gluNewQuadric();
if (m_quadric != nullptr) if (m_quadric != nullptr)
@ -137,9 +158,46 @@ Bed3D::Axes::~Axes()
if (m_quadric != nullptr) if (m_quadric != nullptr)
::gluDeleteQuadric(m_quadric); ::gluDeleteQuadric(m_quadric);
} }
#endif // ENABLE_GCODE_VIEWER
void Bed3D::Axes::render() const void Bed3D::Axes::render() const
{ {
#if ENABLE_GCODE_VIEWER
auto render_axis = [this](const Transform3f& transform, GLint color_id, const std::array<float, 4>& color) {
if (color_id >= 0)
glsafe(::glUniform4fv(color_id, 1, (const GLfloat*)color.data()));
glsafe(::glPushMatrix());
glsafe(::glMultMatrixf(transform.data()));
m_arrow.render();
glsafe(::glPopMatrix());
};
m_arrow.init_from(stilized_arrow(16, DefaultTipRadius, DefaultTipLength, DefaultStemRadius, m_stem_length));
if (!m_shader.init("gouraud_light.vs", "gouraud_light.fs"))
BOOST_LOG_TRIVIAL(error) << "Unable to initialize gouraud_light shader: please, check that the files gouraud_light.vs and gouraud_light.fs are available";
if (!m_shader.is_initialized())
return;
glsafe(::glEnable(GL_DEPTH_TEST));
m_shader.start_using();
GLint color_id = ::glGetUniformLocation(m_shader.get_shader_program_id(), "uniform_color");
// x axis
render_axis(Geometry::assemble_transform(m_origin, { 0.0, 0.5 * M_PI, 0.0f }).cast<float>(), color_id, { 0.75f, 0.0f, 0.0f, 1.0f });
// y axis
render_axis(Geometry::assemble_transform(m_origin, { -0.5 * M_PI, 0.0, 0.0f }).cast<float>(), color_id, { 0.0f, 0.75f, 0.0f, 1.0f });
// z axis
render_axis(Geometry::assemble_transform(m_origin).cast<float>(), color_id, { 0.0f, 0.0f, 0.75f, 1.0f });
m_shader.stop_using();
glsafe(::glDisable(GL_DEPTH_TEST));
#else
if (m_quadric == nullptr) if (m_quadric == nullptr)
return; return;
@ -171,8 +229,10 @@ void Bed3D::Axes::render() const
glsafe(::glDisable(GL_LIGHTING)); glsafe(::glDisable(GL_LIGHTING));
glsafe(::glDisable(GL_DEPTH_TEST)); glsafe(::glDisable(GL_DEPTH_TEST));
#endif // !ENABLE_GCODE_VIEWER
} }
#if !ENABLE_GCODE_VIEWER
void Bed3D::Axes::render_axis(double length) const void Bed3D::Axes::render_axis(double length) const
{ {
::gluQuadricOrientation(m_quadric, GLU_OUTSIDE); ::gluQuadricOrientation(m_quadric, GLU_OUTSIDE);
@ -185,6 +245,7 @@ void Bed3D::Axes::render_axis(double length) const
::gluQuadricOrientation(m_quadric, GLU_INSIDE); ::gluQuadricOrientation(m_quadric, GLU_INSIDE);
::gluDisk(m_quadric, 0.0, ArrowBaseRadius, 32, 1); ::gluDisk(m_quadric, 0.0, ArrowBaseRadius, 32, 1);
} }
#endif // !ENABLE_GCODE_VIEWER
Bed3D::Bed3D() Bed3D::Bed3D()
: m_type(Custom) : m_type(Custom)
@ -242,8 +303,13 @@ bool Bed3D::set_shape(const Pointfs& shape, const std::string& custom_texture, c
m_model.reset(); m_model.reset();
// Set the origin and size for rendering the coordinate system axes. // Set the origin and size for rendering the coordinate system axes.
#if ENABLE_GCODE_VIEWER
m_axes.set_origin({ 0.0, 0.0, static_cast<double>(GROUND_Z) });
m_axes.set_stem_length(0.1f * static_cast<float>(m_bounding_box.max_size()));
#else
m_axes.origin = Vec3d(0.0, 0.0, (double)GROUND_Z); m_axes.origin = Vec3d(0.0, 0.0, (double)GROUND_Z);
m_axes.length = 0.1 * m_bounding_box.max_size() * Vec3d::Ones(); m_axes.length = 0.1 * m_bounding_box.max_size() * Vec3d::Ones();
#endif // ENABLE_GCODE_VIEWER
// Let the calee to update the UI. // Let the calee to update the UI.
return true; return true;
@ -290,7 +356,11 @@ void Bed3D::calc_bounding_boxes() const
m_extended_bounding_box = m_bounding_box; m_extended_bounding_box = m_bounding_box;
// extend to contain axes // extend to contain axes
#if ENABLE_GCODE_VIEWER
m_extended_bounding_box.merge(m_axes.get_total_length() * Vec3d::Ones());
#else
m_extended_bounding_box.merge(m_axes.length + Axes::ArrowLength * Vec3d::Ones()); m_extended_bounding_box.merge(m_axes.length + Axes::ArrowLength * Vec3d::Ones());
#endif // ENABLE_GCODE_VIEWER
// extend to contain model, if any // extend to contain model, if any
if (!m_model.get_filename().empty()) if (!m_model.get_filename().empty())
@ -410,7 +480,7 @@ void Bed3D::render_texture(bool bottom, GLCanvas3D& canvas) const
if (boost::algorithm::iends_with(m_texture_filename, ".svg")) if (boost::algorithm::iends_with(m_texture_filename, ".svg"))
{ {
// use higher resolution images if graphic card and opengl version allow // use higher resolution images if graphic card and opengl version allow
GLint max_tex_size = GLCanvas3DManager::get_gl_info().get_max_tex_size(); GLint max_tex_size = OpenGLManager::get_gl_info().get_max_tex_size();
if ((m_temp_texture.get_id() == 0) || (m_temp_texture.get_source() != m_texture_filename)) if ((m_temp_texture.get_id() == 0) || (m_temp_texture.get_source() != m_texture_filename))
{ {
// generate a temporary lower resolution texture to show while no main texture levels have been compressed // generate a temporary lower resolution texture to show while no main texture levels have been compressed

View File

@ -4,11 +4,16 @@
#include "GLTexture.hpp" #include "GLTexture.hpp"
#include "3DScene.hpp" #include "3DScene.hpp"
#include "GLShader.hpp" #include "GLShader.hpp"
#if ENABLE_GCODE_VIEWER
#include "GLModel.hpp"
#endif // ENABLE_GCODE_VIEWER
#include <tuple> #include <tuple>
#if !ENABLE_GCODE_VIEWER
class GLUquadric; class GLUquadric;
typedef class GLUquadric GLUquadricObj; typedef class GLUquadric GLUquadricObj;
#endif // !ENABLE_GCODE_VIEWER
namespace Slic3r { namespace Slic3r {
namespace GUI { namespace GUI {
@ -45,22 +50,50 @@ public:
class Bed3D class Bed3D
{ {
#if ENABLE_GCODE_VIEWER
class Axes
{
static const float DefaultStemRadius;
static const float DefaultStemLength;
static const float DefaultTipRadius;
static const float DefaultTipLength;
#else
struct Axes struct Axes
{ {
static const double Radius; static const double Radius;
static const double ArrowBaseRadius; static const double ArrowBaseRadius;
static const double ArrowLength; static const double ArrowLength;
#endif // ENABLE_GCODE_VIEWER
#if ENABLE_GCODE_VIEWER
Vec3d m_origin{ Vec3d::Zero() };
float m_stem_length{ DefaultStemLength };
mutable GL_Model m_arrow;
mutable Shader m_shader;
public:
#else
Vec3d origin; Vec3d origin;
Vec3d length; Vec3d length;
GLUquadricObj* m_quadric; GLUquadricObj* m_quadric;
#endif // ENABLE_GCODE_VIEWER
#if !ENABLE_GCODE_VIEWER
Axes(); Axes();
~Axes(); ~Axes();
#endif // !ENABLE_GCODE_VIEWER
#if ENABLE_GCODE_VIEWER
void set_origin(const Vec3d& origin) { m_origin = origin; }
void set_stem_length(float length);
float get_total_length() const { return m_stem_length + DefaultTipLength; }
#endif // ENABLE_GCODE_VIEWER
void render() const; void render() const;
#if !ENABLE_GCODE_VIEWER
private: private:
void render_axis(double length) const; void render_axis(double length) const;
#endif // !ENABLE_GCODE_VIEWER
}; };
public: public:

View File

@ -5,11 +5,15 @@
#include "libslic3r/ExtrusionEntity.hpp" #include "libslic3r/ExtrusionEntity.hpp"
#include "libslic3r/ExtrusionEntityCollection.hpp" #include "libslic3r/ExtrusionEntityCollection.hpp"
#include "libslic3r/Geometry.hpp" #include "libslic3r/Geometry.hpp"
#if !ENABLE_GCODE_VIEWER
#include "libslic3r/GCode/PreviewData.hpp" #include "libslic3r/GCode/PreviewData.hpp"
#endif // !ENABLE_GCODE_VIEWER
#include "libslic3r/Print.hpp" #include "libslic3r/Print.hpp"
#include "libslic3r/SLAPrint.hpp" #include "libslic3r/SLAPrint.hpp"
#include "libslic3r/Slicing.hpp" #include "libslic3r/Slicing.hpp"
#if !ENABLE_GCODE_VIEWER
#include "libslic3r/GCode/Analyzer.hpp" #include "libslic3r/GCode/Analyzer.hpp"
#endif // !ENABLE_GCODE_VIEWER
#include "slic3r/GUI/BitmapCache.hpp" #include "slic3r/GUI/BitmapCache.hpp"
#include "libslic3r/Format/STL.hpp" #include "libslic3r/Format/STL.hpp"
#include "libslic3r/Utils.hpp" #include "libslic3r/Utils.hpp"
@ -1853,10 +1857,6 @@ void _3DScene::point3_to_verts(const Vec3crd& point, double width, double height
thick_point_to_verts(point, width, height, volume); thick_point_to_verts(point, width, height, volume);
} }
#if !ENABLE_NON_STATIC_CANVAS_MANAGER
GUI::GLCanvas3DManager _3DScene::s_canvas_mgr;
#endif // !ENABLE_NON_STATIC_CANVAS_MANAGER
GLModel::GLModel() GLModel::GLModel()
: m_filename("") : m_filename("")
{ {
@ -1944,6 +1944,7 @@ void GLModel::render() const
glsafe(::glDisable(GL_BLEND)); glsafe(::glDisable(GL_BLEND));
} }
#if !ENABLE_GCODE_VIEWER
bool GLArrow::on_init() bool GLArrow::on_init()
{ {
Pointf3s vertices; Pointf3s vertices;
@ -2115,6 +2116,7 @@ bool GLCurvedArrow::on_init()
m_volume.indexed_vertex_array.finalize_geometry(true); m_volume.indexed_vertex_array.finalize_geometry(true);
return true; return true;
} }
#endif // !ENABLE_GCODE_VIEWER
bool GLBed::on_init_from_file(const std::string& filename) bool GLBed::on_init_from_file(const std::string& filename)
{ {
@ -2147,41 +2149,4 @@ bool GLBed::on_init_from_file(const std::string& filename)
return true; return true;
} }
#if !ENABLE_NON_STATIC_CANVAS_MANAGER
std::string _3DScene::get_gl_info(bool format_as_html, bool extensions)
{
return Slic3r::GUI::GLCanvas3DManager::get_gl_info().to_string(format_as_html, extensions);
}
bool _3DScene::add_canvas(wxGLCanvas* canvas, GUI::Bed3D& bed, GUI::Camera& camera, GUI::GLToolbar& view_toolbar)
{
return s_canvas_mgr.add(canvas, bed, camera, view_toolbar);
}
bool _3DScene::remove_canvas(wxGLCanvas* canvas)
{
return s_canvas_mgr.remove(canvas);
}
void _3DScene::remove_all_canvases()
{
s_canvas_mgr.remove_all();
}
bool _3DScene::init(wxGLCanvas* canvas)
{
return s_canvas_mgr.init(canvas);
}
void _3DScene::destroy()
{
s_canvas_mgr.destroy();
}
GUI::GLCanvas3D* _3DScene::get_canvas(wxGLCanvas* canvas)
{
return s_canvas_mgr.get_canvas(canvas);
}
#endif // !ENABLE_NON_STATIC_CANVAS_MANAGER
} // namespace Slic3r } // namespace Slic3r

View File

@ -7,9 +7,6 @@
#include "libslic3r/TriangleMesh.hpp" #include "libslic3r/TriangleMesh.hpp"
#include "libslic3r/Utils.hpp" #include "libslic3r/Utils.hpp"
#include "libslic3r/Model.hpp" #include "libslic3r/Model.hpp"
#if !ENABLE_NON_STATIC_CANVAS_MANAGER
#include "slic3r/GUI/GLCanvas3DManager.hpp"
#endif // !ENABLE_NON_STATIC_CANVAS_MANAGER
#include <functional> #include <functional>
@ -645,6 +642,7 @@ protected:
virtual bool on_init_from_file(const std::string& filename) { return false; } virtual bool on_init_from_file(const std::string& filename) { return false; }
}; };
#if !ENABLE_GCODE_VIEWER
class GLArrow : public GLModel class GLArrow : public GLModel
{ {
protected: protected:
@ -661,6 +659,7 @@ public:
protected: protected:
bool on_init() override; bool on_init() override;
}; };
#endif // !ENABLE_GCODE_VIEWER
class GLBed : public GLModel class GLBed : public GLModel
{ {
@ -668,30 +667,8 @@ protected:
bool on_init_from_file(const std::string& filename) override; bool on_init_from_file(const std::string& filename) override;
}; };
#if ENABLE_NON_STATIC_CANVAS_MANAGER
struct _3DScene struct _3DScene
#else
class _3DScene
#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
{ {
#if !ENABLE_NON_STATIC_CANVAS_MANAGER
static GUI::GLCanvas3DManager s_canvas_mgr;
#endif // !ENABLE_NON_STATIC_CANVAS_MANAGER
#if !ENABLE_NON_STATIC_CANVAS_MANAGER
public:
static std::string get_gl_info(bool format_as_html, bool extensions);
static bool add_canvas(wxGLCanvas* canvas, GUI::Bed3D& bed, GUI::Camera& camera, GUI::GLToolbar& view_toolbar);
static bool remove_canvas(wxGLCanvas* canvas);
static void remove_all_canvases();
static bool init(wxGLCanvas* canvas);
static void destroy();
static GUI::GLCanvas3D* get_canvas(wxGLCanvas* canvas);
#endif // !ENABLE_NON_STATIC_CANVAS_MANAGER
static void thick_lines_to_verts(const Lines& lines, const std::vector<double>& widths, const std::vector<double>& heights, bool closed, double top_z, GLVolume& volume); static void thick_lines_to_verts(const Lines& lines, const std::vector<double>& widths, const std::vector<double>& heights, bool closed, double top_z, GLVolume& volume);
static void thick_lines_to_verts(const Lines3& lines, const std::vector<double>& widths, const std::vector<double>& heights, bool closed, GLVolume& volume); static void thick_lines_to_verts(const Lines3& lines, const std::vector<double>& widths, const std::vector<double>& heights, bool closed, GLVolume& volume);
static void extrusionentity_to_verts(const Polyline &polyline, float width, float height, float print_z, GLVolume& volume); static void extrusionentity_to_verts(const Polyline &polyline, float width, float height, float print_z, GLVolume& volume);

View File

@ -84,6 +84,9 @@ void AppConfig::set_defaults()
if (get("custom_toolbar_size").empty()) if (get("custom_toolbar_size").empty())
set("custom_toolbar_size", "100"); set("custom_toolbar_size", "100");
if (get("auto_toolbar_size").empty())
set("auto_toolbar_size", "100");
if (get("use_perspective_camera").empty()) if (get("use_perspective_camera").empty())
set("use_perspective_camera", "1"); set("use_perspective_camera", "1");

View File

@ -18,7 +18,9 @@
#include "libslic3r/SLAPrint.hpp" #include "libslic3r/SLAPrint.hpp"
#include "libslic3r/Utils.hpp" #include "libslic3r/Utils.hpp"
#include "libslic3r/GCode/PostProcessor.hpp" #include "libslic3r/GCode/PostProcessor.hpp"
#if !ENABLE_GCODE_VIEWER
#include "libslic3r/GCode/PreviewData.hpp" #include "libslic3r/GCode/PreviewData.hpp"
#endif // !ENABLE_GCODE_VIEWER
#include "libslic3r/Format/SL1.hpp" #include "libslic3r/Format/SL1.hpp"
#include "libslic3r/libslic3r.h" #include "libslic3r/libslic3r.h"
@ -89,7 +91,7 @@ void BackgroundSlicingProcess::process_fff()
m_print->process(); m_print->process();
wxQueueEvent(GUI::wxGetApp().mainframe->m_plater, new wxCommandEvent(m_event_slicing_completed_id)); wxQueueEvent(GUI::wxGetApp().mainframe->m_plater, new wxCommandEvent(m_event_slicing_completed_id));
#if ENABLE_GCODE_VIEWER #if ENABLE_GCODE_VIEWER
m_fff_print->export_gcode(m_temp_output_path, m_gcode_preview_data, m_gcode_result, m_thumbnail_cb); m_fff_print->export_gcode(m_temp_output_path, m_gcode_result, m_thumbnail_cb);
#else #else
m_fff_print->export_gcode(m_temp_output_path, m_gcode_preview_data, m_thumbnail_cb); m_fff_print->export_gcode(m_temp_output_path, m_gcode_preview_data, m_thumbnail_cb);
#endif // ENABLE_GCODE_VIEWER #endif // ENABLE_GCODE_VIEWER
@ -385,9 +387,7 @@ Print::ApplyStatus BackgroundSlicingProcess::apply(const Model &model, const Dyn
// Some FFF status was invalidated, and the G-code was not exported yet. // Some FFF status was invalidated, and the G-code was not exported yet.
// Let the G-code preview UI know that the final G-code preview is not valid. // Let the G-code preview UI know that the final G-code preview is not valid.
// In addition, this early memory deallocation reduces memory footprint. // In addition, this early memory deallocation reduces memory footprint.
if (m_gcode_preview_data != nullptr) if (m_gcode_result != nullptr)
m_gcode_preview_data->reset();
else if (m_gcode_result != nullptr)
m_gcode_result->reset(); m_gcode_result->reset();
} }
#else #else

View File

@ -50,10 +50,11 @@ public:
void set_fff_print(Print *print) { m_fff_print = print; } void set_fff_print(Print *print) { m_fff_print = print; }
void set_sla_print(SLAPrint *print) { m_sla_print = print; m_sla_print->set_printer(&m_sla_archive); } void set_sla_print(SLAPrint *print) { m_sla_print = print; m_sla_print->set_printer(&m_sla_archive); }
void set_gcode_preview_data(GCodePreviewData *gpd) { m_gcode_preview_data = gpd; } void set_thumbnail_cb(ThumbnailsGeneratorCallback cb) { m_thumbnail_cb = cb; }
void set_thumbnail_cb(ThumbnailsGeneratorCallback cb) { m_thumbnail_cb = cb; }
#if ENABLE_GCODE_VIEWER #if ENABLE_GCODE_VIEWER
void set_gcode_result(GCodeProcessor::Result* result) { m_gcode_result = result; } void set_gcode_result(GCodeProcessor::Result* result) { m_gcode_result = result; }
#else
void set_gcode_preview_data(GCodePreviewData* gpd) { m_gcode_preview_data = gpd; }
#endif // ENABLE_GCODE_VIEWER #endif // ENABLE_GCODE_VIEWER
// The following wxCommandEvent will be sent to the UI thread / Plater window, when the slicing is finished // The following wxCommandEvent will be sent to the UI thread / Plater window, when the slicing is finished
@ -156,15 +157,17 @@ private:
// Non-owned pointers to Print instances. // Non-owned pointers to Print instances.
Print *m_fff_print = nullptr; Print *m_fff_print = nullptr;
SLAPrint *m_sla_print = nullptr; SLAPrint *m_sla_print = nullptr;
#if ENABLE_GCODE_VIEWER
// Data structure, to which the G-code export writes its annotations.
GCodeProcessor::Result *m_gcode_result = nullptr;
#else
// Data structure, to which the G-code export writes its annotations. // Data structure, to which the G-code export writes its annotations.
GCodePreviewData *m_gcode_preview_data = nullptr; GCodePreviewData *m_gcode_preview_data = nullptr;
// Callback function, used to write thumbnails into gcode. #endif // ENABLE_GCODE_VIEWER
// Callback function, used to write thumbnails into gcode.
ThumbnailsGeneratorCallback m_thumbnail_cb = nullptr; ThumbnailsGeneratorCallback m_thumbnail_cb = nullptr;
SL1Archive m_sla_archive; SL1Archive m_sla_archive;
#if ENABLE_GCODE_VIEWER // Temporary G-code, there is one defined for the BackgroundSlicingProcess, differentiated from the other processes by a process ID.
GCodeProcessor::Result* m_gcode_result = nullptr;
#endif // ENABLE_GCODE_VIEWER
// Temporary G-code, there is one defined for the BackgroundSlicingProcess, differentiated from the other processes by a process ID.
std::string m_temp_output_path; std::string m_temp_output_path;
// Output path provided by the user. The output path may be set even if the slicing is running, // Output path provided by the user. The output path may be set even if the slicing is running,
// but once set, it cannot be re-set. // but once set, it cannot be re-set.

View File

@ -1,5 +1,11 @@
#include "libslic3r/libslic3r.h"
#if ENABLE_GCODE_VIEWER
#include "DoubleSlider.hpp"
#include "libslic3r/GCode.hpp"
#else
#include "wxExtensions.hpp" #include "wxExtensions.hpp"
#include "libslic3r/GCode/PreviewData.hpp" #include "libslic3r/GCode/PreviewData.hpp"
#endif // ENABLE_GCODE_VIEWER
#include "GUI.hpp" #include "GUI.hpp"
#include "GUI_App.hpp" #include "GUI_App.hpp"
#include "I18N.hpp" #include "I18N.hpp"
@ -1945,7 +1951,11 @@ std::string TickCodeInfo::get_color_for_tick(TickCode tick, const std::string& c
{ {
if (mode == t_mode::SingleExtruder && code == ColorChangeCode && m_use_default_colors) if (mode == t_mode::SingleExtruder && code == ColorChangeCode && m_use_default_colors)
{ {
#if ENABLE_GCODE_VIEWER
const std::vector<std::string>& colors = ColorPrintColors::get();
#else
const std::vector<std::string>& colors = GCodePreviewData::ColorPrintColors(); const std::vector<std::string>& colors = GCodePreviewData::ColorPrintColors();
#endif // ENABLE_GCODE_VIEWER
if (ticks.empty()) if (ticks.empty())
return colors[0]; return colors[0];
m_default_color_idx++; m_default_color_idx++;

View File

@ -4,7 +4,9 @@
#include "libslic3r/CustomGCode.hpp" #include "libslic3r/CustomGCode.hpp"
#include "wxExtensions.hpp" #include "wxExtensions.hpp"
#if !ENABLE_GCODE_VIEWER
#include <wx/wx.h> #include <wx/wx.h>
#endif // !ENABLE_GCODE_VIEWER
#include <wx/window.h> #include <wx/window.h>
#include <wx/control.h> #include <wx/control.h>
#include <wx/dc.h> #include <wx/dc.h>

View File

@ -9,6 +9,7 @@
#include <regex> #include <regex>
#include <wx/numformatter.h> #include <wx/numformatter.h>
#include <wx/tooltip.h> #include <wx/tooltip.h>
#include <wx/notebook.h>
#include <boost/algorithm/string/predicate.hpp> #include <boost/algorithm/string/predicate.hpp>
#ifdef __WXOSX__ #ifdef __WXOSX__
@ -79,6 +80,29 @@ void Field::PostInitialize()
m_em_unit = em_unit(m_parent); m_em_unit = em_unit(m_parent);
BUILD(); BUILD();
// For the mode, when settings are in non-modal dialog, neither dialog nor tabpanel doesn't receive wxEVT_KEY_UP event, when some field is selected.
// So, like a workaround check wxEVT_KEY_UP event for the Filed and switch between tabs if Ctrl+(1-4) was pressed
if (getWindow())
getWindow()->Bind(wxEVT_KEY_UP, [](wxKeyEvent& evt) {
if ((evt.GetModifiers() & wxMOD_CONTROL) != 0) {
int tab_id = -1;
switch (evt.GetKeyCode()) {
case '1': { tab_id = 0; break; }
case '2': { tab_id = 1; break; }
case '3': { tab_id = 2; break; }
case '4': { tab_id = 3; break; }
default: break;
}
if (tab_id >= 0)
wxGetApp().mainframe->select_tab(tab_id);
if (tab_id > 0)
// tab panel should be focused for correct navigation between tabs
wxGetApp().tab_panel()->SetFocus();
}
evt.Skip();
});
} }
// Values of width to alignments of fields // Values of width to alignments of fields
@ -397,7 +421,7 @@ void TextCtrl::BUILD() {
bKilledFocus = false; bKilledFocus = false;
#endif // __WXOSX__ #endif // __WXOSX__
}), temp->GetId()); }), temp->GetId());
/*
// select all text using Ctrl+A // select all text using Ctrl+A
temp->Bind(wxEVT_CHAR, ([temp](wxKeyEvent& event) temp->Bind(wxEVT_CHAR, ([temp](wxKeyEvent& event)
{ {
@ -405,7 +429,7 @@ void TextCtrl::BUILD() {
temp->SetSelection(-1, -1); //select all temp->SetSelection(-1, -1); //select all
event.Skip(); event.Skip();
})); }));
*/
// recast as a wxWindow to fit the calling convention // recast as a wxWindow to fit the calling convention
window = dynamic_cast<wxWindow*>(temp); window = dynamic_cast<wxWindow*>(temp);
} }

View File

@ -3,6 +3,7 @@
#if ENABLE_GCODE_VIEWER #if ENABLE_GCODE_VIEWER
#include "libslic3r/Print.hpp" #include "libslic3r/Print.hpp"
#include "libslic3r/Geometry.hpp"
#include "GUI_App.hpp" #include "GUI_App.hpp"
#include "PresetBundle.hpp" #include "PresetBundle.hpp"
#include "Camera.hpp" #include "Camera.hpp"
@ -100,8 +101,7 @@ void GCodeViewer::IBuffer::reset()
} }
// release cpu memory // release cpu memory
data = std::vector<unsigned int>(); indices_count = 0;
data_size = 0;
paths = std::vector<Path>(); paths = std::vector<Path>();
render_paths = std::vector<RenderPath>(); render_paths = std::vector<RenderPath>();
} }
@ -116,9 +116,9 @@ bool GCodeViewer::IBuffer::init_shader(const std::string& vertex_shader_src, con
return true; return true;
} }
void GCodeViewer::IBuffer::add_path(const GCodeProcessor::MoveVertex& move, unsigned int v_id) void GCodeViewer::IBuffer::add_path(const GCodeProcessor::MoveVertex& move, unsigned int i_id, unsigned int s_id)
{ {
Path::Endpoint endpoint = { static_cast<unsigned int>(data.size()), v_id, move.position }; Path::Endpoint endpoint = { i_id, s_id, move.position };
paths.push_back({ move.type, move.extrusion_role, endpoint, endpoint, move.delta_extruder, move.height, move.width, move.feedrate, move.fan_speed, move.volumetric_rate(), move.extruder_id, move.cp_color_id }); paths.push_back({ move.type, move.extrusion_role, endpoint, endpoint, move.delta_extruder, move.height, move.width, move.feedrate, move.fan_speed, move.volumetric_rate(), move.extruder_id, move.cp_color_id });
} }
@ -145,7 +145,44 @@ GCodeViewer::Color GCodeViewer::Extrusions::Range::get_color_at(float value) con
return ret; return ret;
} }
const std::vector<GCodeViewer::Color> GCodeViewer::Extrusion_Role_Colors{ { void GCodeViewer::SequentialView::Marker::init()
{
m_model.init_from(stilized_arrow(16, 2.0f, 4.0f, 1.0f, 8.0f));
init_shader();
}
void GCodeViewer::SequentialView::Marker::render() const
{
if (!m_visible || !m_shader.is_initialized())
return;
glsafe(::glEnable(GL_BLEND));
glsafe(::glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA));
m_shader.start_using();
GLint color_id = ::glGetUniformLocation(m_shader.get_shader_program_id(), "uniform_color");
if (color_id >= 0)
glsafe(::glUniform4fv(color_id, 1, (const GLfloat*)m_color.data()));
glsafe(::glPushMatrix());
glsafe(::glMultMatrixf(m_world_transform.data()));
m_model.render();
glsafe(::glPopMatrix());
m_shader.stop_using();
glsafe(::glDisable(GL_BLEND));
}
void GCodeViewer::SequentialView::Marker::init_shader()
{
if (!m_shader.init("gouraud_light.vs", "gouraud_light.fs"))
BOOST_LOG_TRIVIAL(error) << "Unable to initialize gouraud_light shader: please, check that the files gouraud_light.vs and gouraud_light.fs are available";
}
const std::vector<GCodeViewer::Color> GCodeViewer::Extrusion_Role_Colors {{
{ 0.50f, 0.50f, 0.50f }, // erNone { 0.50f, 0.50f, 0.50f }, // erNone
{ 1.00f, 1.00f, 0.40f }, // erPerimeter { 1.00f, 1.00f, 0.40f }, // erPerimeter
{ 1.00f, 0.65f, 0.00f }, // erExternalPerimeter { 1.00f, 0.65f, 0.00f }, // erExternalPerimeter
@ -153,7 +190,7 @@ const std::vector<GCodeViewer::Color> GCodeViewer::Extrusion_Role_Colors{ {
{ 0.69f, 0.19f, 0.16f }, // erInternalInfill { 0.69f, 0.19f, 0.16f }, // erInternalInfill
{ 0.84f, 0.20f, 0.84f }, // erSolidInfill { 0.84f, 0.20f, 0.84f }, // erSolidInfill
{ 1.00f, 0.10f, 0.10f }, // erTopSolidInfill { 1.00f, 0.10f, 0.10f }, // erTopSolidInfill
{ 0.00f, 1.00f, 1.00f }, // erIroning { 1.00f, 0.55f, 0.41f }, // erIroning
{ 0.60f, 0.60f, 1.00f }, // erBridgeInfill { 0.60f, 0.60f, 1.00f }, // erBridgeInfill
{ 1.00f, 1.00f, 1.00f }, // erGapFill { 1.00f, 1.00f, 1.00f }, // erGapFill
{ 0.52f, 0.48f, 0.13f }, // erSkirt { 0.52f, 0.48f, 0.13f }, // erSkirt
@ -164,13 +201,13 @@ const std::vector<GCodeViewer::Color> GCodeViewer::Extrusion_Role_Colors{ {
{ 0.00f, 0.00f, 0.00f } // erMixed { 0.00f, 0.00f, 0.00f } // erMixed
}}; }};
const std::vector<GCodeViewer::Color> GCodeViewer::Travel_Colors{ { const std::vector<GCodeViewer::Color> GCodeViewer::Travel_Colors {{
{ 0.0f, 0.0f, 0.5f }, // Move { 0.0f, 0.0f, 0.5f }, // Move
{ 0.0f, 0.5f, 0.0f }, // Extrude { 0.0f, 0.5f, 0.0f }, // Extrude
{ 0.5f, 0.0f, 0.0f } // Retract { 0.5f, 0.0f, 0.0f } // Retract
}}; }};
const std::vector<GCodeViewer::Color> GCodeViewer::Range_Colors{ { const std::vector<GCodeViewer::Color> GCodeViewer::Range_Colors {{
{ 0.043f, 0.173f, 0.478f }, // bluish { 0.043f, 0.173f, 0.478f }, // bluish
{ 0.075f, 0.349f, 0.522f }, { 0.075f, 0.349f, 0.522f },
{ 0.110f, 0.533f, 0.569f }, { 0.110f, 0.533f, 0.569f },
@ -278,11 +315,16 @@ void GCodeViewer::render() const
m_statistics.reset_opengl(); m_statistics.reset_opengl();
#endif // ENABLE_GCODE_VIEWER_STATISTICS #endif // ENABLE_GCODE_VIEWER_STATISTICS
if (m_roles.empty())
return;
glsafe(::glEnable(GL_DEPTH_TEST)); glsafe(::glEnable(GL_DEPTH_TEST));
render_toolpaths(); render_toolpaths();
m_sequential_view.marker.set_world_transform(Geometry::assemble_transform(m_sequential_view.current_position.cast<double>() + (0.5 + 12.0) * Vec3d::UnitZ(), { M_PI, 0.0, 0.0 }).cast<float>());
m_sequential_view.marker.render();
render_shells(); render_shells();
render_legend(); render_legend();
render_sequential_dlg(); render_sequential_bar();
#if ENABLE_GCODE_VIEWER_STATISTICS #if ENABLE_GCODE_VIEWER_STATISTICS
render_statistics(); render_statistics();
#endif // ENABLE_GCODE_VIEWER_STATISTICS #endif // ENABLE_GCODE_VIEWER_STATISTICS
@ -316,7 +358,8 @@ unsigned int GCodeViewer::get_options_visibility_flags() const
flags = set_flag(flags, 5, is_toolpath_move_type_visible(GCodeProcessor::EMoveType::Pause_Print)); flags = set_flag(flags, 5, is_toolpath_move_type_visible(GCodeProcessor::EMoveType::Pause_Print));
flags = set_flag(flags, 6, is_toolpath_move_type_visible(GCodeProcessor::EMoveType::Custom_GCode)); flags = set_flag(flags, 6, is_toolpath_move_type_visible(GCodeProcessor::EMoveType::Custom_GCode));
flags = set_flag(flags, 7, m_shells.visible); flags = set_flag(flags, 7, m_shells.visible);
flags = set_flag(flags, 8, is_legend_enabled()); flags = set_flag(flags, 8, m_sequential_view.marker.is_visible());
flags = set_flag(flags, 9, is_legend_enabled());
return flags; return flags;
} }
@ -334,7 +377,8 @@ void GCodeViewer::set_options_visibility_from_flags(unsigned int flags)
set_toolpath_move_type_visible(GCodeProcessor::EMoveType::Pause_Print, is_flag_set(5)); set_toolpath_move_type_visible(GCodeProcessor::EMoveType::Pause_Print, is_flag_set(5));
set_toolpath_move_type_visible(GCodeProcessor::EMoveType::Custom_GCode, is_flag_set(6)); set_toolpath_move_type_visible(GCodeProcessor::EMoveType::Custom_GCode, is_flag_set(6));
m_shells.visible = is_flag_set(7); m_shells.visible = is_flag_set(7);
enable_legend(is_flag_set(8)); m_sequential_view.marker.set_visible(is_flag_set(8));
enable_legend(is_flag_set(9));
} }
bool GCodeViewer::init_shaders() bool GCodeViewer::init_shaders()
@ -388,10 +432,13 @@ void GCodeViewer::load_toolpaths(const GCodeProcessor::Result& gcode_result)
std::vector<float> vertices_data(m_vertices.vertices_count * 3); std::vector<float> vertices_data(m_vertices.vertices_count * 3);
for (size_t i = 0; i < m_vertices.vertices_count; ++i) { for (size_t i = 0; i < m_vertices.vertices_count; ++i) {
const GCodeProcessor::MoveVertex& move = gcode_result.moves[i]; const GCodeProcessor::MoveVertex& move = gcode_result.moves[i];
m_bounding_box.merge(move.position.cast<double>()); if (move.type == GCodeProcessor::EMoveType::Extrude)
m_bounding_box.merge(move.position.cast<double>());
::memcpy(static_cast<void*>(&vertices_data[i * 3]), static_cast<const void*>(move.position.data()), 3 * sizeof(float)); ::memcpy(static_cast<void*>(&vertices_data[i * 3]), static_cast<const void*>(move.position.data()), 3 * sizeof(float));
} }
m_bounding_box.merge(m_bounding_box.max + m_sequential_view.marker.get_bounding_box().max[2] * Vec3d::UnitZ());
#if ENABLE_GCODE_VIEWER_STATISTICS #if ENABLE_GCODE_VIEWER_STATISTICS
m_statistics.vertices_size = SLIC3R_STDVEC_MEMSIZE(vertices_data, float); m_statistics.vertices_size = SLIC3R_STDVEC_MEMSIZE(vertices_data, float);
m_statistics.vertices_gpu_size = vertices_data.size() * sizeof(float); m_statistics.vertices_gpu_size = vertices_data.size() * sizeof(float);
@ -403,10 +450,11 @@ void GCodeViewer::load_toolpaths(const GCodeProcessor::Result& gcode_result)
glsafe(::glBufferData(GL_ARRAY_BUFFER, vertices_data.size() * sizeof(float), vertices_data.data(), GL_STATIC_DRAW)); glsafe(::glBufferData(GL_ARRAY_BUFFER, vertices_data.size() * sizeof(float), vertices_data.data(), GL_STATIC_DRAW));
glsafe(::glBindBuffer(GL_ARRAY_BUFFER, 0)); glsafe(::glBindBuffer(GL_ARRAY_BUFFER, 0));
// vertex data -> free ram // vertex data -> no more needed, free ram
vertices_data = std::vector<float>(); vertices_data = std::vector<float>();
// indices data -> extract from result // indices data -> extract from result
std::vector<std::vector<unsigned int>> indices(m_buffers.size());
for (size_t i = 0; i < m_vertices.vertices_count; ++i) for (size_t i = 0; i < m_vertices.vertices_count; ++i)
{ {
// skip first vertex // skip first vertex
@ -416,7 +464,9 @@ void GCodeViewer::load_toolpaths(const GCodeProcessor::Result& gcode_result)
const GCodeProcessor::MoveVertex& prev = gcode_result.moves[i - 1]; const GCodeProcessor::MoveVertex& prev = gcode_result.moves[i - 1];
const GCodeProcessor::MoveVertex& curr = gcode_result.moves[i]; const GCodeProcessor::MoveVertex& curr = gcode_result.moves[i];
IBuffer& buffer = m_buffers[buffer_id(curr.type)]; unsigned char id = buffer_id(curr.type);
IBuffer& buffer = m_buffers[id];
std::vector<unsigned int>& buffer_indices = indices[id];
switch (curr.type) switch (curr.type)
{ {
@ -427,23 +477,23 @@ void GCodeViewer::load_toolpaths(const GCodeProcessor::Result& gcode_result)
case GCodeProcessor::EMoveType::Retract: case GCodeProcessor::EMoveType::Retract:
case GCodeProcessor::EMoveType::Unretract: case GCodeProcessor::EMoveType::Unretract:
{ {
buffer.add_path(curr, static_cast<unsigned int>(i)); buffer.add_path(curr, static_cast<unsigned int>(buffer_indices.size()), static_cast<unsigned int>(i));
buffer.data.push_back(static_cast<unsigned int>(i)); buffer_indices.push_back(static_cast<unsigned int>(i));
break; break;
} }
case GCodeProcessor::EMoveType::Extrude: case GCodeProcessor::EMoveType::Extrude:
case GCodeProcessor::EMoveType::Travel: case GCodeProcessor::EMoveType::Travel:
{ {
if (prev.type != curr.type || !buffer.paths.back().matches(curr)) { if (prev.type != curr.type || !buffer.paths.back().matches(curr)) {
buffer.add_path(curr, static_cast<unsigned int>(i)); buffer.add_path(curr, static_cast<unsigned int>(buffer_indices.size()), static_cast<unsigned int>(i));
Path& last_path = buffer.paths.back(); Path& last_path = buffer.paths.back();
last_path.first.position = prev.position; last_path.first.position = prev.position;
last_path.first.s_id = static_cast<unsigned int>(i - 1); last_path.first.s_id = static_cast<unsigned int>(i - 1);
buffer.data.push_back(static_cast<unsigned int>(i - 1)); buffer_indices.push_back(static_cast<unsigned int>(i - 1));
} }
buffer.paths.back().last = { static_cast<unsigned int>(buffer.data.size()), static_cast<unsigned int>(i), curr.position }; buffer.paths.back().last = { static_cast<unsigned int>(buffer_indices.size()), static_cast<unsigned int>(i), curr.position };
buffer.data.push_back(static_cast<unsigned int>(i)); buffer_indices.push_back(static_cast<unsigned int>(i));
break; break;
} }
default: default:
@ -461,22 +511,21 @@ void GCodeViewer::load_toolpaths(const GCodeProcessor::Result& gcode_result)
#endif // ENABLE_GCODE_VIEWER_STATISTICS #endif // ENABLE_GCODE_VIEWER_STATISTICS
// indices data -> send data to gpu // indices data -> send data to gpu
for (IBuffer& buffer : m_buffers) for (size_t i = 0; i < m_buffers.size(); ++i)
{ {
buffer.data_size = buffer.data.size(); IBuffer& buffer = m_buffers[i];
std::vector<unsigned int>& buffer_indices = indices[i];
buffer.indices_count = buffer_indices.size();
#if ENABLE_GCODE_VIEWER_STATISTICS #if ENABLE_GCODE_VIEWER_STATISTICS
m_statistics.indices_size += SLIC3R_STDVEC_MEMSIZE(buffer.data, unsigned int); m_statistics.indices_size += SLIC3R_STDVEC_MEMSIZE(buffer_indices, unsigned int);
m_statistics.indices_gpu_size += buffer.data_size * sizeof(unsigned int); m_statistics.indices_gpu_size += buffer.indices_count * sizeof(unsigned int);
#endif // ENABLE_GCODE_VIEWER_STATISTICS #endif // ENABLE_GCODE_VIEWER_STATISTICS
if (buffer.data_size > 0) { if (buffer.indices_count > 0) {
glsafe(::glGenBuffers(1, &buffer.ibo_id)); glsafe(::glGenBuffers(1, &buffer.ibo_id));
glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer.ibo_id)); glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer.ibo_id));
glsafe(::glBufferData(GL_ELEMENT_ARRAY_BUFFER, buffer.data_size * sizeof(unsigned int), buffer.data.data(), GL_STATIC_DRAW)); glsafe(::glBufferData(GL_ELEMENT_ARRAY_BUFFER, buffer.indices_count * sizeof(unsigned int), buffer_indices.data(), GL_STATIC_DRAW));
glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0)); glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0));
// indices data -> free ram
buffer.data = std::vector<unsigned int>();
} }
} }
@ -641,6 +690,10 @@ void GCodeViewer::refresh_render_paths(bool keep_sequential_current) const
// update current sequential position // update current sequential position
m_sequential_view.current = keep_sequential_current ? std::clamp(m_sequential_view.current, m_sequential_view.first, m_sequential_view.last) : m_sequential_view.last; m_sequential_view.current = keep_sequential_current ? std::clamp(m_sequential_view.current, m_sequential_view.first, m_sequential_view.last) : m_sequential_view.last;
glsafe(::glBindBuffer(GL_ARRAY_BUFFER, m_vertices.vbo_id));
size_t v_size = VBuffer::vertex_size_bytes();
glsafe(::glGetBufferSubData(GL_ARRAY_BUFFER, static_cast<GLintptr>(m_sequential_view.current * v_size), static_cast<GLsizeiptr>(v_size), static_cast<void*>(m_sequential_view.current_position.data())));
glsafe(::glBindBuffer(GL_ARRAY_BUFFER, 0));
// second pass: filter paths by sequential data // second pass: filter paths by sequential data
for (auto&& [buffer, id] : paths) { for (auto&& [buffer, id] : paths) {
@ -683,7 +736,7 @@ void GCodeViewer::render_toolpaths() const
{ {
auto set_color = [](GLint current_program_id, const Color& color) { auto set_color = [](GLint current_program_id, const Color& color) {
if (current_program_id > 0) { if (current_program_id > 0) {
GLint color_id = (current_program_id > 0) ? ::glGetUniformLocation(current_program_id, "uniform_color") : -1; GLint color_id = ::glGetUniformLocation(current_program_id, "uniform_color");
if (color_id >= 0) { if (color_id >= 0) {
glsafe(::glUniform3fv(color_id, 1, (const GLfloat*)color.data())); glsafe(::glUniform3fv(color_id, 1, (const GLfloat*)color.data()));
return; return;
@ -715,9 +768,6 @@ void GCodeViewer::render_toolpaths() const
buffer.shader.start_using(); buffer.shader.start_using();
GLint current_program_id;
glsafe(::glGetIntegerv(GL_CURRENT_PROGRAM, &current_program_id));
glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer.ibo_id)); glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer.ibo_id));
switch (type) switch (type)
@ -725,7 +775,7 @@ void GCodeViewer::render_toolpaths() const
case GCodeProcessor::EMoveType::Tool_change: case GCodeProcessor::EMoveType::Tool_change:
{ {
Color color = { 1.0f, 1.0f, 1.0f }; Color color = { 1.0f, 1.0f, 1.0f };
set_color(current_program_id, color); set_color(static_cast<GLint>(buffer.shader.get_shader_program_id()), color);
for (const RenderPath& path : buffer.render_paths) for (const RenderPath& path : buffer.render_paths)
{ {
glsafe(::glEnable(GL_PROGRAM_POINT_SIZE)); glsafe(::glEnable(GL_PROGRAM_POINT_SIZE));
@ -741,7 +791,7 @@ void GCodeViewer::render_toolpaths() const
case GCodeProcessor::EMoveType::Color_change: case GCodeProcessor::EMoveType::Color_change:
{ {
Color color = { 1.0f, 0.0f, 0.0f }; Color color = { 1.0f, 0.0f, 0.0f };
set_color(current_program_id, color); set_color(static_cast<GLint>(buffer.shader.get_shader_program_id()), color);
for (const RenderPath& path : buffer.render_paths) for (const RenderPath& path : buffer.render_paths)
{ {
glsafe(::glEnable(GL_PROGRAM_POINT_SIZE)); glsafe(::glEnable(GL_PROGRAM_POINT_SIZE));
@ -757,7 +807,7 @@ void GCodeViewer::render_toolpaths() const
case GCodeProcessor::EMoveType::Pause_Print: case GCodeProcessor::EMoveType::Pause_Print:
{ {
Color color = { 0.0f, 1.0f, 0.0f }; Color color = { 0.0f, 1.0f, 0.0f };
set_color(current_program_id, color); set_color(static_cast<GLint>(buffer.shader.get_shader_program_id()), color);
for (const RenderPath& path : buffer.render_paths) for (const RenderPath& path : buffer.render_paths)
{ {
glsafe(::glEnable(GL_PROGRAM_POINT_SIZE)); glsafe(::glEnable(GL_PROGRAM_POINT_SIZE));
@ -773,7 +823,7 @@ void GCodeViewer::render_toolpaths() const
case GCodeProcessor::EMoveType::Custom_GCode: case GCodeProcessor::EMoveType::Custom_GCode:
{ {
Color color = { 0.0f, 0.0f, 1.0f }; Color color = { 0.0f, 0.0f, 1.0f };
set_color(current_program_id, color); set_color(static_cast<GLint>(buffer.shader.get_shader_program_id()), color);
for (const RenderPath& path : buffer.render_paths) for (const RenderPath& path : buffer.render_paths)
{ {
glsafe(::glEnable(GL_PROGRAM_POINT_SIZE)); glsafe(::glEnable(GL_PROGRAM_POINT_SIZE));
@ -789,7 +839,7 @@ void GCodeViewer::render_toolpaths() const
case GCodeProcessor::EMoveType::Retract: case GCodeProcessor::EMoveType::Retract:
{ {
Color color = { 1.0f, 0.0f, 1.0f }; Color color = { 1.0f, 0.0f, 1.0f };
set_color(current_program_id, color); set_color(static_cast<GLint>(buffer.shader.get_shader_program_id()), color);
for (const RenderPath& path : buffer.render_paths) for (const RenderPath& path : buffer.render_paths)
{ {
glsafe(::glEnable(GL_PROGRAM_POINT_SIZE)); glsafe(::glEnable(GL_PROGRAM_POINT_SIZE));
@ -805,7 +855,7 @@ void GCodeViewer::render_toolpaths() const
case GCodeProcessor::EMoveType::Unretract: case GCodeProcessor::EMoveType::Unretract:
{ {
Color color = { 0.0f, 1.0f, 1.0f }; Color color = { 0.0f, 1.0f, 1.0f };
set_color(current_program_id, color); set_color(static_cast<GLint>(buffer.shader.get_shader_program_id()), color);
for (const RenderPath& path : buffer.render_paths) for (const RenderPath& path : buffer.render_paths)
{ {
glsafe(::glEnable(GL_PROGRAM_POINT_SIZE)); glsafe(::glEnable(GL_PROGRAM_POINT_SIZE));
@ -822,7 +872,7 @@ void GCodeViewer::render_toolpaths() const
{ {
for (const RenderPath& path : buffer.render_paths) for (const RenderPath& path : buffer.render_paths)
{ {
set_color(current_program_id, path.color); set_color(static_cast<GLint>(buffer.shader.get_shader_program_id()), path.color);
glsafe(::glMultiDrawElements(GL_LINE_STRIP, (const GLsizei*)path.sizes.data(), GL_UNSIGNED_INT, (const void* const*)path.offsets.data(), (GLsizei)path.sizes.size())); glsafe(::glMultiDrawElements(GL_LINE_STRIP, (const GLsizei*)path.sizes.data(), GL_UNSIGNED_INT, (const void* const*)path.offsets.data(), (GLsizei)path.sizes.size()));
#if ENABLE_GCODE_VIEWER_STATISTICS #if ENABLE_GCODE_VIEWER_STATISTICS
++m_statistics.gl_multi_line_strip_calls_count; ++m_statistics.gl_multi_line_strip_calls_count;
@ -835,7 +885,7 @@ void GCodeViewer::render_toolpaths() const
{ {
for (const RenderPath& path : buffer.render_paths) for (const RenderPath& path : buffer.render_paths)
{ {
set_color(current_program_id, path.color); set_color(static_cast<GLint>(buffer.shader.get_shader_program_id()), path.color);
glsafe(::glMultiDrawElements(GL_LINE_STRIP, (const GLsizei*)path.sizes.data(), GL_UNSIGNED_INT, (const void* const*)path.offsets.data(), (GLsizei)path.sizes.size())); glsafe(::glMultiDrawElements(GL_LINE_STRIP, (const GLsizei*)path.sizes.data(), GL_UNSIGNED_INT, (const void* const*)path.offsets.data(), (GLsizei)path.sizes.size()));
#if ENABLE_GCODE_VIEWER_STATISTICS #if ENABLE_GCODE_VIEWER_STATISTICS
++m_statistics.gl_multi_line_strip_calls_count; ++m_statistics.gl_multi_line_strip_calls_count;
@ -874,7 +924,7 @@ void GCodeViewer::render_legend() const
static const ImVec4 ORANGE(1.0f, 0.49f, 0.22f, 1.0f); static const ImVec4 ORANGE(1.0f, 0.49f, 0.22f, 1.0f);
static const ImU32 ICON_BORDER_COLOR = ImGui::GetColorU32(ImVec4(0.0f, 0.0f, 0.0f, 1.0f)); static const ImU32 ICON_BORDER_COLOR = ImGui::GetColorU32(ImVec4(0.0f, 0.0f, 0.0f, 1.0f));
if (!m_legend_enabled || m_roles.empty()) if (!m_legend_enabled)
return; return;
ImGuiWrapper& imgui = *wxGetApp().imgui(); ImGuiWrapper& imgui = *wxGetApp().imgui();
@ -928,14 +978,14 @@ void GCodeViewer::render_legend() const
ImGui::PushStyleColor(ImGuiCol_Text, ORANGE); ImGui::PushStyleColor(ImGuiCol_Text, ORANGE);
switch (m_view_type) switch (m_view_type)
{ {
case EViewType::FeatureType: { imgui.text(I18N::translate_utf8(L("Feature type"))); break; } case EViewType::FeatureType: { imgui.text(_u8L("Feature type")); break; }
case EViewType::Height: { imgui.text(I18N::translate_utf8(L("Height (mm)"))); break; } case EViewType::Height: { imgui.text(_u8L("Height (mm)")); break; }
case EViewType::Width: { imgui.text(I18N::translate_utf8(L("Width (mm)"))); break; } case EViewType::Width: { imgui.text(_u8L("Width (mm)")); break; }
case EViewType::Feedrate: { imgui.text(I18N::translate_utf8(L("Speed (mm/s)"))); break; } case EViewType::Feedrate: { imgui.text(_u8L("Speed (mm/s)")); break; }
case EViewType::FanSpeed: { imgui.text(I18N::translate_utf8(L("Fan Speed (%%)"))); break; } case EViewType::FanSpeed: { imgui.text(_u8L("Fan Speed (%%)")); break; }
case EViewType::VolumetricRate: { imgui.text(I18N::translate_utf8(L("Volumetric flow rate (mm³/s)"))); break; } case EViewType::VolumetricRate: { imgui.text(_u8L("Volumetric flow rate (mm³/s)")); break; }
case EViewType::Tool: { imgui.text(I18N::translate_utf8(L("Tool"))); break; } case EViewType::Tool: { imgui.text(_u8L("Tool")); break; }
case EViewType::ColorPrint: { imgui.text(I18N::translate_utf8(L("Color Print"))); break; } case EViewType::ColorPrint: { imgui.text(_u8L("Color Print")); break; }
default: { break; } default: { break; }
} }
ImGui::PopStyleColor(); ImGui::PopStyleColor();
@ -951,7 +1001,7 @@ void GCodeViewer::render_legend() const
if (!visible) if (!visible)
ImGui::PushStyleVar(ImGuiStyleVar_Alpha, 0.3333f); ImGui::PushStyleVar(ImGuiStyleVar_Alpha, 0.3333f);
add_item(Extrusion_Role_Colors[static_cast<unsigned int>(role)], I18N::translate_utf8(ExtrusionEntity::role_to_string(role)), [this, role]() { add_item(Extrusion_Role_Colors[static_cast<unsigned int>(role)], _u8L(ExtrusionEntity::role_to_string(role)), [this, role]() {
if (role < erCount) if (role < erCount)
{ {
m_extrusions.role_visibility_flags = is_visible(role) ? m_extrusions.role_visibility_flags & ~(1 << role) : m_extrusions.role_visibility_flags | (1 << role); m_extrusions.role_visibility_flags = is_visible(role) ? m_extrusions.role_visibility_flags & ~(1 << role) : m_extrusions.role_visibility_flags | (1 << role);
@ -981,7 +1031,7 @@ void GCodeViewer::render_legend() const
if (it == m_extruder_ids.end()) if (it == m_extruder_ids.end())
continue; continue;
add_item(m_tool_colors[i], (boost::format(I18N::translate_utf8(L("Extruder %d"))) % (i + 1)).str()); add_item(m_tool_colors[i], (boost::format(_u8L("Extruder %d")) % (i + 1)).str());
} }
break; break;
} }
@ -992,7 +1042,7 @@ void GCodeViewer::render_legend() const
if (extruders_count == 1) { // single extruder use case if (extruders_count == 1) { // single extruder use case
if (custom_gcode_per_print_z.empty()) if (custom_gcode_per_print_z.empty())
// no data to show // no data to show
add_item(m_tool_colors.front(), I18N::translate_utf8(L("Default print color"))); add_item(m_tool_colors.front(), _u8L("Default print color"));
else { else {
std::vector<std::pair<double, double>> cp_values; std::vector<std::pair<double, double>> cp_values;
cp_values.reserve(custom_gcode_per_print_z.size()); cp_values.reserve(custom_gcode_per_print_z.size());
@ -1016,7 +1066,7 @@ void GCodeViewer::render_legend() const
const int items_cnt = static_cast<int>(cp_values.size()); const int items_cnt = static_cast<int>(cp_values.size());
if (items_cnt == 0) { // There is no one color change, but there are some pause print or custom Gcode if (items_cnt == 0) { // There is no one color change, but there are some pause print or custom Gcode
add_item(m_tool_colors.front(), I18N::translate_utf8(L("Default print color"))); add_item(m_tool_colors.front(), _u8L("Default print color"));
} }
else { else {
for (int i = items_cnt; i >= 0; --i) { for (int i = items_cnt; i >= 0; --i) {
@ -1024,14 +1074,14 @@ void GCodeViewer::render_legend() const
std::string id_str = " (" + std::to_string(i + 1) + ")"; std::string id_str = " (" + std::to_string(i + 1) + ")";
if (i == 0) { if (i == 0) {
add_item(m_tool_colors[i], (boost::format(I18N::translate_utf8(L("up to %.2f mm"))) % cp_values.front().first).str() + id_str); add_item(m_tool_colors[i], (boost::format(_u8L("up to %.2f mm")) % cp_values.front().first).str() + id_str);
break; break;
} }
else if (i == items_cnt) { else if (i == items_cnt) {
add_item(m_tool_colors[i], (boost::format(I18N::translate_utf8(L("above %.2f mm"))) % cp_values[i - 1].second).str() + id_str); add_item(m_tool_colors[i], (boost::format(_u8L("above %.2f mm")) % cp_values[i - 1].second).str() + id_str);
continue; continue;
} }
add_item(m_tool_colors[i], (boost::format(I18N::translate_utf8(L("%.2f - %.2f mm"))) % cp_values[i - 1].second % cp_values[i].first).str() + id_str); add_item(m_tool_colors[i], (boost::format(_u8L("%.2f - %.2f mm")) % cp_values[i - 1].second% cp_values[i].first).str() + id_str);
} }
} }
} }
@ -1040,7 +1090,7 @@ void GCodeViewer::render_legend() const
{ {
// extruders // extruders
for (unsigned int i = 0; i < (unsigned int)extruders_count; ++i) { for (unsigned int i = 0; i < (unsigned int)extruders_count; ++i) {
add_item(m_tool_colors[i], (boost::format(I18N::translate_utf8(L("Extruder %d"))) % (i + 1)).str()); add_item(m_tool_colors[i], (boost::format(_u8L("Extruder %d")) % (i + 1)).str());
} }
// color changes // color changes
@ -1052,7 +1102,7 @@ void GCodeViewer::render_legend() const
std::string id_str = " (" + std::to_string(color_change_idx--) + ")"; std::string id_str = " (" + std::to_string(color_change_idx--) + ")";
add_item(m_tool_colors[last_color_id--], add_item(m_tool_colors[last_color_id--],
(boost::format(I18N::translate_utf8(L("Color change for Extruder %d at %.2f mm"))) % custom_gcode_per_print_z[i].extruder % custom_gcode_per_print_z[i].print_z).str() + id_str); (boost::format(_u8L("Color change for Extruder %d at %.2f mm")) % custom_gcode_per_print_z[i].extruder % custom_gcode_per_print_z[i].print_z).str() + id_str);
} }
} }
} }
@ -1079,14 +1129,14 @@ void GCodeViewer::render_legend() const
ImGui::Spacing(); ImGui::Spacing();
ImGui::Spacing(); ImGui::Spacing();
ImGui::PushStyleColor(ImGuiCol_Text, ORANGE); ImGui::PushStyleColor(ImGuiCol_Text, ORANGE);
imgui.text(I18N::translate_utf8(L("Travel"))); imgui.text(_u8L("Travel"));
ImGui::PopStyleColor(); ImGui::PopStyleColor();
ImGui::Separator(); ImGui::Separator();
// items // items
add_item(Travel_Colors[0], I18N::translate_utf8(L("Movement"))); add_item(Travel_Colors[0], _u8L("Movement"));
add_item(Travel_Colors[1], I18N::translate_utf8(L("Extrusion"))); add_item(Travel_Colors[1], _u8L("Extrusion"));
add_item(Travel_Colors[2], I18N::translate_utf8(L("Retraction"))); add_item(Travel_Colors[2], _u8L("Retraction"));
break; break;
} }
@ -1097,7 +1147,7 @@ void GCodeViewer::render_legend() const
ImGui::PopStyleVar(); ImGui::PopStyleVar();
} }
void GCodeViewer::render_sequential_dlg() const void GCodeViewer::render_sequential_bar() const
{ {
static const float MARGIN = 125.0f; static const float MARGIN = 125.0f;
static const float BUTTON_W = 50.0f; static const float BUTTON_W = 50.0f;
@ -1107,9 +1157,6 @@ void GCodeViewer::render_sequential_dlg() const
refresh_render_paths(true); refresh_render_paths(true);
}; };
if (m_roles.empty())
return;
if (m_sequential_view.last <= m_sequential_view.first) if (m_sequential_view.last <= m_sequential_view.first)
return; return;
@ -1191,9 +1238,6 @@ void GCodeViewer::render_statistics() const
static const ImVec4 ORANGE(1.0f, 0.49f, 0.22f, 1.0f); static const ImVec4 ORANGE(1.0f, 0.49f, 0.22f, 1.0f);
static const float offset = 250.0f; static const float offset = 250.0f;
if (m_roles.empty())
return;
ImGuiWrapper& imgui = *wxGetApp().imgui(); ImGuiWrapper& imgui = *wxGetApp().imgui();
imgui.set_next_window_pos(0.5f * wxGetApp().plater()->get_current_canvas3D()->get_canvas_size().get_width(), 0.0f, ImGuiCond_Once, 0.5f, 0.0f); imgui.set_next_window_pos(0.5f * wxGetApp().plater()->get_current_canvas3D()->get_canvas_size().get_width(), 0.0f, ImGuiCond_Once, 0.5f, 0.0f);

View File

@ -5,11 +5,15 @@
#include "GLShader.hpp" #include "GLShader.hpp"
#include "3DScene.hpp" #include "3DScene.hpp"
#include "libslic3r/GCode/GCodeProcessor.hpp" #include "libslic3r/GCode/GCodeProcessor.hpp"
#include "GLModel.hpp"
#include <float.h> #include <float.h>
namespace Slic3r { namespace Slic3r {
class Print; class Print;
class TriangleMesh;
namespace GUI { namespace GUI {
class GCodeViewer class GCodeViewer
@ -73,19 +77,18 @@ class GCodeViewer
struct IBuffer struct IBuffer
{ {
unsigned int ibo_id{ 0 }; unsigned int ibo_id{ 0 };
size_t indices_count{ 0 };
Shader shader; Shader shader;
std::vector<unsigned int> data;
size_t data_size{ 0 };
std::vector<Path> paths; std::vector<Path> paths;
std::vector<RenderPath> render_paths; std::vector<RenderPath> render_paths;
bool visible{ false }; bool visible{ false };
void reset(); void reset();
bool init_shader(const std::string& vertex_shader_src, const std::string& fragment_shader_src); bool init_shader(const std::string& vertex_shader_src, const std::string& fragment_shader_src);
void add_path(const GCodeProcessor::MoveVertex& move, unsigned int s_id); void add_path(const GCodeProcessor::MoveVertex& move, unsigned int i_id, unsigned int s_id);
}; };
// helper to render shells
struct Shells struct Shells
{ {
GLVolumeCollection volumes; GLVolumeCollection volumes;
@ -148,9 +151,36 @@ class GCodeViewer
struct SequentialView struct SequentialView
{ {
class Marker
{
GL_Model m_model;
Transform3f m_world_transform;
std::array<float, 4> m_color{ 1.0f, 1.0f, 1.0f, 1.0f };
bool m_visible{ false };
Shader m_shader;
public:
void init();
const BoundingBoxf3& get_bounding_box() const { return m_model.get_bounding_box(); }
void set_world_transform(const Transform3f& transform) { m_world_transform = transform; }
void set_color(const std::array<float, 4>& color) { m_color = color; }
bool is_visible() const { return m_visible; }
void set_visible(bool visible) { m_visible = visible; }
void render() const;
private:
void init_shader();
};
unsigned int first{ 0 }; unsigned int first{ 0 };
unsigned int last{ 0 }; unsigned int last{ 0 };
unsigned int current{ 0 }; unsigned int current{ 0 };
Vec3f current_position{ Vec3f::Zero() };
Marker marker;
}; };
#if ENABLE_GCODE_VIEWER_STATISTICS #if ENABLE_GCODE_VIEWER_STATISTICS
@ -237,6 +267,7 @@ public:
bool init() { bool init() {
set_toolpath_move_type_visible(GCodeProcessor::EMoveType::Extrude, true); set_toolpath_move_type_visible(GCodeProcessor::EMoveType::Extrude, true);
m_sequential_view.marker.init();
return init_shaders(); return init_shaders();
} }
@ -285,7 +316,7 @@ private:
void render_toolpaths() const; void render_toolpaths() const;
void render_shells() const; void render_shells() const;
void render_legend() const; void render_legend() const;
void render_sequential_dlg() const; void render_sequential_bar() const;
#if ENABLE_GCODE_VIEWER_STATISTICS #if ENABLE_GCODE_VIEWER_STATISTICS
void render_statistics() const; void render_statistics() const;
#endif // ENABLE_GCODE_VIEWER_STATISTICS #endif // ENABLE_GCODE_VIEWER_STATISTICS

File diff suppressed because it is too large Load Diff

View File

@ -16,9 +16,6 @@
#include "GUI_ObjectLayers.hpp" #include "GUI_ObjectLayers.hpp"
#include "GLSelectionRectangle.hpp" #include "GLSelectionRectangle.hpp"
#include "MeshUtils.hpp" #include "MeshUtils.hpp"
#if !ENABLE_NON_STATIC_CANVAS_MANAGER
#include "Camera.hpp"
#endif // !ENABLE_NON_STATIC_CANVAS_MANAGER
#if ENABLE_GCODE_VIEWER #if ENABLE_GCODE_VIEWER
#include "libslic3r/GCode/GCodeProcessor.hpp" #include "libslic3r/GCode/GCodeProcessor.hpp"
#include "GCodeViewer.hpp" #include "GCodeViewer.hpp"
@ -35,9 +32,7 @@ class wxMouseEvent;
class wxTimerEvent; class wxTimerEvent;
class wxPaintEvent; class wxPaintEvent;
class wxGLCanvas; class wxGLCanvas;
#if ENABLE_NON_STATIC_CANVAS_MANAGER
class wxGLContext; class wxGLContext;
#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
// Support for Retina OpenGL on Mac OS // Support for Retina OpenGL on Mac OS
#define ENABLE_RETINA_GL __APPLE__ #define ENABLE_RETINA_GL __APPLE__
@ -420,6 +415,7 @@ private:
class Slope class Slope
{ {
bool m_enabled{ false }; bool m_enabled{ false };
bool m_dialog_shown{ false };
GLCanvas3D& m_canvas; GLCanvas3D& m_canvas;
GLVolumeCollection& m_volumes; GLVolumeCollection& m_volumes;
@ -428,9 +424,14 @@ private:
void enable(bool enable) { m_enabled = enable; } void enable(bool enable) { m_enabled = enable; }
bool is_enabled() const { return m_enabled; } bool is_enabled() const { return m_enabled; }
void show(bool show) { m_volumes.set_slope_active(m_enabled ? show : false); } void use(bool use) { m_volumes.set_slope_active(m_enabled ? use : false); }
bool is_shown() const { return m_volumes.is_slope_active(); } bool is_used() const { return m_volumes.is_slope_active(); }
void show_dialog(bool show) { if (show && is_used()) return; use(show); m_dialog_shown = show; }
bool is_dialog_shown() const { return m_dialog_shown; }
void render() const; void render() const;
void set_range(const std::array<float, 2>& range) const {
m_volumes.set_slope_z_range({ -::cos(Geometry::deg2rad(90.0f - range[0])), -::cos(Geometry::deg2rad(90.0f - range[1])) });
}
}; };
#endif // ENABLE_SLOPE_RENDERING #endif // ENABLE_SLOPE_RENDERING
@ -453,11 +454,6 @@ private:
#endif // !ENABLE_GCODE_VIEWER #endif // !ENABLE_GCODE_VIEWER
WarningTexture m_warning_texture; WarningTexture m_warning_texture;
wxTimer m_timer; wxTimer m_timer;
#if !ENABLE_NON_STATIC_CANVAS_MANAGER
Bed3D& m_bed;
Camera& m_camera;
GLToolbar& m_view_toolbar;
#endif // !ENABLE_NON_STATIC_CANVAS_MANAGER
LayersEditing m_layers_editing; LayersEditing m_layers_editing;
Shader m_shader; Shader m_shader;
Mouse m_mouse; Mouse m_mouse;
@ -526,22 +522,17 @@ private:
Labels m_labels; Labels m_labels;
#if ENABLE_CANVAS_TOOLTIP_USING_IMGUI #if ENABLE_CANVAS_TOOLTIP_USING_IMGUI
mutable Tooltip m_tooltip; mutable Tooltip m_tooltip;
mutable bool m_tooltip_enabled{ true };
#endif // ENABLE_CANVAS_TOOLTIP_USING_IMGUI #endif // ENABLE_CANVAS_TOOLTIP_USING_IMGUI
#if ENABLE_SLOPE_RENDERING #if ENABLE_SLOPE_RENDERING
Slope m_slope; Slope m_slope;
#endif // ENABLE_SLOPE_RENDERING #endif // ENABLE_SLOPE_RENDERING
public: public:
#if ENABLE_NON_STATIC_CANVAS_MANAGER
explicit GLCanvas3D(wxGLCanvas* canvas); explicit GLCanvas3D(wxGLCanvas* canvas);
#else
GLCanvas3D(wxGLCanvas* canvas, Bed3D& bed, Camera& camera, GLToolbar& view_toolbar);
#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
~GLCanvas3D(); ~GLCanvas3D();
#if ENABLE_NON_STATIC_CANVAS_MANAGER
bool is_initialized() const { return m_initialized; } bool is_initialized() const { return m_initialized; }
#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
void set_context(wxGLContext* context) { m_context = context; } void set_context(wxGLContext* context) { m_context = context; }
@ -593,13 +584,7 @@ public:
void set_color_by(const std::string& value); void set_color_by(const std::string& value);
#if ENABLE_NON_STATIC_CANVAS_MANAGER
void refresh_camera_scene_box(); void refresh_camera_scene_box();
#else
void refresh_camera_scene_box() { m_camera.set_scene_box(scene_bounding_box()); }
const Camera& get_camera() const { return m_camera; }
Camera& get_camera() { return m_camera; }
#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
const Shader& get_shader() const { return m_shader; } const Shader& get_shader() const { return m_shader; }
BoundingBoxf3 volumes_bounding_box() const; BoundingBoxf3 volumes_bounding_box() const;
@ -607,6 +592,7 @@ public:
bool is_layers_editing_enabled() const; bool is_layers_editing_enabled() const;
bool is_layers_editing_allowed() const; bool is_layers_editing_allowed() const;
bool is_search_pressed() const;
void reset_layer_height_profile(); void reset_layer_height_profile();
void adaptive_layer_height_profile(float quality_factor); void adaptive_layer_height_profile(float quality_factor);
@ -662,7 +648,6 @@ public:
void set_toolpaths_z_range(const std::array<double, 2>& range); void set_toolpaths_z_range(const std::array<double, 2>& range);
#else #else
std::vector<double> get_current_print_zs(bool active_only) const; std::vector<double> get_current_print_zs(bool active_only) const;
void set_toolpaths_range(double low, double high);
#endif // ENABLE_GCODE_VIEWER #endif // ENABLE_GCODE_VIEWER
void set_toolpaths_range(double low, double high); void set_toolpaths_range(double low, double high);
@ -694,6 +679,9 @@ public:
void on_timer(wxTimerEvent& evt); void on_timer(wxTimerEvent& evt);
void on_mouse(wxMouseEvent& evt); void on_mouse(wxMouseEvent& evt);
void on_paint(wxPaintEvent& evt); void on_paint(wxPaintEvent& evt);
#if ENABLE_CANVAS_TOOLTIP_USING_IMGUI
void on_set_focus(wxFocusEvent& evt);
#endif // ENABLE_CANVAS_TOOLTIP_USING_IMGUI
Size get_canvas_size() const; Size get_canvas_size() const;
Vec2d get_local_mouse_position() const; Vec2d get_local_mouse_position() const;
@ -719,10 +707,6 @@ public:
void update_ui_from_settings(); void update_ui_from_settings();
#if !ENABLE_NON_STATIC_CANVAS_MANAGER
float get_view_toolbar_height() const { return m_view_toolbar.get_height(); }
#endif // !ENABLE_NON_STATIC_CANVAS_MANAGER
int get_move_volume_id() const { return m_mouse.drag.move_volume_idx; } int get_move_volume_id() const { return m_mouse.drag.move_volume_idx; }
int get_first_hover_volume_idx() const { return m_hover_volume_idxs.empty() ? -1 : m_hover_volume_idxs.front(); } int get_first_hover_volume_idx() const { return m_hover_volume_idxs.empty() ? -1 : m_hover_volume_idxs.front(); }
void set_selected_extruder(int extruder) { m_selected_extruder = extruder;} void set_selected_extruder(int extruder) { m_selected_extruder = extruder;}
@ -765,6 +749,7 @@ public:
int get_main_toolbar_item_id(const std::string& name) const { return m_main_toolbar.get_item_id(name); } int get_main_toolbar_item_id(const std::string& name) const { return m_main_toolbar.get_item_id(name); }
void force_main_toolbar_left_action(int item_id) { m_main_toolbar.force_left_action(item_id, *this); } void force_main_toolbar_left_action(int item_id) { m_main_toolbar.force_left_action(item_id, *this); }
void force_main_toolbar_right_action(int item_id) { m_main_toolbar.force_right_action(item_id, *this); } void force_main_toolbar_right_action(int item_id) { m_main_toolbar.force_right_action(item_id, *this); }
void update_tooltip_for_settings_item_in_main_toolbar();
bool has_toolpaths_to_export() const; bool has_toolpaths_to_export() const;
void export_toolpaths_to_obj(const char* filename) const; void export_toolpaths_to_obj(const char* filename) const;
@ -775,8 +760,10 @@ public:
void show_labels(bool show) { m_labels.show(show); } void show_labels(bool show) { m_labels.show(show); }
#if ENABLE_SLOPE_RENDERING #if ENABLE_SLOPE_RENDERING
bool is_slope_shown() const { return m_slope.is_shown(); } bool is_slope_shown() const { return m_slope.is_dialog_shown(); }
void show_slope(bool show) { m_slope.show(show); } void use_slope(bool use) { m_slope.use(use); }
void show_slope(bool show) { m_slope.show_dialog(show); }
void set_slope_range(const std::array<float, 2>& range) { m_slope.set_range(range); }
#endif // ENABLE_SLOPE_RENDERING #endif // ENABLE_SLOPE_RENDERING
private: private:
@ -810,6 +797,7 @@ private:
#if ENABLE_RENDER_SELECTION_CENTER #if ENABLE_RENDER_SELECTION_CENTER
void _render_selection_center() const; void _render_selection_center() const;
#endif // ENABLE_RENDER_SELECTION_CENTER #endif // ENABLE_RENDER_SELECTION_CENTER
void _check_and_update_toolbar_icon_scale() const;
void _render_overlays() const; void _render_overlays() const;
void _render_warning_texture() const; void _render_warning_texture() const;
#if !ENABLE_GCODE_VIEWER #if !ENABLE_GCODE_VIEWER
@ -872,8 +860,10 @@ private:
#endif // !ENABLE_GCODE_VIEWER #endif // !ENABLE_GCODE_VIEWER
// Load SLA objects and support structures for objects, for which the slaposSliceSupports step has been finished. // Load SLA objects and support structures for objects, for which the slaposSliceSupports step has been finished.
void _load_sla_shells(); void _load_sla_shells();
#if !ENABLE_GCODE_VIEWER
// sets gcode geometry visibility according to user selection // sets gcode geometry visibility according to user selection
void _update_gcode_volumes_visibility(const GCodePreviewData& preview_data); void _update_gcode_volumes_visibility(const GCodePreviewData& preview_data);
#endif // !ENABLE_GCODE_VIEWER
void _update_toolpath_volumes_outside_state(); void _update_toolpath_volumes_outside_state();
void _update_sla_shells_outside_state(); void _update_sla_shells_outside_state();
void _show_warning_texture_if_needed(WarningTexture::Warning warning); void _show_warning_texture_if_needed(WarningTexture::Warning warning);

View File

@ -1,211 +0,0 @@
#ifndef slic3r_GLCanvas3DManager_hpp_
#define slic3r_GLCanvas3DManager_hpp_
#include "libslic3r/BoundingBox.hpp"
#include <map>
#include <vector>
class wxWindow;
class wxGLCanvas;
class wxGLContext;
namespace Slic3r {
class BackgroundSlicingProcess;
class DynamicPrintConfig;
class Model;
class ExPolygon;
typedef std::vector<ExPolygon> ExPolygons;
class ModelObject;
class PrintObject;
namespace GUI {
class GLCanvas3D;
#if !ENABLE_NON_STATIC_CANVAS_MANAGER
class Bed3D;
class GLToolbar;
struct Camera;
#endif // !ENABLE_NON_STATIC_CANVAS_MANAGER
class GLCanvas3DManager
{
public:
#if ENABLE_NON_STATIC_CANVAS_MANAGER
enum class EFramebufferType : unsigned char
{
Unknown,
Arb,
Ext
};
#else
enum EFramebufferType : unsigned char
{
FB_None,
FB_Arb,
FB_Ext
};
#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
class GLInfo
{
#if ENABLE_NON_STATIC_CANVAS_MANAGER
mutable bool m_detected{ false };
mutable int m_max_tex_size{ 0 };
mutable float m_max_anisotropy{ 0.0f };
mutable std::string m_version;
mutable std::string m_glsl_version;
mutable std::string m_vendor;
mutable std::string m_renderer;
#else
mutable bool m_detected;
mutable std::string m_version;
mutable std::string m_glsl_version;
mutable std::string m_vendor;
mutable std::string m_renderer;
mutable int m_max_tex_size;
mutable float m_max_anisotropy;
#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
public:
#if ENABLE_NON_STATIC_CANVAS_MANAGER
GLInfo() = default;
#else
GLInfo();
#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
const std::string& get_version() const;
const std::string& get_glsl_version() const;
const std::string& get_vendor() const;
const std::string& get_renderer() const;
int get_max_tex_size() const;
float get_max_anisotropy() const;
bool is_version_greater_or_equal_to(unsigned int major, unsigned int minor) const;
std::string to_string(bool format_as_html, bool extensions) const;
private:
void detect() const;
};
#if ENABLE_HACK_CLOSING_ON_OSX_10_9_5
#ifdef __APPLE__
// Part of hack to remove crash when closing the application on OSX 10.9.5 when building against newer wxWidgets
struct OSInfo
{
int major{ 0 };
int minor{ 0 };
int micro{ 0 };
};
#endif //__APPLE__
#endif // ENABLE_HACK_CLOSING_ON_OSX_10_9_5
private:
#if ENABLE_NON_STATIC_CANVAS_MANAGER
enum class EMultisampleState : unsigned char
{
Unknown,
Enabled,
Disabled
};
#else
enum EMultisampleState : unsigned char
{
MS_Unknown,
MS_Enabled,
MS_Disabled
};
typedef std::map<wxGLCanvas*, GLCanvas3D*> CanvasesMap;
#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
#if ENABLE_NON_STATIC_CANVAS_MANAGER
bool m_gl_initialized{ false };
wxGLContext* m_context{ nullptr };
#else
wxGLContext* m_context;
bool m_gl_initialized;
CanvasesMap m_canvases;
#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
static GLInfo s_gl_info;
#if ENABLE_HACK_CLOSING_ON_OSX_10_9_5
#ifdef __APPLE__
// Part of hack to remove crash when closing the application on OSX 10.9.5 when building against newer wxWidgets
static OSInfo s_os_info;
#endif //__APPLE__
#endif // ENABLE_HACK_CLOSING_ON_OSX_10_9_5
static bool s_compressed_textures_supported;
static EMultisampleState s_multisample;
static EFramebufferType s_framebuffers_type;
public:
#if ENABLE_NON_STATIC_CANVAS_MANAGER
GLCanvas3DManager() = default;
#else
GLCanvas3DManager();
#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
~GLCanvas3DManager();
#if !ENABLE_NON_STATIC_CANVAS_MANAGER
bool add(wxGLCanvas* canvas, Bed3D& bed, Camera& camera, GLToolbar& view_toolbar);
bool remove(wxGLCanvas* canvas);
void remove_all();
size_t count() const;
#endif // !ENABLE_NON_STATIC_CANVAS_MANAGER
#if ENABLE_NON_STATIC_CANVAS_MANAGER
bool init_gl();
#else
void init_gl();
#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
#if ENABLE_NON_STATIC_CANVAS_MANAGER
wxGLContext* init_glcontext(wxGLCanvas& canvas);
#else
bool init(wxGLCanvas* canvas);
void destroy();
#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
#if !ENABLE_NON_STATIC_CANVAS_MANAGER
GLCanvas3D* get_canvas(wxGLCanvas* canvas);
#endif // !ENABLE_NON_STATIC_CANVAS_MANAGER
static bool are_compressed_textures_supported() { return s_compressed_textures_supported; }
#if ENABLE_NON_STATIC_CANVAS_MANAGER
static bool can_multisample() { return s_multisample == EMultisampleState::Enabled; }
static bool are_framebuffers_supported() { return (s_framebuffers_type != EFramebufferType::Unknown); }
#else
static bool can_multisample() { return s_multisample == MS_Enabled; }
static bool are_framebuffers_supported() { return (s_framebuffers_type != FB_None); }
#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
static EFramebufferType get_framebuffers_type() { return s_framebuffers_type; }
#if ENABLE_NON_STATIC_CANVAS_MANAGER
static wxGLCanvas* create_wxglcanvas(wxWindow& parent);
#else
static wxGLCanvas* create_wxglcanvas(wxWindow *parent);
#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
static const GLInfo& get_gl_info() { return s_gl_info; }
private:
#if !ENABLE_NON_STATIC_CANVAS_MANAGER
CanvasesMap::iterator do_get_canvas(wxGLCanvas* canvas);
CanvasesMap::const_iterator do_get_canvas(wxGLCanvas* canvas) const;
bool init(GLCanvas3D& canvas);
#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
static void detect_multisample(int* attribList);
};
} // namespace GUI
} // namespace Slic3r
#endif // slic3r_GLCanvas3DManager_hpp_

508
src/slic3r/GUI/GLModel.cpp Normal file
View File

@ -0,0 +1,508 @@
#include "libslic3r/libslic3r.h"
#include "GLModel.hpp"
#include "3DScene.hpp"
#include "libslic3r/TriangleMesh.hpp"
#include <GL/glew.h>
namespace Slic3r {
namespace GUI {
void GL_Model::init_from(const GLModelInitializationData& data)
{
assert(!data.positions.empty() && !data.triangles.empty());
assert(data.positions.size() == data.normals.size());
if (m_vbo_id > 0) // call reset() if you want to reuse this model
return;
// vertices/normals data
std::vector<float> vertices(6 * data.positions.size());
for (size_t i = 0; i < data.positions.size(); ++i) {
::memcpy(static_cast<void*>(&vertices[i * 6]), static_cast<const void*>(data.positions[i].data()), 3 * sizeof(float));
::memcpy(static_cast<void*>(&vertices[3 + i * 6]), static_cast<const void*>(data.normals[i].data()), 3 * sizeof(float));
}
// indices data
std::vector<unsigned int> indices(3 * data.triangles.size());
for (size_t i = 0; i < data.triangles.size(); ++i) {
for (size_t j = 0; j < 3; ++j) {
indices[i * 3 + j] = static_cast<unsigned int>(data.triangles[i][j]);
}
}
m_indices_count = static_cast<unsigned int>(indices.size());
m_bounding_box = BoundingBoxf3();
for (size_t i = 0; i < data.positions.size(); ++i) {
m_bounding_box.merge(data.positions[i].cast<double>());
}
send_to_gpu(vertices, indices);
}
void GL_Model::init_from(const TriangleMesh& mesh)
{
auto get_normal = [](const std::array<stl_vertex, 3>& triangle) {
return (triangle[1] - triangle[0]).cross(triangle[2] - triangle[0]).normalized();
};
if (m_vbo_id > 0) // call reset() if you want to reuse this model
return;
assert(!mesh.its.vertices.empty() && !mesh.its.indices.empty()); // call require_shared_vertices() before to pass the mesh to this method
// vertices data -> load from mesh
std::vector<float> vertices(6 * mesh.its.vertices.size());
for (size_t i = 0; i < mesh.its.vertices.size(); ++i) {
::memcpy(static_cast<void*>(&vertices[i * 6]), static_cast<const void*>(mesh.its.vertices[i].data()), 3 * sizeof(float));
}
// indices/normals data -> load from mesh
std::vector<unsigned int> indices(3 * mesh.its.indices.size());
for (size_t i = 0; i < mesh.its.indices.size(); ++i) {
const stl_triangle_vertex_indices& triangle = mesh.its.indices[i];
for (size_t j = 0; j < 3; ++j) {
indices[i * 3 + j] = static_cast<unsigned int>(triangle[j]);
}
Vec3f normal = get_normal({ mesh.its.vertices[triangle[0]], mesh.its.vertices[triangle[1]], mesh.its.vertices[triangle[2]] });
::memcpy(static_cast<void*>(&vertices[3 + static_cast<size_t>(triangle[0]) * 6]), static_cast<const void*>(normal.data()), 3 * sizeof(float));
::memcpy(static_cast<void*>(&vertices[3 + static_cast<size_t>(triangle[1]) * 6]), static_cast<const void*>(normal.data()), 3 * sizeof(float));
::memcpy(static_cast<void*>(&vertices[3 + static_cast<size_t>(triangle[2]) * 6]), static_cast<const void*>(normal.data()), 3 * sizeof(float));
}
m_indices_count = static_cast<unsigned int>(indices.size());
m_bounding_box = mesh.bounding_box();
send_to_gpu(vertices, indices);
}
void GL_Model::reset()
{
// release gpu memory
if (m_ibo_id > 0) {
glsafe(::glDeleteBuffers(1, &m_ibo_id));
m_ibo_id = 0;
}
if (m_vbo_id > 0) {
glsafe(::glDeleteBuffers(1, &m_vbo_id));
m_vbo_id = 0;
}
m_indices_count = 0;
m_bounding_box = BoundingBoxf3();
}
void GL_Model::render() const
{
if (m_vbo_id == 0 || m_ibo_id == 0)
return;
glsafe(::glBindBuffer(GL_ARRAY_BUFFER, m_vbo_id));
glsafe(::glVertexPointer(3, GL_FLOAT, 6 * sizeof(float), (const void*)0));
glsafe(::glNormalPointer(GL_FLOAT, 6 * sizeof(float), (const void*)(3 * sizeof(float))));
glsafe(::glEnableClientState(GL_VERTEX_ARRAY));
glsafe(::glEnableClientState(GL_NORMAL_ARRAY));
glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_ibo_id));
glsafe(::glDrawElements(GL_TRIANGLES, static_cast<GLsizei>(m_indices_count), GL_UNSIGNED_INT, (const void*)0));
glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0));
glsafe(::glDisableClientState(GL_NORMAL_ARRAY));
glsafe(::glDisableClientState(GL_VERTEX_ARRAY));
glsafe(::glBindBuffer(GL_ARRAY_BUFFER, 0));
}
void GL_Model::send_to_gpu(const std::vector<float>& vertices, const std::vector<unsigned int>& indices)
{
// vertex data -> send to gpu
glsafe(::glGenBuffers(1, &m_vbo_id));
glsafe(::glBindBuffer(GL_ARRAY_BUFFER, m_vbo_id));
glsafe(::glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(float), vertices.data(), GL_STATIC_DRAW));
glsafe(::glBindBuffer(GL_ARRAY_BUFFER, 0));
// indices data -> send to gpu
glsafe(::glGenBuffers(1, &m_ibo_id));
glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_ibo_id));
glsafe(::glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size() * sizeof(unsigned int), indices.data(), GL_STATIC_DRAW));
glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0));
}
GLModelInitializationData stilized_arrow(int resolution, float tip_radius, float tip_height, float stem_radius, float stem_height)
{
auto append_vertex = [](GLModelInitializationData& data, const Vec3f& position, const Vec3f& normal) {
data.positions.emplace_back(position);
data.normals.emplace_back(normal);
};
resolution = std::max(4, resolution);
GLModelInitializationData data;
const float angle_step = 2.0f * M_PI / static_cast<float>(resolution);
std::vector<float> cosines(resolution);
std::vector<float> sines(resolution);
for (int i = 0; i < resolution; ++i)
{
float angle = angle_step * static_cast<float>(i);
cosines[i] = ::cos(angle);
sines[i] = -::sin(angle);
}
const float total_height = tip_height + stem_height;
// tip vertices/normals
append_vertex(data, { 0.0f, 0.0f, total_height }, Vec3f::UnitZ());
for (int i = 0; i < resolution; ++i)
{
append_vertex(data, { tip_radius * sines[i], tip_radius * cosines[i], stem_height }, { sines[i], cosines[i], 0.0f });
}
// tip triangles
for (int i = 0; i < resolution; ++i)
{
int v3 = (i < resolution - 1) ? i + 2 : 1;
data.triangles.emplace_back(0, i + 1, v3);
}
// tip cap outer perimeter vertices
for (int i = 0; i < resolution; ++i)
{
append_vertex(data, { tip_radius * sines[i], tip_radius * cosines[i], stem_height }, -Vec3f::UnitZ());
}
// tip cap inner perimeter vertices
for (int i = 0; i < resolution; ++i)
{
append_vertex(data, { stem_radius * sines[i], stem_radius * cosines[i], stem_height }, -Vec3f::UnitZ());
}
// tip cap triangles
for (int i = 0; i < resolution; ++i)
{
int v2 = (i < resolution - 1) ? i + resolution + 2 : resolution + 1;
int v3 = (i < resolution - 1) ? i + 2 * resolution + 2 : 2 * resolution + 1;
data.triangles.emplace_back(i + resolution + 1, v3, v2);
data.triangles.emplace_back(i + resolution + 1, i + 2 * resolution + 1, v3);
}
// stem bottom vertices
for (int i = 0; i < resolution; ++i)
{
append_vertex(data, { stem_radius * sines[i], stem_radius * cosines[i], stem_height }, { sines[i], cosines[i], 0.0f });
}
// stem top vertices
for (int i = 0; i < resolution; ++i)
{
append_vertex(data, { stem_radius * sines[i], stem_radius * cosines[i], 0.0f }, { sines[i], cosines[i], 0.0f });
}
// stem triangles
for (int i = 0; i < resolution; ++i)
{
int v2 = (i < resolution - 1) ? i + 3 * resolution + 2 : 3 * resolution + 1;
int v3 = (i < resolution - 1) ? i + 4 * resolution + 2 : 4 * resolution + 1;
data.triangles.emplace_back(i + 3 * resolution + 1, v3, v2);
data.triangles.emplace_back(i + 3 * resolution + 1, i + 4 * resolution + 1, v3);
}
// stem cap vertices
append_vertex(data, Vec3f::Zero(), -Vec3f::UnitZ());
for (int i = 0; i < resolution; ++i)
{
append_vertex(data, { stem_radius * sines[i], stem_radius * cosines[i], 0.0f }, -Vec3f::UnitZ());
}
// stem cap triangles
for (int i = 0; i < resolution; ++i)
{
int v3 = (i < resolution - 1) ? i + 5 * resolution + 3 : 5 * resolution + 2;
data.triangles.emplace_back(5 * resolution + 1, v3, i + 5 * resolution + 2);
}
return data;
}
GLModelInitializationData circular_arrow(int resolution, float radius, float tip_height, float tip_width, float stem_width, float thickness)
{
auto append_vertex = [](GLModelInitializationData& data, const Vec3f& position, const Vec3f& normal) {
data.positions.emplace_back(position);
data.normals.emplace_back(normal);
};
resolution = std::max(2, resolution);
GLModelInitializationData data;
const float half_thickness = 0.5f * thickness;
const float half_stem_width = 0.5f * stem_width;
const float half_tip_width = 0.5f * tip_width;
const float outer_radius = radius + half_stem_width;
const float inner_radius = radius - half_stem_width;
const float step_angle = 0.5f * PI / static_cast<float>(resolution);
// tip
// top face vertices
append_vertex(data, { 0.0f, outer_radius, half_thickness }, Vec3f::UnitZ());
append_vertex(data, { 0.0f, radius + half_tip_width, half_thickness }, Vec3f::UnitZ());
append_vertex(data, { -tip_height, radius, half_thickness }, Vec3f::UnitZ());
append_vertex(data, { 0.0f, radius - half_tip_width, half_thickness }, Vec3f::UnitZ());
append_vertex(data, { 0.0f, inner_radius, half_thickness }, Vec3f::UnitZ());
// top face triangles
data.triangles.emplace_back(0, 1, 2);
data.triangles.emplace_back(0, 2, 4);
data.triangles.emplace_back(4, 2, 3);
// bottom face vertices
append_vertex(data, { 0.0f, outer_radius, -half_thickness }, -Vec3f::UnitZ());
append_vertex(data, { 0.0f, radius + half_tip_width, -half_thickness }, -Vec3f::UnitZ());
append_vertex(data, { -tip_height, radius, -half_thickness }, -Vec3f::UnitZ());
append_vertex(data, { 0.0f, radius - half_tip_width, -half_thickness }, -Vec3f::UnitZ());
append_vertex(data, { 0.0f, inner_radius, -half_thickness }, -Vec3f::UnitZ());
// bottom face triangles
data.triangles.emplace_back(5, 7, 6);
data.triangles.emplace_back(5, 9, 7);
data.triangles.emplace_back(9, 8, 7);
// side faces vertices
append_vertex(data, { 0.0f, outer_radius, -half_thickness }, Vec3f::UnitX());
append_vertex(data, { 0.0f, radius + half_tip_width, -half_thickness }, Vec3f::UnitX());
append_vertex(data, { 0.0f, outer_radius, half_thickness }, Vec3f::UnitX());
append_vertex(data, { 0.0f, radius + half_tip_width, half_thickness }, Vec3f::UnitX());
Vec3f normal(-half_tip_width, tip_height, 0.0f);
normal.normalize();
append_vertex(data, { 0.0f, radius + half_tip_width, -half_thickness }, normal);
append_vertex(data, { -tip_height, radius, -half_thickness }, normal);
append_vertex(data, { 0.0f, radius + half_tip_width, half_thickness }, normal);
append_vertex(data, { -tip_height, radius, half_thickness }, normal);
normal = Vec3f(-half_tip_width, -tip_height, 0.0f);
normal.normalize();
append_vertex(data, { -tip_height, radius, -half_thickness }, normal);
append_vertex(data, { 0.0f, radius - half_tip_width, -half_thickness }, normal);
append_vertex(data, { -tip_height, radius, half_thickness }, normal);
append_vertex(data, { 0.0f, radius - half_tip_width, half_thickness }, normal);
append_vertex(data, { 0.0f, radius - half_tip_width, -half_thickness }, Vec3f::UnitX());
append_vertex(data, { 0.0f, inner_radius, -half_thickness }, Vec3f::UnitX());
append_vertex(data, { 0.0f, radius - half_tip_width, half_thickness }, Vec3f::UnitX());
append_vertex(data, { 0.0f, inner_radius, half_thickness }, Vec3f::UnitX());
// side face triangles
for (int i = 0; i < 4; ++i)
{
int ii = i * 4;
data.triangles.emplace_back(10 + ii, 11 + ii, 13 + ii);
data.triangles.emplace_back(10 + ii, 13 + ii, 12 + ii);
}
// stem
// top face vertices
for (int i = 0; i <= resolution; ++i)
{
float angle = static_cast<float>(i) * step_angle;
append_vertex(data, { inner_radius * ::sin(angle), inner_radius * ::cos(angle), half_thickness }, Vec3f::UnitZ());
}
for (int i = 0; i <= resolution; ++i)
{
float angle = static_cast<float>(i) * step_angle;
append_vertex(data, { outer_radius * ::sin(angle), outer_radius * ::cos(angle), half_thickness }, Vec3f::UnitZ());
}
// top face triangles
for (int i = 0; i < resolution; ++i)
{
data.triangles.emplace_back(26 + i, 27 + i, 27 + resolution + i);
data.triangles.emplace_back(27 + i, 28 + resolution + i, 27 + resolution + i);
}
// bottom face vertices
for (int i = 0; i <= resolution; ++i)
{
float angle = static_cast<float>(i) * step_angle;
append_vertex(data, { inner_radius * ::sin(angle), inner_radius * ::cos(angle), -half_thickness }, -Vec3f::UnitZ());
}
for (int i = 0; i <= resolution; ++i)
{
float angle = static_cast<float>(i) * step_angle;
append_vertex(data, { outer_radius * ::sin(angle), outer_radius * ::cos(angle), -half_thickness }, -Vec3f::UnitZ());
}
// bottom face triangles
for (int i = 0; i < resolution; ++i)
{
data.triangles.emplace_back(28 + 2 * resolution + i, 29 + 3 * resolution + i, 29 + 2 * resolution + i);
data.triangles.emplace_back(29 + 2 * resolution + i, 29 + 3 * resolution + i, 30 + 3 * resolution + i);
}
// side faces vertices and triangles
for (int i = 0; i <= resolution; ++i)
{
float angle = static_cast<float>(i) * step_angle;
float c = ::cos(angle);
float s = ::sin(angle);
append_vertex(data, { inner_radius * s, inner_radius * c, -half_thickness }, { -s, -c, 0.0f });
}
for (int i = 0; i <= resolution; ++i)
{
float angle = static_cast<float>(i) * step_angle;
float c = ::cos(angle);
float s = ::sin(angle);
append_vertex(data, { inner_radius * s, inner_radius * c, half_thickness }, { -s, -c, 0.0f });
}
int first_id = 26 + 4 * (resolution + 1);
for (int i = 0; i < resolution; ++i)
{
int ii = first_id + i;
data.triangles.emplace_back(ii, ii + 1, ii + resolution + 2);
data.triangles.emplace_back(ii, ii + resolution + 2, ii + resolution + 1);
}
append_vertex(data, { inner_radius, 0.0f, -half_thickness }, -Vec3f::UnitY());
append_vertex(data, { outer_radius, 0.0f, -half_thickness }, -Vec3f::UnitY());
append_vertex(data, { inner_radius, 0.0f, half_thickness }, -Vec3f::UnitY());
append_vertex(data, { outer_radius, 0.0f, half_thickness }, -Vec3f::UnitY());
first_id = 26 + 6 * (resolution + 1);
data.triangles.emplace_back(first_id, first_id + 1, first_id + 3);
data.triangles.emplace_back(first_id, first_id + 3, first_id + 2);
for (int i = resolution; i >= 0; --i)
{
float angle = static_cast<float>(i) * step_angle;
float c = ::cos(angle);
float s = ::sin(angle);
append_vertex(data, { outer_radius * s, outer_radius * c, -half_thickness }, { s, c, 0.0f });
}
for (int i = resolution; i >= 0; --i)
{
float angle = static_cast<float>(i) * step_angle;
float c = ::cos(angle);
float s = ::sin(angle);
append_vertex(data, { outer_radius * s, outer_radius * c, +half_thickness }, { s, c, 0.0f });
}
first_id = 30 + 6 * (resolution + 1);
for (int i = 0; i < resolution; ++i)
{
int ii = first_id + i;
data.triangles.emplace_back(ii, ii + 1, ii + resolution + 2);
data.triangles.emplace_back(ii, ii + resolution + 2, ii + resolution + 1);
}
return data;
}
GLModelInitializationData straight_arrow(float tip_width, float tip_height, float stem_width, float stem_height, float thickness)
{
auto append_vertex = [](GLModelInitializationData& data, const Vec3f& position, const Vec3f& normal) {
data.positions.emplace_back(position);
data.normals.emplace_back(normal);
};
GLModelInitializationData data;
const float half_thickness = 0.5f * thickness;
const float half_stem_width = 0.5f * stem_width;
const float half_tip_width = 0.5f * tip_width;
const float total_height = tip_height + stem_height;
// top face vertices
append_vertex(data, { half_stem_width, 0.0, half_thickness }, Vec3f::UnitZ());
append_vertex(data, { half_stem_width, stem_height, half_thickness }, Vec3f::UnitZ());
append_vertex(data, { half_tip_width, stem_height, half_thickness }, Vec3f::UnitZ());
append_vertex(data, { 0.0, total_height, half_thickness }, Vec3f::UnitZ());
append_vertex(data, { -half_tip_width, stem_height, half_thickness }, Vec3f::UnitZ());
append_vertex(data, { -half_stem_width, stem_height, half_thickness }, Vec3f::UnitZ());
append_vertex(data, { -half_stem_width, 0.0, half_thickness }, Vec3f::UnitZ());
// top face triangles
data.triangles.emplace_back(0, 1, 6);
data.triangles.emplace_back(6, 1, 5);
data.triangles.emplace_back(4, 5, 3);
data.triangles.emplace_back(5, 1, 3);
data.triangles.emplace_back(1, 2, 3);
// bottom face vertices
append_vertex(data, { half_stem_width, 0.0, -half_thickness }, -Vec3f::UnitZ());
append_vertex(data, { half_stem_width, stem_height, -half_thickness }, -Vec3f::UnitZ());
append_vertex(data, { half_tip_width, stem_height, -half_thickness }, -Vec3f::UnitZ());
append_vertex(data, { 0.0, total_height, -half_thickness }, -Vec3f::UnitZ());
append_vertex(data, { -half_tip_width, stem_height, -half_thickness }, -Vec3f::UnitZ());
append_vertex(data, { -half_stem_width, stem_height, -half_thickness }, -Vec3f::UnitZ());
append_vertex(data, { -half_stem_width, 0.0, -half_thickness }, -Vec3f::UnitZ());
// bottom face triangles
data.triangles.emplace_back(7, 13, 8);
data.triangles.emplace_back(13, 12, 8);
data.triangles.emplace_back(12, 11, 10);
data.triangles.emplace_back(8, 12, 10);
data.triangles.emplace_back(9, 8, 10);
// side faces vertices
append_vertex(data, { half_stem_width, 0.0, -half_thickness }, Vec3f::UnitX());
append_vertex(data, { half_stem_width, stem_height, -half_thickness }, Vec3f::UnitX());
append_vertex(data, { half_stem_width, 0.0, half_thickness }, Vec3f::UnitX());
append_vertex(data, { half_stem_width, stem_height, half_thickness }, Vec3f::UnitX());
append_vertex(data, { half_stem_width, stem_height, -half_thickness }, -Vec3f::UnitY());
append_vertex(data, { half_tip_width, stem_height, -half_thickness }, -Vec3f::UnitY());
append_vertex(data, { half_stem_width, stem_height, half_thickness }, -Vec3f::UnitY());
append_vertex(data, { half_tip_width, stem_height, half_thickness }, -Vec3f::UnitY());
Vec3f normal(tip_height, half_tip_width, 0.0f);
normal.normalize();
append_vertex(data, { half_tip_width, stem_height, -half_thickness }, normal);
append_vertex(data, { 0.0, total_height, -half_thickness }, normal);
append_vertex(data, { half_tip_width, stem_height, half_thickness }, normal);
append_vertex(data, { 0.0, total_height, half_thickness }, normal);
normal = Vec3f(-tip_height, half_tip_width, 0.0f);
normal.normalize();
append_vertex(data, { 0.0, total_height, -half_thickness }, normal);
append_vertex(data, { -half_tip_width, stem_height, -half_thickness }, normal);
append_vertex(data, { 0.0, total_height, half_thickness }, normal);
append_vertex(data, { -half_tip_width, stem_height, half_thickness }, normal);
append_vertex(data, { -half_tip_width, stem_height, -half_thickness }, -Vec3f::UnitY());
append_vertex(data, { -half_stem_width, stem_height, -half_thickness }, -Vec3f::UnitY());
append_vertex(data, { -half_tip_width, stem_height, half_thickness }, -Vec3f::UnitY());
append_vertex(data, { -half_stem_width, stem_height, half_thickness }, -Vec3f::UnitY());
append_vertex(data, { -half_stem_width, stem_height, -half_thickness }, -Vec3f::UnitX());
append_vertex(data, { -half_stem_width, 0.0, -half_thickness }, -Vec3f::UnitX());
append_vertex(data, { -half_stem_width, stem_height, half_thickness }, -Vec3f::UnitX());
append_vertex(data, { -half_stem_width, 0.0, half_thickness }, -Vec3f::UnitX());
append_vertex(data, { -half_stem_width, 0.0, -half_thickness }, -Vec3f::UnitY());
append_vertex(data, { half_stem_width, 0.0, -half_thickness }, -Vec3f::UnitY());
append_vertex(data, { -half_stem_width, 0.0, half_thickness }, -Vec3f::UnitY());
append_vertex(data, { half_stem_width, 0.0, half_thickness }, -Vec3f::UnitY());
// side face triangles
for (int i = 0; i < 7; ++i)
{
int ii = i * 4;
data.triangles.emplace_back(14 + ii, 15 + ii, 17 + ii);
data.triangles.emplace_back(14 + ii, 17 + ii, 16 + ii);
}
return data;
}
} // namespace GUI
} // namespace Slic3r

View File

@ -0,0 +1,64 @@
#ifndef slic3r_GLModel_hpp_
#define slic3r_GLModel_hpp_
#include "libslic3r/Point.hpp"
#include "libslic3r/BoundingBox.hpp"
#include <vector>
namespace Slic3r {
class TriangleMesh;
namespace GUI {
struct GLModelInitializationData
{
std::vector<Vec3f> positions;
std::vector<Vec3f> normals;
std::vector<Vec3i> triangles;
};
class GL_Model
{
unsigned int m_vbo_id{ 0 };
unsigned int m_ibo_id{ 0 };
size_t m_indices_count{ 0 };
BoundingBoxf3 m_bounding_box;
public:
virtual ~GL_Model() { reset(); }
void init_from(const GLModelInitializationData& data);
void init_from(const TriangleMesh& mesh);
void reset();
void render() const;
const BoundingBoxf3& get_bounding_box() const { return m_bounding_box; }
private:
void send_to_gpu(const std::vector<float>& vertices, const std::vector<unsigned int>& indices);
};
// create an arrow with cylindrical stem and conical tip, with the given dimensions and resolution
// the origin of the arrow is in the center of the stem cap
// the arrow has its axis of symmetry along the Z axis and is pointing upward
GLModelInitializationData stilized_arrow(int resolution, float tip_radius, float tip_height,
float stem_radius, float stem_height);
// create an arrow whose stem is a quarter of circle, with the given dimensions and resolution
// the origin of the arrow is in the center of the circle
// the arrow is contained in the 1st quadrant of the XY plane and is pointing counterclockwise
GLModelInitializationData circular_arrow(int resolution, float radius, float tip_height, float tip_width, float stem_width, float thickness);
// create an arrow with the given dimensions
// the origin of the arrow is in the center of the stem cap
// the arrow is contained in XY plane and has its main axis along the Y axis
GLModelInitializationData straight_arrow(float tip_width, float tip_height, float stem_width, float stem_height, float thickness);
} // namespace GUI
} // namespace Slic3r
#endif // slic3r_GLModel_hpp_

View File

@ -2,9 +2,7 @@
#include "Camera.hpp" #include "Camera.hpp"
#include "3DScene.hpp" #include "3DScene.hpp"
#include "GLCanvas3D.hpp" #include "GLCanvas3D.hpp"
#if ENABLE_NON_STATIC_CANVAS_MANAGER
#include "GUI_App.hpp" #include "GUI_App.hpp"
#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
#include <GL/glew.h> #include <GL/glew.h>
@ -38,11 +36,7 @@ namespace GUI {
m_state = Off; m_state = Off;
#if ENABLE_NON_STATIC_CANVAS_MANAGER
const Camera& camera = wxGetApp().plater()->get_camera(); const Camera& camera = wxGetApp().plater()->get_camera();
#else
const Camera& camera = canvas.get_camera();
#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
const std::array<int, 4>& viewport = camera.get_viewport(); const std::array<int, 4>& viewport = camera.get_viewport();
const Transform3d& modelview_matrix = camera.get_view_matrix(); const Transform3d& modelview_matrix = camera.get_view_matrix();
const Transform3d& projection_matrix = camera.get_projection_matrix(); const Transform3d& projection_matrix = camera.get_projection_matrix();
@ -75,11 +69,7 @@ namespace GUI {
if (!is_dragging()) if (!is_dragging())
return; return;
#if ENABLE_NON_STATIC_CANVAS_MANAGER
const Camera& camera = wxGetApp().plater()->get_camera(); const Camera& camera = wxGetApp().plater()->get_camera();
#else
const Camera& camera = canvas.get_camera();
#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
float inv_zoom = (float)camera.get_inv_zoom(); float inv_zoom = (float)camera.get_inv_zoom();
Size cnv_size = canvas.get_canvas_size(); Size cnv_size = canvas.get_canvas_size();

View File

@ -2,9 +2,7 @@
#include "GLTexture.hpp" #include "GLTexture.hpp"
#include "3DScene.hpp" #include "3DScene.hpp"
#if ENABLE_NON_STATIC_CANVAS_MANAGER #include "OpenGLManager.hpp"
#include "GLCanvas3DManager.hpp"
#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
#include <GL/glew.h> #include <GL/glew.h>
@ -443,7 +441,7 @@ bool GLTexture::load_from_png(const std::string& filename, bool use_mipmaps, ECo
if (apply_anisotropy) if (apply_anisotropy)
{ {
GLfloat max_anisotropy = GLCanvas3DManager::get_gl_info().get_max_anisotropy(); GLfloat max_anisotropy = OpenGLManager::get_gl_info().get_max_anisotropy();
if (max_anisotropy > 1.0f) if (max_anisotropy > 1.0f)
glsafe(::glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, max_anisotropy)); glsafe(::glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, max_anisotropy));
} }
@ -592,7 +590,7 @@ bool GLTexture::load_from_svg(const std::string& filename, bool use_mipmaps, boo
if (apply_anisotropy) if (apply_anisotropy)
{ {
GLfloat max_anisotropy = GLCanvas3DManager::get_gl_info().get_max_anisotropy(); GLfloat max_anisotropy = OpenGLManager::get_gl_info().get_max_anisotropy();
if (max_anisotropy > 1.0f) if (max_anisotropy > 1.0f)
glsafe(::glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, max_anisotropy)); glsafe(::glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, max_anisotropy));
} }

View File

@ -3,14 +3,9 @@
#include "GLToolbar.hpp" #include "GLToolbar.hpp"
#if ENABLE_NON_STATIC_CANVAS_MANAGER
#include "slic3r/GUI/GLCanvas3D.hpp" #include "slic3r/GUI/GLCanvas3D.hpp"
#include "slic3r/GUI/GUI_App.hpp" #include "slic3r/GUI/GUI_App.hpp"
#include "slic3r/GUI/Camera.hpp" #include "slic3r/GUI/Camera.hpp"
#else
#include "../../slic3r/GUI/GLCanvas3D.hpp"
#include "../../slic3r/GUI/Camera.hpp"
#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
#include <wx/event.h> #include <wx/event.h>
#include <wx/bitmap.h> #include <wx/bitmap.h>
@ -252,7 +247,7 @@ bool GLToolbar::is_enabled() const
void GLToolbar::set_enabled(bool enable) void GLToolbar::set_enabled(bool enable)
{ {
m_enabled = true; m_enabled = enable;//true; etFIXME
} }
bool GLToolbar::add_item(const GLToolbarItem::Data& data) bool GLToolbar::add_item(const GLToolbarItem::Data& data)
@ -537,7 +532,12 @@ bool GLToolbar::on_mouse(wxMouseEvent& evt, GLCanvas3D& parent)
m_mouse_capture.left = true; m_mouse_capture.left = true;
m_mouse_capture.parent = &parent; m_mouse_capture.parent = &parent;
processed = true; processed = true;
#if ENABLE_CANVAS_TOOLTIP_USING_IMGUI
if ((item_id != -2) && !m_items[item_id]->is_separator() && !m_items[item_id]->is_disabled() &&
((m_pressed_toggable_id == -1) || (m_items[item_id]->get_last_action_type() == GLToolbarItem::Left)))
#else
if ((item_id != -2) && !m_items[item_id]->is_separator() && ((m_pressed_toggable_id == -1) || (m_items[item_id]->get_last_action_type() == GLToolbarItem::Left))) if ((item_id != -2) && !m_items[item_id]->is_separator() && ((m_pressed_toggable_id == -1) || (m_items[item_id]->get_last_action_type() == GLToolbarItem::Left)))
#endif // ENABLE_CANVAS_TOOLTIP_USING_IMGUI
{ {
// mouse is inside an icon // mouse is inside an icon
do_action(GLToolbarItem::Left, item_id, parent, true); do_action(GLToolbarItem::Left, item_id, parent, true);
@ -554,7 +554,12 @@ bool GLToolbar::on_mouse(wxMouseEvent& evt, GLCanvas3D& parent)
m_mouse_capture.right = true; m_mouse_capture.right = true;
m_mouse_capture.parent = &parent; m_mouse_capture.parent = &parent;
processed = true; processed = true;
#if ENABLE_CANVAS_TOOLTIP_USING_IMGUI
if ((item_id != -2) && !m_items[item_id]->is_separator() && !m_items[item_id]->is_disabled() &&
((m_pressed_toggable_id == -1) || (m_items[item_id]->get_last_action_type() == GLToolbarItem::Right)))
#else
if ((item_id != -2) && !m_items[item_id]->is_separator() && ((m_pressed_toggable_id == -1) || (m_items[item_id]->get_last_action_type() == GLToolbarItem::Right))) if ((item_id != -2) && !m_items[item_id]->is_separator() && ((m_pressed_toggable_id == -1) || (m_items[item_id]->get_last_action_type() == GLToolbarItem::Right)))
#endif // ENABLE_CANVAS_TOOLTIP_USING_IMGUI
{ {
// mouse is inside an icon // mouse is inside an icon
do_action(GLToolbarItem::Right, item_id, parent, true); do_action(GLToolbarItem::Right, item_id, parent, true);
@ -632,6 +637,16 @@ float GLToolbar::get_main_size() const
return size * m_layout.scale; return size * m_layout.scale;
} }
int GLToolbar::get_visible_items_cnt() const
{
int cnt = 0;
for (unsigned int i = 0; i < (unsigned int)m_items.size(); ++i)
if (m_items[i]->is_visible() && !m_items[i]->is_separator())
cnt++;
return cnt;
}
void GLToolbar::do_action(GLToolbarItem::EActionType type, int item_id, GLCanvas3D& parent, bool check_hover) void GLToolbar::do_action(GLToolbarItem::EActionType type, int item_id, GLCanvas3D& parent, bool check_hover)
{ {
if ((m_pressed_toggable_id == -1) || (m_pressed_toggable_id == item_id)) if ((m_pressed_toggable_id == -1) || (m_pressed_toggable_id == item_id))
@ -639,7 +654,11 @@ void GLToolbar::do_action(GLToolbarItem::EActionType type, int item_id, GLCanvas
if ((0 <= item_id) && (item_id < (int)m_items.size())) if ((0 <= item_id) && (item_id < (int)m_items.size()))
{ {
GLToolbarItem* item = m_items[item_id]; GLToolbarItem* item = m_items[item_id];
#if ENABLE_CANVAS_TOOLTIP_USING_IMGUI
if ((item != nullptr) && !item->is_separator() && !item->is_disabled() && (!check_hover || item->is_hovered()))
#else
if ((item != nullptr) && !item->is_separator() && (!check_hover || item->is_hovered())) if ((item != nullptr) && !item->is_separator() && (!check_hover || item->is_hovered()))
#endif // ENABLE_CANVAS_TOOLTIP_USING_IMGUI
{ {
if (((type == GLToolbarItem::Right) && item->is_right_toggable()) || if (((type == GLToolbarItem::Right) && item->is_right_toggable()) ||
((type == GLToolbarItem::Left) && item->is_left_toggable())) ((type == GLToolbarItem::Left) && item->is_left_toggable()))
@ -729,11 +748,7 @@ std::string GLToolbar::update_hover_state_horizontal(const Vec2d& mouse_pos, GLC
{ {
// NB: mouse_pos is already scaled appropriately // NB: mouse_pos is already scaled appropriately
#if ENABLE_NON_STATIC_CANVAS_MANAGER
float inv_zoom = (float)wxGetApp().plater()->get_camera().get_inv_zoom(); float inv_zoom = (float)wxGetApp().plater()->get_camera().get_inv_zoom();
#else
float inv_zoom = (float)parent.get_camera().get_inv_zoom();
#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
float factor = m_layout.scale * inv_zoom; float factor = m_layout.scale * inv_zoom;
Size cnv_size = parent.get_canvas_size(); Size cnv_size = parent.get_canvas_size();
@ -874,11 +889,7 @@ std::string GLToolbar::update_hover_state_vertical(const Vec2d& mouse_pos, GLCan
{ {
// NB: mouse_pos is already scaled appropriately // NB: mouse_pos is already scaled appropriately
#if ENABLE_NON_STATIC_CANVAS_MANAGER
float inv_zoom = (float)wxGetApp().plater()->get_camera().get_inv_zoom(); float inv_zoom = (float)wxGetApp().plater()->get_camera().get_inv_zoom();
#else
float inv_zoom = (float)parent.get_camera().get_inv_zoom();
#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
float factor = m_layout.scale * inv_zoom; float factor = m_layout.scale * inv_zoom;
Size cnv_size = parent.get_canvas_size(); Size cnv_size = parent.get_canvas_size();
@ -1027,11 +1038,7 @@ int GLToolbar::contains_mouse_horizontal(const Vec2d& mouse_pos, const GLCanvas3
{ {
// NB: mouse_pos is already scaled appropriately // NB: mouse_pos is already scaled appropriately
#if ENABLE_NON_STATIC_CANVAS_MANAGER
float inv_zoom = (float)wxGetApp().plater()->get_camera().get_inv_zoom(); float inv_zoom = (float)wxGetApp().plater()->get_camera().get_inv_zoom();
#else
float inv_zoom = (float)parent.get_camera().get_inv_zoom();
#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
float factor = m_layout.scale * inv_zoom; float factor = m_layout.scale * inv_zoom;
Size cnv_size = parent.get_canvas_size(); Size cnv_size = parent.get_canvas_size();
@ -1104,11 +1111,7 @@ int GLToolbar::contains_mouse_vertical(const Vec2d& mouse_pos, const GLCanvas3D&
{ {
// NB: mouse_pos is already scaled appropriately // NB: mouse_pos is already scaled appropriately
#if ENABLE_NON_STATIC_CANVAS_MANAGER
float inv_zoom = (float)wxGetApp().plater()->get_camera().get_inv_zoom(); float inv_zoom = (float)wxGetApp().plater()->get_camera().get_inv_zoom();
#else
float inv_zoom = (float)parent.get_camera().get_inv_zoom();
#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
float factor = m_layout.scale * inv_zoom; float factor = m_layout.scale * inv_zoom;
Size cnv_size = parent.get_canvas_size(); Size cnv_size = parent.get_canvas_size();
@ -1260,11 +1263,7 @@ void GLToolbar::render_horizontal(const GLCanvas3D& parent) const
int tex_width = m_icons_texture.get_width(); int tex_width = m_icons_texture.get_width();
int tex_height = m_icons_texture.get_height(); int tex_height = m_icons_texture.get_height();
#if ENABLE_NON_STATIC_CANVAS_MANAGER
float inv_zoom = (float)wxGetApp().plater()->get_camera().get_inv_zoom(); float inv_zoom = (float)wxGetApp().plater()->get_camera().get_inv_zoom();
#else
float inv_zoom = (float)parent.get_camera().get_inv_zoom();
#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
float factor = inv_zoom * m_layout.scale; float factor = inv_zoom * m_layout.scale;
float scaled_icons_size = m_layout.icons_size * factor; float scaled_icons_size = m_layout.icons_size * factor;
@ -1312,11 +1311,7 @@ void GLToolbar::render_vertical(const GLCanvas3D& parent) const
int tex_width = m_icons_texture.get_width(); int tex_width = m_icons_texture.get_width();
int tex_height = m_icons_texture.get_height(); int tex_height = m_icons_texture.get_height();
#if ENABLE_NON_STATIC_CANVAS_MANAGER
float inv_zoom = (float)wxGetApp().plater()->get_camera().get_inv_zoom(); float inv_zoom = (float)wxGetApp().plater()->get_camera().get_inv_zoom();
#else
float inv_zoom = (float)parent.get_camera().get_inv_zoom();
#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
float factor = inv_zoom * m_layout.scale; float factor = inv_zoom * m_layout.scale;
float scaled_icons_size = m_layout.icons_size * factor; float scaled_icons_size = m_layout.icons_size * factor;

View File

@ -319,6 +319,7 @@ public:
void get_additional_tooltip(int item_id, std::string& text); void get_additional_tooltip(int item_id, std::string& text);
void set_additional_tooltip(int item_id, const std::string& text); void set_additional_tooltip(int item_id, const std::string& text);
void set_tooltip(int item_id, const std::string& text); void set_tooltip(int item_id, const std::string& text);
int get_visible_items_cnt() const;
// returns true if any item changed its state // returns true if any item changed its state
bool update_items_state(); bool update_items_state();

View File

@ -283,29 +283,27 @@ GUI_App::~GUI_App()
delete preset_updater; delete preset_updater;
} }
#if ENABLE_NON_STATIC_CANVAS_MANAGER
std::string GUI_App::get_gl_info(bool format_as_html, bool extensions) std::string GUI_App::get_gl_info(bool format_as_html, bool extensions)
{ {
return GLCanvas3DManager::get_gl_info().to_string(format_as_html, extensions); return OpenGLManager::get_gl_info().to_string(format_as_html, extensions);
} }
wxGLContext* GUI_App::init_glcontext(wxGLCanvas& canvas) wxGLContext* GUI_App::init_glcontext(wxGLCanvas& canvas)
{ {
return m_canvas_mgr.init_glcontext(canvas); return m_opengl_mgr.init_glcontext(canvas);
} }
bool GUI_App::init_opengl() bool GUI_App::init_opengl()
{ {
return m_canvas_mgr.init_gl(); return m_opengl_mgr.init_gl();
} }
#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
void GUI_App::init_app_config() void GUI_App::init_app_config()
{ {
// Profiles for the alpha are stored into the PrusaSlicer-alpha directory to not mix with the current release. // Profiles for the alpha are stored into the PrusaSlicer-alpha directory to not mix with the current release.
SetAppName(SLIC3R_APP_KEY); SetAppName(SLIC3R_APP_KEY);
//SetAppName(SLIC3R_APP_KEY "-beta"); SetAppName(SLIC3R_APP_KEY "-alpha");
SetAppDisplayName(SLIC3R_APP_NAME); // SetAppDisplayName(SLIC3R_APP_NAME);
// Set the Slic3r data directory at the Slic3r XS module. // Set the Slic3r data directory at the Slic3r XS module.
// Unix: ~/ .Slic3r // Unix: ~/ .Slic3r
@ -324,6 +322,7 @@ void GUI_App::init_app_config()
app_config->load(); app_config->load();
} }
} }
bool GUI_App::OnInit() bool GUI_App::OnInit()
{ {
try { try {
@ -413,7 +412,8 @@ bool GUI_App::on_init_inner()
if (wxImage::FindHandler(wxBITMAP_TYPE_PNG) == nullptr) if (wxImage::FindHandler(wxBITMAP_TYPE_PNG) == nullptr)
wxImage::AddHandler(new wxPNGHandler()); wxImage::AddHandler(new wxPNGHandler());
mainframe = new MainFrame(); mainframe = new MainFrame();
mainframe->switch_to(true); // hide settings tabs after first Layout // hide settings tabs after first Layout
mainframe->select_tab(0);
sidebar().obj_list()->init_objects(); // propagate model objects to object list sidebar().obj_list()->init_objects(); // propagate model objects to object list
// update_mode(); // !!! do that later // update_mode(); // !!! do that later
@ -580,28 +580,47 @@ float GUI_App::toolbar_icon_scale(const bool is_limited/* = false*/) const
const std::string& use_val = app_config->get("use_custom_toolbar_size"); const std::string& use_val = app_config->get("use_custom_toolbar_size");
const std::string& val = app_config->get("custom_toolbar_size"); const std::string& val = app_config->get("custom_toolbar_size");
const std::string& auto_val = app_config->get("auto_toolbar_size");
if (val.empty() || use_val.empty() || use_val == "0") if (val.empty() || auto_val.empty() || use_val.empty())
return icon_sc; return icon_sc;
int int_val = atoi(val.c_str()); int int_val = use_val == "0" ? 100 : atoi(val.c_str());
// correct value in respect to auto_toolbar_size
int_val = std::min(atoi(auto_val.c_str()), int_val);
if (is_limited && int_val < 50) if (is_limited && int_val < 50)
int_val = 50; int_val = 50;
return 0.01f * int_val * icon_sc; return 0.01f * int_val * icon_sc;
} }
void GUI_App::recreate_GUI() void GUI_App::set_auto_toolbar_icon_scale(float scale) const
{
#ifdef __APPLE__
const float icon_sc = 1.0f; // for Retina display will be used its own scale
#else
const float icon_sc = m_em_unit * 0.1f;
#endif // __APPLE__
int int_val = std::min(int(scale / icon_sc * 100), 100);
std::string val = std::to_string(int_val);
app_config->set("auto_toolbar_size", val);
}
void GUI_App::recreate_GUI(const wxString& msg_name)
{ {
mainframe->shutdown(); mainframe->shutdown();
const auto msg_name = _(L("Changing of an application language")) + dots;
wxProgressDialog dlg(msg_name, msg_name); wxProgressDialog dlg(msg_name, msg_name);
dlg.Pulse(); dlg.Pulse();
dlg.Update(10, _(L("Recreating")) + dots); dlg.Update(10, _(L("Recreating")) + dots);
MainFrame *old_main_frame = mainframe; MainFrame *old_main_frame = mainframe;
mainframe = new MainFrame(); mainframe = new MainFrame();
// hide settings tabs after first Layout
mainframe->select_tab(0);
// Propagate model objects to object list. // Propagate model objects to object list.
sidebar().obj_list()->init_objects(); sidebar().obj_list()->init_objects();
SetTopWindow(mainframe); SetTopWindow(mainframe);
@ -705,12 +724,6 @@ void GUI_App::load_project(wxWindow *parent, wxString& input_file) const
void GUI_App::import_model(wxWindow *parent, wxArrayString& input_files) const void GUI_App::import_model(wxWindow *parent, wxArrayString& input_files) const
{ {
#if ENABLE_CANVAS_TOOLTIP_USING_IMGUI
if (this->plater_ != nullptr)
// hides the tooltip
plater_->get_current_canvas3D()->set_tooltip("");
#endif // ENABLE_CANVAS_TOOLTIP_USING_IMGUI
input_files.Clear(); input_files.Clear();
wxFileDialog dialog(parent ? parent : GetTopWindow(), wxFileDialog dialog(parent ? parent : GetTopWindow(),
_(L("Choose one or more files (STL/OBJ/AMF/3MF/PRUSA):")), _(L("Choose one or more files (STL/OBJ/AMF/3MF/PRUSA):")),
@ -724,7 +737,7 @@ void GUI_App::import_model(wxWindow *parent, wxArrayString& input_files) const
bool GUI_App::switch_language() bool GUI_App::switch_language()
{ {
if (select_language()) { if (select_language()) {
recreate_GUI(); recreate_GUI(_L("Changing of an application language") + dots);
return true; return true;
} else { } else {
return false; return false;
@ -1028,8 +1041,17 @@ void GUI_App::add_config_menu(wxMenuBar *menu)
break; break;
case ConfigMenuPreferences: case ConfigMenuPreferences:
{ {
PreferencesDialog dlg(mainframe); bool recreate_app = false;
dlg.ShowModal(); {
// the dialog needs to be destroyed before the call to recreate_GUI()
// or sometimes the application crashes into wxDialogBase() destructor
// so we put it into an inner scope
PreferencesDialog dlg(mainframe);
dlg.ShowModal();
recreate_app = dlg.settings_layout_changed();
}
if (recreate_app)
recreate_GUI(_L("Changing of the settings layout") + dots);
break; break;
} }
case ConfigMenuLanguage: case ConfigMenuLanguage:

View File

@ -7,9 +7,7 @@
#include "MainFrame.hpp" #include "MainFrame.hpp"
#include "ImGuiWrapper.hpp" #include "ImGuiWrapper.hpp"
#include "ConfigWizard.hpp" #include "ConfigWizard.hpp"
#if ENABLE_NON_STATIC_CANVAS_MANAGER #include "OpenGLManager.hpp"
#include "GLCanvas3DManager.hpp"
#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
#include <wx/app.h> #include <wx/app.h>
#include <wx/colour.h> #include <wx/colour.h>
@ -100,9 +98,7 @@ class GUI_App : public wxApp
// Best translation language, provided by Windows or OSX, owned by wxWidgets. // Best translation language, provided by Windows or OSX, owned by wxWidgets.
const wxLanguageInfo *m_language_info_best = nullptr; const wxLanguageInfo *m_language_info_best = nullptr;
#if ENABLE_NON_STATIC_CANVAS_MANAGER OpenGLManager m_opengl_mgr;
GLCanvas3DManager m_canvas_mgr;
#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
std::unique_ptr<RemovableDriveManager> m_removable_drive_manager; std::unique_ptr<RemovableDriveManager> m_removable_drive_manager;
@ -117,11 +113,9 @@ public:
GUI_App(); GUI_App();
~GUI_App() override; ~GUI_App() override;
#if ENABLE_NON_STATIC_CANVAS_MANAGER
static std::string get_gl_info(bool format_as_html, bool extensions); static std::string get_gl_info(bool format_as_html, bool extensions);
wxGLContext* init_glcontext(wxGLCanvas& canvas); wxGLContext* init_glcontext(wxGLCanvas& canvas);
bool init_opengl(); bool init_opengl();
#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
static unsigned get_colour_approx_luma(const wxColour &colour); static unsigned get_colour_approx_luma(const wxColour &colour);
static bool dark_mode(); static bool dark_mode();
@ -141,8 +135,9 @@ public:
const wxFont& normal_font() { return m_normal_font; } const wxFont& normal_font() { return m_normal_font; }
int em_unit() const { return m_em_unit; } int em_unit() const { return m_em_unit; }
float toolbar_icon_scale(const bool is_limited = false) const; float toolbar_icon_scale(const bool is_limited = false) const;
void set_auto_toolbar_icon_scale(float scale) const;
void recreate_GUI(); void recreate_GUI(const wxString& message);
void system_info(); void system_info();
void keyboard_shortcuts(); void keyboard_shortcuts();
void load_project(wxWindow *parent, wxString& input_file) const; void load_project(wxWindow *parent, wxString& input_file) const;
@ -168,6 +163,7 @@ public:
wxString current_language_code() const { return m_wxLocale->GetCanonicalName(); } wxString current_language_code() const { return m_wxLocale->GetCanonicalName(); }
// Translate the language code to a code, for which Prusa Research maintains translations. Defaults to "en_US". // Translate the language code to a code, for which Prusa Research maintains translations. Defaults to "en_US".
wxString current_language_code_safe() const; wxString current_language_code_safe() const;
bool is_localized() const { return m_wxLocale->GetLocale() != "English"; }
virtual bool OnExceptionInMainLoop() override; virtual bool OnExceptionInMainLoop() override;

View File

@ -2771,6 +2771,7 @@ void ObjectList::delete_all_objects_from_list()
void ObjectList::increase_object_instances(const size_t obj_idx, const size_t num) void ObjectList::increase_object_instances(const size_t obj_idx, const size_t num)
{ {
select_item(m_objects_model->AddInstanceChild(m_objects_model->GetItemById(obj_idx), num)); select_item(m_objects_model->AddInstanceChild(m_objects_model->GetItemById(obj_idx), num));
selection_changed();
} }
void ObjectList::decrease_object_instances(const size_t obj_idx, const size_t num) void ObjectList::decrease_object_instances(const size_t obj_idx, const size_t num)

View File

@ -1,5 +1,7 @@
#include "libslic3r/libslic3r.h" #include "libslic3r/libslic3r.h"
#if !ENABLE_GCODE_VIEWER
#include "libslic3r/GCode/PreviewData.hpp" #include "libslic3r/GCode/PreviewData.hpp"
#endif // !ENABLE_GCODE_VIEWER
#include "GUI_Preview.hpp" #include "GUI_Preview.hpp"
#include "GUI_App.hpp" #include "GUI_App.hpp"
#include "GUI.hpp" #include "GUI.hpp"
@ -7,7 +9,7 @@
#include "AppConfig.hpp" #include "AppConfig.hpp"
#include "3DScene.hpp" #include "3DScene.hpp"
#include "BackgroundSlicingProcess.hpp" #include "BackgroundSlicingProcess.hpp"
#include "GLCanvas3DManager.hpp" #include "OpenGLManager.hpp"
#include "GLCanvas3D.hpp" #include "GLCanvas3D.hpp"
#include "PresetBundle.hpp" #include "PresetBundle.hpp"
#include "DoubleSlider.hpp" #include "DoubleSlider.hpp"
@ -27,65 +29,36 @@
namespace Slic3r { namespace Slic3r {
namespace GUI { namespace GUI {
#if ENABLE_NON_STATIC_CANVAS_MANAGER
View3D::View3D(wxWindow* parent, Model* model, DynamicPrintConfig* config, BackgroundSlicingProcess* process) View3D::View3D(wxWindow* parent, Model* model, DynamicPrintConfig* config, BackgroundSlicingProcess* process)
: m_canvas_widget(nullptr) : m_canvas_widget(nullptr)
, m_canvas(nullptr) , m_canvas(nullptr)
{ {
init(parent, model, config, process); init(parent, model, config, process);
} }
#else
View3D::View3D(wxWindow* parent, Bed3D& bed, Camera& camera, GLToolbar& view_toolbar, Model* model, DynamicPrintConfig* config, BackgroundSlicingProcess* process)
: m_canvas_widget(nullptr)
, m_canvas(nullptr)
{
init(parent, bed, camera, view_toolbar, model, config, process);
}
#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
View3D::~View3D() View3D::~View3D()
{ {
#if ENABLE_NON_STATIC_CANVAS_MANAGER
if (m_canvas != nullptr) if (m_canvas != nullptr)
delete m_canvas; delete m_canvas;
#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
if (m_canvas_widget != nullptr) if (m_canvas_widget != nullptr)
{
#if !ENABLE_NON_STATIC_CANVAS_MANAGER
_3DScene::remove_canvas(m_canvas_widget);
#endif // !ENABLE_NON_STATIC_CANVAS_MANAGER
delete m_canvas_widget; delete m_canvas_widget;
#if !ENABLE_NON_STATIC_CANVAS_MANAGER
m_canvas = nullptr;
#endif // !ENABLE_NON_STATIC_CANVAS_MANAGER
}
} }
#if ENABLE_NON_STATIC_CANVAS_MANAGER
bool View3D::init(wxWindow* parent, Model* model, DynamicPrintConfig* config, BackgroundSlicingProcess* process) bool View3D::init(wxWindow* parent, Model* model, DynamicPrintConfig* config, BackgroundSlicingProcess* process)
#else
bool View3D::init(wxWindow* parent, Bed3D& bed, Camera& camera, GLToolbar& view_toolbar, Model* model, DynamicPrintConfig* config, BackgroundSlicingProcess* process)
#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
{ {
if (!Create(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0 /* disable wxTAB_TRAVERSAL */)) if (!Create(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0 /* disable wxTAB_TRAVERSAL */))
return false; return false;
#if ENABLE_NON_STATIC_CANVAS_MANAGER m_canvas_widget = OpenGLManager::create_wxglcanvas(*this);
m_canvas_widget = GLCanvas3DManager::create_wxglcanvas(*this);
if (m_canvas_widget == nullptr) if (m_canvas_widget == nullptr)
return false; return false;
m_canvas = new GLCanvas3D(m_canvas_widget); m_canvas = new GLCanvas3D(m_canvas_widget);
m_canvas->set_context(wxGetApp().init_glcontext(*m_canvas_widget)); m_canvas->set_context(wxGetApp().init_glcontext(*m_canvas_widget));
m_canvas->bind_event_handlers(); m_canvas->bind_event_handlers();
#else
m_canvas_widget = GLCanvas3DManager::create_wxglcanvas(this);
_3DScene::add_canvas(m_canvas_widget, bed, camera, view_toolbar);
m_canvas = _3DScene::get_canvas(this->m_canvas_widget);
#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
m_canvas->allow_multisample(GLCanvas3DManager::can_multisample()); m_canvas->allow_multisample(OpenGLManager::can_multisample());
// XXX: If have OpenGL // XXX: If have OpenGL
m_canvas->enable_picking(true); m_canvas->enable_picking(true);
m_canvas->enable_moving(true); m_canvas->enable_moving(true);
@ -199,27 +172,15 @@ void View3D::render()
m_canvas->set_as_dirty(); m_canvas->set_as_dirty();
} }
#if ENABLE_NON_STATIC_CANVAS_MANAGER
#if ENABLE_GCODE_VIEWER #if ENABLE_GCODE_VIEWER
Preview::Preview( Preview::Preview(
wxWindow* parent, Model* model, DynamicPrintConfig* config, wxWindow* parent, Model* model, DynamicPrintConfig* config,
BackgroundSlicingProcess* process, GCodePreviewData* gcode_preview_data, GCodeProcessor::Result* gcode_result, std::function<void()> schedule_background_process_func) BackgroundSlicingProcess* process, GCodeProcessor::Result* gcode_result, std::function<void()> schedule_background_process_func)
#else #else
Preview::Preview( Preview::Preview(
wxWindow* parent, Model* model, DynamicPrintConfig* config, wxWindow* parent, Model* model, DynamicPrintConfig* config,
BackgroundSlicingProcess* process, GCodePreviewData* gcode_preview_data, std::function<void()> schedule_background_process_func) BackgroundSlicingProcess* process, GCodePreviewData* gcode_preview_data, std::function<void()> schedule_background_process_func)
#endif // ENABLE_GCODE_VIEWER #endif // ENABLE_GCODE_VIEWER
#else
#if ENABLE_GCODE_VIEWER
Preview::Preview(
wxWindow* parent, Bed3D& bed, Camera& camera, GLToolbar& view_toolbar, Model* model, DynamicPrintConfig* config,
BackgroundSlicingProcess* process, GCodePreviewData* gcode_preview_data, GCodeProcessor::Result* gcode_result, std::function<void()> schedule_background_process_func)
#else
Preview::Preview(
wxWindow* parent, Bed3D& bed, Camera& camera, GLToolbar& view_toolbar, Model* model, DynamicPrintConfig* config,
BackgroundSlicingProcess* process, GCodePreviewData* gcode_preview_data, std::function<void()> schedule_background_process_func)
#endif // ENABLE_GCODE_VIEWER
#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
: m_canvas_widget(nullptr) : m_canvas_widget(nullptr)
, m_canvas(nullptr) , m_canvas(nullptr)
, m_double_slider_sizer(nullptr) , m_double_slider_sizer(nullptr)
@ -241,9 +202,10 @@ Preview::Preview(
#endif // ENABLE_GCODE_VIEWER #endif // ENABLE_GCODE_VIEWER
, m_config(config) , m_config(config)
, m_process(process) , m_process(process)
, m_gcode_preview_data(gcode_preview_data)
#if ENABLE_GCODE_VIEWER #if ENABLE_GCODE_VIEWER
, m_gcode_result(gcode_result) , m_gcode_result(gcode_result)
#else
, m_gcode_preview_data(gcode_preview_data)
#endif // ENABLE_GCODE_VIEWER #endif // ENABLE_GCODE_VIEWER
, m_number_extruders(1) , m_number_extruders(1)
, m_preferred_color_mode("feature") , m_preferred_color_mode("feature")
@ -254,11 +216,7 @@ Preview::Preview(
, m_volumes_cleanup_required(false) , m_volumes_cleanup_required(false)
#endif // __linux__ #endif // __linux__
{ {
#if ENABLE_NON_STATIC_CANVAS_MANAGER
if (init(parent, model)) if (init(parent, model))
#else
if (init(parent, bed, camera, view_toolbar, model))
#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
{ {
#if !ENABLE_GCODE_VIEWER #if !ENABLE_GCODE_VIEWER
show_hide_ui_elements("none"); show_hide_ui_elements("none");
@ -267,29 +225,19 @@ Preview::Preview(
} }
} }
#if ENABLE_NON_STATIC_CANVAS_MANAGER
bool Preview::init(wxWindow* parent, Model* model) bool Preview::init(wxWindow* parent, Model* model)
#else
bool Preview::init(wxWindow* parent, Bed3D& bed, Camera& camera, GLToolbar& view_toolbar, Model* model)
#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
{ {
if (!Create(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0 /* disable wxTAB_TRAVERSAL */)) if (!Create(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0 /* disable wxTAB_TRAVERSAL */))
return false; return false;
#if ENABLE_NON_STATIC_CANVAS_MANAGER m_canvas_widget = OpenGLManager::create_wxglcanvas(*this);
m_canvas_widget = GLCanvas3DManager::create_wxglcanvas(*this);
if (m_canvas_widget == nullptr) if (m_canvas_widget == nullptr)
return false; return false;
m_canvas = new GLCanvas3D(m_canvas_widget); m_canvas = new GLCanvas3D(m_canvas_widget);
m_canvas->set_context(wxGetApp().init_glcontext(*m_canvas_widget)); m_canvas->set_context(wxGetApp().init_glcontext(*m_canvas_widget));
m_canvas->bind_event_handlers(); m_canvas->bind_event_handlers();
#else m_canvas->allow_multisample(OpenGLManager::can_multisample());
m_canvas_widget = GLCanvas3DManager::create_wxglcanvas(this);
_3DScene::add_canvas(m_canvas_widget, bed, camera, view_toolbar);
m_canvas = _3DScene::get_canvas(this->m_canvas_widget);
#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
m_canvas->allow_multisample(GLCanvas3DManager::can_multisample());
m_canvas->set_config(m_config); m_canvas->set_config(m_config);
m_canvas->set_model(model); m_canvas->set_model(model);
m_canvas->set_process(m_process); m_canvas->set_process(m_process);
@ -350,8 +298,9 @@ bool Preview::init(wxWindow* parent, Bed3D& bed, Camera& camera, GLToolbar& view
_L("Pause prints") + "|0|" + _L("Pause prints") + "|0|" +
_L("Custom GCodes") + "|0|" + _L("Custom GCodes") + "|0|" +
_L("Shells") + "|0|" + _L("Shells") + "|0|" +
_L("Tool marker") + "|1|" +
_L("Legend") + "|1" _L("Legend") + "|1"
); );
Slic3r::GUI::create_combochecklist(m_combochecklist_options, GUI::into_u8(_L("Options")), options_items); Slic3r::GUI::create_combochecklist(m_combochecklist_options, GUI::into_u8(_L("Options")), options_items);
#else #else
m_checkbox_travel = new wxCheckBox(this, wxID_ANY, _(L("Travel"))); m_checkbox_travel = new wxCheckBox(this, wxID_ANY, _(L("Travel")));
@ -435,19 +384,11 @@ Preview::~Preview()
{ {
unbind_event_handlers(); unbind_event_handlers();
#if ENABLE_NON_STATIC_CANVAS_MANAGER
if (m_canvas != nullptr) if (m_canvas != nullptr)
delete m_canvas; delete m_canvas;
#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
if (m_canvas_widget != nullptr) if (m_canvas_widget != nullptr)
{
#if !ENABLE_NON_STATIC_CANVAS_MANAGER
_3DScene::remove_canvas(m_canvas_widget);
#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
delete m_canvas_widget; delete m_canvas_widget;
m_canvas = nullptr;
}
} }
void Preview::set_as_dirty() void Preview::set_as_dirty()
@ -464,8 +405,13 @@ void Preview::set_number_extruders(unsigned int number_extruders)
int tool_idx = m_choice_view_type->FindString(_(L("Tool"))); int tool_idx = m_choice_view_type->FindString(_(L("Tool")));
int type = (number_extruders > 1) ? tool_idx /* color by a tool number */ : 0; // color by a feature type int type = (number_extruders > 1) ? tool_idx /* color by a tool number */ : 0; // color by a feature type
m_choice_view_type->SetSelection(type); m_choice_view_type->SetSelection(type);
#if ENABLE_GCODE_VIEWER
if ((0 <= type) && (type < static_cast<int>(GCodeViewer::EViewType::Count)))
m_canvas->set_gcode_view_preview_type(static_cast<GCodeViewer::EViewType>(type));
#else
if ((0 <= type) && (type < (int)GCodePreviewData::Extrusion::Num_View_Types)) if ((0 <= type) && (type < (int)GCodePreviewData::Extrusion::Num_View_Types))
m_gcode_preview_data->extrusion.view_type = (GCodePreviewData::Extrusion::EViewType)type; m_gcode_preview_data->extrusion.view_type = (GCodePreviewData::Extrusion::EViewType)type;
#endif // ENABLE_GCODE_VIEWER
m_preferred_color_mode = (type == tool_idx) ? "tool_or_feature" : "feature"; m_preferred_color_mode = (type == tool_idx) ? "tool_or_feature" : "feature";
} }
@ -742,8 +688,13 @@ void Preview::update_view_type(bool slice_completed)
int type = m_choice_view_type->FindString(choice); int type = m_choice_view_type->FindString(choice);
if (m_choice_view_type->GetSelection() != type) { if (m_choice_view_type->GetSelection() != type) {
m_choice_view_type->SetSelection(type); m_choice_view_type->SetSelection(type);
#if ENABLE_GCODE_VIEWER
if ((0 <= type) && (type < static_cast<int>(GCodeViewer::EViewType::Count)))
m_canvas->set_gcode_view_preview_type(static_cast<GCodeViewer::EViewType>(type));
#else
if (0 <= type && type < (int)GCodePreviewData::Extrusion::Num_View_Types) if (0 <= type && type < (int)GCodePreviewData::Extrusion::Num_View_Types)
m_gcode_preview_data->extrusion.view_type = (GCodePreviewData::Extrusion::EViewType)type; m_gcode_preview_data->extrusion.view_type = (GCodePreviewData::Extrusion::EViewType)type;
#endif // ENABLE_GCODE_VIEWER
m_preferred_color_mode = "feature"; m_preferred_color_mode = "feature";
} }
} }

View File

@ -37,9 +37,7 @@ class GLCanvas3D;
class GLToolbar; class GLToolbar;
class Bed3D; class Bed3D;
struct Camera; struct Camera;
#if ENABLE_NON_STATIC_CANVAS_MANAGER
class Plater; class Plater;
#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
class View3D : public wxPanel class View3D : public wxPanel
{ {
@ -47,11 +45,7 @@ class View3D : public wxPanel
GLCanvas3D* m_canvas; GLCanvas3D* m_canvas;
public: public:
#if ENABLE_NON_STATIC_CANVAS_MANAGER
View3D(wxWindow* parent, Model* model, DynamicPrintConfig* config, BackgroundSlicingProcess* process); View3D(wxWindow* parent, Model* model, DynamicPrintConfig* config, BackgroundSlicingProcess* process);
#else
View3D(wxWindow* parent, Bed3D& bed, Camera& camera, GLToolbar& view_toolbar, Model* model, DynamicPrintConfig* config, BackgroundSlicingProcess* process);
#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
virtual ~View3D(); virtual ~View3D();
wxGLCanvas* get_wxglcanvas() { return m_canvas_widget; } wxGLCanvas* get_wxglcanvas() { return m_canvas_widget; }
@ -79,11 +73,7 @@ public:
void render(); void render();
private: private:
#if ENABLE_NON_STATIC_CANVAS_MANAGER
bool init(wxWindow* parent, Model* model, DynamicPrintConfig* config, BackgroundSlicingProcess* process); bool init(wxWindow* parent, Model* model, DynamicPrintConfig* config, BackgroundSlicingProcess* process);
#else
bool init(wxWindow* parent, Bed3D& bed, Camera& camera, GLToolbar& view_toolbar, Model* model, DynamicPrintConfig* config, BackgroundSlicingProcess* process);
#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
}; };
class Preview : public wxPanel class Preview : public wxPanel
@ -133,23 +123,13 @@ class Preview : public wxPanel
DoubleSlider::Control* m_slider {nullptr}; DoubleSlider::Control* m_slider {nullptr};
public: public:
#if ENABLE_NON_STATIC_CANVAS_MANAGER
#if ENABLE_GCODE_VIEWER #if ENABLE_GCODE_VIEWER
Preview(wxWindow* parent, Model* model, DynamicPrintConfig* config, Preview(wxWindow* parent, Model* model, DynamicPrintConfig* config, BackgroundSlicingProcess* process,
BackgroundSlicingProcess* process, GCodePreviewData* gcode_preview_data, GCodeProcessor::Result* gcode_result, std::function<void()> schedule_background_process = []() {}); GCodeProcessor::Result* gcode_result, std::function<void()> schedule_background_process = []() {});
#else #else
Preview(wxWindow* parent, Model* model, DynamicPrintConfig* config, Preview(wxWindow* parent, Model* model, DynamicPrintConfig* config,
BackgroundSlicingProcess* process, GCodePreviewData* gcode_preview_data, std::function<void()> schedule_background_process = []() {}); BackgroundSlicingProcess* process, GCodePreviewData* gcode_preview_data, std::function<void()> schedule_background_process = []() {});
#endif // ENABLE_GCODE_VIEWER #endif // ENABLE_GCODE_VIEWER
#else
#if ENABLE_GCODE_VIEWER
Preview(wxWindow* parent, Bed3D& bed, Camera& camera, GLToolbar& view_toolbar, Model* model, DynamicPrintConfig* config,
BackgroundSlicingProcess* process, GCodePreviewData* gcode_preview_data, GCodeProcessor::Result* gcode_result, std::function<void()> schedule_background_process = []() {});
#else
Preview(wxWindow* parent, Bed3D& bed, Camera& camera, GLToolbar& view_toolbar, Model* model, DynamicPrintConfig* config,
BackgroundSlicingProcess* process, GCodePreviewData* gcode_preview_data, std::function<void()> schedule_background_process = []() {});
#endif // ENABLE_GCODE_VIEWER
#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
virtual ~Preview(); virtual ~Preview();
wxGLCanvas* get_wxglcanvas() { return m_canvas_widget; } wxGLCanvas* get_wxglcanvas() { return m_canvas_widget; }
@ -180,11 +160,7 @@ public:
#endif // ENABLE_GCODE_VIEWER #endif // ENABLE_GCODE_VIEWER
private: private:
#if ENABLE_NON_STATIC_CANVAS_MANAGER
bool init(wxWindow* parent, Model* model); bool init(wxWindow* parent, Model* model);
#else
bool init(wxWindow* parent, Bed3D& bed, Camera& camera, GLToolbar& view_toolbar, Model* model);
#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
void bind_event_handlers(); void bind_event_handlers();
void unbind_event_handlers(); void unbind_event_handlers();

View File

@ -134,11 +134,8 @@ wxFont get_default_font_for_dpi(int dpi)
NONCLIENTMETRICS nm; NONCLIENTMETRICS nm;
memset(&nm, 0, sizeof(NONCLIENTMETRICS)); memset(&nm, 0, sizeof(NONCLIENTMETRICS));
nm.cbSize = sizeof(NONCLIENTMETRICS); nm.cbSize = sizeof(NONCLIENTMETRICS);
if (SystemParametersInfoForDpi_fn(SPI_GETNONCLIENTMETRICS, sizeof(NONCLIENTMETRICS), &nm, 0, dpi)) { if (SystemParametersInfoForDpi_fn(SPI_GETNONCLIENTMETRICS, sizeof(NONCLIENTMETRICS), &nm, 0, dpi))
wxNativeFontInfo info; return wxFont(wxNativeFontInfo(nm.lfMessageFont));
info.lf = nm.lfMessageFont;
return wxFont(info);
}
} }
// Then try to guesstimate the font DPI scaling on Windows 8. // Then try to guesstimate the font DPI scaling on Windows 8.
// Let's hope that the font returned by the SystemParametersInfo(), which is used by wxWidgets internally, makes sense. // Let's hope that the font returned by the SystemParametersInfo(), which is used by wxWidgets internally, makes sense.

View File

@ -58,10 +58,10 @@ void GLGizmoFdmSupports::set_fdm_support_data(ModelObject* model_object, const S
return; return;
if (mo && selection.is_from_single_instance() if (mo && selection.is_from_single_instance()
&& (mo != m_old_mo || mo->volumes.size() != m_old_volumes_size)) && (mo->id() != m_old_mo_id || mo->volumes.size() != m_old_volumes_size))
{ {
update_mesh(); update_from_model_object();
m_old_mo = mo; m_old_mo_id = mo->id();
m_old_volumes_size = mo->volumes.size(); m_old_volumes_size = mo->volumes.size();
} }
} }
@ -84,12 +84,29 @@ void GLGizmoFdmSupports::on_render() const
void GLGizmoFdmSupports::render_triangles(const Selection& selection) const void GLGizmoFdmSupports::render_triangles(const Selection& selection) const
{ {
if (m_setting_angle)
return;
const ModelObject* mo = m_c->selection_info()->model_object(); const ModelObject* mo = m_c->selection_info()->model_object();
glsafe(::glEnable(GL_POLYGON_OFFSET_FILL)); glsafe(::glEnable(GL_POLYGON_OFFSET_FILL));
ScopeGuard offset_fill_guard([]() { glsafe(::glDisable(GL_POLYGON_OFFSET_FILL)); } ); ScopeGuard offset_fill_guard([]() { glsafe(::glDisable(GL_POLYGON_OFFSET_FILL)); } );
glsafe(::glPolygonOffset(-1.0, 1.0)); glsafe(::glPolygonOffset(-1.0, 1.0));
// Take care of the clipping plane. The normal of the clipping plane is
// saved with opposite sign than we need to pass to OpenGL (FIXME)
bool clipping_plane_active = m_c->object_clipper()->get_position() != 0.;
if (clipping_plane_active) {
const ClippingPlane* clp = m_c->object_clipper()->get_clipping_plane();
double clp_data[4];
memcpy(clp_data, clp->get_data(), 4 * sizeof(double));
for (int i=0; i<3; ++i)
clp_data[i] = -1. * clp_data[i];
glsafe(::glClipPlane(GL_CLIP_PLANE0, (GLdouble*)clp_data));
glsafe(::glEnable(GL_CLIP_PLANE0));
}
int mesh_id = -1; int mesh_id = -1;
for (const ModelVolume* mv : mo->volumes) { for (const ModelVolume* mv : mo->volumes) {
if (! mv->is_model_part()) if (! mv->is_model_part())
@ -113,6 +130,8 @@ void GLGizmoFdmSupports::render_triangles(const Selection& selection) const
} }
glsafe(::glPopMatrix()); glsafe(::glPopMatrix());
} }
if (clipping_plane_active)
glsafe(::glDisable(GL_CLIP_PLANE0));
} }
@ -161,14 +180,21 @@ void GLGizmoFdmSupports::render_cursor_circle() const
} }
void GLGizmoFdmSupports::on_render_for_picking() const void GLGizmoFdmSupports::update_model_object() const
{ {
ModelObject* mo = m_c->selection_info()->model_object();
int idx = -1;
for (ModelVolume* mv : mo->volumes) {
++idx;
if (! mv->is_model_part())
continue;
for (int i=0; i<int(m_selected_facets[idx].size()); ++i)
mv->m_supported_facets.set_facet(i, m_selected_facets[idx][i]);
}
} }
void GLGizmoFdmSupports::update_from_model_object()
void GLGizmoFdmSupports::update_mesh()
{ {
wxBusyCursor wait; wxBusyCursor wait;
@ -177,7 +203,6 @@ void GLGizmoFdmSupports::update_mesh()
for (const ModelVolume* mv : mo->volumes) for (const ModelVolume* mv : mo->volumes)
if (mv->is_model_part()) if (mv->is_model_part())
++num_of_volumes; ++num_of_volumes;
m_selected_facets.resize(num_of_volumes); m_selected_facets.resize(num_of_volumes);
m_neighbors.resize(num_of_volumes); m_neighbors.resize(num_of_volumes);
m_ivas.clear(); m_ivas.clear();
@ -218,6 +243,21 @@ void GLGizmoFdmSupports::update_mesh()
bool GLGizmoFdmSupports::is_mesh_point_clipped(const Vec3d& point) const
{
if (m_c->object_clipper()->get_position() == 0.)
return false;
auto sel_info = m_c->selection_info();
int active_inst = m_c->selection_info()->get_active_instance();
const ModelInstance* mi = sel_info->model_object()->instances[active_inst];
const Transform3d& trafo = mi->get_transformation().get_matrix();
Vec3d transformed_point = trafo * point;
transformed_point(2) += sel_info->get_sla_shift();
return m_c->object_clipper()->get_clipping_plane()->is_point_clipped(transformed_point);
}
bool operator<(const GLGizmoFdmSupports::NeighborData& a, const GLGizmoFdmSupports::NeighborData& b) { bool operator<(const GLGizmoFdmSupports::NeighborData& a, const GLGizmoFdmSupports::NeighborData& b) {
return a.first < b.first; return a.first < b.first;
@ -310,6 +350,12 @@ bool GLGizmoFdmSupports::gizmo_event(SLAGizmoEventType action, const Vec2d& mous
m_clipping_plane.get(), m_clipping_plane.get(),
&facet)) &facet))
{ {
// In case this hit is clipped, skip it.
if (is_mesh_point_clipped(hit.cast<double>())) {
some_mesh_was_hit = true;
continue;
}
// Is this hit the closest to the camera so far? // Is this hit the closest to the camera so far?
double hit_squared_distance = (camera.get_position()-trafo_matrices[mesh_id]*hit.cast<double>()).squaredNorm(); double hit_squared_distance = (camera.get_position()-trafo_matrices[mesh_id]*hit.cast<double>()).squaredNorm();
if (hit_squared_distance < closest_hit_squared_distance) { if (hit_squared_distance < closest_hit_squared_distance) {
@ -430,19 +476,16 @@ bool GLGizmoFdmSupports::gizmo_event(SLAGizmoEventType action, const Vec2d& mous
if ((action == SLAGizmoEventType::LeftUp || action == SLAGizmoEventType::RightUp) if ((action == SLAGizmoEventType::LeftUp || action == SLAGizmoEventType::RightUp)
&& m_button_down != Button::None) { && m_button_down != Button::None) {
// Take snapshot and update ModelVolume data.
wxString action_name = shift_down
? _L("Remove selection")
: (m_button_down == Button::Left
? _L("Add supports")
: _L("Block supports"));
Plater::TakeSnapshot(wxGetApp().plater(), action_name);
update_model_object();
m_button_down = Button::None; m_button_down = Button::None;
// Synchronize gizmo with ModelVolume data.
ModelObject* mo = m_c->selection_info()->model_object();
int idx = -1;
for (ModelVolume* mv : mo->volumes) {
++idx;
if (! mv->is_model_part())
continue;
for (int i=0; i<int(m_selected_facets[idx].size()); ++i)
mv->m_supported_facets.set_facet(i, m_selected_facets[idx][i]);
}
return true; return true;
} }
@ -481,6 +524,46 @@ void GLGizmoFdmSupports::update_vertex_buffers(const ModelVolume* mv,
} }
void GLGizmoFdmSupports::select_facets_by_angle(float threshold_deg, bool overwrite, bool block)
{
float threshold = (M_PI/180.)*threshold_deg;
const Selection& selection = m_parent.get_selection();
const ModelObject* mo = m_c->selection_info()->model_object();
const ModelInstance* mi = mo->instances[selection.get_instance_idx()];
int mesh_id = -1;
for (const ModelVolume* mv : mo->volumes) {
if (! mv->is_model_part())
continue;
++mesh_id;
const Transform3d trafo_matrix = mi->get_matrix(true) * mv->get_matrix(true);
Vec3f down = (trafo_matrix.inverse() * (-Vec3d::UnitZ())).cast<float>().normalized();
Vec3f limit = (trafo_matrix.inverse() * Vec3d(std::sin(threshold), 0, -std::cos(threshold))).cast<float>().normalized();
float dot_limit = limit.dot(down);
// Now calculate dot product of vert_direction and facets' normals.
int idx = -1;
for (const stl_facet& facet : mv->mesh().stl.facet_start) {
++idx;
if (facet.normal.dot(down) > dot_limit && (overwrite || m_selected_facets[mesh_id][idx] == FacetSupportType::NONE))
m_selected_facets[mesh_id][idx] = block
? FacetSupportType::BLOCKER
: FacetSupportType::ENFORCER;
}
update_vertex_buffers(mv, mesh_id, true, true);
}
Plater::TakeSnapshot(wxGetApp().plater(), block ? _L("Block supports by angle")
: _L("Add supports by angle"));
update_model_object();
m_parent.set_as_dirty();
m_setting_angle = false;
}
void GLGizmoFdmSupports::on_render_input_window(float x, float y, float bottom_limit) void GLGizmoFdmSupports::on_render_input_window(float x, float y, float bottom_limit)
{ {
if (! m_c->selection_info()->model_object()) if (! m_c->selection_info()->model_object())
@ -489,96 +572,131 @@ void GLGizmoFdmSupports::on_render_input_window(float x, float y, float bottom_l
const float approx_height = m_imgui->scaled(18.0f); const float approx_height = m_imgui->scaled(18.0f);
y = std::min(y, bottom_limit - approx_height); y = std::min(y, bottom_limit - approx_height);
m_imgui->set_next_window_pos(x, y, ImGuiCond_Always); m_imgui->set_next_window_pos(x, y, ImGuiCond_Always);
m_imgui->begin(on_get_name(), ImGuiWindowFlags_NoMove | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoCollapse);
// First calculate width of all the texts that are could possibly be shown. We will decide set the dialog width based on that: if (! m_setting_angle) {
const float clipping_slider_left = std::max(m_imgui->calc_text_size(m_desc.at("clipping_of_view")).x, m_imgui->calc_text_size(m_desc.at("reset_direction")).x) + m_imgui->scaled(1.5f); m_imgui->begin(on_get_name(), ImGuiWindowFlags_NoMove | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoCollapse);
const float cursor_slider_left = m_imgui->calc_text_size(m_desc.at("cursor_size")).x + m_imgui->scaled(1.f);
const float button_width = m_imgui->calc_text_size(m_desc.at("remove_all")).x + m_imgui->scaled(1.f);
const float minimal_slider_width = m_imgui->scaled(4.f);
float caption_max = 0.f; // First calculate width of all the texts that are could possibly be shown. We will decide set the dialog width based on that:
float total_text_max = 0.; const float clipping_slider_left = std::max(m_imgui->calc_text_size(m_desc.at("clipping_of_view")).x, m_imgui->calc_text_size(m_desc.at("reset_direction")).x) + m_imgui->scaled(1.5f);
for (const std::string& t : {"enforce", "block", "remove"}) { const float cursor_slider_left = m_imgui->calc_text_size(m_desc.at("cursor_size")).x + m_imgui->scaled(1.f);
caption_max = std::max(caption_max, m_imgui->calc_text_size(m_desc.at(t+"_caption")).x); const float button_width = m_imgui->calc_text_size(m_desc.at("remove_all")).x + m_imgui->scaled(1.f);
total_text_max = std::max(total_text_max, caption_max + m_imgui->calc_text_size(m_desc.at(t)).x); const float minimal_slider_width = m_imgui->scaled(4.f);
}
caption_max += m_imgui->scaled(1.f);
total_text_max += m_imgui->scaled(1.f);
float window_width = minimal_slider_width + std::max(cursor_slider_left, clipping_slider_left); float caption_max = 0.f;
window_width = std::max(window_width, total_text_max); float total_text_max = 0.;
window_width = std::max(window_width, button_width); for (const std::string& t : {"enforce", "block", "remove"}) {
caption_max = std::max(caption_max, m_imgui->calc_text_size(m_desc.at(t+"_caption")).x);
total_text_max = std::max(total_text_max, caption_max + m_imgui->calc_text_size(m_desc.at(t)).x);
}
caption_max += m_imgui->scaled(1.f);
total_text_max += m_imgui->scaled(1.f);
auto draw_text_with_caption = [this, &caption_max](const wxString& caption, const wxString& text) { float window_width = minimal_slider_width + std::max(cursor_slider_left, clipping_slider_left);
static const ImVec4 ORANGE(1.0f, 0.49f, 0.22f, 1.0f); window_width = std::max(window_width, total_text_max);
ImGui::PushStyleColor(ImGuiCol_Text, ORANGE); window_width = std::max(window_width, button_width);
m_imgui->text(caption);
ImGui::PopStyleColor();
ImGui::SameLine(caption_max);
m_imgui->text(text);
};
for (const std::string& t : {"enforce", "block", "remove"}) auto draw_text_with_caption = [this, &caption_max](const wxString& caption, const wxString& text) {
draw_text_with_caption(m_desc.at(t + "_caption"), m_desc.at(t)); static const ImVec4 ORANGE(1.0f, 0.49f, 0.22f, 1.0f);
ImGui::PushStyleColor(ImGuiCol_Text, ORANGE);
m_imgui->text(caption);
ImGui::PopStyleColor();
ImGui::SameLine(caption_max);
m_imgui->text(text);
};
m_imgui->text(""); for (const std::string& t : {"enforce", "block", "remove"})
draw_text_with_caption(m_desc.at(t + "_caption"), m_desc.at(t));
if (m_imgui->button(m_desc.at("remove_all"))) { m_imgui->text("");
ModelObject* mo = m_c->selection_info()->model_object();
int idx = -1; if (m_imgui->button("Autoset by angle...")) {
for (ModelVolume* mv : mo->volumes) { m_setting_angle = true;
++idx; }
if (mv->is_model_part()) {
m_selected_facets[idx].assign(m_selected_facets[idx].size(), FacetSupportType::NONE); ImGui::SameLine();
mv->m_supported_facets.clear();
update_vertex_buffers(mv, idx, true, true); if (m_imgui->button(m_desc.at("remove_all"))) {
m_parent.set_as_dirty(); ModelObject* mo = m_c->selection_info()->model_object();
int idx = -1;
for (ModelVolume* mv : mo->volumes) {
++idx;
if (mv->is_model_part()) {
m_selected_facets[idx].assign(m_selected_facets[idx].size(), FacetSupportType::NONE);
mv->m_supported_facets.clear();
update_vertex_buffers(mv, idx, true, true);
m_parent.set_as_dirty();
}
} }
} }
}
const float max_tooltip_width = ImGui::GetFontSize() * 20.0f; const float max_tooltip_width = ImGui::GetFontSize() * 20.0f;
m_imgui->text(m_desc.at("cursor_size")); m_imgui->text(m_desc.at("cursor_size"));
ImGui::SameLine(clipping_slider_left); ImGui::SameLine(clipping_slider_left);
ImGui::PushItemWidth(window_width - clipping_slider_left); ImGui::PushItemWidth(window_width - clipping_slider_left);
ImGui::SliderFloat(" ", &m_cursor_radius, CursorRadiusMin, CursorRadiusMax, "%.2f"); ImGui::SliderFloat(" ", &m_cursor_radius, CursorRadiusMin, CursorRadiusMax, "%.2f");
if (ImGui::IsItemHovered()) { if (ImGui::IsItemHovered()) {
ImGui::BeginTooltip(); ImGui::BeginTooltip();
ImGui::PushTextWrapPos(max_tooltip_width); ImGui::PushTextWrapPos(max_tooltip_width);
ImGui::TextUnformatted(_L("Alt + Mouse wheel").ToUTF8().data()); ImGui::TextUnformatted(_L("Alt + Mouse wheel").ToUTF8().data());
ImGui::PopTextWrapPos(); ImGui::PopTextWrapPos();
ImGui::EndTooltip(); ImGui::EndTooltip();
} }
ImGui::Separator(); ImGui::Separator();
if (m_c->object_clipper()->get_position() == 0.f) if (m_c->object_clipper()->get_position() == 0.f)
m_imgui->text(m_desc.at("clipping_of_view")); m_imgui->text(m_desc.at("clipping_of_view"));
else { else {
if (m_imgui->button(m_desc.at("reset_direction"))) { if (m_imgui->button(m_desc.at("reset_direction"))) {
wxGetApp().CallAfter([this](){ wxGetApp().CallAfter([this](){
m_c->object_clipper()->set_position(-1., false); m_c->object_clipper()->set_position(-1., false);
}); });
}
}
ImGui::SameLine(clipping_slider_left);
ImGui::PushItemWidth(window_width - clipping_slider_left);
float clp_dist = m_c->object_clipper()->get_position();
if (ImGui::SliderFloat(" ", &clp_dist, 0.f, 1.f, "%.2f"))
m_c->object_clipper()->set_position(clp_dist, true);
if (ImGui::IsItemHovered()) {
ImGui::BeginTooltip();
ImGui::PushTextWrapPos(max_tooltip_width);
ImGui::TextUnformatted(_L("Ctrl + Mouse wheel").ToUTF8().data());
ImGui::PopTextWrapPos();
ImGui::EndTooltip();
}
m_imgui->end();
if (m_setting_angle) {
m_parent.show_slope(false);
m_parent.set_slope_range({90.f - m_angle_threshold_deg, 90.f - m_angle_threshold_deg});
m_parent.use_slope(true);
m_parent.set_as_dirty();
} }
} }
else {
ImGui::SameLine(clipping_slider_left); std::string name = "Autoset custom supports";
ImGui::PushItemWidth(window_width - clipping_slider_left); m_imgui->begin(wxString(name), ImGuiWindowFlags_NoMove | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoCollapse);
float clp_dist = m_c->object_clipper()->get_position(); m_imgui->text("Threshold:");
if (ImGui::SliderFloat(" ", &clp_dist, 0.f, 1.f, "%.2f")) ImGui::SameLine();
m_c->object_clipper()->set_position(clp_dist, true); if (m_imgui->slider_float("", &m_angle_threshold_deg, 0.f, 90.f, "%.f"))
if (ImGui::IsItemHovered()) { m_parent.set_slope_range({90.f - m_angle_threshold_deg, 90.f - m_angle_threshold_deg});
ImGui::BeginTooltip(); m_imgui->checkbox(wxString("Overwrite already selected facets"), m_overwrite_selected);
ImGui::PushTextWrapPos(max_tooltip_width); if (m_imgui->button("Enforce"))
ImGui::TextUnformatted(_L("Ctrl + Mouse wheel").ToUTF8().data()); select_facets_by_angle(m_angle_threshold_deg, m_overwrite_selected, false);
ImGui::PopTextWrapPos(); ImGui::SameLine();
ImGui::EndTooltip(); if (m_imgui->button("Block"))
select_facets_by_angle(m_angle_threshold_deg, m_overwrite_selected, true);
ImGui::SameLine();
if (m_imgui->button("Cancel"))
m_setting_angle = false;
m_imgui->end();
if (! m_setting_angle) {
m_parent.use_slope(false);
m_parent.set_as_dirty();
}
} }
m_imgui->end();
} }
bool GLGizmoFdmSupports::on_is_activable() const bool GLGizmoFdmSupports::on_is_activable() const
@ -627,12 +745,24 @@ void GLGizmoFdmSupports::on_set_state()
return; return;
if (m_state == On && m_old_state != On) { // the gizmo was just turned on if (m_state == On && m_old_state != On) { // the gizmo was just turned on
Plater::TakeSnapshot snapshot(wxGetApp().plater(), _(L("FDM gizmo turned on"))); {
Plater::TakeSnapshot snapshot(wxGetApp().plater(), _(L("FDM gizmo turned on")));
}
if (! m_parent.get_gizmos_manager().is_serializing()) {
wxGetApp().CallAfter([]() {
wxGetApp().plater()->enter_gizmos_stack();
});
}
} }
if (m_state == Off && m_old_state != Off) { // the gizmo was just turned Off if (m_state == Off && m_old_state != Off) { // the gizmo was just turned Off
// we are actually shutting down // we are actually shutting down
Plater::TakeSnapshot snapshot(wxGetApp().plater(), _(L("FDM gizmo turned off"))); m_setting_angle = false;
m_old_mo = nullptr; m_parent.use_slope(false);
wxGetApp().plater()->leave_gizmos_stack();
{
Plater::TakeSnapshot snapshot(wxGetApp().plater(), _(L("FDM gizmo turned off")));
}
m_old_mo_id = -1;
m_ivas.clear(); m_ivas.clear();
m_neighbors.clear(); m_neighbors.clear();
m_selected_facets.clear(); m_selected_facets.clear();
@ -657,7 +787,7 @@ void GLGizmoFdmSupports::on_stop_dragging()
void GLGizmoFdmSupports::on_load(cereal::BinaryInputArchive& ar) void GLGizmoFdmSupports::on_load(cereal::BinaryInputArchive& ar)
{ {
update_from_model_object();
} }

View File

@ -19,7 +19,7 @@ enum class SLAGizmoEventType : unsigned char;
class GLGizmoFdmSupports : public GLGizmoBase class GLGizmoFdmSupports : public GLGizmoBase
{ {
private: private:
const ModelObject* m_old_mo = nullptr; ObjectID m_old_mo_id;
size_t m_old_volumes_size = 0; size_t m_old_volumes_size = 0;
GLUquadricObj* m_quadric; GLUquadricObj* m_quadric;
@ -53,14 +53,23 @@ public:
private: private:
bool on_init() override; bool on_init() override;
void on_render() const override; void on_render() const override;
void on_render_for_picking() const override; void on_render_for_picking() const override {}
void render_triangles(const Selection& selection) const; void render_triangles(const Selection& selection) const;
void render_cursor_circle() const; void render_cursor_circle() const;
void update_mesh();
void update_model_object() const;
void update_from_model_object();
void select_facets_by_angle(float threshold, bool overwrite, bool block);
bool m_overwrite_selected = false;
float m_angle_threshold_deg = 45.f;
bool is_mesh_point_clipped(const Vec3d& point) const;
float m_clipping_plane_distance = 0.f; float m_clipping_plane_distance = 0.f;
std::unique_ptr<ClippingPlane> m_clipping_plane; std::unique_ptr<ClippingPlane> m_clipping_plane;
bool m_setting_angle = false;
// This map holds all translated description texts, so they can be easily referenced during layout calculations // This map holds all translated description texts, so they can be easily referenced during layout calculations
// etc. When language changes, GUI is recreated and this class constructed again, so the change takes effect. // etc. When language changes, GUI is recreated and this class constructed again, so the change takes effect.

View File

@ -58,7 +58,10 @@ void GLGizmoHollow::set_sla_support_data(ModelObject*, const Selection&)
const ModelObject* mo = m_c->selection_info()->model_object(); const ModelObject* mo = m_c->selection_info()->model_object();
if (mo) { if (mo) {
reload_cache(); if (m_old_mo_id != mo->id()) {
reload_cache();
m_old_mo_id = mo->id();
}
if (m_c->hollowed_mesh() && m_c->hollowed_mesh()->get_hollowed_mesh()) if (m_c->hollowed_mesh() && m_c->hollowed_mesh()->get_hollowed_mesh())
m_holes_in_drilled_mesh = mo->sla_drain_holes; m_holes_in_drilled_mesh = mo->sla_drain_holes;
} }
@ -220,11 +223,7 @@ bool GLGizmoHollow::unproject_on_mesh(const Vec2d& mouse_pos, std::pair<Vec3f, V
if (! m_c->raycaster()->raycaster()) if (! m_c->raycaster()->raycaster())
return false; return false;
#if ENABLE_NON_STATIC_CANVAS_MANAGER
const Camera& camera = wxGetApp().plater()->get_camera(); const Camera& camera = wxGetApp().plater()->get_camera();
#else
const Camera& camera = m_parent.get_camera();
#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
const Selection& selection = m_parent.get_selection(); const Selection& selection = m_parent.get_selection();
const GLVolume* volume = selection.get_volume(*selection.get_volume_idxs().begin()); const GLVolume* volume = selection.get_volume(*selection.get_volume_idxs().begin());
Geometry::Transformation trafo = volume->get_instance_transformation(); Geometry::Transformation trafo = volume->get_instance_transformation();

View File

@ -43,6 +43,8 @@ private:
void hollow_mesh(bool postpone_error_messages = false); void hollow_mesh(bool postpone_error_messages = false);
bool unsaved_changes() const; bool unsaved_changes() const;
ObjectID m_old_mo_id = -1;
// bool m_show_supports = true; // bool m_show_supports = true;
float m_new_hole_radius = 2.f; // Size of a new hole. float m_new_hole_radius = 2.f; // Size of a new hole.
float m_new_hole_height = 6.f; float m_new_hole_height = 6.f;

View File

@ -66,11 +66,10 @@ void GLGizmoSlaSupports::set_sla_support_data(ModelObject* model_object, const S
ModelObject* mo = m_c->selection_info()->model_object(); ModelObject* mo = m_c->selection_info()->model_object();
if (mo != m_old_mo) { if (mo && mo->id() != m_old_mo_id) {
disable_editing_mode(); disable_editing_mode();
if (mo) reload_cache();
reload_cache(); m_old_mo_id = mo->id();
m_old_mo = mo;
} }
// If we triggered autogeneration before, check backend and fetch results if they are there // If we triggered autogeneration before, check backend and fetch results if they are there

View File

@ -83,7 +83,7 @@ private:
float m_density_stash = 0.f; // and again float m_density_stash = 0.f; // and again
mutable std::vector<CacheEntry> m_editing_cache; // a support point and whether it is currently selected mutable std::vector<CacheEntry> m_editing_cache; // a support point and whether it is currently selected
std::vector<sla::SupportPoint> m_normal_cache; // to restore after discarding changes or undo/redo std::vector<sla::SupportPoint> m_normal_cache; // to restore after discarding changes or undo/redo
const ModelObject* m_old_mo = nullptr; ObjectID m_old_mo_id;
// This map holds all translated description texts, so they can be easily referenced during layout calculations // This map holds all translated description texts, so they can be easily referenced during layout calculations
// etc. When language changes, GUI is recreated and this class constructed again, so the change takes effect. // etc. When language changes, GUI is recreated and this class constructed again, so the change takes effect.

View File

@ -2,9 +2,7 @@
#include "GLGizmosManager.hpp" #include "GLGizmosManager.hpp"
#include "slic3r/GUI/GLCanvas3D.hpp" #include "slic3r/GUI/GLCanvas3D.hpp"
#include "slic3r/GUI/3DScene.hpp" #include "slic3r/GUI/3DScene.hpp"
#if ENABLE_NON_STATIC_CANVAS_MANAGER
#include "slic3r/GUI/Camera.hpp" #include "slic3r/GUI/Camera.hpp"
#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
#include "slic3r/GUI/GUI_App.hpp" #include "slic3r/GUI/GUI_App.hpp"
#include "slic3r/GUI/GUI_ObjectManipulation.hpp" #include "slic3r/GUI/GUI_ObjectManipulation.hpp"
#include "slic3r/GUI/PresetBundle.hpp" #include "slic3r/GUI/PresetBundle.hpp"
@ -371,15 +369,6 @@ void GLGizmosManager::set_sla_support_data(ModelObject* model_object)
|| wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology() != ptSLA) || wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology() != ptSLA)
return; return;
/*m_common_gizmos_data->update_from_backend(m_parent, model_object);
auto* gizmo_supports = dynamic_cast<GLGizmoSlaSupports*>(m_gizmos[SlaSupports].get());
// note: sla support gizmo takes care of updating the common data.
// following lines are thus dependent
//gizmo_supports->set_sla_support_data(model_object, m_parent.get_selection());
*/
auto* gizmo_hollow = dynamic_cast<GLGizmoHollow*>(m_gizmos[Hollow].get()); auto* gizmo_hollow = dynamic_cast<GLGizmoHollow*>(m_gizmos[Hollow].get());
auto* gizmo_supports = dynamic_cast<GLGizmoSlaSupports*>(m_gizmos[SlaSupports].get()); auto* gizmo_supports = dynamic_cast<GLGizmoSlaSupports*>(m_gizmos[SlaSupports].get());
gizmo_hollow->set_sla_support_data(model_object, m_parent.get_selection()); gizmo_hollow->set_sla_support_data(model_object, m_parent.get_selection());
@ -1076,13 +1065,8 @@ void GLGizmosManager::do_render_overlay() const
float cnv_w = (float)m_parent.get_canvas_size().get_width(); float cnv_w = (float)m_parent.get_canvas_size().get_width();
float cnv_h = (float)m_parent.get_canvas_size().get_height(); float cnv_h = (float)m_parent.get_canvas_size().get_height();
#if ENABLE_NON_STATIC_CANVAS_MANAGER
float zoom = (float)wxGetApp().plater()->get_camera().get_zoom(); float zoom = (float)wxGetApp().plater()->get_camera().get_zoom();
float inv_zoom = (float)wxGetApp().plater()->get_camera().get_inv_zoom(); float inv_zoom = (float)wxGetApp().plater()->get_camera().get_inv_zoom();
#else
float zoom = (float)m_parent.get_camera().get_zoom();
float inv_zoom = (float)m_parent.get_camera().get_inv_zoom();
#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
float height = get_scaled_total_height(); float height = get_scaled_total_height();
float width = get_scaled_total_width(); float width = get_scaled_total_width();
@ -1133,11 +1117,7 @@ void GLGizmosManager::do_render_overlay() const
GLTexture::render_sub_texture(icons_texture_id, zoomed_top_x, zoomed_top_x + zoomed_icons_size, zoomed_top_y - zoomed_icons_size, zoomed_top_y, { { u_left, v_bottom }, { u_right, v_bottom }, { u_right, v_top }, { u_left, v_top } }); GLTexture::render_sub_texture(icons_texture_id, zoomed_top_x, zoomed_top_x + zoomed_icons_size, zoomed_top_y - zoomed_icons_size, zoomed_top_y, { { u_left, v_bottom }, { u_right, v_bottom }, { u_right, v_top }, { u_left, v_top } });
if (idx == m_current) { if (idx == m_current) {
#if ENABLE_NON_STATIC_CANVAS_MANAGER
float toolbar_top = cnv_h - wxGetApp().plater()->get_view_toolbar().get_height(); float toolbar_top = cnv_h - wxGetApp().plater()->get_view_toolbar().get_height();
#else
float toolbar_top = cnv_h - m_parent.get_view_toolbar_height();
#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
gizmo->render_input_window(width, 0.5f * cnv_h - zoomed_top_y * zoom, toolbar_top); gizmo->render_input_window(width, 0.5f * cnv_h - zoomed_top_y * zoom, toolbar_top);
} }
zoomed_top_y -= zoomed_stride_y; zoomed_top_y -= zoomed_stride_y;

View File

@ -139,6 +139,11 @@ public:
EType new_current = m_current; EType new_current = m_current;
m_current = old_current; m_current = old_current;
// Update common data. They should be updated when activate_gizmo is
// called, so it can be used in on_set_state which is called from there.
if (new_current != Undefined)
m_common_gizmos_data->update(m_gizmos[new_current]->get_requirements());
// activate_gizmo call sets m_current and calls set_state for the gizmo // activate_gizmo call sets m_current and calls set_state for the gizmo
// it does nothing in case the gizmo is already activated // it does nothing in case the gizmo is already activated
// it can safely be called for Undefined gizmo // it can safely be called for Undefined gizmo
@ -167,6 +172,7 @@ public:
void refresh_on_off_state(); void refresh_on_off_state();
void reset_all_states(); void reset_all_states();
bool is_serializing() const { return m_serializing; }
void set_hover_id(int id); void set_hover_id(int id);
void enable_grabber(EType type, unsigned int id, bool enable); void enable_grabber(EType type, unsigned int id, bool enable);
@ -220,6 +226,8 @@ public:
void update_after_undo_redo(const UndoRedo::Snapshot& snapshot); void update_after_undo_redo(const UndoRedo::Snapshot& snapshot);
int get_selectable_icons_cnt() const { return get_selectable_idxs().size(); }
private: private:
void render_background(float left, float top, float right, float bottom, float border) const; void render_background(float left, float top, float right, float bottom, float border) const;
void do_render_overlay() const; void do_render_overlay() const;

View File

@ -7,6 +7,7 @@
#include <boost/format.hpp> #include <boost/format.hpp>
#include <boost/log/trivial.hpp> #include <boost/log/trivial.hpp>
#include <boost/filesystem.hpp>
#include <wx/string.h> #include <wx/string.h>
#include <wx/event.h> #include <wx/event.h>
@ -27,10 +28,22 @@
#include "I18N.hpp" #include "I18N.hpp"
#include "Search.hpp" #include "Search.hpp"
#include "../Utils/MacDarkMode.hpp"
#include "nanosvg/nanosvg.h"
#include "nanosvg/nanosvgrast.h"
namespace Slic3r { namespace Slic3r {
namespace GUI { namespace GUI {
static const std::map<const char, std::string> font_icons = {
{ImGui::PrintIconMarker , "cog" },
{ImGui::PrinterIconMarker , "printer" },
{ImGui::PrinterSlaIconMarker, "sla_printer"},
{ImGui::FilamentIconMarker , "spool" },
{ImGui::MaterialIconMarker , "resin" }
};
ImGuiWrapper::ImGuiWrapper() ImGuiWrapper::ImGuiWrapper()
: m_glyph_ranges(nullptr) : m_glyph_ranges(nullptr)
, m_font_cjk(false) , m_font_cjk(false)
@ -614,8 +627,9 @@ static void process_key_down(ImGuiKey imgui_key, std::function<void()> f)
} }
void ImGuiWrapper::search_list(const ImVec2& size_, bool (*items_getter)(int, const char** label, const char** tooltip), char* search_str, void ImGuiWrapper::search_list(const ImVec2& size_, bool (*items_getter)(int, const char** label, const char** tooltip), char* search_str,
Search::OptionViewParameters& view_params, int& selected, bool& edited, int& mouse_wheel) Search::OptionViewParameters& view_params, int& selected, bool& edited, int& mouse_wheel, bool is_localized)
{ {
int& hovered_id = view_params.hovered_id;
// ImGui::ListBoxHeader("", size); // ImGui::ListBoxHeader("", size);
{ {
// rewrote part of function to add a TextInput instead of label Text // rewrote part of function to add a TextInput instead of label Text
@ -655,7 +669,7 @@ void ImGuiWrapper::search_list(const ImVec2& size_, bool (*items_getter)(int, co
ImGui::InputTextEx("", NULL, search_str, 20, search_size, ImGuiInputTextFlags_AutoSelectAll, NULL, NULL); ImGui::InputTextEx("", NULL, search_str, 20, search_size, ImGuiInputTextFlags_AutoSelectAll, NULL, NULL);
edited = ImGui::IsItemEdited(); edited = ImGui::IsItemEdited();
if (edited) if (edited)
view_params.hovered_id = -1; hovered_id = 0;
process_key_down(ImGuiKey_Escape, [&selected, search_str, str]() { process_key_down(ImGuiKey_Escape, [&selected, search_str, str]() {
// use 9999 to mark selection as a Esc key // use 9999 to mark selection as a Esc key
@ -671,7 +685,6 @@ void ImGuiWrapper::search_list(const ImVec2& size_, bool (*items_getter)(int, co
const char* item_text; const char* item_text;
const char* tooltip; const char* tooltip;
int mouse_hovered = -1; int mouse_hovered = -1;
int& hovered_id = view_params.hovered_id;
while (items_getter(i, &item_text, &tooltip)) while (items_getter(i, &item_text, &tooltip))
{ {
@ -679,7 +692,7 @@ void ImGuiWrapper::search_list(const ImVec2& size_, bool (*items_getter)(int, co
if (ImGui::IsItemHovered()) { if (ImGui::IsItemHovered()) {
ImGui::SetTooltip("%s", /*item_text*/tooltip); ImGui::SetTooltip("%s", /*item_text*/tooltip);
view_params.hovered_id = -1; hovered_id = -1;
mouse_hovered = i; mouse_hovered = i;
} }
@ -688,8 +701,6 @@ void ImGuiWrapper::search_list(const ImVec2& size_, bool (*items_getter)(int, co
i++; i++;
} }
scroll_y(mouse_hovered);
// Process mouse wheel // Process mouse wheel
if (mouse_hovered > 0) if (mouse_hovered > 0)
process_mouse_wheel(mouse_wheel); process_mouse_wheel(mouse_wheel);
@ -699,7 +710,7 @@ void ImGuiWrapper::search_list(const ImVec2& size_, bool (*items_getter)(int, co
if (mouse_hovered > 0) if (mouse_hovered > 0)
scroll_up(); scroll_up();
else { else {
if (hovered_id > 0 && hovered_id != size_t(-1)) if (hovered_id > 0)
--hovered_id; --hovered_id;
scroll_y(hovered_id); scroll_y(hovered_id);
} }
@ -709,9 +720,9 @@ void ImGuiWrapper::search_list(const ImVec2& size_, bool (*items_getter)(int, co
if (mouse_hovered > 0) if (mouse_hovered > 0)
scroll_down(); scroll_down();
else { else {
if (hovered_id == size_t(-1)) if (hovered_id < 0)
hovered_id = 0; hovered_id = 0;
else if (hovered_id < size_t(i - 1)) else if (hovered_id < i - 1)
++hovered_id; ++hovered_id;
scroll_y(hovered_id); scroll_y(hovered_id);
} }
@ -735,9 +746,10 @@ void ImGuiWrapper::search_list(const ImVec2& size_, bool (*items_getter)(int, co
// add checkboxes for show/hide Categories and Groups // add checkboxes for show/hide Categories and Groups
text(_L("Use for search")+":"); text(_L("Use for search")+":");
check_box(_L("Type"), view_params.type);
check_box(_L("Category"), view_params.category); check_box(_L("Category"), view_params.category);
check_box(_L("Group"), view_params.group); check_box(_L("Group"), view_params.group);
if (is_localized)
check_box(_L("Search in English"), view_params.english);
} }
void ImGuiWrapper::disabled_begin(bool disabled) void ImGuiWrapper::disabled_begin(bool disabled)
@ -791,6 +803,59 @@ static const ImWchar ranges_keyboard_shortcuts[] =
}; };
#endif // __APPLE__ #endif // __APPLE__
std::vector<unsigned char> ImGuiWrapper::load_svg(const std::string& bitmap_name, unsigned target_width, unsigned target_height)
{
#ifdef __APPLE__
// Note: win->GetContentScaleFactor() is not used anymore here because it tends to
// return bogus results quite often (such as 1.0 on Retina or even 0.0).
// We're using the max scaling factor across all screens because it's very likely to be good enough.
double scale = mac_max_scaling_factor();
#else
double scale = 1.0;
#endif
std::vector<unsigned char> empty_vector;
#ifdef __WXMSW__
std::string folder = "white\\";
#else
std::string folder = "white/";
#endif
if (!boost::filesystem::exists(Slic3r::var(folder + bitmap_name + ".svg")))
folder.clear();
NSVGimage* image = ::nsvgParseFromFile(Slic3r::var(folder + bitmap_name + ".svg").c_str(), "px", 96.0f);
if (image == nullptr)
return empty_vector;
target_height != 0 ? target_height *= scale : target_width *= scale;
float svg_scale = target_height != 0 ?
(float)target_height / image->height : target_width != 0 ?
(float)target_width / image->width : 1;
int width = (int)(svg_scale * image->width + 0.5f);
int height = (int)(svg_scale * image->height + 0.5f);
int n_pixels = width * height;
if (n_pixels <= 0) {
::nsvgDelete(image);
return empty_vector;
}
NSVGrasterizer* rast = ::nsvgCreateRasterizer();
if (rast == nullptr) {
::nsvgDelete(image);
return empty_vector;
}
std::vector<unsigned char> data(n_pixels * 4, 0);
::nsvgRasterize(rast, image, 0, 0, svg_scale, data.data(), width, height, width * 4);
::nsvgDeleteRasterizer(rast);
::nsvgDelete(image);
return data;
}
void ImGuiWrapper::init_font(bool compress) void ImGuiWrapper::init_font(bool compress)
{ {
destroy_font(); destroy_font();
@ -829,11 +894,33 @@ void ImGuiWrapper::init_font(bool compress)
} }
#endif #endif
float font_scale = m_font_size/15;
int icon_sz = lround(16 * font_scale); // default size of icon is 16 px
int rect_id = io.Fonts->CustomRects.Size; // id of the rectangle added next
// add rectangles for the icons to the font atlas
for (auto& icon : font_icons)
io.Fonts->AddCustomRectFontGlyph(font, icon.first, icon_sz, icon_sz, 3.0 * font_scale + icon_sz);
// Build texture atlas // Build texture atlas
unsigned char* pixels; unsigned char* pixels;
int width, height; int width, height;
io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height); // Load as RGBA 32-bits (75% of the memory is wasted, but default font is so small) because it is more likely to be compatible with user's existing shaders. If your ImTextureId represent a higher-level concept than just a GL texture id, consider calling GetTexDataAsAlpha8() instead to save on GPU memory. io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height); // Load as RGBA 32-bits (75% of the memory is wasted, but default font is so small) because it is more likely to be compatible with user's existing shaders. If your ImTextureId represent a higher-level concept than just a GL texture id, consider calling GetTexDataAsAlpha8() instead to save on GPU memory.
// Fill rectangles from the SVG-icons
for (auto icon : font_icons) {
if (const ImFontAtlas::CustomRect* rect = io.Fonts->GetCustomRectByIndex(rect_id)) {
std::vector<unsigned char> raw_data = load_svg(icon.second, icon_sz, icon_sz);
const ImU32* pIn = (ImU32*)raw_data.data();
for (int y = 0; y < icon_sz; y++) {
ImU32* pOut = (ImU32*)pixels + (rect->Y + y) * width + (rect->X);
for (int x = 0; x < icon_sz; x++)
*pOut++ = *pIn++;
}
}
rect_id++;
}
// Upload texture to graphics system // Upload texture to graphics system
GLint last_texture; GLint last_texture;
glsafe(::glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture)); glsafe(::glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture));

View File

@ -79,7 +79,7 @@ public:
bool combo(const wxString& label, const std::vector<std::string>& options, int& selection); // Use -1 to not mark any option as selected bool combo(const wxString& label, const std::vector<std::string>& options, int& selection); // Use -1 to not mark any option as selected
bool undo_redo_list(const ImVec2& size, const bool is_undo, bool (*items_getter)(const bool, int, const char**), int& hovered, int& selected, int& mouse_wheel); bool undo_redo_list(const ImVec2& size, const bool is_undo, bool (*items_getter)(const bool, int, const char**), int& hovered, int& selected, int& mouse_wheel);
void search_list(const ImVec2& size, bool (*items_getter)(int, const char** label, const char** tooltip), char* search_str, void search_list(const ImVec2& size, bool (*items_getter)(int, const char** label, const char** tooltip), char* search_str,
Search::OptionViewParameters& view_params, int& selected, bool& edited, int& mouse_wheel); Search::OptionViewParameters& view_params, int& selected, bool& edited, int& mouse_wheel, bool is_localized);
void disabled_begin(bool disabled); void disabled_begin(bool disabled);
void disabled_end(); void disabled_end();
@ -96,6 +96,7 @@ private:
void render_draw_data(ImDrawData *draw_data); void render_draw_data(ImDrawData *draw_data);
bool display_initialized() const; bool display_initialized() const;
void destroy_font(); void destroy_font();
std::vector<unsigned char> load_svg(const std::string& bitmap_name, unsigned target_width, unsigned target_height);
static const char* clipboard_get(void* user_data); static const char* clipboard_get(void* user_data);
static void clipboard_set(void* user_data, const char* text); static void clipboard_set(void* user_data, const char* text);

View File

@ -7,7 +7,7 @@
#include <wx/menu.h> #include <wx/menu.h>
#include <wx/progdlg.h> #include <wx/progdlg.h>
#include <wx/tooltip.h> #include <wx/tooltip.h>
#include <wx/glcanvas.h> //#include <wx/glcanvas.h>
#include <wx/debug.h> #include <wx/debug.h>
#include <boost/algorithm/string/predicate.hpp> #include <boost/algorithm/string/predicate.hpp>
@ -28,6 +28,7 @@
#include "RemovableDriveManager.hpp" #include "RemovableDriveManager.hpp"
#include "InstanceCheck.hpp" #include "InstanceCheck.hpp"
#include "I18N.hpp" #include "I18N.hpp"
#include "GLCanvas3D.hpp"
#include <fstream> #include <fstream>
#include "GUI_App.hpp" #include "GUI_App.hpp"
@ -90,10 +91,12 @@ DPIFrame(NULL, wxID_ANY, "", wxDefaultPosition, wxDefaultSize, wxDEFAULT_FRAME_S
// initialize layout // initialize layout
auto sizer = new wxBoxSizer(wxVERTICAL); auto sizer = new wxBoxSizer(wxVERTICAL);
if (m_plater) if (m_plater && m_layout != slOld)
sizer->Add(m_plater, 1, wxEXPAND); sizer->Add(m_plater, 1, wxEXPAND);
if (m_tabpanel)
if (m_tabpanel && m_layout != slDlg)
sizer->Add(m_tabpanel, 1, wxEXPAND); sizer->Add(m_tabpanel, 1, wxEXPAND);
sizer->SetSizeHints(this); sizer->SetSizeHints(this);
SetSizer(sizer); SetSizer(sizer);
Fit(); Fit();
@ -212,7 +215,6 @@ void MainFrame::shutdown()
if (m_plater) if (m_plater)
m_plater->stop_jobs(); m_plater->stop_jobs();
#if ENABLE_NON_STATIC_CANVAS_MANAGER
// Unbinding of wxWidgets event handling in canvases needs to be done here because on MAC, // Unbinding of wxWidgets event handling in canvases needs to be done here because on MAC,
// when closing the application using Command+Q, a mouse event is triggered after this lambda is completed, // when closing the application using Command+Q, a mouse event is triggered after this lambda is completed,
// causing a crash // causing a crash
@ -221,7 +223,6 @@ void MainFrame::shutdown()
// Cleanup of canvases' volumes needs to be done here or a crash may happen on some Linux Debian flavours // Cleanup of canvases' volumes needs to be done here or a crash may happen on some Linux Debian flavours
// see: https://github.com/prusa3d/PrusaSlicer/issues/3964 // see: https://github.com/prusa3d/PrusaSlicer/issues/3964
if (m_plater) m_plater->reset_canvas_volumes(); if (m_plater) m_plater->reset_canvas_volumes();
#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
// Weird things happen as the Paint messages are floating around the windows being destructed. // Weird things happen as the Paint messages are floating around the windows being destructed.
// Avoid the Paint messages by hiding the main window. // Avoid the Paint messages by hiding the main window.
@ -229,6 +230,9 @@ void MainFrame::shutdown()
// In addition, there were some crashes due to the Paint events sent to already destructed windows. // In addition, there were some crashes due to the Paint events sent to already destructed windows.
this->Show(false); this->Show(false);
if (m_settings_dialog)
m_settings_dialog->Destroy();
// Stop the background thread (Windows and Linux). // Stop the background thread (Windows and Linux).
// Disconnect from a 3DConnextion driver (OSX). // Disconnect from a 3DConnextion driver (OSX).
m_plater->get_mouse3d_controller().shutdown(); m_plater->get_mouse3d_controller().shutdown();
@ -244,9 +248,6 @@ void MainFrame::shutdown()
wxGetApp().app_config->save(); wxGetApp().app_config->save();
// if (m_plater) // if (m_plater)
// m_plater->print = undef; // m_plater->print = undef;
#if !ENABLE_NON_STATIC_CANVAS_MANAGER
_3DScene::remove_all_canvases();
#endif // !ENABLE_NON_STATIC_CANVAS_MANAGER
// Slic3r::GUI::deregister_on_request_update_callback(); // Slic3r::GUI::deregister_on_request_update_callback();
// set to null tabs and a plater // set to null tabs and a plater
@ -289,12 +290,25 @@ void MainFrame::update_title()
void MainFrame::init_tabpanel() void MainFrame::init_tabpanel()
{ {
// wxNB_NOPAGETHEME: Disable Windows Vista theme for the Notebook background. The theme performance is terrible on Windows 10 m_layout = wxGetApp().app_config->get("old_settings_layout_mode") == "1" ? slOld :
// with multiple high resolution displays connected. wxGetApp().app_config->get("new_settings_layout_mode") == "1" ? slNew :
m_tabpanel = new wxNotebook(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxNB_TOP | wxTAB_TRAVERSAL | wxNB_NOPAGETHEME); wxGetApp().app_config->get("dlg_settings_layout_mode") == "1" ? slDlg : slOld;
// From the very beginning the Print settings should be selected
m_last_selected_tab = m_layout == slDlg ? 0 : 1;
if (m_layout == slDlg) {
m_settings_dialog = new SettingsDialog(this);
m_tabpanel = m_settings_dialog->get_tabpanel();
}
else {
// wxNB_NOPAGETHEME: Disable Windows Vista theme for the Notebook background. The theme performance is terrible on Windows 10
// with multiple high resolution displays connected.
m_tabpanel = new wxNotebook(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxNB_TOP | wxTAB_TRAVERSAL | wxNB_NOPAGETHEME);
#ifndef __WXOSX__ // Don't call SetFont under OSX to avoid name cutting in ObjectList #ifndef __WXOSX__ // Don't call SetFont under OSX to avoid name cutting in ObjectList
m_tabpanel->SetFont(Slic3r::GUI::wxGetApp().normal_font()); m_tabpanel->SetFont(Slic3r::GUI::wxGetApp().normal_font());
#endif #endif
}
m_tabpanel->Bind(wxEVT_NOTEBOOK_PAGE_CHANGED, [this](wxEvent&) { m_tabpanel->Bind(wxEVT_NOTEBOOK_PAGE_CHANGED, [this](wxEvent&) {
auto panel = m_tabpanel->GetCurrentPage(); auto panel = m_tabpanel->GetCurrentPage();
@ -307,17 +321,22 @@ void MainFrame::init_tabpanel()
// On GTK, the wxEVT_NOTEBOOK_PAGE_CHANGED event is triggered // On GTK, the wxEVT_NOTEBOOK_PAGE_CHANGED event is triggered
// before the MainFrame is fully set up. // before the MainFrame is fully set up.
static_cast<Tab*>(panel)->OnActivate(); static_cast<Tab*>(panel)->OnActivate();
m_last_selected_tab = m_tabpanel->GetSelection();
} }
else else
select_tab(0); select_tab(0);
}); });
//! m_plater = new Slic3r::GUI::Plater(m_tabpanel, this); if (m_layout == slOld) {
m_plater = new Plater(this, this); m_plater = new Plater(m_tabpanel, this);
m_tabpanel->AddPage(m_plater, _L("Plater"));
}
else {
m_plater = new Plater(this, this);
if (m_layout == slNew)
m_tabpanel->AddPage(new wxPanel(m_tabpanel), _L("Plater")); // empty panel just for Plater tab
}
wxGetApp().plater_ = m_plater; wxGetApp().plater_ = m_plater;
// m_tabpanel->AddPage(m_plater, _(L("Plater")));
m_tabpanel->AddPage(new wxPanel(m_tabpanel), _L("Plater")); // empty panel just for Plater tab
wxGetApp().obj_list()->create_popup_menus(); wxGetApp().obj_list()->create_popup_menus();
@ -343,13 +362,6 @@ void MainFrame::init_tabpanel()
} }
} }
void MainFrame::switch_to(bool plater)
{
this->m_plater->Show(plater);
this->m_tabpanel->Show(!plater);
this->Layout();
}
void MainFrame::create_preset_tabs() void MainFrame::create_preset_tabs()
{ {
wxGetApp().update_label_colours_from_appconfig(); wxGetApp().update_label_colours_from_appconfig();
@ -465,6 +477,11 @@ bool MainFrame::can_slice() const
bool MainFrame::can_change_view() const bool MainFrame::can_change_view() const
{ {
if (m_layout == slNew)
return m_plater->IsShown();
if (m_layout == slDlg)
return true;
// slOld layout mode
int page_id = m_tabpanel->GetSelection(); int page_id = m_tabpanel->GetSelection();
return page_id != wxNOT_FOUND && dynamic_cast<const Slic3r::GUI::Plater*>(m_tabpanel->GetPage((size_t)page_id)) != nullptr; return page_id != wxNOT_FOUND && dynamic_cast<const Slic3r::GUI::Plater*>(m_tabpanel->GetPage((size_t)page_id)) != nullptr;
} }
@ -763,25 +780,21 @@ void MainFrame::init_menubar()
// Window menu // Window menu
auto windowMenu = new wxMenu(); auto windowMenu = new wxMenu();
{ {
//! size_t tab_offset = 0;
if (m_plater) { if (m_plater) {
append_menu_item(windowMenu, wxID_HIGHEST + 1, _(L("&Plater Tab")) + "\tCtrl+1", _(L("Show the plater")), append_menu_item(windowMenu, wxID_HIGHEST + 1, _(L("&Plater Tab")) + "\tCtrl+1", _(L("Show the plater")),
[this/*, tab_offset*/](wxCommandEvent&) { select_tab(/*(size_t)(-1)*/0); }, "plater", nullptr, [this](wxCommandEvent&) { select_tab(0); }, "plater", nullptr,
[this]() {return true; }, this); [this]() {return true; }, this);
//! tab_offset += 1;
//! }
//! if (tab_offset > 0) {
windowMenu->AppendSeparator(); windowMenu->AppendSeparator();
} }
append_menu_item(windowMenu, wxID_HIGHEST + 2, _(L("P&rint Settings Tab")) + "\tCtrl+2", _(L("Show the print settings")), append_menu_item(windowMenu, wxID_HIGHEST + 2, _(L("P&rint Settings Tab")) + "\tCtrl+2", _(L("Show the print settings")),
[this/*, tab_offset*/](wxCommandEvent&) { select_tab(/*tab_offset + 0*/1); }, "cog", nullptr, [this/*, tab_offset*/](wxCommandEvent&) { select_tab(1); }, "cog", nullptr,
[this]() {return true; }, this); [this]() {return true; }, this);
wxMenuItem* item_material_tab = append_menu_item(windowMenu, wxID_HIGHEST + 3, _(L("&Filament Settings Tab")) + "\tCtrl+3", _(L("Show the filament settings")), wxMenuItem* item_material_tab = append_menu_item(windowMenu, wxID_HIGHEST + 3, _(L("&Filament Settings Tab")) + "\tCtrl+3", _(L("Show the filament settings")),
[this/*, tab_offset*/](wxCommandEvent&) { select_tab(/*tab_offset + 1*/2); }, "spool", nullptr, [this/*, tab_offset*/](wxCommandEvent&) { select_tab(2); }, "spool", nullptr,
[this]() {return true; }, this); [this]() {return true; }, this);
m_changeable_menu_items.push_back(item_material_tab); m_changeable_menu_items.push_back(item_material_tab);
wxMenuItem* item_printer_tab = append_menu_item(windowMenu, wxID_HIGHEST + 4, _(L("Print&er Settings Tab")) + "\tCtrl+4", _(L("Show the printer settings")), wxMenuItem* item_printer_tab = append_menu_item(windowMenu, wxID_HIGHEST + 4, _(L("Print&er Settings Tab")) + "\tCtrl+4", _(L("Show the printer settings")),
[this/*, tab_offset*/](wxCommandEvent&) { select_tab(/*tab_offset + 2*/3); }, "printer", nullptr, [this/*, tab_offset*/](wxCommandEvent&) { select_tab(3); }, "printer", nullptr,
[this]() {return true; }, this); [this]() {return true; }, this);
m_changeable_menu_items.push_back(item_printer_tab); m_changeable_menu_items.push_back(item_printer_tab);
if (m_plater) { if (m_plater) {
@ -1245,17 +1258,39 @@ void MainFrame::load_config(const DynamicPrintConfig& config)
#endif #endif
} }
void MainFrame::select_tab(size_t tab) void MainFrame::select_tab(size_t tab/* = size_t(-1)*/)
{ {
if (tab == /*(size_t)(-1)*/0) { if (m_layout == slDlg) {
if (m_plater && !m_plater->IsShown()) if (tab==0) {
this->switch_to(true); if (m_settings_dialog->IsShown())
this->SetFocus();
// plater should be focused for correct navigation inside search window
if (m_plater->canvas3D()->is_search_pressed())
m_plater->SetFocus();
return;
}
// Show/Activate Settings Dialog
if (m_settings_dialog->IsShown())
#ifdef __WXOSX__ // Don't call SetFont under OSX to avoid name cutting in ObjectList
m_settings_dialog->Hide();
#else
m_settings_dialog->SetFocus();
else
#endif
m_settings_dialog->Show();
} }
else { else if (m_layout == slNew) {
if (m_plater && m_plater->IsShown()) m_plater->Show(tab == 0);
switch_to(false); m_tabpanel->Show(tab != 0);
m_tabpanel->SetSelection(tab);
// plater should be focused for correct navigation inside search window
if (tab == 0 && m_plater->canvas3D()->is_search_pressed())
m_plater->SetFocus();
Layout();
} }
// when tab == -1, it means we should to show the last selected tab
m_tabpanel->SetSelection(tab == (size_t)(-1) ? m_last_selected_tab : (m_layout == slDlg && tab != 0) ? tab-1 : tab);
} }
// Set a camera direction, zoom to all objects. // Set a camera direction, zoom to all objects.
@ -1360,5 +1395,79 @@ std::string MainFrame::get_dir_name(const wxString &full_name) const
return boost::filesystem::path(full_name.wx_str()).parent_path().string(); return boost::filesystem::path(full_name.wx_str()).parent_path().string();
} }
// ----------------------------------------------------------------------------
// SettingsDialog
// ----------------------------------------------------------------------------
SettingsDialog::SettingsDialog(MainFrame* mainframe)
: DPIDialog(nullptr, wxID_ANY, wxString(SLIC3R_APP_NAME) + " - " + _L("Settings")),
m_main_frame(mainframe)
{
this->SetFont(wxGetApp().normal_font());
wxColour bgr_clr = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW);
this->SetBackgroundColour(bgr_clr);
// Load the icon either from the exe, or from the ico file.
#if _WIN32
{
TCHAR szExeFileName[MAX_PATH];
GetModuleFileName(nullptr, szExeFileName, MAX_PATH);
SetIcon(wxIcon(szExeFileName, wxBITMAP_TYPE_ICO));
}
#else
SetIcon(wxIcon(var("PrusaSlicer_128px.png"), wxBITMAP_TYPE_PNG));
#endif // _WIN32
// wxNB_NOPAGETHEME: Disable Windows Vista theme for the Notebook background. The theme performance is terrible on Windows 10
// with multiple high resolution displays connected.
m_tabpanel = new wxNotebook(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxNB_TOP | wxTAB_TRAVERSAL | wxNB_NOPAGETHEME);
#ifndef __WXOSX__ // Don't call SetFont under OSX to avoid name cutting in ObjectList
m_tabpanel->SetFont(Slic3r::GUI::wxGetApp().normal_font());
#endif
m_tabpanel->Bind(wxEVT_KEY_UP, [this](wxKeyEvent& evt) {
if ((evt.GetModifiers() & wxMOD_CONTROL) != 0) {
switch (evt.GetKeyCode()) {
case '1': { m_main_frame->select_tab(0); break; }
case '2': { m_main_frame->select_tab(1); break; }
case '3': { m_main_frame->select_tab(2); break; }
case '4': { m_main_frame->select_tab(3); break; }
default:break;
}
}
});
// initialize layout
auto sizer = new wxBoxSizer(wxVERTICAL);
sizer->Add(m_tabpanel, 1, wxEXPAND);
sizer->SetSizeHints(this);
SetSizer(sizer);
Fit();
const wxSize min_size = wxSize(85 * em_unit(), 50 * em_unit());
#ifdef __APPLE__
// Using SetMinSize() on Mac messes up the window position in some cases
// cf. https://groups.google.com/forum/#!topic/wx-users/yUKPBBfXWO0
SetSize(min_size);
#else
SetMinSize(min_size);
SetSize(GetMinSize());
#endif
Layout();
}
void SettingsDialog::on_dpi_changed(const wxRect& suggested_rect)
{
const int& em = em_unit();
const wxSize& size = wxSize(85 * em, 50 * em);
SetMinSize(size);
Fit();
Refresh();
}
} // GUI } // GUI
} // Slic3r } // Slic3r

View File

@ -43,6 +43,23 @@ struct PresetTab {
PrinterTechnology technology; PrinterTechnology technology;
}; };
// ----------------------------------------------------------------------------
// SettingsDialog
// ----------------------------------------------------------------------------
class SettingsDialog : public DPIDialog
{
wxNotebook* m_tabpanel { nullptr };
MainFrame* m_main_frame {nullptr };
public:
SettingsDialog(MainFrame* mainframe);
~SettingsDialog() {}
wxNotebook* get_tabpanel() { return m_tabpanel; }
protected:
void on_dpi_changed(const wxRect& suggested_rect) override;
};
class MainFrame : public DPIFrame class MainFrame : public DPIFrame
{ {
bool m_loaded {false}; bool m_loaded {false};
@ -57,6 +74,8 @@ class MainFrame : public DPIFrame
PrintHostQueueDialog *m_printhost_queue_dlg; PrintHostQueueDialog *m_printhost_queue_dlg;
size_t m_last_selected_tab;
std::string get_base_name(const wxString &full_name, const char *extension = nullptr) const; std::string get_base_name(const wxString &full_name, const char *extension = nullptr) const;
std::string get_dir_name(const wxString &full_name) const; std::string get_dir_name(const wxString &full_name) const;
@ -94,6 +113,12 @@ class MainFrame : public DPIFrame
wxFileHistory m_recent_projects; wxFileHistory m_recent_projects;
enum SettingsLayout {
slOld = 0,
slNew,
slDlg,
} m_layout;
protected: protected:
virtual void on_dpi_changed(const wxRect &suggested_rect); virtual void on_dpi_changed(const wxRect &suggested_rect);
@ -109,7 +134,6 @@ public:
void update_title(); void update_title();
void init_tabpanel(); void init_tabpanel();
void switch_to(bool plater);
void create_preset_tabs(); void create_preset_tabs();
void add_created_tab(Tab* panel); void add_created_tab(Tab* panel);
void init_menubar(); void init_menubar();
@ -130,7 +154,9 @@ public:
void export_configbundle(); void export_configbundle();
void load_configbundle(wxString file = wxEmptyString); void load_configbundle(wxString file = wxEmptyString);
void load_config(const DynamicPrintConfig& config); void load_config(const DynamicPrintConfig& config);
void select_tab(size_t tab); // Select tab in m_tabpanel
// When tab == -1, will be selected last selected tab
void select_tab(size_t tab = size_t(-1));
void select_view(const std::string& direction); void select_view(const std::string& direction);
// Propagate changed configuration from the Tab to the Plater and save changes to the AppConfig // Propagate changed configuration from the Tab to the Plater and save changes to the AppConfig
void on_config_changed(DynamicPrintConfig* cfg) const ; void on_config_changed(DynamicPrintConfig* cfg) const ;
@ -141,6 +167,7 @@ public:
Plater* m_plater { nullptr }; Plater* m_plater { nullptr };
wxNotebook* m_tabpanel { nullptr }; wxNotebook* m_tabpanel { nullptr };
SettingsDialog* m_settings_dialog { nullptr };
wxProgressDialog* m_progress_dialog { nullptr }; wxProgressDialog* m_progress_dialog { nullptr };
std::shared_ptr<ProgressStatusBar> m_statusbar; std::shared_ptr<ProgressStatusBar> m_statusbar;

View File

@ -1710,10 +1710,11 @@ bool BitmapChoiceRenderer::Render(wxRect rect, wxDC* dc, int state)
{ {
dc->DrawBitmap(icon, rect.x, rect.y + (rect.height - icon.GetHeight()) / 2); dc->DrawBitmap(icon, rect.x, rect.y + (rect.height - icon.GetHeight()) / 2);
xoffset = icon.GetWidth() + 4; xoffset = icon.GetWidth() + 4;
if (rect.height==0)
rect.height= icon.GetHeight();
} }
if (rect.height==0)
rect.height= icon.GetHeight();
RenderText(m_value.GetText(), xoffset, rect, dc, state); RenderText(m_value.GetText(), xoffset, rect, dc, state);
return true; return true;

View File

@ -1,23 +1,18 @@
#include "libslic3r/libslic3r.h" #include "libslic3r/libslic3r.h"
#include "GLCanvas3DManager.hpp" #include "OpenGLManager.hpp"
#include "../../slic3r/GUI/GUI.hpp"
#include "../../slic3r/GUI/AppConfig.hpp" #include "GUI.hpp"
#include "../../slic3r/GUI/GLCanvas3D.hpp" #include "I18N.hpp"
#include "3DScene.hpp"
#include <GL/glew.h> #include <GL/glew.h>
#include <boost/algorithm/string/split.hpp> #include <boost/algorithm/string/split.hpp>
#include <boost/algorithm/string/classification.hpp> #include <boost/algorithm/string/classification.hpp>
#if ENABLE_NON_STATIC_CANVAS_MANAGER
#include <boost/log/trivial.hpp> #include <boost/log/trivial.hpp>
#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
#include <wx/glcanvas.h>
#include <wx/timer.h>
#include <wx/msgdlg.h>
#include <vector> #include <wx/glcanvas.h>
#include <string> #include <wx/msgdlg.h>
#include <iostream>
#if ENABLE_HACK_CLOSING_ON_OSX_10_9_5 #if ENABLE_HACK_CLOSING_ON_OSX_10_9_5
#ifdef __APPLE__ #ifdef __APPLE__
@ -33,20 +28,7 @@
namespace Slic3r { namespace Slic3r {
namespace GUI { namespace GUI {
#if !ENABLE_NON_STATIC_CANVAS_MANAGER const std::string& OpenGLManager::GLInfo::get_version() const
GLCanvas3DManager::GLInfo::GLInfo()
: m_detected(false)
, m_version("")
, m_glsl_version("")
, m_vendor("")
, m_renderer("")
, m_max_tex_size(0)
, m_max_anisotropy(0.0f)
{
}
#endif // !ENABLE_NON_STATIC_CANVAS_MANAGER
const std::string& GLCanvas3DManager::GLInfo::get_version() const
{ {
if (!m_detected) if (!m_detected)
detect(); detect();
@ -54,7 +36,7 @@ const std::string& GLCanvas3DManager::GLInfo::get_version() const
return m_version; return m_version;
} }
const std::string& GLCanvas3DManager::GLInfo::get_glsl_version() const const std::string& OpenGLManager::GLInfo::get_glsl_version() const
{ {
if (!m_detected) if (!m_detected)
detect(); detect();
@ -62,7 +44,7 @@ const std::string& GLCanvas3DManager::GLInfo::get_glsl_version() const
return m_glsl_version; return m_glsl_version;
} }
const std::string& GLCanvas3DManager::GLInfo::get_vendor() const const std::string& OpenGLManager::GLInfo::get_vendor() const
{ {
if (!m_detected) if (!m_detected)
detect(); detect();
@ -70,7 +52,7 @@ const std::string& GLCanvas3DManager::GLInfo::get_vendor() const
return m_vendor; return m_vendor;
} }
const std::string& GLCanvas3DManager::GLInfo::get_renderer() const const std::string& OpenGLManager::GLInfo::get_renderer() const
{ {
if (!m_detected) if (!m_detected)
detect(); detect();
@ -78,7 +60,7 @@ const std::string& GLCanvas3DManager::GLInfo::get_renderer() const
return m_renderer; return m_renderer;
} }
int GLCanvas3DManager::GLInfo::get_max_tex_size() const int OpenGLManager::GLInfo::get_max_tex_size() const
{ {
if (!m_detected) if (!m_detected)
detect(); detect();
@ -93,7 +75,7 @@ int GLCanvas3DManager::GLInfo::get_max_tex_size() const
#endif // __APPLE__ #endif // __APPLE__
} }
float GLCanvas3DManager::GLInfo::get_max_anisotropy() const float OpenGLManager::GLInfo::get_max_anisotropy() const
{ {
if (!m_detected) if (!m_detected)
detect(); detect();
@ -101,7 +83,7 @@ float GLCanvas3DManager::GLInfo::get_max_anisotropy() const
return m_max_anisotropy; return m_max_anisotropy;
} }
void GLCanvas3DManager::GLInfo::detect() const void OpenGLManager::GLInfo::detect() const
{ {
const char* data = (const char*)::glGetString(GL_VERSION); const char* data = (const char*)::glGetString(GL_VERSION);
if (data != nullptr) if (data != nullptr)
@ -132,7 +114,7 @@ void GLCanvas3DManager::GLInfo::detect() const
m_detected = true; m_detected = true;
} }
bool GLCanvas3DManager::GLInfo::is_version_greater_or_equal_to(unsigned int major, unsigned int minor) const bool OpenGLManager::GLInfo::is_version_greater_or_equal_to(unsigned int major, unsigned int minor) const
{ {
if (!m_detected) if (!m_detected)
detect(); detect();
@ -163,7 +145,7 @@ bool GLCanvas3DManager::GLInfo::is_version_greater_or_equal_to(unsigned int majo
return gl_minor >= minor; return gl_minor >= minor;
} }
std::string GLCanvas3DManager::GLInfo::to_string(bool format_as_html, bool extensions) const std::string OpenGLManager::GLInfo::to_string(bool format_as_html, bool extensions) const
{ {
if (!m_detected) if (!m_detected)
detect(); detect();
@ -203,34 +185,20 @@ std::string GLCanvas3DManager::GLInfo::to_string(bool format_as_html, bool exten
return out.str(); return out.str();
} }
GLCanvas3DManager::GLInfo GLCanvas3DManager::s_gl_info; OpenGLManager::GLInfo OpenGLManager::s_gl_info;
bool GLCanvas3DManager::s_compressed_textures_supported = false; bool OpenGLManager::s_compressed_textures_supported = false;
#if ENABLE_NON_STATIC_CANVAS_MANAGER OpenGLManager::EMultisampleState OpenGLManager::s_multisample = OpenGLManager::EMultisampleState::Unknown;
GLCanvas3DManager::EMultisampleState GLCanvas3DManager::s_multisample = GLCanvas3DManager::EMultisampleState::Unknown; OpenGLManager::EFramebufferType OpenGLManager::s_framebuffers_type = OpenGLManager::EFramebufferType::Unknown;
GLCanvas3DManager::EFramebufferType GLCanvas3DManager::s_framebuffers_type = GLCanvas3DManager::EFramebufferType::Unknown;
#else
GLCanvas3DManager::EMultisampleState GLCanvas3DManager::s_multisample = GLCanvas3DManager::MS_Unknown;
GLCanvas3DManager::EFramebufferType GLCanvas3DManager::s_framebuffers_type = GLCanvas3DManager::FB_None;
#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
#if ENABLE_HACK_CLOSING_ON_OSX_10_9_5 #if ENABLE_HACK_CLOSING_ON_OSX_10_9_5
#ifdef __APPLE__ #ifdef __APPLE__
// Part of hack to remove crash when closing the application on OSX 10.9.5 when building against newer wxWidgets // Part of hack to remove crash when closing the application on OSX 10.9.5 when building against newer wxWidgets
GLCanvas3DManager::OSInfo GLCanvas3DManager::s_os_info; OpenGLManager::OSInfo OpenGLManager::s_os_info;
#endif // __APPLE__ #endif // __APPLE__
#endif // ENABLE_HACK_CLOSING_ON_OSX_10_9_5 #endif // ENABLE_HACK_CLOSING_ON_OSX_10_9_5
#if !ENABLE_NON_STATIC_CANVAS_MANAGER OpenGLManager::~OpenGLManager()
GLCanvas3DManager::GLCanvas3DManager()
: m_context(nullptr)
, m_gl_initialized(false)
{ {
}
#endif // !ENABLE_NON_STATIC_CANVAS_MANAGER
GLCanvas3DManager::~GLCanvas3DManager()
{
#if ENABLE_NON_STATIC_CANVAS_MANAGER
#if ENABLE_HACK_CLOSING_ON_OSX_10_9_5 #if ENABLE_HACK_CLOSING_ON_OSX_10_9_5
#ifdef __APPLE__ #ifdef __APPLE__
// This is an ugly hack needed to solve the crash happening when closing the application on OSX 10.9.5 with newer wxWidgets // This is an ugly hack needed to solve the crash happening when closing the application on OSX 10.9.5 with newer wxWidgets
@ -248,116 +216,29 @@ GLCanvas3DManager::~GLCanvas3DManager()
} }
#endif //__APPLE__ #endif //__APPLE__
#endif // ENABLE_HACK_CLOSING_ON_OSX_10_9_5 #endif // ENABLE_HACK_CLOSING_ON_OSX_10_9_5
#else
this->destroy();
#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
} }
#if !ENABLE_NON_STATIC_CANVAS_MANAGER bool OpenGLManager::init_gl()
bool GLCanvas3DManager::add(wxGLCanvas* canvas, Bed3D& bed, Camera& camera, GLToolbar& view_toolbar)
{
if (canvas == nullptr)
return false;
if (do_get_canvas(canvas) != m_canvases.end())
return false;
GLCanvas3D* canvas3D = new GLCanvas3D(canvas, bed, camera, view_toolbar);
if (canvas3D == nullptr)
return false;
canvas3D->bind_event_handlers();
if (m_context == nullptr)
{
m_context = new wxGLContext(canvas);
if (m_context == nullptr)
return false;
#if ENABLE_HACK_CLOSING_ON_OSX_10_9_5
#ifdef __APPLE__
// Part of hack to remove crash when closing the application on OSX 10.9.5 when building against newer wxWidgets
s_os_info.major = wxPlatformInfo::Get().GetOSMajorVersion();
s_os_info.minor = wxPlatformInfo::Get().GetOSMinorVersion();
s_os_info.micro = wxPlatformInfo::Get().GetOSMicroVersion();
#endif //__APPLE__
#endif // ENABLE_HACK_CLOSING_ON_OSX_10_9_5
}
canvas3D->set_context(m_context);
m_canvases.insert(CanvasesMap::value_type(canvas, canvas3D));
return true;
}
bool GLCanvas3DManager::remove(wxGLCanvas* canvas)
{
CanvasesMap::iterator it = do_get_canvas(canvas);
if (it == m_canvases.end())
return false;
it->second->unbind_event_handlers();
delete it->second;
m_canvases.erase(it);
return true;
}
void GLCanvas3DManager::remove_all()
{
for (CanvasesMap::value_type& item : m_canvases)
{
item.second->unbind_event_handlers();
delete item.second;
}
m_canvases.clear();
}
size_t GLCanvas3DManager::count() const
{
return m_canvases.size();
}
#endif // !ENABLE_NON_STATIC_CANVAS_MANAGER
#if ENABLE_NON_STATIC_CANVAS_MANAGER
bool GLCanvas3DManager::init_gl()
#else
void GLCanvas3DManager::init_gl()
#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
{ {
if (!m_gl_initialized) if (!m_gl_initialized)
{ {
#if ENABLE_NON_STATIC_CANVAS_MANAGER
if (glewInit() != GLEW_OK) if (glewInit() != GLEW_OK)
{ {
BOOST_LOG_TRIVIAL(error) << "Unable to init glew library"; BOOST_LOG_TRIVIAL(error) << "Unable to init glew library";
return false; return false;
} }
#else
glewInit();
#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
m_gl_initialized = true; m_gl_initialized = true;
if (GLEW_EXT_texture_compression_s3tc) if (GLEW_EXT_texture_compression_s3tc)
s_compressed_textures_supported = true; s_compressed_textures_supported = true;
else else
s_compressed_textures_supported = false; s_compressed_textures_supported = false;
#if ENABLE_NON_STATIC_CANVAS_MANAGER
if (GLEW_ARB_framebuffer_object) if (GLEW_ARB_framebuffer_object)
s_framebuffers_type = EFramebufferType::Arb; s_framebuffers_type = EFramebufferType::Arb;
else if (GLEW_EXT_framebuffer_object) else if (GLEW_EXT_framebuffer_object)
s_framebuffers_type = EFramebufferType::Ext; s_framebuffers_type = EFramebufferType::Ext;
else else
s_framebuffers_type = EFramebufferType::Unknown; s_framebuffers_type = EFramebufferType::Unknown;
#else
if (GLEW_ARB_framebuffer_object)
s_framebuffers_type = FB_Arb;
else if (GLEW_EXT_framebuffer_object)
s_framebuffers_type = FB_Ext;
else
s_framebuffers_type = FB_None;
#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
if (! s_gl_info.is_version_greater_or_equal_to(2, 0)) { if (! s_gl_info.is_version_greater_or_equal_to(2, 0)) {
// Complain about the OpenGL version. // Complain about the OpenGL version.
@ -365,22 +246,19 @@ void GLCanvas3DManager::init_gl()
_utf8(L("PrusaSlicer requires OpenGL 2.0 capable graphics driver to run correctly, \n" _utf8(L("PrusaSlicer requires OpenGL 2.0 capable graphics driver to run correctly, \n"
"while OpenGL version %s, render %s, vendor %s was detected."))) % s_gl_info.get_version() % s_gl_info.get_renderer() % s_gl_info.get_vendor()).str()); "while OpenGL version %s, render %s, vendor %s was detected."))) % s_gl_info.get_version() % s_gl_info.get_renderer() % s_gl_info.get_vendor()).str());
message += "\n"; message += "\n";
message += _(L("You may need to update your graphics card driver.")); message += _L("You may need to update your graphics card driver.");
#ifdef _WIN32 #ifdef _WIN32
message += "\n"; message += "\n";
message += _(L("As a workaround, you may run PrusaSlicer with a software rendered 3D graphics by running prusa-slicer.exe with the --sw_renderer parameter.")); message += _L("As a workaround, you may run PrusaSlicer with a software rendered 3D graphics by running prusa-slicer.exe with the --sw_renderer parameter.");
#endif #endif
wxMessageBox(message, wxString("PrusaSlicer - ") + _(L("Unsupported OpenGL version")), wxOK | wxICON_ERROR); wxMessageBox(message, wxString("PrusaSlicer - ") + _L("Unsupported OpenGL version"), wxOK | wxICON_ERROR);
} }
} }
#if ENABLE_NON_STATIC_CANVAS_MANAGER
return true; return true;
#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
} }
#if ENABLE_NON_STATIC_CANVAS_MANAGER wxGLContext* OpenGLManager::init_glcontext(wxGLCanvas& canvas)
wxGLContext* GLCanvas3DManager::init_glcontext(wxGLCanvas& canvas)
{ {
if (m_context == nullptr) if (m_context == nullptr)
{ {
@ -397,48 +275,8 @@ wxGLContext* GLCanvas3DManager::init_glcontext(wxGLCanvas& canvas)
} }
return m_context; return m_context;
} }
#else
bool GLCanvas3DManager::init(wxGLCanvas* canvas)
{
CanvasesMap::const_iterator it = do_get_canvas(canvas);
if (it != m_canvases.end())
return (it->second != nullptr) ? init(*it->second) : false;
else
return false;
}
void GLCanvas3DManager::destroy() wxGLCanvas* OpenGLManager::create_wxglcanvas(wxWindow& parent)
{
if (m_context != nullptr)
{
#if ENABLE_HACK_CLOSING_ON_OSX_10_9_5
#ifdef __APPLE__
// this is an ugly hack needed to solve the crash happening when closing the application on OSX 10.9.5
// the crash is inside wxGLContext destructor
if (s_os_info.major == 10 && s_os_info.minor == 9 && s_os_info.micro == 5)
return;
#endif //__APPLE__
#endif // ENABLE_HACK_CLOSING_ON_OSX_10_9_5
delete m_context;
m_context = nullptr;
}
}
#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
#if !ENABLE_NON_STATIC_CANVAS_MANAGER
GLCanvas3D* GLCanvas3DManager::get_canvas(wxGLCanvas* canvas)
{
CanvasesMap::const_iterator it = do_get_canvas(canvas);
return (it != m_canvases.end()) ? it->second : nullptr;
}
#endif // !ENABLE_NON_STATIC_CANVAS_MANAGER
#if ENABLE_NON_STATIC_CANVAS_MANAGER
wxGLCanvas* GLCanvas3DManager::create_wxglcanvas(wxWindow& parent)
#else
wxGLCanvas* GLCanvas3DManager::create_wxglcanvas(wxWindow *parent)
#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
{ {
int attribList[] = { int attribList[] = {
WX_GL_RGBA, WX_GL_RGBA,
@ -456,11 +294,7 @@ wxGLCanvas* GLCanvas3DManager::create_wxglcanvas(wxWindow *parent)
0 0
}; };
#if ENABLE_NON_STATIC_CANVAS_MANAGER
if (s_multisample == EMultisampleState::Unknown) if (s_multisample == EMultisampleState::Unknown)
#else
if (s_multisample == MS_Unknown)
#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
{ {
detect_multisample(attribList); detect_multisample(attribList);
// // debug output // // debug output
@ -470,42 +304,14 @@ wxGLCanvas* GLCanvas3DManager::create_wxglcanvas(wxWindow *parent)
if (! can_multisample()) if (! can_multisample())
attribList[12] = 0; attribList[12] = 0;
#if ENABLE_NON_STATIC_CANVAS_MANAGER
return new wxGLCanvas(&parent, wxID_ANY, attribList, wxDefaultPosition, wxDefaultSize, wxWANTS_CHARS); return new wxGLCanvas(&parent, wxID_ANY, attribList, wxDefaultPosition, wxDefaultSize, wxWANTS_CHARS);
#else
return new wxGLCanvas(parent, wxID_ANY, attribList, wxDefaultPosition, wxDefaultSize, wxWANTS_CHARS);
#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
} }
#if !ENABLE_NON_STATIC_CANVAS_MANAGER void OpenGLManager::detect_multisample(int* attribList)
GLCanvas3DManager::CanvasesMap::iterator GLCanvas3DManager::do_get_canvas(wxGLCanvas* canvas)
{
return (canvas == nullptr) ? m_canvases.end() : m_canvases.find(canvas);
}
GLCanvas3DManager::CanvasesMap::const_iterator GLCanvas3DManager::do_get_canvas(wxGLCanvas* canvas) const
{
return (canvas == nullptr) ? m_canvases.end() : m_canvases.find(canvas);
}
bool GLCanvas3DManager::init(GLCanvas3D& canvas)
{
if (!m_gl_initialized)
init_gl();
return canvas.init();
}
#endif // !ENABLE_NON_STATIC_CANVAS_MANAGER
void GLCanvas3DManager::detect_multisample(int* attribList)
{ {
int wxVersion = wxMAJOR_VERSION * 10000 + wxMINOR_VERSION * 100 + wxRELEASE_NUMBER; int wxVersion = wxMAJOR_VERSION * 10000 + wxMINOR_VERSION * 100 + wxRELEASE_NUMBER;
bool enable_multisample = wxVersion >= 30003; bool enable_multisample = wxVersion >= 30003;
#if ENABLE_NON_STATIC_CANVAS_MANAGER
s_multisample = (enable_multisample && wxGLCanvas::IsDisplaySupported(attribList)) ? EMultisampleState::Enabled : EMultisampleState::Disabled; s_multisample = (enable_multisample && wxGLCanvas::IsDisplaySupported(attribList)) ? EMultisampleState::Enabled : EMultisampleState::Disabled;
#else
s_multisample = (enable_multisample && wxGLCanvas::IsDisplaySupported(attribList)) ? MS_Enabled : MS_Disabled;
#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
// Alternative method: it was working on previous version of wxWidgets but not with the latest, at least on Windows // 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"); // s_multisample = enable_multisample && wxGLCanvas::IsExtensionSupported("WGL_ARB_multisample");
} }

View File

@ -0,0 +1,106 @@
#ifndef slic3r_OpenGLManager_hpp_
#define slic3r_OpenGLManager_hpp_
class wxWindow;
class wxGLCanvas;
class wxGLContext;
namespace Slic3r {
namespace GUI {
class OpenGLManager
{
public:
enum class EFramebufferType : unsigned char
{
Unknown,
Arb,
Ext
};
class GLInfo
{
mutable bool m_detected{ false };
mutable int m_max_tex_size{ 0 };
mutable float m_max_anisotropy{ 0.0f };
mutable std::string m_version;
mutable std::string m_glsl_version;
mutable std::string m_vendor;
mutable std::string m_renderer;
public:
GLInfo() = default;
const std::string& get_version() const;
const std::string& get_glsl_version() const;
const std::string& get_vendor() const;
const std::string& get_renderer() const;
int get_max_tex_size() const;
float get_max_anisotropy() const;
bool is_version_greater_or_equal_to(unsigned int major, unsigned int minor) const;
std::string to_string(bool format_as_html, bool extensions) const;
private:
void detect() const;
};
#if ENABLE_HACK_CLOSING_ON_OSX_10_9_5
#ifdef __APPLE__
// Part of hack to remove crash when closing the application on OSX 10.9.5 when building against newer wxWidgets
struct OSInfo
{
int major{ 0 };
int minor{ 0 };
int micro{ 0 };
};
#endif //__APPLE__
#endif // ENABLE_HACK_CLOSING_ON_OSX_10_9_5
private:
enum class EMultisampleState : unsigned char
{
Unknown,
Enabled,
Disabled
};
bool m_gl_initialized{ false };
wxGLContext* m_context{ nullptr };
static GLInfo s_gl_info;
#if ENABLE_HACK_CLOSING_ON_OSX_10_9_5
#ifdef __APPLE__
// Part of hack to remove crash when closing the application on OSX 10.9.5 when building against newer wxWidgets
static OSInfo s_os_info;
#endif //__APPLE__
#endif // ENABLE_HACK_CLOSING_ON_OSX_10_9_5
static bool s_compressed_textures_supported;
static EMultisampleState s_multisample;
static EFramebufferType s_framebuffers_type;
public:
OpenGLManager() = default;
~OpenGLManager();
bool init_gl();
wxGLContext* init_glcontext(wxGLCanvas& canvas);
static bool are_compressed_textures_supported() { return s_compressed_textures_supported; }
static bool can_multisample() { return s_multisample == EMultisampleState::Enabled; }
static bool are_framebuffers_supported() { return (s_framebuffers_type != EFramebufferType::Unknown); }
static EFramebufferType get_framebuffers_type() { return s_framebuffers_type; }
static wxGLCanvas* create_wxglcanvas(wxWindow& parent);
static const GLInfo& get_gl_info() { return s_gl_info; }
private:
static void detect_multisample(int* attribList);
};
} // namespace GUI
} // namespace Slic3r
#endif // slic3r_OpenGLManager_hpp_

View File

@ -105,6 +105,7 @@ void OptionsGroup::add_undo_buttuns_to_sizer(wxSizer* sizer, const t_field& fiel
if (!m_show_modified_btns) { if (!m_show_modified_btns) {
field->m_Undo_btn->set_as_hidden(); field->m_Undo_btn->set_as_hidden();
field->m_Undo_to_sys_btn->set_as_hidden(); field->m_Undo_to_sys_btn->set_as_hidden();
field->m_blinking_bmp->Hide();
return; return;
} }

View File

@ -178,7 +178,7 @@ public:
if (staticbox) { if (staticbox) {
stb = new wxStaticBox(_parent, wxID_ANY, _(title)); stb = new wxStaticBox(_parent, wxID_ANY, _(title));
if (!wxOSX) stb->SetBackgroundStyle(wxBG_STYLE_PAINT); if (!wxOSX) stb->SetBackgroundStyle(wxBG_STYLE_PAINT);
stb->SetFont(wxGetApp().bold_font()); stb->SetFont(wxOSX ? wxGetApp().normal_font() : wxGetApp().bold_font());
} else } else
stb = nullptr; stb = nullptr;
sizer = (staticbox ? new wxStaticBoxSizer(stb, wxVERTICAL) : new wxBoxSizer(wxVERTICAL)); sizer = (staticbox ? new wxStaticBoxSizer(stb, wxVERTICAL) : new wxBoxSizer(wxVERTICAL));

View File

@ -33,7 +33,9 @@
#include "libslic3r/Format/STL.hpp" #include "libslic3r/Format/STL.hpp"
#include "libslic3r/Format/AMF.hpp" #include "libslic3r/Format/AMF.hpp"
#include "libslic3r/Format/3mf.hpp" #include "libslic3r/Format/3mf.hpp"
#if !ENABLE_GCODE_VIEWER
#include "libslic3r/GCode/PreviewData.hpp" #include "libslic3r/GCode/PreviewData.hpp"
#endif // !ENABLE_GCODE_VIEWER
#include "libslic3r/GCode/ThumbnailData.hpp" #include "libslic3r/GCode/ThumbnailData.hpp"
#include "libslic3r/Model.hpp" #include "libslic3r/Model.hpp"
#include "libslic3r/SLA/Hollowing.hpp" #include "libslic3r/SLA/Hollowing.hpp"
@ -77,11 +79,9 @@
#include "RemovableDriveManager.hpp" #include "RemovableDriveManager.hpp"
#include "InstanceCheck.hpp" #include "InstanceCheck.hpp"
#if ENABLE_NON_STATIC_CANVAS_MANAGER
#ifdef __APPLE__ #ifdef __APPLE__
#include "Gizmos/GLGizmosManager.hpp" #include "Gizmos/GLGizmosManager.hpp"
#endif // __APPLE__ #endif // __APPLE__
#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
#include <wx/glcanvas.h> // Needs to be last because reasons :-/ #include <wx/glcanvas.h> // Needs to be last because reasons :-/
#include "WipeTowerDialog.hpp" #include "WipeTowerDialog.hpp"
@ -356,10 +356,10 @@ PresetBitmapComboBox(parent, wxSize(15 * wxGetApp().em_unit(), -1)),
if (page_id == wxNOT_FOUND) if (page_id == wxNOT_FOUND)
return; return;
wxGetApp().tab_panel()->ChangeSelection(page_id); wxGetApp().tab_panel()->SetSelection(page_id);
// Switch to Settings NotePad // Switch to Settings NotePad
wxGetApp().mainframe->switch_to(false); wxGetApp().mainframe->select_tab();
/* In a case of a multi-material printing, for editing another Filament Preset /* In a case of a multi-material printing, for editing another Filament Preset
* it's needed to select this preset for the "Filament settings" Tab * it's needed to select this preset for the "Filament settings" Tab
@ -1101,9 +1101,8 @@ void Sidebar::jump_to_option(size_t selected)
const Search::Option& opt = p->searcher.get_option(selected); const Search::Option& opt = p->searcher.get_option(selected);
wxGetApp().get_tab(opt.type)->activate_option(boost::nowide::narrow(opt.opt_key), boost::nowide::narrow(opt.category)); wxGetApp().get_tab(opt.type)->activate_option(boost::nowide::narrow(opt.opt_key), boost::nowide::narrow(opt.category));
// Switch to the Settings NotePad, if plater is shown // Switch to the Settings NotePad
if (p->plater->IsShown()) wxGetApp().mainframe->select_tab();
wxGetApp().mainframe->switch_to(false);
} }
ObjectManipulation* Sidebar::obj_manipul() ObjectManipulation* Sidebar::obj_manipul()
@ -1530,9 +1529,10 @@ struct Plater::priv
Slic3r::SLAPrint sla_print; Slic3r::SLAPrint sla_print;
Slic3r::Model model; Slic3r::Model model;
PrinterTechnology printer_technology = ptFFF; PrinterTechnology printer_technology = ptFFF;
Slic3r::GCodePreviewData gcode_preview_data;
#if ENABLE_GCODE_VIEWER #if ENABLE_GCODE_VIEWER
Slic3r::GCodeProcessor::Result gcode_result; Slic3r::GCodeProcessor::Result gcode_result;
#else
Slic3r::GCodePreviewData gcode_preview_data;
#endif // ENABLE_GCODE_VIEWER #endif // ENABLE_GCODE_VIEWER
// GUI elements // GUI elements
@ -1635,10 +1635,8 @@ struct Plater::priv
void set_current_canvas_as_dirty(); void set_current_canvas_as_dirty();
GLCanvas3D* get_current_canvas3D(); GLCanvas3D* get_current_canvas3D();
#if ENABLE_NON_STATIC_CANVAS_MANAGER
void unbind_canvas_event_handlers(); void unbind_canvas_event_handlers();
void reset_canvas_volumes(); void reset_canvas_volumes();
#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
bool init_view_toolbar(); bool init_view_toolbar();
#if ENABLE_GCODE_VIEWER #if ENABLE_GCODE_VIEWER
@ -1647,6 +1645,7 @@ struct Plater::priv
void reset_all_gizmos(); void reset_all_gizmos();
void update_ui_from_settings(); void update_ui_from_settings();
void update_main_toolbar_tooltips();
std::shared_ptr<ProgressStatusBar> statusbar(); std::shared_ptr<ProgressStatusBar> statusbar();
std::string get_config(const std::string &key) const; std::string get_config(const std::string &key) const;
BoundingBoxf bed_shape_bb() const; BoundingBoxf bed_shape_bb() const;
@ -1844,9 +1843,10 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame)
background_process.set_fff_print(&fff_print); background_process.set_fff_print(&fff_print);
background_process.set_sla_print(&sla_print); background_process.set_sla_print(&sla_print);
background_process.set_gcode_preview_data(&gcode_preview_data);
#if ENABLE_GCODE_VIEWER #if ENABLE_GCODE_VIEWER
background_process.set_gcode_result(&gcode_result); background_process.set_gcode_result(&gcode_result);
#else
background_process.set_gcode_preview_data(&gcode_preview_data);
#endif // ENABLE_GCODE_VIEWER #endif // ENABLE_GCODE_VIEWER
background_process.set_thumbnail_cb([this](ThumbnailsList& thumbnails, const Vec2ds& sizes, bool printable_only, bool parts_only, bool show_bed, bool transparent_background) background_process.set_thumbnail_cb([this](ThumbnailsList& thumbnails, const Vec2ds& sizes, bool printable_only, bool parts_only, bool show_bed, bool transparent_background)
{ {
@ -1870,10 +1870,9 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame)
sla_print.set_status_callback(statuscb); sla_print.set_status_callback(statuscb);
this->q->Bind(EVT_SLICING_UPDATE, &priv::on_slicing_update, this); this->q->Bind(EVT_SLICING_UPDATE, &priv::on_slicing_update, this);
#if ENABLE_NON_STATIC_CANVAS_MANAGER
view3D = new View3D(q, &model, config, &background_process); view3D = new View3D(q, &model, config, &background_process);
#if ENABLE_GCODE_VIEWER #if ENABLE_GCODE_VIEWER
preview = new Preview(q, &model, config, &background_process, &gcode_preview_data, &gcode_result, [this]() { schedule_background_process(); }); preview = new Preview(q, &model, config, &background_process, &gcode_result, [this]() { schedule_background_process(); });
#else #else
preview = new Preview(q, &model, config, &background_process, &gcode_preview_data, [this]() { schedule_background_process(); }); preview = new Preview(q, &model, config, &background_process, &gcode_preview_data, [this]() { schedule_background_process(); });
#endif // ENABLE_GCODE_VIEWER #endif // ENABLE_GCODE_VIEWER
@ -1882,14 +1881,6 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame)
// set default view_toolbar icons size equal to GLGizmosManager::Default_Icons_Size // set default view_toolbar icons size equal to GLGizmosManager::Default_Icons_Size
view_toolbar.set_icons_size(GLGizmosManager::Default_Icons_Size); view_toolbar.set_icons_size(GLGizmosManager::Default_Icons_Size);
#endif // __APPLE__ #endif // __APPLE__
#else
view3D = new View3D(q, bed, camera, view_toolbar, &model, config, &background_process);
#if ENABLE_GCODE_VIEWER
preview = new Preview(q, bed, camera, view_toolbar, &model, config, &background_process, &gcode_preview_data, &gcode_result, [this]() { schedule_background_process(); });
#else
preview = new Preview(q, bed, camera, view_toolbar, &model, config, &background_process, &gcode_preview_data, [this]() { schedule_background_process(); });
#endif // ENABLE_GCODE_VIEWER
#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
panels.push_back(view3D); panels.push_back(view3D);
panels.push_back(preview); panels.push_back(preview);
@ -1990,10 +1981,6 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame)
// Drop target: // Drop target:
q->SetDropTarget(new PlaterDropTarget(q)); // if my understanding is right, wxWindow takes the owenership q->SetDropTarget(new PlaterDropTarget(q)); // if my understanding is right, wxWindow takes the owenership
#if !ENABLE_NON_STATIC_CANVAS_MANAGER
update_ui_from_settings();
#endif // !ENABLE_NON_STATIC_CANVAS_MANAGER
q->Layout(); q->Layout();
set_current_panel(view3D); set_current_panel(view3D);
@ -2059,7 +2046,11 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame)
// collapse sidebar according to saved value // collapse sidebar according to saved value
sidebar->collapse(wxGetApp().app_config->get("collapsed_sidebar") == "1"); bool is_collapsed = wxGetApp().app_config->get("collapsed_sidebar") == "1";
sidebar->collapse(is_collapsed);
// Update an enable of the collapse_toolbar: if sidebar is collapsed, then collapse_toolbar should be visible
if (is_collapsed)
wxGetApp().app_config->set("show_collapse_button", "1");
} }
Plater::priv::~priv() Plater::priv::~priv()
@ -2134,6 +2125,13 @@ void Plater::priv::update_ui_from_settings()
preview->get_canvas3d()->update_ui_from_settings(); preview->get_canvas3d()->update_ui_from_settings();
} }
// Called after the print technology was changed.
// Update the tooltips for "Switch to Settings" button in maintoolbar
void Plater::priv::update_main_toolbar_tooltips()
{
view3D->get_canvas3d()->update_tooltip_for_settings_item_in_main_toolbar();
}
std::shared_ptr<ProgressStatusBar> Plater::priv::statusbar() std::shared_ptr<ProgressStatusBar> Plater::priv::statusbar()
{ {
return main_frame->m_statusbar; return main_frame->m_statusbar;
@ -3801,7 +3799,6 @@ GLCanvas3D* Plater::priv::get_current_canvas3D()
return (current_panel == view3D) ? view3D->get_canvas3d() : ((current_panel == preview) ? preview->get_canvas3d() : nullptr); return (current_panel == view3D) ? view3D->get_canvas3d() : ((current_panel == preview) ? preview->get_canvas3d() : nullptr);
} }
#if ENABLE_NON_STATIC_CANVAS_MANAGER
void Plater::priv::unbind_canvas_event_handlers() void Plater::priv::unbind_canvas_event_handlers()
{ {
if (view3D != nullptr) if (view3D != nullptr)
@ -3819,7 +3816,6 @@ void Plater::priv::reset_canvas_volumes()
if (preview != nullptr) if (preview != nullptr)
preview->get_canvas3d()->reset_volumes(); preview->get_canvas3d()->reset_volumes();
} }
#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
bool Plater::priv::init_view_toolbar() bool Plater::priv::init_view_toolbar()
{ {
@ -4478,8 +4474,6 @@ void Plater::increase_instances(size_t num)
// p->print.get_object(obj_idx)->add_copy(Slic3r::to_2d(offset_vec)); // p->print.get_object(obj_idx)->add_copy(Slic3r::to_2d(offset_vec));
} }
sidebar().obj_list()->increase_object_instances(obj_idx, was_one_instance ? num + 1 : num);
if (p->get_config("autocenter") == "1") if (p->get_config("autocenter") == "1")
arrange(); arrange();
@ -4487,8 +4481,9 @@ void Plater::increase_instances(size_t num)
p->get_selection().add_instance(obj_idx, (int)model_object->instances.size() - 1); p->get_selection().add_instance(obj_idx, (int)model_object->instances.size() - 1);
p->selection_changed(); sidebar().obj_list()->increase_object_instances(obj_idx, was_one_instance ? num + 1 : num);
p->selection_changed();
this->p->schedule_background_process(); this->p->schedule_background_process();
} }
@ -5270,7 +5265,6 @@ void Plater::set_current_canvas_as_dirty()
p->set_current_canvas_as_dirty(); p->set_current_canvas_as_dirty();
} }
#if ENABLE_NON_STATIC_CANVAS_MANAGER
void Plater::unbind_canvas_event_handlers() void Plater::unbind_canvas_event_handlers()
{ {
p->unbind_canvas_event_handlers(); p->unbind_canvas_event_handlers();
@ -5280,7 +5274,6 @@ void Plater::reset_canvas_volumes()
{ {
p->reset_canvas_volumes(); p->reset_canvas_volumes();
} }
#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
PrinterTechnology Plater::printer_technology() const PrinterTechnology Plater::printer_technology() const
{ {
@ -5303,6 +5296,10 @@ void Plater::set_printer_technology(PrinterTechnology printer_technology)
if (wxGetApp().mainframe) if (wxGetApp().mainframe)
wxGetApp().mainframe->update_menubar(); wxGetApp().mainframe->update_menubar();
p->update_main_toolbar_tooltips();
p->sidebar->get_searcher().set_printer_technology(printer_technology);
} }
void Plater::changed_object(int obj_idx) void Plater::changed_object(int obj_idx)
@ -5391,6 +5388,9 @@ void Plater::paste_from_clipboard()
void Plater::search(bool plater_is_active) void Plater::search(bool plater_is_active)
{ {
if (plater_is_active) { if (plater_is_active) {
// plater should be focused for correct navigation inside search window
this->SetFocus();
wxKeyEvent evt; wxKeyEvent evt;
#ifdef __APPLE__ #ifdef __APPLE__
evt.m_keyCode = 'f'; evt.m_keyCode = 'f';
@ -5438,7 +5438,6 @@ Camera& Plater::get_camera()
return p->camera; return p->camera;
} }
#if ENABLE_NON_STATIC_CANVAS_MANAGER
const Bed3D& Plater::get_bed() const const Bed3D& Plater::get_bed() const
{ {
return p->bed; return p->bed;
@ -5458,7 +5457,6 @@ GLToolbar& Plater::get_view_toolbar()
{ {
return p->view_toolbar; return p->view_toolbar;
} }
#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
#if ENABLE_GCODE_VIEWER #if ENABLE_GCODE_VIEWER
void Plater::update_preview_bottom_toolbar() void Plater::update_preview_bottom_toolbar()

View File

@ -45,10 +45,8 @@ class ObjectList;
class GLCanvas3D; class GLCanvas3D;
class Mouse3DController; class Mouse3DController;
struct Camera; struct Camera;
#if ENABLE_NON_STATIC_CANVAS_MANAGER
class Bed3D; class Bed3D;
class GLToolbar; class GLToolbar;
#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
using t_optgroups = std::vector <std::shared_ptr<ConfigOptionsGroup>>; using t_optgroups = std::vector <std::shared_ptr<ConfigOptionsGroup>>;
@ -280,10 +278,8 @@ public:
void find_new_position(const ModelInstancePtrs &instances, coord_t min_d); void find_new_position(const ModelInstancePtrs &instances, coord_t min_d);
void set_current_canvas_as_dirty(); void set_current_canvas_as_dirty();
#if ENABLE_NON_STATIC_CANVAS_MANAGER
void unbind_canvas_event_handlers(); void unbind_canvas_event_handlers();
void reset_canvas_volumes(); void reset_canvas_volumes();
#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
PrinterTechnology printer_technology() const; PrinterTechnology printer_technology() const;
const DynamicPrintConfig * config() const; const DynamicPrintConfig * config() const;
@ -316,13 +312,11 @@ public:
const Camera& get_camera() const; const Camera& get_camera() const;
Camera& get_camera(); Camera& get_camera();
#if ENABLE_NON_STATIC_CANVAS_MANAGER
const Bed3D& get_bed() const; const Bed3D& get_bed() const;
Bed3D& get_bed(); Bed3D& get_bed();
const GLToolbar& get_view_toolbar() const; const GLToolbar& get_view_toolbar() const;
GLToolbar& get_view_toolbar(); GLToolbar& get_view_toolbar();
#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
#if ENABLE_GCODE_VIEWER #if ENABLE_GCODE_VIEWER
void update_preview_bottom_toolbar(); void update_preview_bottom_toolbar();

View File

@ -147,6 +147,13 @@ void PreferencesDialog::build()
} }
}; };
def.label = L("Show the button for the collapse sidebar");
def.type = coBool;
def.tooltip = L("If enabled, the button for the collapse sidebar will be appeared in top right corner of the 3D Scene");
def.set_default_value(new ConfigOptionBool{ app_config->get("show_collapse_button") == "1" });
option = Option(def, "show_collapse_button");
m_optgroup_gui->append_single_option_line(option);
def.label = L("Use custom size for toolbar icons"); def.label = L("Use custom size for toolbar icons");
def.type = coBool; def.type = coBool;
def.tooltip = L("If enabled, you can change size of toolbar icons manually."); def.tooltip = L("If enabled, you can change size of toolbar icons manually.");
@ -157,6 +164,8 @@ void PreferencesDialog::build()
create_icon_size_slider(); create_icon_size_slider();
m_icon_size_sizer->ShowItems(app_config->get("use_custom_toolbar_size") == "1"); m_icon_size_sizer->ShowItems(app_config->get("use_custom_toolbar_size") == "1");
create_settings_mode_widget();
auto sizer = new wxBoxSizer(wxVERTICAL); auto sizer = new wxBoxSizer(wxVERTICAL);
sizer->Add(m_optgroup_general->sizer, 0, wxEXPAND | wxBOTTOM | wxLEFT | wxRIGHT, 10); sizer->Add(m_optgroup_general->sizer, 0, wxEXPAND | wxBOTTOM | wxLEFT | wxRIGHT, 10);
sizer->Add(m_optgroup_camera->sizer, 0, wxEXPAND | wxBOTTOM | wxLEFT | wxRIGHT, 10); sizer->Add(m_optgroup_camera->sizer, 0, wxEXPAND | wxBOTTOM | wxLEFT | wxRIGHT, 10);
@ -167,7 +176,7 @@ void PreferencesDialog::build()
auto buttons = CreateStdDialogButtonSizer(wxOK | wxCANCEL); auto buttons = CreateStdDialogButtonSizer(wxOK | wxCANCEL);
wxButton* btn = static_cast<wxButton*>(FindWindowById(wxID_OK, this)); wxButton* btn = static_cast<wxButton*>(FindWindowById(wxID_OK, this));
btn->Bind(wxEVT_BUTTON, [this](wxCommandEvent&) { accept(); }); btn->Bind(wxEVT_BUTTON, [this](wxCommandEvent&) { accept(); });
sizer->Add(buttons, 0, wxALIGN_CENTER_HORIZONTAL | wxBOTTOM, 10); sizer->Add(buttons, 0, wxALIGN_CENTER_HORIZONTAL | wxBOTTOM, 5);
SetSizer(sizer); SetSizer(sizer);
sizer->SetSizeHints(this); sizer->SetSizeHints(this);
@ -179,17 +188,53 @@ void PreferencesDialog::accept()
warning_catcher(this, wxString::Format(_(L("You need to restart %s to make the changes effective.")), SLIC3R_APP_NAME)); warning_catcher(this, wxString::Format(_(L("You need to restart %s to make the changes effective.")), SLIC3R_APP_NAME));
} }
auto app_config = get_app_config(); auto app_config = get_app_config();
for (std::map<std::string, std::string>::iterator it = m_values.begin(); it != m_values.end(); ++it) {
app_config->set(it->first, it->second); m_settings_layout_changed = false;
for (const std::string& key : {"old_settings_layout_mode",
"new_settings_layout_mode",
"dlg_settings_layout_mode" })
{
auto it = m_values.find(key);
if (it != m_values.end() && app_config->get(key) != it->second) {
m_settings_layout_changed = true;
break;
}
} }
app_config->save(); if (m_settings_layout_changed) {
// the dialog needs to be destroyed before the call to recreate_gui()
// or sometimes the application crashes into wxDialogBase() destructor
// so we put it into an inner scope
wxMessageDialog dialog(nullptr,
_L("Switching the settings layout mode will trigger application restart.\n"
"You will lose content of the plater.") + "\n\n" +
_L("Do you want to proceed?"),
wxString(SLIC3R_APP_NAME) + " - " + _L("Switching the settings layout mode"),
wxICON_QUESTION | wxOK | wxCANCEL);
if (dialog.ShowModal() == wxID_CANCEL)
{
int selection = app_config->get("old_settings_layout_mode") == "1" ? 0 :
app_config->get("new_settings_layout_mode") == "1" ? 1 :
app_config->get("dlg_settings_layout_mode") == "1" ? 2 : 0;
m_layout_mode_box->SetSelection(selection);
return;
}
}
for (std::map<std::string, std::string>::iterator it = m_values.begin(); it != m_values.end(); ++it)
app_config->set(it->first, it->second);
app_config->save();
EndModal(wxID_OK); EndModal(wxID_OK);
// Nothify the UI to update itself from the ini file. if (m_settings_layout_changed)
wxGetApp().update_ui_from_settings(); ;// application will be recreated after Preference dialog will be destroyed
else
// Nothify the UI to update itself from the ini file.
wxGetApp().update_ui_from_settings();
} }
void PreferencesDialog::on_dpi_changed(const wxRect &suggested_rect) void PreferencesDialog::on_dpi_changed(const wxRect &suggested_rect)
@ -272,6 +317,38 @@ void PreferencesDialog::create_icon_size_slider()
m_optgroup_gui->sizer->Add(m_icon_size_sizer, 0, wxEXPAND | wxALL, em); m_optgroup_gui->sizer->Add(m_icon_size_sizer, 0, wxEXPAND | wxALL, em);
} }
void PreferencesDialog::create_settings_mode_widget()
{
wxString choices[] = { _L("Old regular layout with tab bar"),
_L("New layout without the tab bar on the platter"),
_L("Settings will be shown in non-modal dialog") };
auto app_config = get_app_config();
int selection = app_config->get("old_settings_layout_mode") == "1" ? 0 :
app_config->get("new_settings_layout_mode") == "1" ? 1 :
app_config->get("dlg_settings_layout_mode") == "1" ? 2 : 0;
wxWindow* parent = m_optgroup_gui->ctrl_parent();
m_layout_mode_box = new wxRadioBox(parent, wxID_ANY, _L("Settings layout mode"), wxDefaultPosition, wxDefaultSize, WXSIZEOF(choices), choices,
3, wxRA_SPECIFY_ROWS);
m_layout_mode_box->SetFont(wxGetApp().normal_font());
m_layout_mode_box->SetSelection(selection);
m_layout_mode_box->Bind(wxEVT_RADIOBOX, [this](wxCommandEvent& e) {
int selection = e.GetSelection();
m_values["old_settings_layout_mode"] = boost::any_cast<bool>(selection == 0) ? "1" : "0";
m_values["new_settings_layout_mode"] = boost::any_cast<bool>(selection == 1) ? "1" : "0";
m_values["dlg_settings_layout_mode"] = boost::any_cast<bool>(selection == 2) ? "1" : "0";
});
auto sizer = new wxBoxSizer(wxHORIZONTAL);
sizer->Add(m_layout_mode_box, 1, wxALIGN_CENTER_VERTICAL);
m_optgroup_gui->sizer->Add(sizer, 0, wxEXPAND);
}
} // GUI } // GUI
} // Slic3r } // Slic3r

View File

@ -7,6 +7,8 @@
#include <wx/dialog.h> #include <wx/dialog.h>
#include <map> #include <map>
class wxRadioBox;
namespace Slic3r { namespace Slic3r {
namespace GUI { namespace GUI {
@ -19,11 +21,15 @@ class PreferencesDialog : public DPIDialog
std::shared_ptr<ConfigOptionsGroup> m_optgroup_camera; std::shared_ptr<ConfigOptionsGroup> m_optgroup_camera;
std::shared_ptr<ConfigOptionsGroup> m_optgroup_gui; std::shared_ptr<ConfigOptionsGroup> m_optgroup_gui;
wxSizer* m_icon_size_sizer; wxSizer* m_icon_size_sizer;
wxRadioBox* m_layout_mode_box;
bool isOSX {false}; bool isOSX {false};
bool m_settings_layout_changed {false};
public: public:
PreferencesDialog(wxWindow* parent); PreferencesDialog(wxWindow* parent);
~PreferencesDialog() {} ~PreferencesDialog() {}
bool settings_layout_changed() { return m_settings_layout_changed; }
void build(); void build();
void accept(); void accept();
@ -31,6 +37,7 @@ protected:
void on_dpi_changed(const wxRect &suggested_rect) override; void on_dpi_changed(const wxRect &suggested_rect) override;
void layout(); void layout();
void create_icon_size_slider(); void create_icon_size_slider();
void create_settings_mode_widget();
}; };
} // GUI } // GUI

View File

@ -125,6 +125,7 @@ public:
TYPE_FILAMENT, TYPE_FILAMENT,
TYPE_SLA_MATERIAL, TYPE_SLA_MATERIAL,
TYPE_PRINTER, TYPE_PRINTER,
TYPE_COUNT,
}; };
Preset(Type type, const std::string &name, bool is_default = false) : type(type), is_default(is_default), name(name) {} Preset(Type type, const std::string &name, bool is_default = false) : type(type), is_default(is_default), name(name) {}

View File

@ -25,41 +25,35 @@ using GUI::into_u8;
namespace Search { namespace Search {
static std::map<Preset::Type, std::string> NameByType = { static const std::vector<std::wstring>& NameByType()
{ Preset::TYPE_PRINT, L("Print") },
{ Preset::TYPE_FILAMENT, L("Filament") },
{ Preset::TYPE_SLA_MATERIAL, L("Material") },
{ Preset::TYPE_SLA_PRINT, L("Print") },
{ Preset::TYPE_PRINTER, L("Printer") }
};
FMFlag Option::fuzzy_match(wchar_t const* search_pattern, int& outScore, std::vector<uint16_t> &out_matches) const
{ {
FMFlag flag = fmUndef; static std::vector<std::wstring> data;
int score; if (data.empty()) {
data.assign(Preset::TYPE_COUNT, std::wstring());
data[Preset::TYPE_PRINT ] = _L("Print" ).ToStdWstring();
data[Preset::TYPE_FILAMENT ] = _L("Filament" ).ToStdWstring();
data[Preset::TYPE_SLA_MATERIAL ] = _L("Material" ).ToStdWstring();
data[Preset::TYPE_SLA_PRINT ] = _L("Print" ).ToStdWstring();
data[Preset::TYPE_PRINTER ] = _L("Printer" ).ToStdWstring();
};
return data;
}
uint16_t matches[fts::max_matches + 1]; // +1 for the stopper static char marker_by_type(Preset::Type type, PrinterTechnology pt)
auto save_matches = [&matches, &out_matches]() { {
size_t cnt = 0; switch(type) {
for (; matches[cnt] != fts::stopper; ++cnt); case Preset::TYPE_PRINT:
out_matches.assign(matches, matches + cnt); case Preset::TYPE_SLA_PRINT:
}; return ImGui::PrintIconMarker;
if (fts::fuzzy_match(search_pattern, label_local.c_str(), score, matches) && outScore < score) { case Preset::TYPE_FILAMENT:
outScore = score; flag = fmLabelLocal ; save_matches(); } return ImGui::FilamentIconMarker;
if (fts::fuzzy_match(search_pattern, group_local.c_str(), score, matches) && outScore < score) { case Preset::TYPE_SLA_MATERIAL:
outScore = score; flag = fmGroupLocal ; save_matches(); } return ImGui::MaterialIconMarker;
if (fts::fuzzy_match(search_pattern, category_local.c_str(), score, matches) && outScore < score) { case Preset::TYPE_PRINTER:
outScore = score; flag = fmCategoryLocal; save_matches(); } return pt == ptSLA ? ImGui::PrinterSlaIconMarker : ImGui::PrinterIconMarker;
if (fts::fuzzy_match(search_pattern, opt_key.c_str(), score, matches) && outScore < score) { default:
outScore = score; flag = fmOptKey ; save_matches(); } return ' ';
if (fts::fuzzy_match(search_pattern, label.c_str(), score, matches) && outScore < score) { }
outScore = score; flag = fmLabel ; save_matches(); }
if (fts::fuzzy_match(search_pattern, group.c_str(), score, matches) && outScore < score) {
outScore = score; flag = fmGroup ; save_matches(); }
if (fts::fuzzy_match(search_pattern, category.c_str(), score, matches) && outScore < score) {
outScore = score; flag = fmCategory ; save_matches(); }
return flag;
} }
void FoundOption::get_marked_label_and_tooltip(const char** label_, const char** tooltip_) const void FoundOption::get_marked_label_and_tooltip(const char** label_, const char** tooltip_) const
@ -89,12 +83,16 @@ void OptionsSearcher::append_options(DynamicPrintConfig* config, Preset::Type ty
return; return;
wxString suffix; wxString suffix;
if (gc.category == "Machine limits") wxString suffix_local;
if (gc.category == "Machine limits") {
suffix = opt_key.back()=='1' ? L("Stealth") : L("Normal"); suffix = opt_key.back()=='1' ? L("Stealth") : L("Normal");
suffix_local = " " + _(suffix);
suffix = " " + suffix;
}
if (!label.IsEmpty()) if (!label.IsEmpty())
options.emplace_back(Option{ boost::nowide::widen(opt_key), type, options.emplace_back(Option{ boost::nowide::widen(opt_key), type,
(label+ " " + suffix).ToStdWstring(), (_(label)+ " " + _(suffix)).ToStdWstring(), (label + suffix).ToStdWstring(), (_(label) + suffix_local).ToStdWstring(),
gc.group.ToStdWstring(), _(gc.group).ToStdWstring(), gc.group.ToStdWstring(), _(gc.group).ToStdWstring(),
gc.category.ToStdWstring(), _(gc.category).ToStdWstring() }); gc.category.ToStdWstring(), _(gc.category).ToStdWstring() });
}; };
@ -125,17 +123,8 @@ void OptionsSearcher::append_options(DynamicPrintConfig* config, Preset::Type ty
emplace(opt_key, label); emplace(opt_key, label);
else else
for (int i = 0; i < cnt; ++i) for (int i = 0; i < cnt; ++i)
// ! It's very important to use "#". opt_key#n is a real option key used in GroupAndCategory
emplace(opt_key + "#" + std::to_string(i), label); emplace(opt_key + "#" + std::to_string(i), label);
/*const GroupAndCategory& gc = groups_and_categories[opt_key];
if (gc.group.IsEmpty() || gc.category.IsEmpty())
continue;
if (!label.IsEmpty())
options.emplace_back(Option{opt_key, type,
label, _(label),
gc.group, _(gc.group),
gc.category, _(gc.category) });*/
} }
} }
@ -179,6 +168,20 @@ bool OptionsSearcher::search()
return search(search_line, true); return search(search_line, true);
} }
static bool fuzzy_match(const std::wstring &search_pattern, const std::wstring &label, int& out_score, std::vector<uint16_t> &out_matches)
{
uint16_t matches[fts::max_matches + 1]; // +1 for the stopper
int score;
if (fts::fuzzy_match(search_pattern.c_str(), label.c_str(), score, matches)) {
size_t cnt = 0;
for (; matches[cnt] != fts::stopper; ++cnt);
out_matches.assign(matches, matches + cnt);
out_score = score;
return true;
} else
return false;
}
bool OptionsSearcher::search(const std::string& search, bool force/* = false*/) bool OptionsSearcher::search(const std::string& search, bool force/* = false*/)
{ {
if (search_line == search && !force) if (search_line == search && !force)
@ -187,72 +190,91 @@ bool OptionsSearcher::search(const std::string& search, bool force/* = false*/)
found.clear(); found.clear();
bool full_list = search.empty(); bool full_list = search.empty();
wxString sep = " : "; std::wstring sep = L" : ";
auto get_label = [this, sep](const Option& opt) auto get_label = [this, &sep](const Option& opt)
{ {
wxString label; std::wstring out;
if (view_params.type) out += marker_by_type(opt.type, printer_technology);
label += _(NameByType[opt.type]) + sep; const std::wstring *prev = nullptr;
if (view_params.category) for (const std::wstring * const s : {
label += opt.category_local + sep; view_params.category ? &opt.category_local : nullptr,
if (view_params.group) view_params.group ? &opt.group_local : nullptr,
label += opt.group_local + sep; &opt.label_local })
label += opt.label_local; if (s != nullptr && (prev == nullptr || *prev != *s)) {
return label; // if (! out.empty())
if (out.size()>2)
out += sep;
out += *s;
prev = s;
}
return out;
}; };
auto get_tooltip = [this, sep](const Option& opt) auto get_label_english = [this, &sep](const Option& opt)
{ {
return _(NameByType[opt.type]) + sep + std::wstring out;
out += marker_by_type(opt.type, printer_technology);
const std::wstring*prev = nullptr;
for (const std::wstring * const s : {
view_params.category ? &opt.category : nullptr,
view_params.group ? &opt.group : nullptr,
&opt.label })
if (s != nullptr && (prev == nullptr || *prev != *s)) {
// if (! out.empty())
if (out.size()>2)
out += sep;
out += *s;
prev = s;
}
return out;
};
auto get_tooltip = [this, &sep](const Option& opt)
{
return marker_by_type(opt.type, printer_technology) +
opt.category_local + sep + opt.category_local + sep +
opt.group_local + sep + opt.label_local; opt.group_local + sep + opt.label_local;
}; };
std::vector<uint16_t> matches; std::vector<uint16_t> matches, matches2;
for (size_t i=0; i < options.size(); i++) for (size_t i=0; i < options.size(); i++)
{ {
const Option &opt = options[i]; const Option &opt = options[i];
if (full_list) { if (full_list) {
std::string label = into_u8(get_label(opt)); std::string label = into_u8(get_label(opt));
found.emplace_back(FoundOption{ label, label, into_u8(get_tooltip(opt)), i, fmUndef, 0 }); found.emplace_back(FoundOption{ label, label, boost::nowide::narrow(get_tooltip(opt)), i, 0 });
continue; continue;
} }
int score = 0; std::wstring wsearch = boost::nowide::widen(search);
FMFlag fuzzy_match_flag = opt.fuzzy_match(boost::nowide::widen(search).c_str(), score, matches); boost::trim_left(wsearch);
if (fuzzy_match_flag != fmUndef) std::wstring label = get_label(opt);
{ std::wstring label_english = get_label_english(opt);
wxString label; int score = std::numeric_limits<int>::min();
int score2;
if (view_params.type) matches.clear();
label += _(NameByType[opt.type]) + sep; fuzzy_match(wsearch, label, score, matches);
if (fuzzy_match_flag == fmCategoryLocal) if (fuzzy_match(wsearch, opt.opt_key, score2, matches2) && score2 > score) {
label += mark_string(opt.category_local, matches) + sep; for (fts::pos_type &pos : matches2)
else if (view_params.category) pos += label.size() + 1;
label += opt.category_local + sep; label += L"(" + opt.opt_key + L")";
if (fuzzy_match_flag == fmGroupLocal) append(matches, matches2);
label += mark_string(opt.group_local, matches) + sep; score = score2;
else if (view_params.group) }
label += opt.group_local + sep; if (view_params.english && fuzzy_match(wsearch, label_english, score2, matches2) && score2 > score) {
label += ((fuzzy_match_flag == fmLabelLocal) ? mark_string(opt.label_local, matches) : opt.label_local) + sep; label = std::move(label_english);
matches = std::move(matches2);
switch (fuzzy_match_flag) { score = score2;
case fmLabelLocal: }
case fmGroupLocal: if (score > std::numeric_limits<int>::min()) {
case fmCategoryLocal: label = mark_string(label, matches);
break; label += L" [" + std::to_wstring(score) + L"]";// add score value
case fmLabel: label = get_label(opt) + "(" + mark_string(opt.label, matches) + ")"; break; std::string label_u8 = into_u8(label);
case fmGroup: label = get_label(opt) + "(" + mark_string(opt.group, matches) + ")"; break; std::string label_plain = label_u8;
case fmCategory: label = get_label(opt) + "(" + mark_string(opt.category, matches) + ")"; break; boost::erase_all(label_plain, std::string(1, char(ImGui::ColorMarkerStart)));
case fmOptKey: label = get_label(opt) + "(" + mark_string(opt.opt_key, matches) + ")"; break; boost::erase_all(label_plain, std::string(1, char(ImGui::ColorMarkerEnd)));
case fmUndef: assert(false); break; found.emplace_back(FoundOption{ label_plain, label_u8, boost::nowide::narrow(get_tooltip(opt)), i, score });
}
std::string label_plain = into_u8(label);
boost::erase_all(label_plain, std::wstring(1, wchar_t(ImGui::ColorMarkerStart)));
boost::erase_all(label_plain, std::wstring(1, wchar_t(ImGui::ColorMarkerEnd)));
found.emplace_back(FoundOption{ label_plain, into_u8(label), into_u8(get_tooltip(opt)), i, fuzzy_match_flag, score });
} }
} }
@ -411,15 +433,17 @@ SearchDialog::SearchDialog(OptionsSearcher* searcher)
wxBoxSizer* check_sizer = new wxBoxSizer(wxHORIZONTAL); wxBoxSizer* check_sizer = new wxBoxSizer(wxHORIZONTAL);
check_type = new wxCheckBox(this, wxID_ANY, _L("Type"));
check_category = new wxCheckBox(this, wxID_ANY, _L("Category")); check_category = new wxCheckBox(this, wxID_ANY, _L("Category"));
check_group = new wxCheckBox(this, wxID_ANY, _L("Group")); check_group = new wxCheckBox(this, wxID_ANY, _L("Group"));
if (GUI::wxGetApp().is_localized())
check_english = new wxCheckBox(this, wxID_ANY, _L("Search in English"));
wxStdDialogButtonSizer* cancel_btn = this->CreateStdDialogButtonSizer(wxCANCEL); wxStdDialogButtonSizer* cancel_btn = this->CreateStdDialogButtonSizer(wxCANCEL);
check_sizer->Add(check_type, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, border);
check_sizer->Add(check_category, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, border); check_sizer->Add(check_category, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, border);
check_sizer->Add(check_group, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, border); check_sizer->Add(check_group, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, border);
if (GUI::wxGetApp().is_localized())
check_sizer->Add(check_english, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, border);
check_sizer->AddStretchSpacer(border); check_sizer->AddStretchSpacer(border);
check_sizer->Add(cancel_btn, 0, wxALIGN_CENTER_VERTICAL); check_sizer->Add(cancel_btn, 0, wxALIGN_CENTER_VERTICAL);
@ -438,7 +462,8 @@ SearchDialog::SearchDialog(OptionsSearcher* searcher)
search_list->Bind(wxEVT_LEFT_UP, &SearchDialog::OnMouseClick, this); search_list->Bind(wxEVT_LEFT_UP, &SearchDialog::OnMouseClick, this);
search_list->Bind(wxEVT_KEY_DOWN,&SearchDialog::OnKeyDown, this); search_list->Bind(wxEVT_KEY_DOWN,&SearchDialog::OnKeyDown, this);
check_type ->Bind(wxEVT_CHECKBOX, &SearchDialog::OnCheck, this); if (GUI::wxGetApp().is_localized())
check_english ->Bind(wxEVT_CHECKBOX, &SearchDialog::OnCheck, this);
check_category->Bind(wxEVT_CHECKBOX, &SearchDialog::OnCheck, this); check_category->Bind(wxEVT_CHECKBOX, &SearchDialog::OnCheck, this);
check_group ->Bind(wxEVT_CHECKBOX, &SearchDialog::OnCheck, this); check_group ->Bind(wxEVT_CHECKBOX, &SearchDialog::OnCheck, this);
@ -458,9 +483,9 @@ void SearchDialog::Popup(wxPoint position /*= wxDefaultPosition*/)
update_list(); update_list();
const OptionViewParameters& params = searcher->view_params; const OptionViewParameters& params = searcher->view_params;
check_type->SetValue(params.type);
check_category->SetValue(params.category); check_category->SetValue(params.category);
check_group->SetValue(params.group); check_group->SetValue(params.group);
check_english->SetValue(params.english);
this->SetPosition(position); this->SetPosition(position);
this->ShowModal(); this->ShowModal();
@ -526,7 +551,7 @@ void SearchDialog::update_list()
const std::vector<FoundOption>& filters = searcher->found_options(); const std::vector<FoundOption>& filters = searcher->found_options();
for (const FoundOption& item : filters) for (const FoundOption& item : filters)
search_list->Append(from_u8(item.label)); search_list->Append(from_u8(item.label).Remove(0, 1));
} }
void SearchDialog::OnKeyDown(wxKeyEvent& event) void SearchDialog::OnKeyDown(wxKeyEvent& event)
@ -558,7 +583,7 @@ void SearchDialog::OnKeyDown(wxKeyEvent& event)
void SearchDialog::OnCheck(wxCommandEvent& event) void SearchDialog::OnCheck(wxCommandEvent& event)
{ {
OptionViewParameters& params = searcher->view_params; OptionViewParameters& params = searcher->view_params;
params.type = check_type->GetValue(); params.english = check_english->GetValue();
params.category = check_category->GetValue(); params.category = check_category->GetValue();
params.group = check_group->GetValue(); params.group = check_group->GetValue();

View File

@ -36,20 +36,6 @@ struct GroupAndCategory {
wxString category; wxString category;
}; };
// fuzzy_match flag
// Sorted by the order of importance. The outputs will be sorted by the importance if the match value given by fuzzy_match is equal.
enum FMFlag
{
fmUndef = 0, // didn't find
fmOptKey,
fmLabel,
fmLabelLocal,
fmGroup,
fmGroupLocal,
fmCategory,
fmCategoryLocal
};
struct Option { struct Option {
bool operator<(const Option& other) const { return other.label > this->label; } bool operator<(const Option& other) const { return other.label > this->label; }
bool operator>(const Option& other) const { return other.label < this->label; } bool operator>(const Option& other) const { return other.label < this->label; }
@ -64,8 +50,6 @@ struct Option {
std::wstring group_local; std::wstring group_local;
std::wstring category; std::wstring category;
std::wstring category_local; std::wstring category_local;
FMFlag fuzzy_match(wchar_t const *search_pattern, int &outScore, std::vector<uint16_t> &out_matches) const;
}; };
struct FoundOption { struct FoundOption {
@ -74,7 +58,6 @@ struct FoundOption {
std::string marked_label; std::string marked_label;
std::string tooltip; std::string tooltip;
size_t option_idx {0}; size_t option_idx {0};
FMFlag category {fmUndef};
int outScore {0}; int outScore {0};
// Returning pointers to contents of std::string members, to be used by ImGUI for rendering. // Returning pointers to contents of std::string members, to be used by ImGUI for rendering.
@ -83,17 +66,18 @@ struct FoundOption {
struct OptionViewParameters struct OptionViewParameters
{ {
bool type {false};
bool category {false}; bool category {false};
bool group {true }; bool group {true };
bool english {false};
int hovered_id {-1}; int hovered_id {0};
}; };
class OptionsSearcher class OptionsSearcher
{ {
std::string search_line; std::string search_line;
std::map<std::string, GroupAndCategory> groups_and_categories; std::map<std::string, GroupAndCategory> groups_and_categories;
PrinterTechnology printer_technology;
std::vector<Option> options {}; std::vector<Option> options {};
std::vector<FoundOption> found {}; std::vector<FoundOption> found {};
@ -106,7 +90,7 @@ class OptionsSearcher
} }
void sort_found() { void sort_found() {
std::sort(found.begin(), found.end(), [](const FoundOption& f1, const FoundOption& f2) { std::sort(found.begin(), found.end(), [](const FoundOption& f1, const FoundOption& f2) {
return f1.outScore > f2.outScore || (f1.outScore == f2.outScore && int(f1.category) < int(f2.category)); }); return f1.outScore > f2.outScore || (f1.outScore == f2.outScore && f1.label < f2.label); });
}; };
size_t options_size() const { return options.size(); } size_t options_size() const { return options.size(); }
@ -137,6 +121,8 @@ public:
const std::vector<FoundOption>& found_options() { return found; } const std::vector<FoundOption>& found_options() { return found; }
const GroupAndCategory& get_group_and_category (const std::string& opt_key) { return groups_and_categories[opt_key]; } const GroupAndCategory& get_group_and_category (const std::string& opt_key) { return groups_and_categories[opt_key]; }
std::string& search_string() { return search_line; } std::string& search_string() { return search_line; }
void set_printer_technology(PrinterTechnology pt) { printer_technology = pt; }
}; };
@ -184,9 +170,9 @@ class SearchDialog : public GUI::DPIDialog
wxTextCtrl* search_line { nullptr }; wxTextCtrl* search_line { nullptr };
wxListBox* search_list { nullptr }; wxListBox* search_list { nullptr };
wxCheckBox* check_type { nullptr };
wxCheckBox* check_category { nullptr }; wxCheckBox* check_category { nullptr };
wxCheckBox* check_group { nullptr }; wxCheckBox* check_group { nullptr };
wxCheckBox* check_english { nullptr };
OptionsSearcher* searcher; OptionsSearcher* searcher;

View File

@ -13,6 +13,9 @@
#include <GL/glew.h> #include <GL/glew.h>
#include <boost/algorithm/string/predicate.hpp> #include <boost/algorithm/string/predicate.hpp>
#if ENABLE_GCODE_VIEWER
#include <boost/log/trivial.hpp>
#endif // ENABLE_GCODE_VIEWER
static const float UNIFORM_SCALE_COLOR[3] = { 1.0f, 0.38f, 0.0f }; static const float UNIFORM_SCALE_COLOR[3] = { 1.0f, 0.38f, 0.0f };
@ -76,7 +79,9 @@ Selection::Selection()
, m_mode(Instance) , m_mode(Instance)
, m_type(Empty) , m_type(Empty)
, m_valid(false) , m_valid(false)
#if !ENABLE_GCODE_VIEWER
, m_curved_arrow(16) , m_curved_arrow(16)
#endif // !ENABLE_GCODE_VIEWER
, m_scale_factor(1.0f) , m_scale_factor(1.0f)
{ {
this->set_bounding_boxes_dirty(); this->set_bounding_boxes_dirty();
@ -104,6 +109,16 @@ void Selection::set_volumes(GLVolumePtrs* volumes)
// Init shall be called from the OpenGL render function, so that the OpenGL context is initialized! // Init shall be called from the OpenGL render function, so that the OpenGL context is initialized!
bool Selection::init() bool Selection::init()
{ {
#if ENABLE_GCODE_VIEWER
m_arrow.init_from(straight_arrow(10.0f, 5.0f, 5.0f, 10.0f, 1.0f));
m_curved_arrow.init_from(circular_arrow(16, 10.0f, 5.0f, 10.0f, 5.0f, 1.0f));
if (!m_arrows_shader.init("gouraud_light.vs", "gouraud_light.fs"))
{
BOOST_LOG_TRIVIAL(error) << "Unable to initialize gouraud_light shader: please, check that the files gouraud_light.vs and gouraud_light.fs are available";
return false;
}
#else
if (!m_arrow.init()) if (!m_arrow.init())
return false; return false;
@ -113,6 +128,8 @@ bool Selection::init()
return false; return false;
m_curved_arrow.set_scale(5.0 * Vec3d::Ones()); m_curved_arrow.set_scale(5.0 * Vec3d::Ones());
#endif //ENABLE_GCODE_VIEWER
return true; return true;
} }
@ -440,11 +457,9 @@ void Selection::clear()
update_type(); update_type();
this->set_bounding_boxes_dirty(); this->set_bounding_boxes_dirty();
#if ENABLE_NON_STATIC_CANVAS_MANAGER
// this happens while the application is closing // this happens while the application is closing
if (wxGetApp().obj_manipul() == nullptr) if (wxGetApp().obj_manipul() == nullptr)
return; return;
#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
// resets the cache in the sidebar // resets the cache in the sidebar
wxGetApp().obj_manipul()->reset_cache(); wxGetApp().obj_manipul()->reset_cache();
@ -1229,16 +1244,28 @@ void Selection::render_center(bool gizmo_is_dragging) const
} }
#endif // ENABLE_RENDER_SELECTION_CENTER #endif // ENABLE_RENDER_SELECTION_CENTER
#if ENABLE_GCODE_VIEWER
void Selection::render_sidebar_hints(const std::string& sidebar_field) const
#else
void Selection::render_sidebar_hints(const std::string& sidebar_field, const Shader& shader) const void Selection::render_sidebar_hints(const std::string& sidebar_field, const Shader& shader) const
#endif // ENABLE_GCODE_VIEWER
{ {
if (sidebar_field.empty()) if (sidebar_field.empty())
return; return;
if (!boost::starts_with(sidebar_field, "layer")) if (!boost::starts_with(sidebar_field, "layer"))
{ {
#if ENABLE_GCODE_VIEWER
if (!m_arrows_shader.is_initialized())
return;
m_arrows_shader.start_using();
glsafe(::glClear(GL_DEPTH_BUFFER_BIT));
#else
shader.start_using(); shader.start_using();
glsafe(::glClear(GL_DEPTH_BUFFER_BIT)); glsafe(::glClear(GL_DEPTH_BUFFER_BIT));
glsafe(::glEnable(GL_LIGHTING)); glsafe(::glEnable(GL_LIGHTING));
#endif // ENABLE_GCODE_VIEWER
} }
glsafe(::glEnable(GL_DEPTH_TEST)); glsafe(::glEnable(GL_DEPTH_TEST));
@ -1309,8 +1336,12 @@ void Selection::render_sidebar_hints(const std::string& sidebar_field, const Sha
if (!boost::starts_with(sidebar_field, "layer")) if (!boost::starts_with(sidebar_field, "layer"))
{ {
#if ENABLE_GCODE_VIEWER
m_arrows_shader.stop_using();
#else
glsafe(::glDisable(GL_LIGHTING)); glsafe(::glDisable(GL_LIGHTING));
shader.stop_using(); shader.stop_using();
#endif // ENABLE_GCODE_VIEWER
} }
} }
@ -1913,6 +1944,33 @@ void Selection::render_bounding_box(const BoundingBoxf3& box, float* color) cons
void Selection::render_sidebar_position_hints(const std::string& sidebar_field) const void Selection::render_sidebar_position_hints(const std::string& sidebar_field) const
{ {
#if ENABLE_GCODE_VIEWER
GLint color_id = ::glGetUniformLocation(m_arrows_shader.get_shader_program_id(), "uniform_color");
if (boost::ends_with(sidebar_field, "x"))
{
if (color_id >= 0)
glsafe(::glUniform4fv(color_id, 1, (const GLfloat*)AXES_COLOR[0]));
glsafe(::glRotated(-90.0, 0.0, 0.0, 1.0));
m_arrow.render();
}
else if (boost::ends_with(sidebar_field, "y"))
{
if (color_id >= 0)
glsafe(::glUniform4fv(color_id, 1, (const GLfloat*)AXES_COLOR[1]));
m_arrow.render();
}
else if (boost::ends_with(sidebar_field, "z"))
{
if (color_id >= 0)
glsafe(::glUniform4fv(color_id, 1, (const GLfloat*)AXES_COLOR[2]));
glsafe(::glRotated(90.0, 1.0, 0.0, 0.0));
m_arrow.render();
}
#else
if (boost::ends_with(sidebar_field, "x")) if (boost::ends_with(sidebar_field, "x"))
{ {
glsafe(::glRotated(-90.0, 0.0, 0.0, 1.0)); glsafe(::glRotated(-90.0, 0.0, 0.0, 1.0));
@ -1925,10 +1983,38 @@ void Selection::render_sidebar_position_hints(const std::string& sidebar_field)
glsafe(::glRotated(90.0, 1.0, 0.0, 0.0)); glsafe(::glRotated(90.0, 1.0, 0.0, 0.0));
render_sidebar_position_hint(Z); render_sidebar_position_hint(Z);
} }
#endif // ENABLE_GCODE_VIEWER
} }
void Selection::render_sidebar_rotation_hints(const std::string& sidebar_field) const void Selection::render_sidebar_rotation_hints(const std::string& sidebar_field) const
{ {
#if ENABLE_GCODE_VIEWER
GLint color_id = ::glGetUniformLocation(m_arrows_shader.get_shader_program_id(), "uniform_color");
if (boost::ends_with(sidebar_field, "x"))
{
if (color_id >= 0)
glsafe(::glUniform4fv(color_id, 1, (const GLfloat*)AXES_COLOR[0]));
glsafe(::glRotated(90.0, 0.0, 1.0, 0.0));
render_sidebar_rotation_hint(X);
}
else if (boost::ends_with(sidebar_field, "y"))
{
if (color_id >= 0)
glsafe(::glUniform4fv(color_id, 1, (const GLfloat*)AXES_COLOR[1]));
glsafe(::glRotated(-90.0, 1.0, 0.0, 0.0));
render_sidebar_rotation_hint(Y);
}
else if (boost::ends_with(sidebar_field, "z"))
{
if (color_id >= 0)
glsafe(::glUniform4fv(color_id, 1, (const GLfloat*)AXES_COLOR[2]));
render_sidebar_rotation_hint(Z);
}
#else
if (boost::ends_with(sidebar_field, "x")) if (boost::ends_with(sidebar_field, "x"))
{ {
glsafe(::glRotated(90.0, 0.0, 1.0, 0.0)); glsafe(::glRotated(90.0, 0.0, 1.0, 0.0));
@ -1941,12 +2027,14 @@ void Selection::render_sidebar_rotation_hints(const std::string& sidebar_field)
} }
else if (boost::ends_with(sidebar_field, "z")) else if (boost::ends_with(sidebar_field, "z"))
render_sidebar_rotation_hint(Z); render_sidebar_rotation_hint(Z);
#endif // ENABLE_GCODE_VIEWER
} }
void Selection::render_sidebar_scale_hints(const std::string& sidebar_field) const void Selection::render_sidebar_scale_hints(const std::string& sidebar_field) const
{ {
bool uniform_scale = requires_uniform_scale() || wxGetApp().obj_manipul()->get_uniform_scaling(); bool uniform_scale = requires_uniform_scale() || wxGetApp().obj_manipul()->get_uniform_scaling();
#if ENABLE_GCODE_VIEWER
if (boost::ends_with(sidebar_field, "x") || uniform_scale) if (boost::ends_with(sidebar_field, "x") || uniform_scale)
{ {
glsafe(::glPushMatrix()); glsafe(::glPushMatrix());
@ -1969,6 +2057,30 @@ void Selection::render_sidebar_scale_hints(const std::string& sidebar_field) con
render_sidebar_scale_hint(Z); render_sidebar_scale_hint(Z);
glsafe(::glPopMatrix()); glsafe(::glPopMatrix());
} }
#else
if (boost::ends_with(sidebar_field, "x") || uniform_scale)
{
glsafe(::glPushMatrix());
glsafe(::glRotated(-90.0, 0.0, 0.0, 1.0));
render_sidebar_scale_hint(X);
glsafe(::glPopMatrix());
}
if (boost::ends_with(sidebar_field, "y") || uniform_scale)
{
glsafe(::glPushMatrix());
render_sidebar_scale_hint(Y);
glsafe(::glPopMatrix());
}
if (boost::ends_with(sidebar_field, "z") || uniform_scale)
{
glsafe(::glPushMatrix());
glsafe(::glRotated(90.0, 1.0, 0.0, 0.0));
render_sidebar_scale_hint(Z);
glsafe(::glPopMatrix());
}
#endif // ENABLE_GCODE_VIEWER
} }
void Selection::render_sidebar_size_hints(const std::string& sidebar_field) const void Selection::render_sidebar_size_hints(const std::string& sidebar_field) const
@ -2048,24 +2160,34 @@ void Selection::render_sidebar_layers_hints(const std::string& sidebar_field) co
glsafe(::glDisable(GL_BLEND)); glsafe(::glDisable(GL_BLEND));
} }
#if !ENABLE_GCODE_VIEWER
void Selection::render_sidebar_position_hint(Axis axis) const void Selection::render_sidebar_position_hint(Axis axis) const
{ {
m_arrow.set_color(AXES_COLOR[axis], 3); m_arrow.set_color(AXES_COLOR[axis], 3);
m_arrow.render(); m_arrow.render();
} }
#endif // !ENABLE_GCODE_VIEWER
void Selection::render_sidebar_rotation_hint(Axis axis) const void Selection::render_sidebar_rotation_hint(Axis axis) const
{ {
#if !ENABLE_GCODE_VIEWER
m_curved_arrow.set_color(AXES_COLOR[axis], 3); m_curved_arrow.set_color(AXES_COLOR[axis], 3);
#endif // !ENABLE_GCODE_VIEWER
m_curved_arrow.render(); m_curved_arrow.render();
glsafe(::glRotated(180.0, 0.0, 0.0, 1.0)); glsafe(::glRotated(180.0, 0.0, 0.0, 1.0));
m_curved_arrow.render(); m_curved_arrow.render();
} }
void Selection::render_sidebar_scale_hint(Axis axis) const void Selection::render_sidebar_scale_hint(Axis axis) const
{ {
#if ENABLE_GCODE_VIEWER
GLint color_id = ::glGetUniformLocation(m_arrows_shader.get_shader_program_id(), "uniform_color");
if (color_id >= 0)
glsafe(::glUniform4fv(color_id, 1, (requires_uniform_scale() || wxGetApp().obj_manipul()->get_uniform_scaling()) ? (const GLfloat*)UNIFORM_SCALE_COLOR : (const GLfloat*)AXES_COLOR[axis]));
#else
m_arrow.set_color(((requires_uniform_scale() || wxGetApp().obj_manipul()->get_uniform_scaling()) ? UNIFORM_SCALE_COLOR : AXES_COLOR[axis]), 3); m_arrow.set_color(((requires_uniform_scale() || wxGetApp().obj_manipul()->get_uniform_scaling()) ? UNIFORM_SCALE_COLOR : AXES_COLOR[axis]), 3);
#endif // ENABLE_GCODE_VIEWER
glsafe(::glTranslated(0.0, 5.0, 0.0)); glsafe(::glTranslated(0.0, 5.0, 0.0));
m_arrow.render(); m_arrow.render();
@ -2075,9 +2197,11 @@ void Selection::render_sidebar_scale_hint(Axis axis) const
m_arrow.render(); m_arrow.render();
} }
#if !ENABLE_GCODE_VIEWER
void Selection::render_sidebar_size_hint(Axis axis, double length) const void Selection::render_sidebar_size_hint(Axis axis, double length) const
{ {
} }
#endif // !ENABLE_GCODE_VIEWER
#ifndef NDEBUG #ifndef NDEBUG
static bool is_rotation_xy_synchronized(const Vec3d &rot_xyz_from, const Vec3d &rot_xyz_to) static bool is_rotation_xy_synchronized(const Vec3d &rot_xyz_from, const Vec3d &rot_xyz_to)

View File

@ -4,6 +4,10 @@
#include <set> #include <set>
#include "libslic3r/Geometry.hpp" #include "libslic3r/Geometry.hpp"
#include "3DScene.hpp" #include "3DScene.hpp"
#if ENABLE_GCODE_VIEWER
#include "GLModel.hpp"
#include "GLShader.hpp"
#endif // ENABLE_GCODE_VIEWER
#if ENABLE_RENDER_SELECTION_CENTER #if ENABLE_RENDER_SELECTION_CENTER
class GLUquadric; class GLUquadric;
@ -200,8 +204,14 @@ private:
#if ENABLE_RENDER_SELECTION_CENTER #if ENABLE_RENDER_SELECTION_CENTER
GLUquadricObj* m_quadric; GLUquadricObj* m_quadric;
#endif // ENABLE_RENDER_SELECTION_CENTER #endif // ENABLE_RENDER_SELECTION_CENTER
#if ENABLE_GCODE_VIEWER
GL_Model m_arrow;
GL_Model m_curved_arrow;
Shader m_arrows_shader;
#else
mutable GLArrow m_arrow; mutable GLArrow m_arrow;
mutable GLCurvedArrow m_curved_arrow; mutable GLCurvedArrow m_curved_arrow;
#endif // ENABLE_GCODE_VIEWER
mutable float m_scale_factor; mutable float m_scale_factor;
@ -316,7 +326,11 @@ public:
#if ENABLE_RENDER_SELECTION_CENTER #if ENABLE_RENDER_SELECTION_CENTER
void render_center(bool gizmo_is_dragging) const; void render_center(bool gizmo_is_dragging) const;
#endif // ENABLE_RENDER_SELECTION_CENTER #endif // ENABLE_RENDER_SELECTION_CENTER
#if ENABLE_GCODE_VIEWER
void render_sidebar_hints(const std::string& sidebar_field) const;
#else
void render_sidebar_hints(const std::string& sidebar_field, const Shader& shader) const; void render_sidebar_hints(const std::string& sidebar_field, const Shader& shader) const;
#endif // ENABLE_GCODE_VIEWER
bool requires_local_axes() const; bool requires_local_axes() const;
@ -359,10 +373,14 @@ private:
void render_sidebar_scale_hints(const std::string& sidebar_field) const; void render_sidebar_scale_hints(const std::string& sidebar_field) const;
void render_sidebar_size_hints(const std::string& sidebar_field) const; void render_sidebar_size_hints(const std::string& sidebar_field) const;
void render_sidebar_layers_hints(const std::string& sidebar_field) const; void render_sidebar_layers_hints(const std::string& sidebar_field) const;
#if !ENABLE_GCODE_VIEWER
void render_sidebar_position_hint(Axis axis) const; void render_sidebar_position_hint(Axis axis) const;
#endif // !ENABLE_GCODE_VIEWER
void render_sidebar_rotation_hint(Axis axis) const; void render_sidebar_rotation_hint(Axis axis) const;
void render_sidebar_scale_hint(Axis axis) const; void render_sidebar_scale_hint(Axis axis) const;
#if !ENABLE_GCODE_VIEWER
void render_sidebar_size_hint(Axis axis, double length) const; void render_sidebar_size_hint(Axis axis, double length) const;
#endif // !ENABLE_GCODE_VIEWER
public: public:
enum SyncRotationType { enum SyncRotationType {

View File

@ -145,11 +145,7 @@ SysInfoDialog::SysInfoDialog()
"</font>" "</font>"
"</body>" "</body>"
"</html>", bgr_clr_str, text_clr_str, text_clr_str, "</html>", bgr_clr_str, text_clr_str, text_clr_str,
#if ENABLE_NON_STATIC_CANVAS_MANAGER
get_mem_info(true) + "<br>" + wxGetApp().get_gl_info(true, true)); get_mem_info(true) + "<br>" + wxGetApp().get_gl_info(true, true));
#else
get_mem_info(true) + "<br>" + _3DScene::get_gl_info(true, true));
#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
m_opengl_info_html->SetPage(text); m_opengl_info_html->SetPage(text);
main_sizer->Add(m_opengl_info_html, 1, wxEXPAND | wxBOTTOM, 15); main_sizer->Add(m_opengl_info_html, 1, wxEXPAND | wxBOTTOM, 15);
} }
@ -202,11 +198,7 @@ void SysInfoDialog::on_dpi_changed(const wxRect &suggested_rect)
void SysInfoDialog::onCopyToClipboard(wxEvent &) void SysInfoDialog::onCopyToClipboard(wxEvent &)
{ {
wxTheClipboard->Open(); wxTheClipboard->Open();
#if ENABLE_NON_STATIC_CANVAS_MANAGER
const auto text = get_main_info(false) + "\n" + wxGetApp().get_gl_info(false, true); const auto text = get_main_info(false) + "\n" + wxGetApp().get_gl_info(false, true);
#else
const auto text = get_main_info(false)+"\n"+_3DScene::get_gl_info(false, true);
#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
wxTheClipboard->SetData(new wxTextDataObject(text)); wxTheClipboard->SetData(new wxTextDataObject(text));
wxTheClipboard->Close(); wxTheClipboard->Close();
} }

View File

@ -57,7 +57,7 @@ namespace fts {
namespace fuzzy_internal { namespace fuzzy_internal {
static bool fuzzy_match_recursive(const char_type * pattern, const char_type * str, int & outScore, const char_type * const strBegin, static bool fuzzy_match_recursive(const char_type * pattern, const char_type * str, int & outScore, const char_type * const strBegin,
pos_type const * srcMatches, pos_type * newMatches, int nextMatch, pos_type const * srcMatches, pos_type * newMatches, int nextMatch,
int & recursionCount, int recursionLimit); int recursionCount, const int recursionLimit);
static void copy_matches(pos_type * dst, pos_type const* src); static void copy_matches(pos_type * dst, pos_type const* src);
} }
@ -93,8 +93,8 @@ namespace fts {
// Recursion count is input / output to track the maximum depth reached. // Recursion count is input / output to track the maximum depth reached.
// Was given by reference &recursionCount, see discussion in https://github.com/forrestthewoods/lib_fts/issues/21 // Was given by reference &recursionCount, see discussion in https://github.com/forrestthewoods/lib_fts/issues/21
// int & recursionCount, // int & recursionCount,
int & recursionCount, int recursionCount,
int recursionLimit) const int recursionLimit)
{ {
// Count recursions // Count recursions
if (++ recursionCount >= recursionLimit) if (++ recursionCount >= recursionLimit)
@ -183,29 +183,44 @@ namespace fts {
// Initialize score // Initialize score
outScore = 100; outScore = 100;
// Start of the first group that contains matches[0].
const char_type *group_start = strBegin + matches[0];
for (const char_type *c = group_start; c >= strBegin && *c != ':'; -- c)
if (*c != ' ' && *c != '\t')
group_start = c;
// Apply leading letter penalty or bonus. // Apply leading letter penalty or bonus.
outScore += matches[0] == 0 ? outScore += matches[0] == int(group_start - strBegin) ?
first_letter_bonus : first_letter_bonus :
std::max(matches[0] * leading_letter_penalty, max_leading_letter_penalty); std::max((matches[0] - int(group_start - strBegin)) * leading_letter_penalty, max_leading_letter_penalty);
// Apply unmatched letters after the end penalty // Apply unmatched letters after the end penalty
// outScore += (int(str - strBegin) - matches[nextMatch-1] + 1) * unmatched_letter_penalty; // outScore += (int(str - group_start) - matches[nextMatch-1] + 1) * unmatched_letter_penalty;
// Apply unmatched penalty // Apply unmatched penalty
outScore += (int(str - strBegin) - nextMatch) * unmatched_letter_penalty; outScore += (int(str - group_start) - nextMatch) * unmatched_letter_penalty;
// Apply ordering bonuses // Apply ordering bonuses
int sequential_state = sequential_bonus;
for (int i = 0; i < nextMatch; ++i) { for (int i = 0; i < nextMatch; ++i) {
pos_type currIdx = matches[i]; pos_type currIdx = matches[i];
// Check for bonuses based on neighbor character value // Check for bonuses based on neighbor character value
if (currIdx > 0) { if (currIdx > 0) {
if (i > 0 && currIdx == matches[i - 1] + 1) if (i > 0 && currIdx == matches[i - 1] + 1) {
// Sequential // Sequential
outScore += sequential_bonus; outScore += sequential_state;
// Camel case // Exponential grow of the sequential bonus.
sequential_state = std::min(5 * sequential_bonus, sequential_state + sequential_state / 3);
} else {
// Reset the sequential bonus exponential grow.
sequential_state = sequential_bonus;
}
char_type prev = strBegin[currIdx - 1]; char_type prev = strBegin[currIdx - 1];
/*
// Camel case
if (std::islower(prev) && std::isupper(strBegin[currIdx])) if (std::islower(prev) && std::isupper(strBegin[currIdx]))
outScore += camel_bonus; outScore += camel_bonus;
*/
// Separator // Separator
if (prev == '_' || prev == ' ') if (prev == '_' || prev == ' ')
outScore += separator_bonus; outScore += separator_bonus;

View File

@ -214,7 +214,7 @@ wxSize wxCheckListBoxComboPopup::GetAdjustedSize(int minWidth, int prefHeight, i
max_width = std::max(max_width, 60 + GetTextExtent(GetString(i)).x); max_width = std::max(max_width, 60 + GetTextExtent(GetString(i)).x);
} }
size.SetWidth(max_width); size.SetWidth(max_width);
size.SetHeight(count * GetTextExtent(GetString(0)).y); size.SetHeight(4 + count * (2 + GetTextExtent(GetString(0)).y));
} }
else else
size.SetHeight(DefaultHeight); size.SetHeight(DefaultHeight);

View File

@ -3,7 +3,7 @@
set(SLIC3R_APP_NAME "PrusaSlicer") set(SLIC3R_APP_NAME "PrusaSlicer")
set(SLIC3R_APP_KEY "PrusaSlicer") set(SLIC3R_APP_KEY "PrusaSlicer")
set(SLIC3R_VERSION "2.2.0") set(SLIC3R_VERSION "2.3.0-alpha0")
set(SLIC3R_BUILD_ID "PrusaSlicer-${SLIC3R_VERSION}+UNKNOWN") set(SLIC3R_BUILD_ID "PrusaSlicer-${SLIC3R_VERSION}+UNKNOWN")
set(SLIC3R_RC_VERSION "2,2,0,0") set(SLIC3R_RC_VERSION "2,3,0,0")
set(SLIC3R_RC_VERSION_DOTS "2.2.0.0") set(SLIC3R_RC_VERSION_DOTS "2.3.0.0")

View File

@ -15,7 +15,7 @@ REGISTER_CLASS(Filler, "Filler");
REGISTER_CLASS(Flow, "Flow"); REGISTER_CLASS(Flow, "Flow");
REGISTER_CLASS(CoolingBuffer, "GCode::CoolingBuffer"); REGISTER_CLASS(CoolingBuffer, "GCode::CoolingBuffer");
REGISTER_CLASS(GCode, "GCode"); REGISTER_CLASS(GCode, "GCode");
REGISTER_CLASS(GCodePreviewData, "GCode::PreviewData"); //REGISTER_CLASS(GCodePreviewData, "GCode::PreviewData");
// REGISTER_CLASS(GCodeSender, "GCode::Sender"); // REGISTER_CLASS(GCodeSender, "GCode::Sender");
REGISTER_CLASS(Layer, "Layer"); REGISTER_CLASS(Layer, "Layer");
REGISTER_CLASS(SupportLayer, "Layer::Support"); REGISTER_CLASS(SupportLayer, "Layer::Support");

View File

@ -26,14 +26,14 @@
croak("%s\n", e.what()); croak("%s\n", e.what());
} }
%}; %};
void do_export_w_preview(Print *print, const char *path, GCodePreviewData *preview_data) // void do_export_w_preview(Print *print, const char *path, GCodePreviewData *preview_data)
%code%{ // %code%{
try { // try {
THIS->do_export(print, path, preview_data); // THIS->do_export(print, path, preview_data);
} catch (std::exception& e) { // } catch (std::exception& e) {
croak("%s\n", e.what()); // croak("%s\n", e.what());
} // }
%}; // %};
Ref<Vec2d> origin() Ref<Vec2d> origin()
%code{% RETVAL = &(THIS->origin()); %}; %code{% RETVAL = &(THIS->origin()); %};
@ -60,26 +60,26 @@
%code{% RETVAL = const_cast<StaticPrintConfig*>(static_cast<const StaticPrintConfig*>(static_cast<const PrintObjectConfig*>(&THIS->config()))); %}; %code{% RETVAL = const_cast<StaticPrintConfig*>(static_cast<const StaticPrintConfig*>(static_cast<const PrintObjectConfig*>(&THIS->config()))); %};
}; };
%name{Slic3r::GCode::PreviewData} class GCodePreviewData { //%name{Slic3r::GCode::PreviewData} class GCodePreviewData {
GCodePreviewData(); // GCodePreviewData();
~GCodePreviewData(); // ~GCodePreviewData();
void reset(); // void reset();
bool empty() const; // bool empty() const;
void set_type(int type) // void set_type(int type)
%code%{ // %code%{
if ((0 <= type) && (type < GCodePreviewData::Extrusion::Num_View_Types)) // if ((0 <= type) && (type < GCodePreviewData::Extrusion::Num_View_Types))
THIS->extrusion.view_type = (GCodePreviewData::Extrusion::EViewType)type; // THIS->extrusion.view_type = (GCodePreviewData::Extrusion::EViewType)type;
%}; // %};
int type() %code%{ RETVAL = (int)THIS->extrusion.view_type; %}; // int type() %code%{ RETVAL = (int)THIS->extrusion.view_type; %};
void set_extrusion_flags(int flags) // void set_extrusion_flags(int flags)
%code%{ THIS->extrusion.role_flags = (unsigned int)flags; %}; // %code%{ THIS->extrusion.role_flags = (unsigned int)flags; %};
void set_travel_visible(bool visible) // void set_travel_visible(bool visible)
%code%{ THIS->travel.is_visible = visible; %}; // %code%{ THIS->travel.is_visible = visible; %};
void set_retractions_visible(bool visible) // void set_retractions_visible(bool visible)
%code%{ THIS->retraction.is_visible = visible; %}; // %code%{ THIS->retraction.is_visible = visible; %};
void set_unretractions_visible(bool visible) // void set_unretractions_visible(bool visible)
%code%{ THIS->unretraction.is_visible = visible; %}; // %code%{ THIS->unretraction.is_visible = visible; %};
void set_shells_visible(bool visible) // void set_shells_visible(bool visible)
%code%{ THIS->shell.is_visible = visible; %}; // %code%{ THIS->shell.is_visible = visible; %};
void set_extrusion_paths_colors(std::vector<std::string> colors); // void set_extrusion_paths_colors(std::vector<std::string> colors);
}; //};

View File

@ -164,7 +164,7 @@ _constant()
void export_gcode(char *path_template) %code%{ void export_gcode(char *path_template) %code%{
try { try {
THIS->export_gcode(path_template, nullptr, nullptr); THIS->export_gcode(path_template, nullptr);
} catch (std::exception& e) { } catch (std::exception& e) {
croak("%s\n", e.what()); croak("%s\n", e.what());
} }

View File

@ -191,9 +191,9 @@ GCode* O_OBJECT_SLIC3R
Ref<GCode> O_OBJECT_SLIC3R_T Ref<GCode> O_OBJECT_SLIC3R_T
Clone<GCode> O_OBJECT_SLIC3R_T Clone<GCode> O_OBJECT_SLIC3R_T
GCodePreviewData* O_OBJECT_SLIC3R //GCodePreviewData* O_OBJECT_SLIC3R
Ref<GCodePreviewData> O_OBJECT_SLIC3R_T //Ref<GCodePreviewData> O_OBJECT_SLIC3R_T
Clone<GCodePreviewData> O_OBJECT_SLIC3R_T //Clone<GCodePreviewData> O_OBJECT_SLIC3R_T
MotionPlanner* O_OBJECT_SLIC3R MotionPlanner* O_OBJECT_SLIC3R
Ref<MotionPlanner> O_OBJECT_SLIC3R_T Ref<MotionPlanner> O_OBJECT_SLIC3R_T

View File

@ -155,9 +155,9 @@
%typemap{Ref<GCode>}{simple}; %typemap{Ref<GCode>}{simple};
%typemap{Clone<GCode>}{simple}; %typemap{Clone<GCode>}{simple};
%typemap{GCodePreviewData*}; //%typemap{GCodePreviewData*};
%typemap{Ref<GCodePreviewData>}{simple}; //%typemap{Ref<GCodePreviewData>}{simple};
%typemap{Clone<GCodePreviewData>}{simple}; //%typemap{Clone<GCodePreviewData>}{simple};
%typemap{Points}; %typemap{Points};
%typemap{Pointfs}; %typemap{Pointfs};