diff --git a/resources/icons/add.svg b/resources/icons/add.svg
new file mode 100644
index 000000000..8a9b253de
--- /dev/null
+++ b/resources/icons/add.svg
@@ -0,0 +1,17 @@
+
+
+
diff --git a/resources/icons/arrange.svg b/resources/icons/arrange.svg
new file mode 100644
index 000000000..4f30e979e
--- /dev/null
+++ b/resources/icons/arrange.svg
@@ -0,0 +1,24 @@
+
+
+
diff --git a/resources/icons/delete_all.svg b/resources/icons/delete_all.svg
new file mode 100644
index 000000000..80e2e503c
--- /dev/null
+++ b/resources/icons/delete_all.svg
@@ -0,0 +1,31 @@
+
+
+
diff --git a/resources/icons/instance_add.svg b/resources/icons/instance_add.svg
new file mode 100644
index 000000000..5ef492cfa
--- /dev/null
+++ b/resources/icons/instance_add.svg
@@ -0,0 +1,50 @@
+
+
+
diff --git a/resources/icons/instance_remove.svg b/resources/icons/instance_remove.svg
new file mode 100644
index 000000000..466752ea8
--- /dev/null
+++ b/resources/icons/instance_remove.svg
@@ -0,0 +1,49 @@
+
+
+
diff --git a/resources/icons/layers.svg b/resources/icons/layers.svg
new file mode 100644
index 000000000..7718a8cbd
--- /dev/null
+++ b/resources/icons/layers.svg
@@ -0,0 +1,25 @@
+
+
+
diff --git a/resources/icons/remove.svg b/resources/icons/remove.svg
new file mode 100644
index 000000000..acd21256c
--- /dev/null
+++ b/resources/icons/remove.svg
@@ -0,0 +1,44 @@
+
+
+
diff --git a/resources/icons/split_objects.svg b/resources/icons/split_objects.svg
new file mode 100644
index 000000000..a7ccc5df8
--- /dev/null
+++ b/resources/icons/split_objects.svg
@@ -0,0 +1,19 @@
+
+
+
diff --git a/resources/icons/split_parts.svg b/resources/icons/split_parts.svg
new file mode 100644
index 000000000..82a292770
--- /dev/null
+++ b/resources/icons/split_parts.svg
@@ -0,0 +1,18 @@
+
+
+
diff --git a/src/libnest2d/include/libnest2d/optimizer.hpp b/src/libnest2d/include/libnest2d/optimizer.hpp
index 78e105598..962a47392 100644
--- a/src/libnest2d/include/libnest2d/optimizer.hpp
+++ b/src/libnest2d/include/libnest2d/optimizer.hpp
@@ -163,7 +163,7 @@ public:
{
dir_ = OptDir::MIN;
return static_cast(this)->template optimize(
- objectfunction, initvals, Bound()... );
+ forward(objectfunction), initvals, Bound()... );
}
template
@@ -171,7 +171,7 @@ public:
{
dir_ = OptDir::MIN;
return static_cast(this)->template optimize(
- objectfunction,
+ forward(objectfunction),
Input(),
Bound()... );
}
@@ -184,7 +184,7 @@ public:
{
dir_ = OptDir::MAX;
return static_cast(this)->template optimize(
- objectfunction, initvals, bounds... );
+ forward(objectfunction), initvals, bounds... );
}
template
@@ -193,7 +193,7 @@ public:
{
dir_ = OptDir::MAX;
return static_cast(this)->template optimize(
- objectfunction, initvals, Bound()... );
+ forward(objectfunction), initvals, Bound()... );
}
template
@@ -201,7 +201,7 @@ public:
{
dir_ = OptDir::MAX;
return static_cast(this)->template optimize(
- objectfunction,
+ forward(objectfunction),
Input(),
Bound()... );
}
diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp
index 7286c5cd8..7d1af094d 100644
--- a/src/libslic3r/PrintConfig.cpp
+++ b/src/libslic3r/PrintConfig.cpp
@@ -2730,6 +2730,17 @@ void PrintConfigDef::init_sla_params()
def->cli = "";
def->min = 0;
def->default_value = new ConfigOptionFloat(1.0);
+
+ def = this->add("pad_wall_slope", coFloat);
+ def->label = L("Pad wall slope");
+ def->category = L("Pad");
+ def->tooltip = L("The slope of the pad wall relative to the bed plane. "
+ "90 degrees means straight walls.");
+ def->sidetext = L("degrees");
+ def->cli = "";
+ def->min = 45;
+ def->max = 90;
+ def->default_value = new ConfigOptionFloat(45.0);
}
void PrintConfigDef::handle_legacy(t_config_option_key &opt_key, std::string &value)
diff --git a/src/libslic3r/PrintConfig.hpp b/src/libslic3r/PrintConfig.hpp
index 1ea556773..9b6f72391 100644
--- a/src/libslic3r/PrintConfig.hpp
+++ b/src/libslic3r/PrintConfig.hpp
@@ -1028,6 +1028,9 @@ public:
// The smoothing radius of the pad edges
ConfigOptionFloat pad_edge_radius /*= 1*/;
+ // The slope of the pad wall...
+ ConfigOptionFloat pad_wall_slope;
+
protected:
void initialize(StaticCacheBase &cache, const char *base_ptr)
{
@@ -1053,6 +1056,7 @@ protected:
OPT_PTR(pad_wall_height);
OPT_PTR(pad_max_merge_distance);
OPT_PTR(pad_edge_radius);
+ OPT_PTR(pad_wall_slope);
}
};
diff --git a/src/libslic3r/SLA/SLABasePool.cpp b/src/libslic3r/SLA/SLABasePool.cpp
index 6f85c43dc..62d8f0f30 100644
--- a/src/libslic3r/SLA/SLABasePool.cpp
+++ b/src/libslic3r/SLA/SLABasePool.cpp
@@ -601,8 +601,8 @@ void create_base_pool(const ExPolygons &ground_layer, TriangleMesh& out,
const double thickness = cfg.min_wall_thickness_mm;
const double wingheight = cfg.min_wall_height_mm;
const double fullheight = wingheight + thickness;
- const double tilt = PI/4;
- const double wingdist = wingheight / std::tan(tilt);
+ const double slope = cfg.wall_slope;
+ const double wingdist = wingheight / std::tan(slope);
// scaled values
const coord_t s_thickness = mm(thickness);
@@ -627,15 +627,22 @@ void create_base_pool(const ExPolygons &ground_layer, TriangleMesh& out,
auto outer_base = concaveh;
outer_base.holes.clear();
offset(outer_base, s_safety_dist + s_wingdist + s_thickness);
- auto inner_base = outer_base;
- offset(inner_base, -(s_thickness + s_wingdist));
+
+
+ ExPolygon bottom_poly = outer_base;
+ bottom_poly.holes.clear();
+ if(s_wingdist > 0) offset(bottom_poly, -s_wingdist);
// Punching a hole in the top plate for the cavity
ExPolygon top_poly;
ExPolygon middle_base;
+ ExPolygon inner_base;
top_poly.contour = outer_base.contour;
if(wingheight > 0) {
+ inner_base = outer_base;
+ offset(inner_base, -(s_thickness + s_wingdist + s_eradius));
+
middle_base = outer_base;
offset(middle_base, -s_thickness);
top_poly.holes.emplace_back(middle_base.contour);
@@ -682,10 +689,10 @@ void create_base_pool(const ExPolygons &ground_layer, TriangleMesh& out,
thrcl,
ob, wh));
- // Now that we have the rounded edge connencting the top plate with
+ // Now that we have the rounded edge connecting the top plate with
// the outer side walls, we can generate and merge the sidewall geometry
- pool.merge(walls(ob.contour, inner_base.contour, wh, -fullheight,
- (s_thickness + s_wingdist) * SCALING_FACTOR, thrcl));
+ pool.merge(walls(ob.contour, bottom_poly.contour, wh, -fullheight,
+ wingdist, thrcl));
if(wingheight > 0) {
// Generate the smoothed edge geometry
@@ -700,14 +707,14 @@ void create_base_pool(const ExPolygons &ground_layer, TriangleMesh& out,
// Next is the cavity walls connecting to the top plate's
// artificially created hole.
pool.merge(walls(inner_base.contour, ob.contour, -wingheight,
- wh, -s_safety_dist * SCALING_FACTOR, thrcl));
+ wh, -wingdist, thrcl));
}
// Now we need to triangulate the top and bottom plates as well as the
// cavity bottom plate which is the same as the bottom plate but it is
// elevated by the thickness.
pool.merge(triangulate_expolygon_3d(top_poly));
- pool.merge(triangulate_expolygon_3d(inner_base, -fullheight, true));
+ pool.merge(triangulate_expolygon_3d(bottom_poly, -fullheight, true));
if(wingheight > 0)
pool.merge(triangulate_expolygon_3d(inner_base, -wingheight));
diff --git a/src/libslic3r/SLA/SLABasePool.hpp b/src/libslic3r/SLA/SLABasePool.hpp
index 3917d995b..3c88e58c8 100644
--- a/src/libslic3r/SLA/SLABasePool.hpp
+++ b/src/libslic3r/SLA/SLABasePool.hpp
@@ -3,6 +3,7 @@
#include
#include
+#include
namespace Slic3r {
@@ -27,15 +28,17 @@ struct PoolConfig {
double min_wall_height_mm = 5;
double max_merge_distance_mm = 50;
double edge_radius_mm = 1;
+ double wall_slope = std::atan(1.0); // Universal constant for Pi/4
ThrowOnCancel throw_on_cancel = [](){};
inline PoolConfig() {}
- inline PoolConfig(double wt, double wh, double md, double er):
+ inline PoolConfig(double wt, double wh, double md, double er, double slope):
min_wall_thickness_mm(wt),
min_wall_height_mm(wh),
max_merge_distance_mm(md),
- edge_radius_mm(er) {}
+ edge_radius_mm(er),
+ wall_slope(slope) {}
};
/// Calculate the pool for the mesh for SLA printing
diff --git a/src/libslic3r/SLA/SLASupportTree.cpp b/src/libslic3r/SLA/SLASupportTree.cpp
index 3e36dfd85..913e9beda 100644
--- a/src/libslic3r/SLA/SLASupportTree.cpp
+++ b/src/libslic3r/SLA/SLASupportTree.cpp
@@ -12,6 +12,7 @@
#include
#include
+#include
#include
#include
@@ -594,7 +595,7 @@ double pinhead_mesh_intersect(const Vec3d& s,
double r_back,
double width,
const EigenMesh3D& m,
- unsigned samples = 8,
+ unsigned samples = 16,
double safety_distance = 0.001)
{
// method based on:
@@ -620,9 +621,20 @@ double pinhead_mesh_intersect(const Vec3d& s,
std::vector phis(samples);
for(size_t i = 0; i < phis.size(); ++i) phis[i] = i*2*PI/phis.size();
- a(Z) = -(v(X)*a(X) + v(Y)*a(Y)) / v(Z);
-
- b = a.cross(v);
+ // We have to address the case when the direction vector v (same as dir)
+ // is coincident with one of the world axes. In this case two of its
+ // components will be completely zero and one is 1.0. Our method becomes
+ // dangerous here due to division with zero. Instead, vector 'a' can be an
+ // element-wise rotated version of 'v'
+ auto chk1 = [] (double val) { return std::abs(std::abs(val) - 1) < 1e-20; };
+ if(chk1(v(X)) || chk1(v(Y)) || chk1(v(Z))) {
+ a = {v(Z), v(X), v(Y)};
+ b = {v(Y), v(Z), v(X)};
+ }
+ else {
+ a(Z) = -(v(Y)*a(Y)) / v(Z); a.normalize();
+ b = a.cross(v);
+ }
// Now a and b vectors are perpendicular to v and to each other. Together
// they define the plane where we have to iterate with the given angles
@@ -647,18 +659,14 @@ double pinhead_mesh_intersect(const Vec3d& s,
s(Z) + rpscos * a(Z) + rpssin * b(Z));
// Point ps is not on mesh but can be inside or outside as well. This
- // would cause many problems with ray-casting. So we query the closest
- // point on the mesh to this.
-// auto psq = m.signed_distance(ps);
+ // would cause many problems with ray-casting. To detect the position we
+ // will use the ray-casting result (which has an is_inside predicate).
// This is the point on the circle on the back sphere
Vec3d p(c(X) + rpbcos * a(X) + rpbsin * b(X),
c(Y) + rpbcos * a(Y) + rpbsin * b(Y),
c(Z) + rpbcos * a(Z) + rpbsin * b(Z));
-// Vec3d n = (p - psq.point_on_mesh()).normalized();
-// phi = m.query_ray_hit(psq.point_on_mesh() + sd*n, n);
-
Vec3d n = (p - ps).normalized();
auto hr = m.query_ray_hit(ps + sd*n, n);
@@ -693,8 +701,18 @@ double bridge_mesh_intersect(const Vec3d& s,
Vec3d a(0, 1, 0), b;
const double& sd = safety_distance;
- a(Z) = -(dir(X)*a(X) + dir(Y)*a(Y)) / dir(Z);
- b = a.cross(dir);
+ // INFO: for explanation of the method used here, see the previous method's
+ // comments.
+
+ auto chk1 = [] (double val) { return std::abs(std::abs(val) - 1) < 1e-20; };
+ if(chk1(dir(X)) || chk1(dir(Y)) || chk1(dir(Z))) {
+ a = {dir(Z), dir(X), dir(Y)};
+ b = {dir(Y), dir(Z), dir(X)};
+ }
+ else {
+ a(Z) = -(dir(Y)*a(Y)) / dir(Z); a.normalize();
+ b = a.cross(dir);
+ }
// circle portions
std::vector phis(samples);
@@ -1156,16 +1174,16 @@ bool SLASupportTree::generate(const PointSet &points,
//...
};
- // t-hrow i-f c-ance-l-ed: It will be called many times so a shorthand will
+ // throw if canceled: It will be called many times so a shorthand will
// come in handy.
- auto& tifcl = ctl.cancelfn;
+ auto& thr = ctl.cancelfn;
// Filtering step: here we will discard inappropriate support points and
// decide the future of the appropriate ones. We will check if a pinhead
// is applicable and adjust its angle at each support point.
// We will also merge the support points that are just too close and can be
// considered as one.
- auto filterfn = [tifcl] (
+ auto filterfn = [thr] (
const SupportConfig& cfg,
const PointSet& points,
const EigenMesh3D& mesh,
@@ -1179,9 +1197,9 @@ bool SLASupportTree::generate(const PointSet &points,
// first one
auto aliases =
cluster(points,
- [tifcl](const SpatElement& p, const SpatElement& se)
+ [thr](const SpatElement& p, const SpatElement& se)
{
- tifcl();
+ thr();
return distance(p.first, se.first) < D_SP;
}, 2);
@@ -1192,10 +1210,10 @@ bool SLASupportTree::generate(const PointSet &points,
filt_pts.row(count++) = points.row(a.front());
}
- tifcl();
+ thr();
// calculate the normals to the triangles belonging to filtered points
- auto nmls = sla::normals(filt_pts, mesh, cfg.head_front_radius_mm, tifcl);
+ auto nmls = sla::normals(filt_pts, mesh, cfg.head_front_radius_mm, thr);
head_norm.resize(count, 3);
head_pos.resize(count, 3);
@@ -1207,9 +1225,15 @@ bool SLASupportTree::generate(const PointSet &points,
// not be enough space for the pinhead. Filtering is applied for
// these reasons.
+ using libnest2d::opt::bound;
+ using libnest2d::opt::initvals;
+ using libnest2d::opt::SimplexOptimizer;
+ using libnest2d::opt::StopCriteria;
+ static const unsigned MAX_TRIES = 100;
+
int pcount = 0, hlcount = 0;
for(int i = 0; i < count; i++) {
- tifcl();
+ thr();
auto n = nmls.row(i);
// for all normals we generate the spherical coordinates and
@@ -1230,32 +1254,67 @@ bool SLASupportTree::generate(const PointSet &points,
// We saturate the polar angle to 3pi/4
polar = std::max(polar, 3*PI / 4);
- // Reassemble the now corrected normal
- Vec3d nn(std::cos(azimuth) * std::sin(polar),
- std::sin(azimuth) * std::sin(polar),
- std::cos(polar));
-
- nn.normalize();
-
// save the head (pinpoint) position
Vec3d hp = filt_pts.row(i);
- // the full width of the head
double w = cfg.head_width_mm +
cfg.head_back_radius_mm +
2*cfg.head_front_radius_mm;
- // We should shoot a ray in the direction of the pinhead and
- // see if there is enough space for it
- double t = pinhead_mesh_intersect(
- hp, // touching point
- nn,
- cfg.head_front_radius_mm, // approx the radius
- cfg.head_back_radius_mm,
- w,
- mesh);
+ // Reassemble the now corrected normal
+ auto nn = Vec3d(std::cos(azimuth) * std::sin(polar),
+ std::sin(azimuth) * std::sin(polar),
+ std::cos(polar)).normalized();
- if(t > w || std::isinf(t)) {
+ // check available distance
+ double t = pinhead_mesh_intersect(
+ hp, // touching point
+ nn, // normal
+ cfg.head_front_radius_mm,
+ cfg.head_back_radius_mm,
+ w,
+ mesh);
+
+ if(t <= w) {
+ // Let's try to optimize this angle, there might be a viable
+ // normal that doesn't collide with the model geometry and
+ // its very close to the default.
+
+ StopCriteria stc;
+ stc.max_iterations = MAX_TRIES;
+ stc.relative_score_difference = 1e-3;
+ stc.stop_score = w; // space greater than w is enough
+ SimplexOptimizer solver(stc);
+
+ auto oresult = solver.optimize_max(
+ [&mesh, &cfg, w, hp](double plr, double azm)
+ {
+ auto n = Vec3d(std::cos(azm) * std::sin(plr),
+ std::sin(azm) * std::sin(plr),
+ std::cos(plr)).normalized();
+
+ double score = pinhead_mesh_intersect(
+ hp, n,
+ cfg.head_front_radius_mm,
+ cfg.head_back_radius_mm,
+ w,
+ mesh);
+ return score;
+ },
+ initvals(polar, azimuth), // let's start with what we have
+ bound(3*PI/4, PI), // Must not exceed the tilt limit
+ bound(-PI, PI) // azimuth can be a full range search
+ );
+
+ t = oresult.score;
+ polar = std::get<0>(oresult.optimum);
+ azimuth = std::get<1>(oresult.optimum);
+ nn = Vec3d(std::cos(azimuth) * std::sin(polar),
+ std::sin(azimuth) * std::sin(polar),
+ std::cos(polar)).normalized();
+ }
+
+ if(t > w) {
head_pos.row(pcount) = hp;
// save the verified and corrected normal
@@ -1263,6 +1322,7 @@ bool SLASupportTree::generate(const PointSet &points,
++pcount;
} else if( polar >= 3*PI/4 ) {
+
// Headless supports do not tilt like the headed ones so
// the normal should point almost to the ground.
headless_norm.row(hlcount) = nn;
@@ -1279,7 +1339,7 @@ bool SLASupportTree::generate(const PointSet &points,
// Pinhead creation: based on the filtering results, the Head objects will
// be constructed (together with their triangle meshes).
- auto pinheadfn = [tifcl] (
+ auto pinheadfn = [thr] (
const SupportConfig& cfg,
PointSet& head_pos,
PointSet& nmls,
@@ -1292,7 +1352,7 @@ bool SLASupportTree::generate(const PointSet &points,
/* ******************************************************** */
for (int i = 0; i < head_pos.rows(); ++i) {
- tifcl();
+ thr();
result.add_head(
cfg.head_back_radius_mm,
cfg.head_front_radius_mm,
@@ -1311,7 +1371,7 @@ bool SLASupportTree::generate(const PointSet &points,
// will process it. Also, the pillars will be grouped into clusters that can
// be interconnected with bridges. Elements of these groups may or may not
// be interconnected. Here we only run the clustering algorithm.
- auto classifyfn = [tifcl] (
+ auto classifyfn = [thr] (
const SupportConfig& cfg,
const EigenMesh3D& mesh,
PointSet& head_pos,
@@ -1320,7 +1380,8 @@ bool SLASupportTree::generate(const PointSet &points,
std::vector& gndheight,
ClusteredPoints& ground_clusters,
Result& result
- ) {
+ )
+ {
/* ******************************************************** */
/* Classification */
@@ -1331,11 +1392,11 @@ bool SLASupportTree::generate(const PointSet &points,
gndidx.reserve(size_t(head_pos.rows()));
nogndidx.reserve(size_t(head_pos.rows()));
- // First we search decide which heads reach the ground and can be full
+ // First we decide which heads reach the ground and can be full
// pillars and which shall be connected to the model surface (or search
// a suitable path around the surface that leads to the ground -- TODO)
for(unsigned i = 0; i < head_pos.rows(); i++) {
- tifcl();
+ thr();
auto& head = result.head(i);
Vec3d dir(0, 0, -1);
@@ -1344,9 +1405,38 @@ bool SLASupportTree::generate(const PointSet &points,
double t = std::numeric_limits::infinity();
double hw = head.width_mm;
+
+ {
+// using libnest2d::opt::Method;
+// using libnest2d::opt::bound;
+// using libnest2d::opt::Optimizer;
+// using libnest2d::opt::TOptimizer;
+// using libnest2d::opt::StopCriteria;
+
+// auto stopcond = [] () { return false; };
+// static const unsigned max_tries = 100;
+
+// auto objfunc =
+// [&head](double polar, double azimuth, double width)
+// {
+// Vec3d nn(std::cos(azimuth) * std::sin(polar),
+// std::sin(azimuth) * std::sin(polar),
+// std::cos(polar));
+
+
+// };
+
+// StopCriteria stc;
+// stc.max_iterations = max_tries;
+// stc.relative_score_difference = 1e-3;
+// stc.stop_condition = stopcond;
+// TOptimizer solver(stc);
+ }
+
+
// We will try to assign a pillar to all the pinheads. If a pillar
// would pierce the model surface, we will try to adjust slightly
- // the head with so that the pillar can be deployed.
+ // the head width so that the pillar can be deployed.
while(!accept && head.width_mm > 0) {
Vec3d startpoint = head.junction_point();
@@ -1358,11 +1448,18 @@ bool SLASupportTree::generate(const PointSet &points,
double tprec = ray_mesh_intersect(startpoint, dir, mesh);
if(std::isinf(tprec) && !std::isinf(t)) {
- // This is a damned case where the pillar melds into the
+ // This is a damned case where the pillar melts into the
// model but its center ray can reach the ground. We can
// not route this to the ground nor to the model surface.
head.width_mm = hw + (ri % 2? -1 : 1) * ri * head.r_back_mm;
} else {
+ if(!std::isinf(t) && !std::isinf(tprec) &&
+ std::abs(tprec - t) > hw)
+ {
+ // In this case the head would scratch the model body
+ BOOST_LOG_TRIVIAL(warning) << "Head scratch detected.";
+ }
+
accept = true; t = tprec;
auto id = head.id;
@@ -1417,9 +1514,9 @@ bool SLASupportTree::generate(const PointSet &points,
ground_clusters =
cluster(
gnd,
- [d_base, tifcl](const SpatElement& p, const SpatElement& s)
+ [d_base, thr](const SpatElement& p, const SpatElement& s)
{
- tifcl();
+ thr();
return distance(Vec2d(p.first(X), p.first(Y)),
Vec2d(s.first(X), s.first(Y))) < d_base;
}, 3); // max 3 heads to connect to one centroid
@@ -1492,7 +1589,7 @@ bool SLASupportTree::generate(const PointSet &points,
// a full pillar (ground connected). Some will connect to a nearby pillar
// using a bridge. The max number of such side-heads for a central pillar
// is limited to avoid bad weight distribution.
- auto routing_ground_fn = [gnd_head_pt, interconnect, tifcl](
+ auto routing_ground_fn = [gnd_head_pt, interconnect, thr](
const SupportConfig& cfg,
const ClusteredPoints& gnd_clusters,
const IndexSet& gndidx,
@@ -1508,7 +1605,7 @@ bool SLASupportTree::generate(const PointSet &points,
cl_centroids.reserve(gnd_clusters.size());
SpatIndex pheadindex; // spatial index for the junctions
- for(auto& cl : gnd_clusters) { tifcl();
+ for(auto& cl : gnd_clusters) { thr();
// place all the centroid head positions into the index. We will
// query for alternative pillar positions. If a sidehead cannot
// connect to the cluster centroid, we have to search for another
@@ -1519,9 +1616,9 @@ bool SLASupportTree::generate(const PointSet &points,
// get the current cluster centroid
long lcid = cluster_centroid(cl, gnd_head_pt,
- [tifcl](const Vec3d& p1, const Vec3d& p2)
+ [thr](const Vec3d& p1, const Vec3d& p2)
{
- tifcl();
+ thr();
return distance(Vec2d(p1(X), p1(Y)), Vec2d(p2(X), p2(Y)));
});
@@ -1542,7 +1639,7 @@ bool SLASupportTree::generate(const PointSet &points,
// sidepoints with the cluster centroid (which is a ground pillar)
// or a nearby pillar if the centroid is unreachable.
size_t ci = 0;
- for(auto cl : gnd_clusters) { tifcl();
+ for(auto cl : gnd_clusters) { thr();
auto cidx = cl_centroids[ci];
cl_centroids[ci++] = cl[cidx];
@@ -1566,12 +1663,12 @@ bool SLASupportTree::generate(const PointSet &points,
// is distributed more effectively on the pillar.
auto search_nearest =
- [&tifcl, &cfg, &result, &emesh, maxbridgelen, gndlvl, pradius]
+ [&thr, &cfg, &result, &emesh, maxbridgelen, gndlvl, pradius]
(SpatIndex& spindex, const Vec3d& jsh)
{
long nearest_id = -1;
const double max_len = maxbridgelen / 2;
- while(nearest_id < 0 && !spindex.empty()) { tifcl();
+ while(nearest_id < 0 && !spindex.empty()) { thr();
// loop until a suitable head is not found
// if there is a pillar closer than the cluster center
// (this may happen as the clustering is not perfect)
@@ -1610,7 +1707,7 @@ bool SLASupportTree::generate(const PointSet &points,
return nearest_id;
};
- for(auto c : cl) { tifcl();
+ for(auto c : cl) { thr();
auto& sidehead = result.head(gndidx[c]);
sidehead.transform();
@@ -1676,7 +1773,7 @@ bool SLASupportTree::generate(const PointSet &points,
ClusterEl ring;
while(!rem.empty()) { // loop until all the points belong to some ring
- tifcl();
+ thr();
std::sort(rem.begin(), rem.end());
auto newring = pts_convex_hull(rem,
@@ -1688,7 +1785,7 @@ bool SLASupportTree::generate(const PointSet &points,
if(!ring.empty()) {
// inner ring is now in 'newring' and outer ring is in 'ring'
SpatIndex innerring;
- for(unsigned i : newring) { tifcl();
+ for(unsigned i : newring) { thr();
const Pillar& pill = result.head_pillar(gndidx[i]);
assert(pill.id >= 0);
innerring.insert(pill.endpoint, unsigned(pill.id));
@@ -1697,7 +1794,7 @@ bool SLASupportTree::generate(const PointSet &points,
// For all pillars in the outer ring find the closest in the
// inner ring and connect them. This will create the spider web
// fashioned connections between pillars
- for(unsigned i : ring) { tifcl();
+ for(unsigned i : ring) { thr();
const Pillar& outerpill = result.head_pillar(gndidx[i]);
auto res = innerring.nearest(outerpill.endpoint, 1);
if(res.empty()) continue;
@@ -1723,7 +1820,7 @@ bool SLASupportTree::generate(const PointSet &points,
next != ring.end();
++it, ++next)
{
- tifcl();
+ thr();
const Pillar& pillar = result.head_pillar(gndidx[*it]);
const Pillar& nextpillar = result.head_pillar(gndidx[*next]);
interconnect(pillar, nextpillar, emesh, result);
@@ -1738,19 +1835,19 @@ bool SLASupportTree::generate(const PointSet &points,
}
};
- // Step: routing the pinheads that are would connect to the model surface
+ // Step: routing the pinheads that would connect to the model surface
// along the Z axis downwards. For now these will actually be connected with
// the model surface with a flipped pinhead. In the future here we could use
// some smart algorithms to search for a safe path to the ground or to a
// nearby pillar that can hold the supported weight.
- auto routing_nongnd_fn = [tifcl](
+ auto routing_nongnd_fn = [thr](
const SupportConfig& cfg,
const std::vector& gndheight,
const IndexSet& nogndidx,
Result& result)
{
// TODO: connect these to the ground pillars if possible
- for(auto idx : nogndidx) { tifcl();
+ for(auto idx : nogndidx) { thr();
double gh = gndheight[idx];
double base_width = cfg.head_width_mm;
@@ -1807,7 +1904,7 @@ bool SLASupportTree::generate(const PointSet &points,
// Step: process the support points where there is not enough space for a
// full pinhead. In this case we will use a rounded sphere as a touching
// point and use a thinner bridge (let's call it a stick).
- auto process_headless = [tifcl](
+ auto process_headless = [thr](
const SupportConfig& cfg,
const PointSet& headless_pts,
const PointSet& headless_norm,
@@ -1822,7 +1919,7 @@ bool SLASupportTree::generate(const PointSet &points,
// We will sink the pins into the model surface for a distance of 1/3 of
// the pin radius
- for(int i = 0; i < headless_pts.rows(); i++) { tifcl();
+ for(int i = 0; i < headless_pts.rows(); i++) { thr();
Vec3d sph = headless_pts.row(i); // Exact support position
Vec3d n = headless_norm.row(i); // mesh outward normal
Vec3d sp = sph - n * HWIDTH_MM; // stick head start point
diff --git a/src/libslic3r/SLA/SLASupportTreeIGL.cpp b/src/libslic3r/SLA/SLASupportTreeIGL.cpp
index 6a3b71e7d..25638fe69 100644
--- a/src/libslic3r/SLA/SLASupportTreeIGL.cpp
+++ b/src/libslic3r/SLA/SLASupportTreeIGL.cpp
@@ -205,9 +205,11 @@ template double distance(const Vec& pp1, const Vec& pp2) {
return std::sqrt(p.transpose() * p);
}
-PointSet normals(const PointSet& points, const EigenMesh3D& mesh,
+PointSet normals(const PointSet& points,
+ const EigenMesh3D& mesh,
double eps,
- std::function throw_on_cancel) {
+ std::function throw_on_cancel)
+{
if(points.rows() == 0 || mesh.V().rows() == 0 || mesh.F().rows() == 0)
return {};
@@ -228,7 +230,7 @@ PointSet normals(const PointSet& points, const EigenMesh3D& mesh,
const Vec3d& p3 = mesh.V().row(trindex(2));
// We should check if the point lies on an edge of the hosting triangle.
- // If it does than all the other triangles using the same two points
+ // If it does then all the other triangles using the same two points
// have to be searched and the final normal should be some kind of
// aggregation of the participating triangle normals. We should also
// consider the cases where the support point lies right on a vertex
diff --git a/src/libslic3r/SLAPrint.cpp b/src/libslic3r/SLAPrint.cpp
index d81498916..827846b71 100644
--- a/src/libslic3r/SLAPrint.cpp
+++ b/src/libslic3r/SLAPrint.cpp
@@ -415,49 +415,73 @@ void SLAPrint::set_task(const TaskParams ¶ms)
n_object_steps = (int)slaposCount;
if (params.single_model_object.valid()) {
+ // Find the print object to be processed with priority.
SLAPrintObject *print_object = nullptr;
size_t idx_print_object = 0;
- for (; idx_print_object < m_objects.size(); ++idx_print_object)
+ for (; idx_print_object < m_objects.size(); ++ idx_print_object)
if (m_objects[idx_print_object]->model_object()->id() == params.single_model_object) {
print_object = m_objects[idx_print_object];
break;
}
assert(print_object != nullptr);
- bool shall_cancel = false;
- for (int istep = 0; istep < n_object_steps; ++istep)
- if (! print_object->m_stepmask[istep]) {
- shall_cancel = true;
+ // Find out whether the priority print object is being currently processed.
+ bool running = false;
+ for (int istep = 0; istep < n_object_steps; ++ istep) {
+ if (! print_object->m_stepmask[istep])
+ // Step was skipped, cancel.
+ break;
+ if (print_object->is_step_started_unguarded(SLAPrintObjectStep(istep))) {
+ // No step was skipped, and a wanted step is being processed. Don't cancel.
+ running = true;
break;
}
- bool running = false;
- if (!shall_cancel) {
- for (int istep = 0; istep < n_object_steps; ++ istep)
- if (print_object->is_step_started_unguarded(SLAPrintObjectStep(istep))) {
- running = true;
- break;
- }
}
- if (!running)
+ if (! running)
this->call_cancel_callback();
// Now the background process is either stopped, or it is inside one of the print object steps to be calculated anyway.
if (params.single_model_instance_only) {
// Suppress all the steps of other instances.
for (SLAPrintObject *po : m_objects)
- for (int istep = 0; istep < (int)slaposCount; ++istep)
+ for (int istep = 0; istep < (int)slaposCount; ++ istep)
po->m_stepmask[istep] = false;
- }
- else if (!running) {
+ } else if (! running) {
// Swap the print objects, so that the selected print_object is first in the row.
// At this point the background processing must be stopped, so it is safe to shuffle print objects.
if (idx_print_object != 0)
std::swap(m_objects.front(), m_objects[idx_print_object]);
}
+ // and set the steps for the current object.
for (int istep = 0; istep < n_object_steps; ++ istep)
print_object->m_stepmask[istep] = true;
- for (int istep = n_object_steps; istep < (int)slaposCount; ++istep)
+ for (int istep = n_object_steps; istep < (int)slaposCount; ++ istep)
print_object->m_stepmask[istep] = false;
- }
+ } else {
+ // Slicing all objects.
+ bool running = false;
+ for (SLAPrintObject *print_object : m_objects)
+ for (int istep = 0; istep < n_object_steps; ++ istep) {
+ if (! print_object->m_stepmask[istep]) {
+ // Step may have been skipped. Restart.
+ goto loop_end;
+ }
+ if (print_object->is_step_started_unguarded(SLAPrintObjectStep(istep))) {
+ // This step is running, and the state cannot be changed due to the this->state_mutex() being locked.
+ // It is safe to manipulate m_stepmask of other SLAPrintObjects and SLAPrint now.
+ running = true;
+ goto loop_end;
+ }
+ }
+ loop_end:
+ if (! running)
+ this->call_cancel_callback();
+ for (SLAPrintObject *po : m_objects) {
+ for (int istep = 0; istep < n_object_steps; ++ istep)
+ po->m_stepmask[istep] = true;
+ for (int istep = n_object_steps; istep < (int)slaposCount; ++ istep)
+ po->m_stepmask[istep] = false;
+ }
+ }
if (params.to_object_step != -1 || params.to_print_step != -1) {
// Limit the print steps.
@@ -484,7 +508,7 @@ void SLAPrint::finalize()
std::string SLAPrint::output_filename() const
{
DynamicConfig config = this->finished() ? this->print_statistics().config() : this->print_statistics().placeholders();
- return this->PrintBase::output_filename(m_print_config.output_filename_format.value, "zip", &config);
+ return this->PrintBase::output_filename(m_print_config.output_filename_format.value, "sl1", &config);
}
namespace {
@@ -727,11 +751,13 @@ void SLAPrint::process()
double wt = po.m_config.pad_wall_thickness.getFloat();
double h = po.m_config.pad_wall_height.getFloat();
double md = po.m_config.pad_max_merge_distance.getFloat();
- double er = po.m_config.pad_edge_radius.getFloat();
+ // Radius is disabled for now...
+ double er = 0; // po.m_config.pad_edge_radius.getFloat();
+ double tilt = po.m_config.pad_wall_slope.getFloat() * PI / 180.0;
double lh = po.m_config.layer_height.getFloat();
double elevation = po.m_config.support_object_elevation.getFloat();
if(!po.m_config.supports_enable.getBool()) elevation = 0;
- sla::PoolConfig pcfg(wt, h, md, er);
+ sla::PoolConfig pcfg(wt, h, md, er, tilt);
ExPolygons bp;
double pad_h = sla::get_pad_fullheight(pcfg);
@@ -742,8 +768,7 @@ void SLAPrint::process()
if(elevation < pad_h) {
// we have to count with the model geometry for the base plate
- sla::base_plate(trmesh, bp, float(pad_h), float(lh),
- thrfn);
+ sla::base_plate(trmesh, bp, float(pad_h), float(lh), thrfn);
}
pcfg.throw_on_cancel = thrfn;
@@ -1344,6 +1369,7 @@ bool SLAPrintObject::invalidate_state_by_config_options(const std::vectorset_step_started(bspsGCodeFinalize)) {
if (! m_export_path.empty()) {
m_sla_print->export_raster(m_export_path);
- m_print->set_status(100, "Zip file exported to " + m_export_path);
+ m_print->set_status(100, "Masked SLA file exported to " + m_export_path);
} else if (! m_upload_job.empty()) {
prepare_upload();
} else {
diff --git a/src/slic3r/GUI/Field.cpp b/src/slic3r/GUI/Field.cpp
index d514615f2..0d65e0ef5 100644
--- a/src/slic3r/GUI/Field.cpp
+++ b/src/slic3r/GUI/Field.cpp
@@ -631,8 +631,13 @@ void Choice::set_value(const boost::any& value, bool change_event)
break;
++idx;
}
- idx == m_opt.enum_values.size() ?
- dynamic_cast(window)->SetValue(text_value) :
+ if (idx == m_opt.enum_values.size()) {
+ // For editable Combobox under OSX is needed to set selection to -1 explicitly,
+ // otherwise selection doesn't be changed
+ dynamic_cast(window)->SetSelection(-1);
+ dynamic_cast(window)->SetValue(text_value);
+ }
+ else
dynamic_cast(window)->SetSelection(idx);
break;
}
diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp
index c8707e75f..9fc1d1e3a 100644
--- a/src/slic3r/GUI/GLCanvas3D.cpp
+++ b/src/slic3r/GUI/GLCanvas3D.cpp
@@ -2405,20 +2405,37 @@ void GLCanvas3D::Selection::_ensure_on_bed()
}
}
+#if ENABLE_SVG_ICONS
+const float GLCanvas3D::Gizmos::Default_Icons_Size = 64;
+#endif // ENABLE_SVG_ICONS
+
GLCanvas3D::Gizmos::Gizmos()
: m_enabled(false)
+#if ENABLE_SVG_ICONS
+ , m_icons_texture_dirty(true)
+#endif // ENABLE_SVG_ICONS
, m_current(Undefined)
+#if ENABLE_SVG_ICONS
+ , m_overlay_icons_size(Default_Icons_Size)
+ , m_overlay_scale(1.0f)
+ , m_overlay_border(5.0f)
+ , m_overlay_gap_y(5.0f)
+{
+}
+#else
{
set_overlay_scale(1.0);
}
+#endif // ENABLE_SVG_ICONS
GLCanvas3D::Gizmos::~Gizmos()
{
- _reset();
+ reset();
}
bool GLCanvas3D::Gizmos::init(GLCanvas3D& parent)
{
+#if !ENABLE_SVG_ICONS
m_icons_texture.metadata.filename = "gizmos.png";
m_icons_texture.metadata.icon_size = 64;
@@ -2426,10 +2443,11 @@ bool GLCanvas3D::Gizmos::init(GLCanvas3D& parent)
{
if (!m_icons_texture.texture.load_from_file(resources_dir() + "/icons/" + m_icons_texture.metadata.filename, false))
{
- _reset();
+ reset();
return false;
}
}
+#endif // !ENABLE_SVG_ICONS
m_background_texture.metadata.filename = "toolbar_background.png";
m_background_texture.metadata.left = 16;
@@ -2441,12 +2459,16 @@ bool GLCanvas3D::Gizmos::init(GLCanvas3D& parent)
{
if (!m_background_texture.texture.load_from_file(resources_dir() + "/icons/" + m_background_texture.metadata.filename, false))
{
- _reset();
+ reset();
return false;
}
}
+#if ENABLE_SVG_ICONS
+ GLGizmoBase* gizmo = new GLGizmoMove3D(parent, "add.svg", 0);
+#else
GLGizmoBase* gizmo = new GLGizmoMove3D(parent, 0);
+#endif // ENABLE_SVG_ICONS
if (gizmo == nullptr)
return false;
@@ -2455,7 +2477,11 @@ bool GLCanvas3D::Gizmos::init(GLCanvas3D& parent)
m_gizmos.insert(GizmosMap::value_type(Move, gizmo));
+#if ENABLE_SVG_ICONS
+ gizmo = new GLGizmoScale3D(parent, "remove.svg", 1);
+#else
gizmo = new GLGizmoScale3D(parent, 1);
+#endif // ENABLE_SVG_ICONS
if (gizmo == nullptr)
return false;
@@ -2464,49 +2490,65 @@ bool GLCanvas3D::Gizmos::init(GLCanvas3D& parent)
m_gizmos.insert(GizmosMap::value_type(Scale, gizmo));
+#if ENABLE_SVG_ICONS
+ gizmo = new GLGizmoRotate3D(parent, "delete_all.svg", 2);
+#else
gizmo = new GLGizmoRotate3D(parent, 2);
+#endif // ENABLE_SVG_ICONS
if (gizmo == nullptr)
{
- _reset();
+ reset();
return false;
}
if (!gizmo->init())
{
- _reset();
+ reset();
return false;
}
m_gizmos.insert(GizmosMap::value_type(Rotate, gizmo));
+#if ENABLE_SVG_ICONS
+ gizmo = new GLGizmoFlatten(parent, "arrange.svg", 3);
+#else
gizmo = new GLGizmoFlatten(parent, 3);
+#endif // ENABLE_SVG_ICONS
if (gizmo == nullptr)
return false;
if (!gizmo->init()) {
- _reset();
+ reset();
return false;
}
m_gizmos.insert(GizmosMap::value_type(Flatten, gizmo));
+#if ENABLE_SVG_ICONS
+ gizmo = new GLGizmoCut(parent, "instance_add.svg", 4);
+#else
gizmo = new GLGizmoCut(parent, 4);
+#endif // ENABLE_SVG_ICONS
if (gizmo == nullptr)
return false;
if (!gizmo->init()) {
- _reset();
+ reset();
return false;
}
m_gizmos.insert(GizmosMap::value_type(Cut, gizmo));
+#if ENABLE_SVG_ICONS
+ gizmo = new GLGizmoSlaSupports(parent, "instance_remove.svg", 5);
+#else
gizmo = new GLGizmoSlaSupports(parent, 5);
+#endif // ENABLE_SVG_ICONS
if (gizmo == nullptr)
return false;
if (!gizmo->init()) {
- _reset();
+ reset();
return false;
}
@@ -2525,11 +2567,30 @@ void GLCanvas3D::Gizmos::set_enabled(bool enable)
m_enabled = enable;
}
+#if ENABLE_SVG_ICONS
+void GLCanvas3D::Gizmos::set_overlay_icon_size(float size)
+{
+ if (m_overlay_icons_size != size)
+ {
+ m_overlay_icons_size = size;
+ m_icons_texture_dirty = true;
+ }
+}
+#endif // ENABLE_SVG_ICONS
+
void GLCanvas3D::Gizmos::set_overlay_scale(float scale)
{
+#if ENABLE_SVG_ICONS
+ if (m_overlay_scale != scale)
+ {
+ m_overlay_scale = scale;
+ m_icons_texture_dirty = true;
+ }
+#else
m_overlay_icons_scale = scale;
m_overlay_border = 5.0f * scale;
m_overlay_gap_y = 5.0f * scale;
+#endif // ENABLE_SVG_ICONS
}
std::string GLCanvas3D::Gizmos::update_hover_state(const GLCanvas3D& canvas, const Vec2d& mouse_pos, const GLCanvas3D::Selection& selection)
@@ -2540,24 +2601,39 @@ std::string GLCanvas3D::Gizmos::update_hover_state(const GLCanvas3D& canvas, con
return name;
float cnv_h = (float)canvas.get_canvas_size().get_height();
- float height = _get_total_overlay_height();
+ float height = get_total_overlay_height();
+#if ENABLE_SVG_ICONS
+ float scaled_icons_size = m_overlay_icons_size * m_overlay_scale;
+ float scaled_border = m_overlay_border * m_overlay_scale;
+ float scaled_gap_y = m_overlay_gap_y * m_overlay_scale;
+ float scaled_stride_y = scaled_icons_size + scaled_gap_y;
+ float top_y = 0.5f * (cnv_h - height) + scaled_border;
+#else
float top_y = 0.5f * (cnv_h - height) + m_overlay_border;
-
float scaled_icons_size = (float)m_icons_texture.metadata.icon_size * m_overlay_icons_scale;
+#endif // ENABLE_SVG_ICONS
for (GizmosMap::iterator it = m_gizmos.begin(); it != m_gizmos.end(); ++it)
{
if ((it->second == nullptr) || !it->second->is_selectable())
continue;
+#if ENABLE_SVG_ICONS
+ bool inside = (scaled_border <= (float)mouse_pos(0)) && ((float)mouse_pos(0) <= scaled_border + scaled_icons_size) && (top_y <= (float)mouse_pos(1)) && ((float)mouse_pos(1) <= top_y + scaled_icons_size);
+#else
bool inside = (m_overlay_border <= (float)mouse_pos(0)) && ((float)mouse_pos(0) <= m_overlay_border + scaled_icons_size) && (top_y <= (float)mouse_pos(1)) && ((float)mouse_pos(1) <= top_y + scaled_icons_size);
+#endif // ENABLE_SVG_ICONS
if (inside)
name = it->second->get_name();
if (it->second->is_activable(selection) && (it->second->get_state() != GLGizmoBase::On))
it->second->set_state(inside ? GLGizmoBase::Hover : GLGizmoBase::Off);
+#if ENABLE_SVG_ICONS
+ top_y += scaled_stride_y;
+#else
top_y += (scaled_icons_size + m_overlay_gap_y);
+#endif // ENABLE_SVG_ICONS
}
return name;
@@ -2569,17 +2645,29 @@ void GLCanvas3D::Gizmos::update_on_off_state(const GLCanvas3D& canvas, const Vec
return;
float cnv_h = (float)canvas.get_canvas_size().get_height();
- float height = _get_total_overlay_height();
- float top_y = 0.5f * (cnv_h - height) + m_overlay_border;
+ float height = get_total_overlay_height();
+#if ENABLE_SVG_ICONS
+ float scaled_icons_size = m_overlay_icons_size * m_overlay_scale;
+ float scaled_border = m_overlay_border * m_overlay_scale;
+ float scaled_gap_y = m_overlay_gap_y * m_overlay_scale;
+ float scaled_stride_y = scaled_icons_size + scaled_gap_y;
+ float top_y = 0.5f * (cnv_h - height) + scaled_border;
+#else
+ float top_y = 0.5f * (cnv_h - height) + m_overlay_border;
float scaled_icons_size = (float)m_icons_texture.metadata.icon_size * m_overlay_icons_scale;
+#endif // ENABLE_SVG_ICONS
for (GizmosMap::iterator it = m_gizmos.begin(); it != m_gizmos.end(); ++it)
{
if ((it->second == nullptr) || !it->second->is_selectable())
continue;
+#if ENABLE_SVG_ICONS
+ bool inside = (scaled_border <= (float)mouse_pos(0)) && ((float)mouse_pos(0) <= scaled_border + scaled_icons_size) && (top_y <= (float)mouse_pos(1)) && ((float)mouse_pos(1) <= top_y + scaled_icons_size);
+#else
bool inside = (m_overlay_border <= (float)mouse_pos(0)) && ((float)mouse_pos(0) <= m_overlay_border + scaled_icons_size) && (top_y <= (float)mouse_pos(1)) && ((float)mouse_pos(1) <= top_y + scaled_icons_size);
+#endif // ENABLE_SVG_ICONS
if (it->second->is_activable(selection) && inside)
{
if ((it->second->get_state() == GLGizmoBase::On))
@@ -2596,7 +2684,11 @@ void GLCanvas3D::Gizmos::update_on_off_state(const GLCanvas3D& canvas, const Vec
else
it->second->set_state(GLGizmoBase::Off);
+#if ENABLE_SVG_ICONS
+ top_y += scaled_stride_y;
+#else
top_y += (scaled_icons_size + m_overlay_gap_y);
+#endif // ENABLE_SVG_ICONS
}
GizmosMap::iterator it = m_gizmos.find(m_current);
@@ -2667,20 +2759,36 @@ bool GLCanvas3D::Gizmos::overlay_contains_mouse(const GLCanvas3D& canvas, const
return false;
float cnv_h = (float)canvas.get_canvas_size().get_height();
- float height = _get_total_overlay_height();
- float top_y = 0.5f * (cnv_h - height) + m_overlay_border;
+ float height = get_total_overlay_height();
+#if ENABLE_SVG_ICONS
+ float scaled_icons_size = m_overlay_icons_size * m_overlay_scale;
+ float scaled_border = m_overlay_border * m_overlay_scale;
+ float scaled_gap_y = m_overlay_gap_y * m_overlay_scale;
+ float scaled_stride_y = scaled_icons_size + scaled_gap_y;
+ float top_y = 0.5f * (cnv_h - height) + scaled_border;
+#else
+ float top_y = 0.5f * (cnv_h - height) + m_overlay_border;
float scaled_icons_size = (float)m_icons_texture.metadata.icon_size * m_overlay_icons_scale;
+#endif // ENABLE_SVG_ICONS
for (GizmosMap::const_iterator it = m_gizmos.begin(); it != m_gizmos.end(); ++it)
{
if ((it->second == nullptr) || !it->second->is_selectable())
continue;
+#if ENABLE_SVG_ICONS
+ if ((scaled_border <= (float)mouse_pos(0)) && ((float)mouse_pos(0) <= scaled_border + scaled_icons_size) && (top_y <= (float)mouse_pos(1)) && ((float)mouse_pos(1) <= top_y + scaled_icons_size))
+#else
if ((m_overlay_border <= (float)mouse_pos(0)) && ((float)mouse_pos(0) <= m_overlay_border + scaled_icons_size) && (top_y <= (float)mouse_pos(1)) && ((float)mouse_pos(1) <= top_y + scaled_icons_size))
+#endif // ENABLE_SVG_ICONS
return true;
+#if ENABLE_SVG_ICONS
+ top_y += scaled_stride_y;
+#else
top_y += (scaled_icons_size + m_overlay_gap_y);
+#endif // ENABLE_SVG_ICONS
}
return false;
@@ -2691,7 +2799,7 @@ bool GLCanvas3D::Gizmos::grabber_contains_mouse() const
if (!m_enabled)
return false;
- GLGizmoBase* curr = _get_current();
+ GLGizmoBase* curr = get_current();
return (curr != nullptr) ? (curr->get_hover_id() != -1) : false;
}
@@ -2700,7 +2808,7 @@ void GLCanvas3D::Gizmos::update(const Linef3& mouse_ray, const Selection& select
if (!m_enabled)
return;
- GLGizmoBase* curr = _get_current();
+ GLGizmoBase* curr = get_current();
if (curr != nullptr)
curr->update(GLGizmoBase::UpdateData(mouse_ray, mouse_pos, shift_down), selection);
}
@@ -2715,7 +2823,7 @@ bool GLCanvas3D::Gizmos::is_running() const
if (!m_enabled)
return false;
- GLGizmoBase* curr = _get_current();
+ GLGizmoBase* curr = get_current();
return (curr != nullptr) ? (curr->get_state() == GLGizmoBase::On) : false;
}
@@ -2765,7 +2873,7 @@ bool GLCanvas3D::Gizmos::is_dragging() const
if (!m_enabled)
return false;
- GLGizmoBase* curr = _get_current();
+ GLGizmoBase* curr = get_current();
return (curr != nullptr) ? curr->is_dragging() : false;
}
@@ -2774,7 +2882,7 @@ void GLCanvas3D::Gizmos::start_dragging(const GLCanvas3D::Selection& selection)
if (!m_enabled)
return;
- GLGizmoBase* curr = _get_current();
+ GLGizmoBase* curr = get_current();
if (curr != nullptr)
curr->start_dragging(selection);
}
@@ -2784,7 +2892,7 @@ void GLCanvas3D::Gizmos::stop_dragging()
if (!m_enabled)
return;
- GLGizmoBase* curr = _get_current();
+ GLGizmoBase* curr = get_current();
if (curr != nullptr)
curr->stop_dragging();
}
@@ -2884,7 +2992,7 @@ void GLCanvas3D::Gizmos::render_current_gizmo(const GLCanvas3D::Selection& selec
if (!m_enabled)
return;
- _render_current_gizmo(selection);
+ do_render_current_gizmo(selection);
}
void GLCanvas3D::Gizmos::render_current_gizmo_for_picking_pass(const GLCanvas3D::Selection& selection) const
@@ -2892,7 +3000,7 @@ void GLCanvas3D::Gizmos::render_current_gizmo_for_picking_pass(const GLCanvas3D:
if (!m_enabled)
return;
- GLGizmoBase* curr = _get_current();
+ GLGizmoBase* curr = get_current();
if (curr != nullptr)
curr->render_for_picking(selection);
}
@@ -2902,12 +3010,17 @@ void GLCanvas3D::Gizmos::render_overlay(const GLCanvas3D& canvas, const GLCanvas
if (!m_enabled)
return;
+#if ENABLE_SVG_ICONS
+ if (m_icons_texture_dirty)
+ generate_icons_texture();
+#endif // ENABLE_SVG_ICONS
+
::glDisable(GL_DEPTH_TEST);
::glPushMatrix();
::glLoadIdentity();
- _render_overlay(canvas, selection);
+ do_render_overlay(canvas, selection);
::glPopMatrix();
}
@@ -2921,7 +3034,7 @@ void GLCanvas3D::Gizmos::create_external_gizmo_widgets(wxWindow *parent)
}
#endif // not ENABLE_IMGUI
-void GLCanvas3D::Gizmos::_reset()
+void GLCanvas3D::Gizmos::reset()
{
for (GizmosMap::value_type& gizmo : m_gizmos)
{
@@ -2932,7 +3045,7 @@ void GLCanvas3D::Gizmos::_reset()
m_gizmos.clear();
}
-void GLCanvas3D::Gizmos::_render_overlay(const GLCanvas3D& canvas, const GLCanvas3D::Selection& selection) const
+void GLCanvas3D::Gizmos::do_render_overlay(const GLCanvas3D& canvas, const GLCanvas3D::Selection& selection) const
{
if (m_gizmos.empty())
return;
@@ -2944,15 +3057,19 @@ void GLCanvas3D::Gizmos::_render_overlay(const GLCanvas3D& canvas, const GLCanva
float zoom = canvas.get_camera_zoom();
float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f;
- float height = _get_total_overlay_height();
+ float height = get_total_overlay_height();
+#if ENABLE_SVG_ICONS
+ float scaled_border = m_overlay_border * m_overlay_scale * inv_zoom;
+#else
float scaled_border = m_overlay_border * inv_zoom;
+#endif // ENABLE_SVG_ICONS
float top_x = (-0.5f * cnv_w) * inv_zoom;
float top_y = (0.5f * height) * inv_zoom;
float left = top_x;
float top = top_y;
- float right = left + _get_total_overlay_width() * inv_zoom;
+ float right = left + get_total_overlay_width() * inv_zoom;
float bottom = top - height * inv_zoom;
// renders background
@@ -3021,6 +3138,16 @@ void GLCanvas3D::Gizmos::_render_overlay(const GLCanvas3D& canvas, const GLCanva
}
}
+#if ENABLE_SVG_ICONS
+ top_x += scaled_border;
+ top_y -= scaled_border;
+ float scaled_gap_y = m_overlay_gap_y * m_overlay_scale * inv_zoom;
+
+ float scaled_icons_size = m_overlay_icons_size * m_overlay_scale * inv_zoom;
+ float scaled_stride_y = scaled_icons_size + scaled_gap_y;
+ unsigned int icons_texture_id = m_icons_texture.get_id();
+ unsigned int texture_size = m_icons_texture.get_width();
+#else
top_x += m_overlay_border * inv_zoom;
top_y -= m_overlay_border * inv_zoom;
float scaled_gap_y = m_overlay_gap_y * inv_zoom;
@@ -3028,8 +3155,14 @@ void GLCanvas3D::Gizmos::_render_overlay(const GLCanvas3D& canvas, const GLCanva
float scaled_icons_size = (float)m_icons_texture.metadata.icon_size * m_overlay_icons_scale * inv_zoom;
unsigned int icons_texture_id = m_icons_texture.texture.get_id();
unsigned int texture_size = m_icons_texture.texture.get_width();
+#endif // ENABLE_SVG_ICONS
float inv_texture_size = (texture_size != 0) ? 1.0f / (float)texture_size : 0.0f;
+#if ENABLE_SVG_ICONS
+ if ((icons_texture_id == 0) || (texture_size <= 0))
+ return;
+#endif // ENABLE_SVG_ICONS
+
for (GizmosMap::const_iterator it = m_gizmos.begin(); it != m_gizmos.end(); ++it)
{
if ((it->second == nullptr) || !it->second->is_selectable())
@@ -3038,7 +3171,11 @@ void GLCanvas3D::Gizmos::_render_overlay(const GLCanvas3D& canvas, const GLCanva
unsigned int sprite_id = it->second->get_sprite_id();
GLGizmoBase::EState state = it->second->get_state();
+#if ENABLE_SVG_ICONS
+ float uv_icon_size = m_overlay_icons_size * inv_texture_size;
+#else
float uv_icon_size = (float)m_icons_texture.metadata.icon_size * inv_texture_size;
+#endif // ENABLE_SVG_ICONS
float top = sprite_id * uv_icon_size;
float left = state * uv_icon_size;
float bottom = top + uv_icon_size;
@@ -3047,48 +3184,98 @@ void GLCanvas3D::Gizmos::_render_overlay(const GLCanvas3D& canvas, const GLCanva
GLTexture::render_sub_texture(icons_texture_id, top_x, top_x + scaled_icons_size, top_y - scaled_icons_size, top_y, { { left, bottom }, { right, bottom }, { right, top }, { left, top } });
#if ENABLE_IMGUI
if (it->second->get_state() == GLGizmoBase::On)
+#if ENABLE_SVG_ICONS
+ it->second->render_input_window(2.0f * scaled_border + scaled_icons_size * zoom, 0.5f * cnv_h - top_y * zoom, selection);
+#else
it->second->render_input_window(2.0f * m_overlay_border + scaled_icons_size * zoom, 0.5f * cnv_h - top_y * zoom, selection);
+#endif // ENABLE_SVG_ICONS
#endif // ENABLE_IMGUI
+#if ENABLE_SVG_ICONS
+ top_y -= scaled_stride_y;
+#else
top_y -= (scaled_icons_size + scaled_gap_y);
+#endif // ENABLE_SVG_ICONS
}
}
-void GLCanvas3D::Gizmos::_render_current_gizmo(const GLCanvas3D::Selection& selection) const
+void GLCanvas3D::Gizmos::do_render_current_gizmo(const GLCanvas3D::Selection& selection) const
{
- GLGizmoBase* curr = _get_current();
+ GLGizmoBase* curr = get_current();
if (curr != nullptr)
curr->render(selection);
}
-float GLCanvas3D::Gizmos::_get_total_overlay_height() const
+float GLCanvas3D::Gizmos::get_total_overlay_height() const
{
+#if ENABLE_SVG_ICONS
+ float scaled_icons_size = m_overlay_icons_size * m_overlay_scale;
+ float scaled_border = m_overlay_border * m_overlay_scale;
+ float scaled_gap_y = m_overlay_gap_y * m_overlay_scale;
+ float scaled_stride_y = scaled_icons_size + scaled_gap_y;
+ float height = 2.0f * scaled_border;
+#else
float height = 2.0f * m_overlay_border;
float scaled_icons_size = (float)m_icons_texture.metadata.icon_size * m_overlay_icons_scale;
+#endif // ENABLE_SVG_ICONS
for (GizmosMap::const_iterator it = m_gizmos.begin(); it != m_gizmos.end(); ++it)
{
if ((it->second == nullptr) || !it->second->is_selectable())
continue;
+#if ENABLE_SVG_ICONS
+ height += scaled_stride_y;
+#else
height += (scaled_icons_size + m_overlay_gap_y);
+#endif // ENABLE_SVG_ICONS
}
+#if ENABLE_SVG_ICONS
+ return height - scaled_gap_y;
+#else
return height - m_overlay_gap_y;
+#endif // ENABLE_SVG_ICONS
}
-float GLCanvas3D::Gizmos::_get_total_overlay_width() const
+float GLCanvas3D::Gizmos::get_total_overlay_width() const
{
- float max_icon_width = std::max(max_icon_width, (float)m_icons_texture.metadata.icon_size * m_overlay_icons_scale);
- return max_icon_width + 2.0f * m_overlay_border;
+#if ENABLE_SVG_ICONS
+ return (2.0f * m_overlay_border + m_overlay_icons_size) * m_overlay_scale;
+#else
+ return (float)m_icons_texture.metadata.icon_size * m_overlay_icons_scale + 2.0f * m_overlay_border;
+#endif // ENABLE_SVG_ICONS
}
-GLGizmoBase* GLCanvas3D::Gizmos::_get_current() const
+GLGizmoBase* GLCanvas3D::Gizmos::get_current() const
{
GizmosMap::const_iterator it = m_gizmos.find(m_current);
return (it != m_gizmos.end()) ? it->second : nullptr;
}
+#if ENABLE_SVG_ICONS
+bool GLCanvas3D::Gizmos::generate_icons_texture() const
+{
+ std::string path = resources_dir() + "/icons/";
+ std::vector filenames;
+ for (GizmosMap::const_iterator it = m_gizmos.begin(); it != m_gizmos.end(); ++it)
+ {
+ if (it->second != nullptr)
+ {
+ const std::string& svg_file = it->second->get_svg_file();
+ if (!svg_file.empty())
+ filenames.push_back(path + svg_file);
+ }
+ }
+
+ bool res = m_icons_texture.load_from_svg_files_as_sprites_array(filenames, GLGizmoBase::Num_States, (unsigned int)(m_overlay_icons_size * m_overlay_scale));
+ if (res)
+ m_icons_texture_dirty = false;
+
+ return res;
+}
+#endif // ENABLE_SVG_ICONS
+
const unsigned char GLCanvas3D::WarningTexture::Background_Color[3] = { 9, 91, 134 };
const unsigned char GLCanvas3D::WarningTexture::Opacity = 255;
@@ -3197,7 +3384,7 @@ bool GLCanvas3D::WarningTexture::_generate(const std::string& msg, const GLCanva
::glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)m_width, (GLsizei)m_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, (const void*)data.data());
::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
- ::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 1);
+ ::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
::glBindTexture(GL_TEXTURE_2D, 0);
return true;
@@ -3450,7 +3637,7 @@ bool GLCanvas3D::LegendTexture::generate(const GCodePreviewData& preview_data, c
::glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)m_width, (GLsizei)m_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, (const void*)data.data());
::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
- ::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 1);
+ ::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
::glBindTexture(GL_TEXTURE_2D, 0);
return true;
@@ -4054,7 +4241,9 @@ void GLCanvas3D::render()
_render_gizmos_overlay();
_render_warning_texture();
_render_legend_texture();
+#if !ENABLE_SVG_ICONS
_resize_toolbars();
+#endif // !ENABLE_SVG_ICONS
_render_toolbar();
_render_view_toolbar();
if (m_layers_editing.last_object_id >= 0)
@@ -4647,7 +4836,19 @@ void GLCanvas3D::on_char(wxKeyEvent& evt)
switch (keyCode)
{
// key ESC
- case WXK_ESCAPE: { m_gizmos.reset_all_states(); m_dirty = true; break; }
+ case WXK_ESCAPE: {
+ if (m_gizmos.get_current_type() != Gizmos::SlaSupports || !m_gizmos.mouse_event(SLAGizmoEventType::DiscardChanges))
+ m_gizmos.reset_all_states();
+ m_dirty = true;
+ break;
+ }
+
+ case WXK_RETURN: {
+ if (m_gizmos.get_current_type() == Gizmos::SlaSupports && m_gizmos.mouse_event(SLAGizmoEventType::ApplyChanges))
+ m_dirty = true;
+ break;
+ }
+
#ifdef __APPLE__
case WXK_BACK: // the low cost Apple solutions are not equipped with a Delete key, use Backspace instead.
#else /* __APPLE__ */
@@ -4670,11 +4871,25 @@ void GLCanvas3D::on_char(wxKeyEvent& evt)
case '-': { post_event(Event(EVT_GLCANVAS_INCREASE_INSTANCES, -1)); break; }
case '?': { post_event(SimpleEvent(EVT_GLCANVAS_QUESTION_MARK)); break; }
case 'A':
- case 'a': { post_event(SimpleEvent(EVT_GLCANVAS_ARRANGE)); break; }
+ case 'a': {
+ if (m_gizmos.get_current_type() == Gizmos::SlaSupports) {
+ if (m_gizmos.mouse_event(SLAGizmoEventType::AutomaticGeneration))
+ m_dirty = true;
+ }
+ else
+ post_event(SimpleEvent(EVT_GLCANVAS_ARRANGE));
+ break;
+ }
case 'B':
case 'b': { zoom_to_bed(); break; }
case 'I':
case 'i': { set_camera_zoom(1.0f); break; }
+ case 'M':
+ case 'm': {
+ if (m_gizmos.get_current_type() == Gizmos::SlaSupports && m_gizmos.mouse_event(SLAGizmoEventType::ManualEditing))
+ m_dirty = true;
+ break;
+ }
case 'O':
case 'o': { set_camera_zoom(-1.0f); break; }
case 'Z':
@@ -4769,6 +4984,54 @@ void GLCanvas3D::on_timer(wxTimerEvent& evt)
_perform_layer_editing_action();
}
+#ifndef NDEBUG
+// #define SLIC3R_DEBUG_MOUSE_EVENTS
+#endif
+
+#ifdef SLIC3R_DEBUG_MOUSE_EVENTS
+std::string format_mouse_event_debug_message(const wxMouseEvent &evt)
+{
+ static int idx = 0;
+ char buf[2048];
+ std::string out;
+ sprintf(buf, "Mouse Event %d - ", idx ++);
+ out = buf;
+
+ if (evt.Entering())
+ out += "Entering ";
+ if (evt.Leaving())
+ out += "Leaving ";
+ if (evt.Dragging())
+ out += "Dragging ";
+ if (evt.Moving())
+ out += "Moving ";
+ if (evt.Magnify())
+ out += "Magnify ";
+ if (evt.LeftDown())
+ out += "LeftDown ";
+ if (evt.LeftUp())
+ out += "LeftUp ";
+ if (evt.LeftDClick())
+ out += "LeftDClick ";
+ if (evt.MiddleDown())
+ out += "MiddleDown ";
+ if (evt.MiddleUp())
+ out += "MiddleUp ";
+ if (evt.MiddleDClick())
+ out += "MiddleDClick ";
+ if (evt.RightDown())
+ out += "RightDown ";
+ if (evt.RightUp())
+ out += "RightUp ";
+ if (evt.RightDClick())
+ out += "RightDClick ";
+
+ sprintf(buf, "(%d, %d)", evt.GetX(), evt.GetY());
+ out += buf;
+ return out;
+}
+#endif /* SLIC3R_DEBUG_MOUSE_EVENTS */
+
void GLCanvas3D::on_mouse(wxMouseEvent& evt)
{
#if ENABLE_RETINA_GL
@@ -4784,15 +5047,27 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
if (imgui->update_mouse_data(evt)) {
m_mouse.position = evt.Leaving() ? Vec2d(-1.0, -1.0) : pos.cast();
render();
- return;
+#ifdef SLIC3R_DEBUG_MOUSE_EVENTS
+ printf((format_mouse_event_debug_message(evt) + " - Consumed by ImGUI\n").c_str());
+#endif /* SLIC3R_DEBUG_MOUSE_EVENTS */
+ return;
}
#endif // ENABLE_IMGUI
+ bool on_enter_workaround = false;
if (! evt.Entering() && ! evt.Leaving() && m_mouse.position.x() == -1.0) {
// Workaround for SPE-832: There seems to be a mouse event sent to the window before evt.Entering()
m_mouse.position = pos.cast();
render();
- }
+#ifdef SLIC3R_DEBUG_MOUSE_EVENTS
+ printf((format_mouse_event_debug_message(evt) + " - OnEnter workaround\n").c_str());
+#endif /* SLIC3R_DEBUG_MOUSE_EVENTS */
+ on_enter_workaround = true;
+ } else {
+#ifdef SLIC3R_DEBUG_MOUSE_EVENTS
+ printf((format_mouse_event_debug_message(evt) + " - other\n").c_str());
+#endif /* SLIC3R_DEBUG_MOUSE_EVENTS */
+ }
if (m_picking_enabled)
_set_current();
@@ -5240,6 +5515,9 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
}
else
evt.Skip();
+
+ if (on_enter_workaround)
+ m_mouse.position = Vec2d(-1., -1.);
}
void GLCanvas3D::on_paint(wxPaintEvent& evt)
@@ -5588,14 +5866,11 @@ bool GLCanvas3D::_init_toolbar()
if (!m_toolbar.is_enabled())
return true;
+#if !ENABLE_SVG_ICONS
ItemsIconsTexture::Metadata icons_data;
icons_data.filename = "toolbar.png";
icons_data.icon_size = 37;
-
-// icons_data.filename = "toolbar141.png";
-// icons_data.icon_size = 52;
-// icons_data.icon_border_size = 0;
-// icons_data.icon_gap_size = 0;
+#endif // !ENABLE_SVG_ICONS
BackgroundTexture::Metadata background_data;
background_data.filename = "toolbar_background.png";
@@ -5604,7 +5879,11 @@ bool GLCanvas3D::_init_toolbar()
background_data.right = 16;
background_data.bottom = 16;
+#if ENABLE_SVG_ICONS
+ if (!m_toolbar.init(background_data))
+#else
if (!m_toolbar.init(icons_data, background_data))
+#endif // ENABLE_SVG_ICONS
{
// unable to init the toolbar texture, disable it
m_toolbar.set_enabled(false);
@@ -5621,6 +5900,9 @@ bool GLCanvas3D::_init_toolbar()
GLToolbarItem::Data item;
item.name = "add";
+#if ENABLE_SVG_ICONS
+ item.svg_file = "add.svg";
+#endif // ENABLE_SVG_ICONS
item.tooltip = GUI::L_str("Add...") + " [" + GUI::shortkey_ctrl_prefix() + "I]";
item.sprite_id = 0;
item.action_event = EVT_GLTOOLBAR_ADD;
@@ -5628,6 +5910,9 @@ bool GLCanvas3D::_init_toolbar()
return false;
item.name = "delete";
+#if ENABLE_SVG_ICONS
+ item.svg_file = "remove.svg";
+#endif // ENABLE_SVG_ICONS
item.tooltip = GUI::L_str("Delete") + " [Del]";
item.sprite_id = 1;
item.action_event = EVT_GLTOOLBAR_DELETE;
@@ -5635,6 +5920,9 @@ bool GLCanvas3D::_init_toolbar()
return false;
item.name = "deleteall";
+#if ENABLE_SVG_ICONS
+ item.svg_file = "delete_all.svg";
+#endif // ENABLE_SVG_ICONS
item.tooltip = GUI::L_str("Delete all") + " [" + GUI::shortkey_ctrl_prefix() + "Del]";
item.sprite_id = 2;
item.action_event = EVT_GLTOOLBAR_DELETE_ALL;
@@ -5642,6 +5930,9 @@ bool GLCanvas3D::_init_toolbar()
return false;
item.name = "arrange";
+#if ENABLE_SVG_ICONS
+ item.svg_file = "arrange.svg";
+#endif // ENABLE_SVG_ICONS
item.tooltip = GUI::L_str("Arrange [A]");
item.sprite_id = 3;
item.action_event = EVT_GLTOOLBAR_ARRANGE;
@@ -5652,6 +5943,9 @@ bool GLCanvas3D::_init_toolbar()
return false;
item.name = "more";
+#if ENABLE_SVG_ICONS
+ item.svg_file = "instance_add.svg";
+#endif // ENABLE_SVG_ICONS
item.tooltip = GUI::L_str("Add instance [+]");
item.sprite_id = 4;
item.action_event = EVT_GLTOOLBAR_MORE;
@@ -5659,6 +5953,9 @@ bool GLCanvas3D::_init_toolbar()
return false;
item.name = "fewer";
+#if ENABLE_SVG_ICONS
+ item.svg_file = "instance_remove.svg";
+#endif // ENABLE_SVG_ICONS
item.tooltip = GUI::L_str("Remove instance [-]");
item.sprite_id = 5;
item.action_event = EVT_GLTOOLBAR_FEWER;
@@ -5669,6 +5966,9 @@ bool GLCanvas3D::_init_toolbar()
return false;
item.name = "splitobjects";
+#if ENABLE_SVG_ICONS
+ item.svg_file = "split_objects.svg";
+#endif // ENABLE_SVG_ICONS
item.tooltip = GUI::L_str("Split to objects");
item.sprite_id = 6;
item.action_event = EVT_GLTOOLBAR_SPLIT_OBJECTS;
@@ -5676,6 +5976,9 @@ bool GLCanvas3D::_init_toolbar()
return false;
item.name = "splitvolumes";
+#if ENABLE_SVG_ICONS
+ item.svg_file = "split_parts.svg";
+#endif // ENABLE_SVG_ICONS
item.tooltip = GUI::L_str("Split to parts");
item.sprite_id = 8;
item.action_event = EVT_GLTOOLBAR_SPLIT_VOLUMES;
@@ -5686,6 +5989,9 @@ bool GLCanvas3D::_init_toolbar()
return false;
item.name = "layersediting";
+#if ENABLE_SVG_ICONS
+ item.svg_file = "layers.svg";
+#endif // ENABLE_SVG_ICONS
item.tooltip = GUI::L_str("Layers editing");
item.sprite_id = 7;
item.is_toggable = true;
@@ -6177,11 +6483,63 @@ void GLCanvas3D::_render_gizmos_overlay() const
void GLCanvas3D::_render_toolbar() const
{
+#if ENABLE_SVG_ICONS
+#if ENABLE_RETINA_GL
+ m_toolbar.set_scale(m_retina_helper->get_scale_factor());
+#else
+ m_toolbar.set_scale(m_canvas->GetContentScaleFactor());
+#endif // ENABLE_RETINA_GL
+
+ Size cnv_size = get_canvas_size();
+ float zoom = get_camera_zoom();
+ float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f;
+
+ GLToolbar::Layout::EOrientation orientation = m_toolbar.get_layout_orientation();
+
+ float top = 0.0f;
+ float left = 0.0f;
+ switch (m_toolbar.get_layout_type())
+ {
+ default:
+ case GLToolbar::Layout::Horizontal:
+ {
+ // centers the toolbar on the top edge of the 3d scene
+ if (orientation == GLToolbar::Layout::Top)
+ {
+ top = 0.5f * (float)cnv_size.get_height() * inv_zoom;
+ left = -0.5f * m_toolbar.get_width() * inv_zoom;
+ }
+ else
+ {
+ top = (-0.5f * (float)cnv_size.get_height() + m_view_toolbar->get_height()) * inv_zoom;
+ left = -0.5f * m_toolbar.get_width() * inv_zoom;
+ }
+ break;
+ }
+ case GLToolbar::Layout::Vertical:
+ {
+ // centers the toolbar on the right edge of the 3d scene
+ if (orientation == GLToolbar::Layout::Left)
+ {
+ top = 0.5f * m_toolbar.get_height() * inv_zoom;
+ left = (-0.5f * (float)cnv_size.get_width()) * inv_zoom;
+ }
+ else
+ {
+ top = 0.5f * m_toolbar.get_height() * inv_zoom;
+ left = (0.5f * (float)cnv_size.get_width() - m_toolbar.get_width()) * inv_zoom;
+ }
+ break;
+ }
+ }
+ m_toolbar.set_position(top, left);
+#else
#if ENABLE_RETINA_GL
m_toolbar.set_icons_scale(m_retina_helper->get_scale_factor());
#else
m_toolbar.set_icons_scale(m_canvas->GetContentScaleFactor());
#endif /* __WXMSW__ */
+#endif // ENABLE_SVG_ICONS
m_toolbar.render(*this);
}
@@ -6189,11 +6547,28 @@ void GLCanvas3D::_render_toolbar() const
void GLCanvas3D::_render_view_toolbar() const
{
if (m_view_toolbar != nullptr) {
+#if ENABLE_SVG_ICONS
+#if ENABLE_RETINA_GL
+ m_view_toolbar->set_scale(m_retina_helper->get_scale_factor());
+#else
+ m_view_toolbar->set_scale(m_canvas->GetContentScaleFactor());
+#endif // ENABLE_RETINA_GL
+
+ Size cnv_size = get_canvas_size();
+ float zoom = get_camera_zoom();
+ float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f;
+
+ // places the toolbar on the bottom-left corner of the 3d scene
+ float top = (-0.5f * (float)cnv_size.get_height() + m_view_toolbar->get_height()) * inv_zoom;
+ float left = -0.5f * (float)cnv_size.get_width() * inv_zoom;
+ m_view_toolbar->set_position(top, left);
+#else
#if ENABLE_RETINA_GL
m_view_toolbar->set_icons_scale(m_retina_helper->get_scale_factor());
#else
m_view_toolbar->set_icons_scale(m_canvas->GetContentScaleFactor());
#endif /* __WXMSW__ */
+#endif // ENABLE_SVG_ICONS
m_view_toolbar->render(*this);
}
}
@@ -7682,6 +8057,7 @@ bool GLCanvas3D::_is_any_volume_outside() const
return false;
}
+#if !ENABLE_SVG_ICONS
void GLCanvas3D::_resize_toolbars() const
{
Size cnv_size = get_canvas_size();
@@ -7749,6 +8125,7 @@ void GLCanvas3D::_resize_toolbars() const
m_view_toolbar->set_position(top, left);
}
}
+#endif // !ENABLE_SVG_ICONS
const Print* GLCanvas3D::fff_print() const
{
diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp
index d322f5e30..096789d4a 100644
--- a/src/slic3r/GUI/GLCanvas3D.hpp
+++ b/src/slic3r/GUI/GLCanvas3D.hpp
@@ -125,7 +125,11 @@ enum class SLAGizmoEventType {
Dragging,
Delete,
SelectAll,
- ShiftUp
+ ShiftUp,
+ ApplyChanges,
+ DiscardChanges,
+ AutomaticGeneration,
+ ManualEditing
};
@@ -631,6 +635,10 @@ private:
class Gizmos
{
public:
+#if ENABLE_SVG_ICONS
+ static const float Default_Icons_Size;
+#endif // ENABLE_SVG_ICONS
+
enum EType : unsigned char
{
Undefined,
@@ -647,11 +655,21 @@ private:
bool m_enabled;
typedef std::map GizmosMap;
GizmosMap m_gizmos;
+#if ENABLE_SVG_ICONS
+ mutable GLTexture m_icons_texture;
+ mutable bool m_icons_texture_dirty;
+#else
ItemsIconsTexture m_icons_texture;
+#endif // ENABLE_SVG_ICONS
BackgroundTexture m_background_texture;
EType m_current;
+#if ENABLE_SVG_ICONS
+ float m_overlay_icons_size;
+ float m_overlay_scale;
+#else
float m_overlay_icons_scale;
+#endif // ENABLE_SVG_ICONS
float m_overlay_border;
float m_overlay_gap_y;
@@ -664,6 +682,9 @@ private:
bool is_enabled() const;
void set_enabled(bool enable);
+#if ENABLE_SVG_ICONS
+ void set_overlay_icon_size(float size);
+#endif // ENABLE_SVG_ICONS
void set_overlay_scale(float scale);
std::string update_hover_state(const GLCanvas3D& canvas, const Vec2d& mouse_pos, const Selection& selection);
@@ -713,15 +734,19 @@ private:
#endif // not ENABLE_IMGUI
private:
- void _reset();
+ void reset();
- void _render_overlay(const GLCanvas3D& canvas, const Selection& selection) const;
- void _render_current_gizmo(const Selection& selection) const;
+ void do_render_overlay(const GLCanvas3D& canvas, const Selection& selection) const;
+ void do_render_current_gizmo(const Selection& selection) const;
- float _get_total_overlay_height() const;
- float _get_total_overlay_width() const;
+ float get_total_overlay_height() const;
+ float get_total_overlay_width() const;
- GLGizmoBase* _get_current() const;
+ GLGizmoBase* get_current() const;
+
+#if ENABLE_SVG_ICONS
+ bool generate_icons_texture() const;
+#endif // ENABLE_SVG_ICONS
};
struct SlaCap
@@ -1092,7 +1117,9 @@ private:
bool _is_any_volume_outside() const;
+#if !ENABLE_SVG_ICONS
void _resize_toolbars() const;
+#endif // !ENABLE_SVG_ICONS
static std::vector _parse_colors(const std::vector& colors);
diff --git a/src/slic3r/GUI/GLGizmo.cpp b/src/slic3r/GUI/GLGizmo.cpp
index fa5ff37f8..b7573410b 100644
--- a/src/slic3r/GUI/GLGizmo.cpp
+++ b/src/slic3r/GUI/GLGizmo.cpp
@@ -157,11 +157,18 @@ void GLGizmoBase::Grabber::render_face(float half_size) const
::glEnd();
}
+#if ENABLE_SVG_ICONS
+GLGizmoBase::GLGizmoBase(GLCanvas3D& parent, const std::string& svg_file, unsigned int sprite_id)
+#else
GLGizmoBase::GLGizmoBase(GLCanvas3D& parent, unsigned int sprite_id)
+#endif // ENABLE_SVG_ICONS
: m_parent(parent)
, m_group_id(-1)
, m_state(Off)
, m_shortcut_key(0)
+#if ENABLE_SVG_ICONS
+ , m_svg_file(svg_file)
+#endif // ENABLE_SVG_ICONS
, m_sprite_id(sprite_id)
, m_hover_id(-1)
, m_dragging(false)
@@ -305,7 +312,11 @@ const unsigned int GLGizmoRotate::SnapRegionsCount = 8;
const float GLGizmoRotate::GrabberOffset = 0.15f; // in percent of radius
GLGizmoRotate::GLGizmoRotate(GLCanvas3D& parent, GLGizmoRotate::Axis axis)
+#if ENABLE_SVG_ICONS
+ : GLGizmoBase(parent, "", -1)
+#else
: GLGizmoBase(parent, -1)
+#endif // ENABLE_SVG_ICONS
, m_axis(axis)
, m_angle(0.0)
, m_quadric(nullptr)
@@ -322,7 +333,11 @@ GLGizmoRotate::GLGizmoRotate(GLCanvas3D& parent, GLGizmoRotate::Axis axis)
}
GLGizmoRotate::GLGizmoRotate(const GLGizmoRotate& other)
+#if ENABLE_SVG_ICONS
+ : GLGizmoBase(other.m_parent, other.m_svg_file, other.m_sprite_id)
+#else
: GLGizmoBase(other.m_parent, other.m_sprite_id)
+#endif // ENABLE_SVG_ICONS
, m_axis(other.m_axis)
, m_angle(other.m_angle)
, m_quadric(nullptr)
@@ -694,8 +709,13 @@ Vec3d GLGizmoRotate::mouse_position_in_local_plane(const Linef3& mouse_ray, cons
return transform(mouse_ray, m).intersect_plane(0.0);
}
+#if ENABLE_SVG_ICONS
+GLGizmoRotate3D::GLGizmoRotate3D(GLCanvas3D& parent, const std::string& svg_file, unsigned int sprite_id)
+ : GLGizmoBase(parent, svg_file, sprite_id)
+#else
GLGizmoRotate3D::GLGizmoRotate3D(GLCanvas3D& parent, unsigned int sprite_id)
: GLGizmoBase(parent, sprite_id)
+#endif // ENABLE_SVG_ICONS
{
m_gizmos.emplace_back(parent, GLGizmoRotate::X);
m_gizmos.emplace_back(parent, GLGizmoRotate::Y);
@@ -774,8 +794,13 @@ void GLGizmoRotate3D::on_render_input_window(float x, float y, const GLCanvas3D:
const float GLGizmoScale3D::Offset = 5.0f;
+#if ENABLE_SVG_ICONS
+GLGizmoScale3D::GLGizmoScale3D(GLCanvas3D& parent, const std::string& svg_file, unsigned int sprite_id)
+ : GLGizmoBase(parent, svg_file, sprite_id)
+#else
GLGizmoScale3D::GLGizmoScale3D(GLCanvas3D& parent, unsigned int sprite_id)
: GLGizmoBase(parent, sprite_id)
+#endif // ENABLE_SVG_ICONS
, m_scale(Vec3d::Ones())
, m_snap_step(0.05)
, m_starting_scale(Vec3d::Ones())
@@ -1120,8 +1145,13 @@ double GLGizmoScale3D::calc_ratio(const UpdateData& data) const
const double GLGizmoMove3D::Offset = 10.0;
+#if ENABLE_SVG_ICONS
+GLGizmoMove3D::GLGizmoMove3D(GLCanvas3D& parent, const std::string& svg_file, unsigned int sprite_id)
+ : GLGizmoBase(parent, svg_file, sprite_id)
+#else
GLGizmoMove3D::GLGizmoMove3D(GLCanvas3D& parent, unsigned int sprite_id)
: GLGizmoBase(parent, sprite_id)
+#endif // ENABLE_SVG_ICONS
, m_displacement(Vec3d::Zero())
, m_snap_step(1.0)
, m_starting_drag_position(Vec3d::Zero())
@@ -1357,8 +1387,13 @@ void GLGizmoMove3D::render_grabber_extension(Axis axis, const BoundingBoxf3& box
::glDisable(GL_LIGHTING);
}
+#if ENABLE_SVG_ICONS
+GLGizmoFlatten::GLGizmoFlatten(GLCanvas3D& parent, const std::string& svg_file, unsigned int sprite_id)
+ : GLGizmoBase(parent, svg_file, sprite_id)
+#else
GLGizmoFlatten::GLGizmoFlatten(GLCanvas3D& parent, unsigned int sprite_id)
: GLGizmoBase(parent, sprite_id)
+#endif // ENABLE_SVG_ICONS
, m_normal(Vec3d::Zero())
, m_starting_center(Vec3d::Zero())
{
@@ -1696,8 +1731,13 @@ Vec3d GLGizmoFlatten::get_flattening_normal() const
return out;
}
+#if ENABLE_SVG_ICONS
+GLGizmoSlaSupports::GLGizmoSlaSupports(GLCanvas3D& parent, const std::string& svg_file, unsigned int sprite_id)
+ : GLGizmoBase(parent, svg_file, sprite_id)
+#else
GLGizmoSlaSupports::GLGizmoSlaSupports(GLCanvas3D& parent, unsigned int sprite_id)
: GLGizmoBase(parent, sprite_id)
+#endif // ENABLE_SVG_ICONS
, m_starting_center(Vec3d::Zero()), m_quadric(nullptr)
{
m_quadric = ::gluNewQuadric();
@@ -1886,12 +1926,6 @@ bool GLGizmoSlaSupports::is_mesh_update_necessary() const
//if (m_state != On || !m_model_object || m_model_object->instances.empty() || ! m_instance_matrix.isApprox(m_source_data.matrix))
// return false;
-
- // following should detect direct mesh changes (can be removed after the mesh is made completely immutable):
- /*const float* first_vertex = m_model_object->volumes.front()->get_convex_hull().first_vertex();
- Vec3d first_point((double)first_vertex[0], (double)first_vertex[1], (double)first_vertex[2]);
- if (first_point != m_source_data.mesh_first_point)
- return true;*/
}
void GLGizmoSlaSupports::update_mesh()
@@ -1967,139 +2001,161 @@ Vec3f GLGizmoSlaSupports::unproject_on_mesh(const Vec2d& mouse_pos)
// concludes that the event was not intended for it, it should return false.
bool GLGizmoSlaSupports::mouse_event(SLAGizmoEventType action, const Vec2d& mouse_position, bool shift_down)
{
- if (!m_editing_mode)
- return false;
+ if (m_editing_mode) {
- // left down - show the selection rectangle:
- if (action == SLAGizmoEventType::LeftDown && shift_down) {
- if (m_hover_id == -1) {
- m_selection_rectangle_active = true;
- m_selection_rectangle_start_corner = mouse_position;
+ // left down - show the selection rectangle:
+ if (action == SLAGizmoEventType::LeftDown && shift_down) {
+ if (m_hover_id == -1) {
+ m_selection_rectangle_active = true;
+ m_selection_rectangle_start_corner = mouse_position;
+ m_selection_rectangle_end_corner = mouse_position;
+ m_canvas_width = m_parent.get_canvas_size().get_width();
+ m_canvas_height = m_parent.get_canvas_size().get_height();
+ }
+ else
+ select_point(m_hover_id);
+
+ return true;
+ }
+
+ // dragging the selection rectangle:
+ if (action == SLAGizmoEventType::Dragging && m_selection_rectangle_active) {
m_selection_rectangle_end_corner = mouse_position;
- m_canvas_width = m_parent.get_canvas_size().get_width();
- m_canvas_height = m_parent.get_canvas_size().get_height();
- }
- else
- select_point(m_hover_id);
-
- return true;
- }
-
- // dragging the selection rectangle:
- if (action == SLAGizmoEventType::Dragging && m_selection_rectangle_active) {
- m_selection_rectangle_end_corner = mouse_position;
- return true;
- }
-
- // mouse up without selection rectangle - place point on the mesh:
- if (action == SLAGizmoEventType::LeftUp && !m_selection_rectangle_active && !shift_down) {
- if (m_ignore_up_event) {
- m_ignore_up_event = false;
- return false;
+ return true;
}
- int instance_id = m_parent.get_selection().get_instance_idx();
- if (m_old_instance_id != instance_id)
- {
- bool something_selected = (m_old_instance_id != -1);
- m_old_instance_id = instance_id;
- if (something_selected)
+ // mouse up without selection rectangle - place point on the mesh:
+ if (action == SLAGizmoEventType::LeftUp && !m_selection_rectangle_active && !shift_down) {
+ if (m_ignore_up_event) {
+ m_ignore_up_event = false;
return false;
- }
- if (instance_id == -1)
- return false;
-
- // If there is some selection, don't add new point and deselect everything instead.
- if (m_selection_empty) {
- Vec3f new_pos;
- try {
- new_pos = unproject_on_mesh(mouse_position); // this can throw - we don't want to create a new point in that case
- m_editing_mode_cache.emplace_back(std::make_pair(sla::SupportPoint(new_pos, m_new_point_head_diameter/2.f, false), false));
- m_unsaved_changes = true;
}
- catch (...) { // not clicked on object
- return true; // prevents deselection of the gizmo by GLCanvas3D
+
+ int instance_id = m_parent.get_selection().get_instance_idx();
+ if (m_old_instance_id != instance_id)
+ {
+ bool something_selected = (m_old_instance_id != -1);
+ m_old_instance_id = instance_id;
+ if (something_selected)
+ return false;
}
- }
- else
- select_point(NoPoints);
+ if (instance_id == -1)
+ return false;
- return true;
- }
-
- // left up with selection rectangle - select points inside the rectangle:
- if ((action == SLAGizmoEventType::LeftUp || action == SLAGizmoEventType::ShiftUp)
- && m_selection_rectangle_active) {
- if (action == SLAGizmoEventType::ShiftUp)
- m_ignore_up_event = true;
- const Transform3d& instance_matrix = m_model_object->instances[m_active_instance]->get_transformation().get_matrix();
- GLint viewport[4];
- ::glGetIntegerv(GL_VIEWPORT, viewport);
- GLdouble modelview_matrix[16];
- ::glGetDoublev(GL_MODELVIEW_MATRIX, modelview_matrix);
- GLdouble projection_matrix[16];
- ::glGetDoublev(GL_PROJECTION_MATRIX, projection_matrix);
-
- const GLCanvas3D::Selection& selection = m_parent.get_selection();
- const GLVolume* volume = selection.get_volume(*selection.get_volume_idxs().begin());
- double z_offset = volume->get_sla_shift_z();
-
- // bounding box created from the rectangle corners - will take care of order of the corners
- BoundingBox rectangle(Points{Point(m_selection_rectangle_start_corner.cast()), Point(m_selection_rectangle_end_corner.cast())});
-
- const Transform3d& instance_matrix_no_translation = volume->get_instance_transformation().get_matrix(true);
- // we'll recover current look direction from the modelview matrix (in world coords)...
- Vec3f direction_to_camera(modelview_matrix[2], modelview_matrix[6], modelview_matrix[10]);
- // ...and transform it to model coords.
- direction_to_camera = (instance_matrix_no_translation.inverse().cast() * direction_to_camera).normalized().eval();
-
- // Iterate over all points, check if they're in the rectangle and if so, check that they are not obscured by the mesh:
- for (unsigned int i=0; i() * support_point.pos;
- pos(2) += z_offset;
- GLdouble out_x, out_y, out_z;
- ::gluProject((GLdouble)pos(0), (GLdouble)pos(1), (GLdouble)pos(2), modelview_matrix, projection_matrix, viewport, &out_x, &out_y, &out_z);
- out_y = m_canvas_height - out_y;
-
- if (rectangle.contains(Point(out_x, out_y))) {
- bool is_obscured = false;
- // Cast a ray in the direction of the camera and look for intersection with the mesh:
- std::vector hits;
- // Offset the start of the ray to the front of the ball + EPSILON to account for numerical inaccuracies.
- if (m_AABB.intersect_ray(m_V, m_F, support_point.pos + direction_to_camera * (support_point.head_front_radius + EPSILON), direction_to_camera, hits))
- // FIXME: the intersection could in theory be behind the camera, but as of now we only have camera direction.
- // Also, the threshold is in mesh coordinates, not in actual dimensions.
- if (hits.size() > 1 || hits.front().t > 0.001f)
- is_obscured = true;
-
- if (!is_obscured)
- select_point(i);
+ // If there is some selection, don't add new point and deselect everything instead.
+ if (m_selection_empty) {
+ Vec3f new_pos;
+ try {
+ new_pos = unproject_on_mesh(mouse_position); // this can throw - we don't want to create a new point in that case
+ m_editing_mode_cache.emplace_back(std::make_pair(sla::SupportPoint(new_pos, m_new_point_head_diameter/2.f, false), false));
+ m_unsaved_changes = true;
+ }
+ catch (...) { // not clicked on object
+ return true; // prevents deselection of the gizmo by GLCanvas3D
+ }
}
+ else
+ select_point(NoPoints);
+
+ return true;
}
- m_selection_rectangle_active = false;
- return true;
- }
- if (action == SLAGizmoEventType::Delete) {
- // delete key pressed
- delete_selected_points();
- return true;
- }
+ // left up with selection rectangle - select points inside the rectangle:
+ if ((action == SLAGizmoEventType::LeftUp || action == SLAGizmoEventType::ShiftUp)
+ && m_selection_rectangle_active) {
+ if (action == SLAGizmoEventType::ShiftUp)
+ m_ignore_up_event = true;
+ const Transform3d& instance_matrix = m_model_object->instances[m_active_instance]->get_transformation().get_matrix();
+ GLint viewport[4];
+ ::glGetIntegerv(GL_VIEWPORT, viewport);
+ GLdouble modelview_matrix[16];
+ ::glGetDoublev(GL_MODELVIEW_MATRIX, modelview_matrix);
+ GLdouble projection_matrix[16];
+ ::glGetDoublev(GL_PROJECTION_MATRIX, projection_matrix);
- if (action == SLAGizmoEventType::RightDown) {
- if (m_hover_id != -1) {
- select_point(NoPoints);
- select_point(m_hover_id);
+ const GLCanvas3D::Selection& selection = m_parent.get_selection();
+ const GLVolume* volume = selection.get_volume(*selection.get_volume_idxs().begin());
+ double z_offset = volume->get_sla_shift_z();
+
+ // bounding box created from the rectangle corners - will take care of order of the corners
+ BoundingBox rectangle(Points{Point(m_selection_rectangle_start_corner.cast()), Point(m_selection_rectangle_end_corner.cast())});
+
+ const Transform3d& instance_matrix_no_translation = volume->get_instance_transformation().get_matrix(true);
+ // we'll recover current look direction from the modelview matrix (in world coords)...
+ Vec3f direction_to_camera(modelview_matrix[2], modelview_matrix[6], modelview_matrix[10]);
+ // ...and transform it to model coords.
+ direction_to_camera = (instance_matrix_no_translation.inverse().cast() * direction_to_camera).normalized().eval();
+
+ // Iterate over all points, check if they're in the rectangle and if so, check that they are not obscured by the mesh:
+ for (unsigned int i=0; i() * support_point.pos;
+ pos(2) += z_offset;
+ GLdouble out_x, out_y, out_z;
+ ::gluProject((GLdouble)pos(0), (GLdouble)pos(1), (GLdouble)pos(2), modelview_matrix, projection_matrix, viewport, &out_x, &out_y, &out_z);
+ out_y = m_canvas_height - out_y;
+
+ if (rectangle.contains(Point(out_x, out_y))) {
+ bool is_obscured = false;
+ // Cast a ray in the direction of the camera and look for intersection with the mesh:
+ std::vector hits;
+ // Offset the start of the ray to the front of the ball + EPSILON to account for numerical inaccuracies.
+ if (m_AABB.intersect_ray(m_V, m_F, support_point.pos + direction_to_camera * (support_point.head_front_radius + EPSILON), direction_to_camera, hits))
+ // FIXME: the intersection could in theory be behind the camera, but as of now we only have camera direction.
+ // Also, the threshold is in mesh coordinates, not in actual dimensions.
+ if (hits.size() > 1 || hits.front().t > 0.001f)
+ is_obscured = true;
+
+ if (!is_obscured)
+ select_point(i);
+ }
+ }
+ m_selection_rectangle_active = false;
+ return true;
+ }
+
+ if (action == SLAGizmoEventType::Delete) {
+ // delete key pressed
delete_selected_points();
return true;
}
- return false;
+
+ if (action == SLAGizmoEventType::ApplyChanges) {
+ editing_mode_apply_changes();
+ return true;
+ }
+
+ if (action == SLAGizmoEventType::DiscardChanges) {
+ editing_mode_discard_changes();
+ return true;
+ }
+
+ if (action == SLAGizmoEventType::RightDown) {
+ if (m_hover_id != -1) {
+ select_point(NoPoints);
+ select_point(m_hover_id);
+ delete_selected_points();
+ return true;
+ }
+ return false;
+ }
+
+ if (action == SLAGizmoEventType::SelectAll) {
+ select_point(AllPoints);
+ return true;
+ }
}
- if (action == SLAGizmoEventType::SelectAll) {
- select_point(AllPoints);
- return true;
+ if (!m_editing_mode) {
+ if (action == SLAGizmoEventType::AutomaticGeneration) {
+ auto_generate();
+ return true;
+ }
+
+ if (action == SLAGizmoEventType::ManualEditing) {
+ switch_to_editing_mode();
+ return true;
+ }
}
return false;
@@ -2186,7 +2242,6 @@ RENDER_AGAIN:
bool force_refresh = false;
bool remove_selected = false;
- bool old_editing_state = m_editing_mode;
if (m_editing_mode) {
m_imgui->text(_(L("Left mouse click - add point")));
@@ -2230,9 +2285,6 @@ RENDER_AGAIN:
if (apply_changes) {
editing_mode_apply_changes();
force_refresh = true;
- // Recalculate support structures once the editing mode is left.
- // m_parent.post_event(SimpleEvent(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS));
- wxGetApp().plater()->reslice_SLA_supports(*m_model_object);
}
ImGui::SameLine();
bool discard_changes = m_imgui->button(_(L("Discard changes")));
@@ -2250,70 +2302,24 @@ RENDER_AGAIN:
ImGui::SameLine();
value_changed |= ImGui::InputDouble("%", &m_density, 0.0f, 0.0f, "%.f");*/
- bool generate = m_imgui->button(_(L("Auto-generate points")));
+ bool generate = m_imgui->button(_(L("Auto-generate points [A]")));
- if (generate) {
-#if SLAGIZMO_IMGUI_MODAL
- ImGui::OpenPopup(_(L("Warning")));
- m_show_modal = true;
- force_refresh = true;
-#else
- wxMessageDialog dlg(GUI::wxGetApp().plater(), _(L(
- "Autogeneration will erase all manually edited points.\n\n"
- "Are you sure you want to do it?\n"
- )), _(L("Warning")), wxICON_WARNING | wxYES | wxNO);
- if (m_model_object->sla_support_points.empty() || dlg.ShowModal() == wxID_YES) {
- m_model_object->sla_support_points.clear();
- m_editing_mode_cache.clear();
- wxGetApp().plater()->reslice_SLA_supports(*m_model_object);
- }
-#endif
- }
-#if SLAGIZMO_IMGUI_MODAL
- if (m_show_modal) {
- if (ImGui::BeginPopupModal(_(L("Warning")), &m_show_modal/*, ImGuiWindowFlags_NoDecoration*/))
- {
- m_imgui->text(_(L("Autogeneration will erase all manually edited points.")));
- m_imgui->text("");
- m_imgui->text(_(L("Are you sure you want to do it?")));
+ if (generate)
+ auto_generate();
- if (m_imgui->button(_(L("Continue"))))
- {
- ImGui::CloseCurrentPopup();
- m_show_modal = false;
-
- m_model_object->sla_support_points.clear();
- m_editing_mode_cache.clear();
- wxGetApp().plater()->reslice_SLA_supports(*m_model_object);
- }
- ImGui::SameLine();
- if (m_imgui->button(_(L("Cancel")))) {
- ImGui::CloseCurrentPopup();
- m_show_modal = false;
- }
- ImGui::EndPopup();
- }
-
- if (!m_show_modal)
- force_refresh = true;
- }
-#endif
m_imgui->text("");
m_imgui->text("");
- bool editing_clicked = m_imgui->button(_(L("Manual editing")));
- if (editing_clicked) {
- editing_mode_reload_cache();
- m_editing_mode = true;
- }
+ if (m_imgui->button(_(L("Manual editing [M]"))))
+ switch_to_editing_mode();
}
m_imgui->end();
- if (m_editing_mode != old_editing_state) { // user just toggled between editing/non-editing mode
+ if (m_editing_mode != m_old_editing_state) { // user toggled between editing/non-editing mode
m_parent.toggle_sla_auxiliaries_visibility(!m_editing_mode);
force_refresh = true;
}
-
+ m_old_editing_state = m_editing_mode;
if (remove_selected) {
force_refresh = false;
@@ -2379,18 +2385,13 @@ void GLGizmoSlaSupports::on_set_state()
m_parent.toggle_model_objects_visibility(true);
m_editing_mode = false; // so it is not active next time the gizmo opens
-
-#if SLAGIZMO_IMGUI_MODAL
- if (m_show_modal) {
- m_show_modal = false;
- on_render_input_window(0,0,m_parent.get_selection()); // this is necessary to allow ImGui to terminate the modal dialog correctly
- }
-#endif
}
}
m_old_state = m_state;
}
+
+
void GLGizmoSlaSupports::on_start_dragging(const GLCanvas3D::Selection& selection)
{
if (m_hover_id != -1) {
@@ -2399,6 +2400,8 @@ void GLGizmoSlaSupports::on_start_dragging(const GLCanvas3D::Selection& selectio
}
}
+
+
void GLGizmoSlaSupports::select_point(int i)
{
if (i == AllPoints || i == NoPoints) {
@@ -2412,6 +2415,8 @@ void GLGizmoSlaSupports::select_point(int i)
}
}
+
+
void GLGizmoSlaSupports::editing_mode_discard_changes()
{
m_editing_mode_cache.clear();
@@ -2421,6 +2426,8 @@ void GLGizmoSlaSupports::editing_mode_discard_changes()
m_unsaved_changes = false;
}
+
+
void GLGizmoSlaSupports::editing_mode_apply_changes()
{
// If there are no changes, don't touch the front-end. The data in the cache could have been
@@ -2432,8 +2439,14 @@ void GLGizmoSlaSupports::editing_mode_apply_changes()
}
m_editing_mode = false;
m_unsaved_changes = false;
+
+ // Recalculate support structures once the editing mode is left.
+ // m_parent.post_event(SimpleEvent(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS));
+ wxGetApp().plater()->reslice_SLA_supports(*m_model_object);
}
+
+
void GLGizmoSlaSupports::editing_mode_reload_cache()
{
m_editing_mode_cache.clear();
@@ -2442,6 +2455,8 @@ void GLGizmoSlaSupports::editing_mode_reload_cache()
m_unsaved_changes = false;
}
+
+
void GLGizmoSlaSupports::get_data_from_backend()
{
for (const SLAPrintObject* po : m_parent.sla_print()->objects()) {
@@ -2459,6 +2474,34 @@ void GLGizmoSlaSupports::get_data_from_backend()
}
+
+void GLGizmoSlaSupports::auto_generate()
+{
+ wxMessageDialog dlg(GUI::wxGetApp().plater(), _(L(
+ "Autogeneration will erase all manually edited points.\n\n"
+ "Are you sure you want to do it?\n"
+ )), _(L("Warning")), wxICON_WARNING | wxYES | wxNO);
+
+ if (m_model_object->sla_support_points.empty() || dlg.ShowModal() == wxID_YES) {
+ m_model_object->sla_support_points.clear();
+ m_editing_mode_cache.clear();
+ wxGetApp().plater()->reslice_SLA_supports(*m_model_object);
+ }
+}
+
+
+
+void GLGizmoSlaSupports::switch_to_editing_mode()
+{
+ editing_mode_reload_cache();
+ m_editing_mode = true;
+}
+
+
+
+
+
+
// GLGizmoCut
class GLGizmoCutPanel : public wxPanel
@@ -2506,8 +2549,13 @@ const double GLGizmoCut::Offset = 10.0;
const double GLGizmoCut::Margin = 20.0;
const std::array GLGizmoCut::GrabberColor = { 1.0, 0.5, 0.0 };
+#if ENABLE_SVG_ICONS
+GLGizmoCut::GLGizmoCut(GLCanvas3D& parent, const std::string& svg_file, unsigned int sprite_id)
+ : GLGizmoBase(parent, svg_file, sprite_id)
+#else
GLGizmoCut::GLGizmoCut(GLCanvas3D& parent, unsigned int sprite_id)
: GLGizmoBase(parent, sprite_id)
+#endif // ENABLE_SVG_ICONS
, m_cut_z(0.0)
, m_max_z(0.0)
#if !ENABLE_IMGUI
diff --git a/src/slic3r/GUI/GLGizmo.hpp b/src/slic3r/GUI/GLGizmo.hpp
index 6cf3afdab..dc632fe80 100644
--- a/src/slic3r/GUI/GLGizmo.hpp
+++ b/src/slic3r/GUI/GLGizmo.hpp
@@ -87,6 +87,9 @@ protected:
int m_group_id;
EState m_state;
int m_shortcut_key;
+#if ENABLE_SVG_ICONS
+ std::string m_svg_file;
+#endif // ENABLE_SVG_ICONS
unsigned int m_sprite_id;
int m_hover_id;
bool m_dragging;
@@ -99,7 +102,11 @@ protected:
#endif // ENABLE_IMGUI
public:
+#if ENABLE_SVG_ICONS
+ GLGizmoBase(GLCanvas3D& parent, const std::string& svg_file, unsigned int sprite_id);
+#else
GLGizmoBase(GLCanvas3D& parent, unsigned int sprite_id);
+#endif // ENABLE_SVG_ICONS
virtual ~GLGizmoBase() {}
bool init() { return on_init(); }
@@ -115,6 +122,10 @@ public:
int get_shortcut_key() const { return m_shortcut_key; }
void set_shortcut_key(int key) { m_shortcut_key = key; }
+#if ENABLE_SVG_ICONS
+ const std::string& get_svg_file() const { return m_svg_file; }
+#endif // ENABLE_SVG_ICONS
+
bool is_activable(const GLCanvas3D::Selection& selection) const { return on_is_activable(selection); }
bool is_selectable() const { return on_is_selectable(); }
@@ -242,7 +253,11 @@ class GLGizmoRotate3D : public GLGizmoBase
std::vector m_gizmos;
public:
+#if ENABLE_SVG_ICONS
+ GLGizmoRotate3D(GLCanvas3D& parent, const std::string& svg_file, unsigned int sprite_id);
+#else
GLGizmoRotate3D(GLCanvas3D& parent, unsigned int sprite_id);
+#endif // ENABLE_SVG_ICONS
Vec3d get_rotation() const { return Vec3d(m_gizmos[X].get_angle(), m_gizmos[Y].get_angle(), m_gizmos[Z].get_angle()); }
void set_rotation(const Vec3d& rotation) { m_gizmos[X].set_angle(rotation(0)); m_gizmos[Y].set_angle(rotation(1)); m_gizmos[Z].set_angle(rotation(2)); }
@@ -313,7 +328,11 @@ class GLGizmoScale3D : public GLGizmoBase
BoundingBoxf3 m_starting_box;
public:
- GLGizmoScale3D(GLCanvas3D& parent, unsigned int sprite_id);
+#if ENABLE_SVG_ICONS
+ GLGizmoScale3D(GLCanvas3D& parent, const std::string& svg_file, unsigned int sprite_id);
+#else
+ GLGizmoScale3D(GLCanvas3D& parent, unsigned int sprite_id);
+#endif // ENABLE_SVG_ICONS
double get_snap_step(double step) const { return m_snap_step; }
void set_snap_step(double step) { m_snap_step = step; }
@@ -360,7 +379,11 @@ class GLGizmoMove3D : public GLGizmoBase
GLUquadricObj* m_quadric;
public:
+#if ENABLE_SVG_ICONS
+ GLGizmoMove3D(GLCanvas3D& parent, const std::string& svg_file, unsigned int sprite_id);
+#else
GLGizmoMove3D(GLCanvas3D& parent, unsigned int sprite_id);
+#endif // ENABLE_SVG_ICONS
virtual ~GLGizmoMove3D();
double get_snap_step(double step) const { return m_snap_step; }
@@ -415,7 +438,11 @@ private:
bool is_plane_update_necessary() const;
public:
+#if ENABLE_SVG_ICONS
+ GLGizmoFlatten(GLCanvas3D& parent, const std::string& svg_file, unsigned int sprite_id);
+#else
GLGizmoFlatten(GLCanvas3D& parent, unsigned int sprite_id);
+#endif // ENABLE_SVG_ICONS
void set_flattening_data(const ModelObject* model_object);
Vec3d get_flattening_normal() const;
@@ -436,6 +463,7 @@ protected:
};
#define SLAGIZMO_IMGUI_MODAL 0
+
class GLGizmoSlaSupports : public GLGizmoBase
{
private:
@@ -453,7 +481,7 @@ private:
igl::AABB m_AABB;
struct SourceDataSummary {
- Vec3d mesh_first_point;
+ Geometry::Transformation transformation;
};
// This holds information to decide whether recalculation is necessary:
@@ -462,7 +490,11 @@ private:
mutable Vec3d m_starting_center;
public:
+#if ENABLE_SVG_ICONS
+ GLGizmoSlaSupports(GLCanvas3D& parent, const std::string& svg_file, unsigned int sprite_id);
+#else
GLGizmoSlaSupports(GLCanvas3D& parent, unsigned int sprite_id);
+#endif // ENABLE_SVG_ICONS
virtual ~GLGizmoSlaSupports();
void set_sla_support_data(ModelObject* model_object, const GLCanvas3D::Selection& selection);
bool mouse_event(SLAGizmoEventType action, const Vec2d& mouse_position, bool shift_down);
@@ -487,6 +519,7 @@ private:
bool m_lock_unique_islands = false;
bool m_editing_mode = false;
+ bool m_old_editing_state = false;
float m_new_point_head_diameter = 0.4f;
double m_minimal_point_distance = 20.;
double m_density = 100.;
@@ -500,9 +533,6 @@ private:
bool m_unsaved_changes = false;
bool m_selection_empty = true;
EState m_old_state = Off; // to be able to see that the gizmo has just been closed (see on_set_state)
-#if SLAGIZMO_IMGUI_MODAL
- bool m_show_modal = false;
-#endif
int m_canvas_width;
int m_canvas_height;
@@ -517,6 +547,8 @@ private:
void editing_mode_discard_changes();
void editing_mode_reload_cache();
void get_data_from_backend();
+ void auto_generate();
+ void switch_to_editing_mode();
protected:
void on_set_state() override;
@@ -555,7 +587,11 @@ class GLGizmoCut : public GLGizmoBase
#endif // not ENABLE_IMGUI
public:
+#if ENABLE_SVG_ICONS
+ GLGizmoCut(GLCanvas3D& parent, const std::string& svg_file, unsigned int sprite_id);
+#else
GLGizmoCut(GLCanvas3D& parent, unsigned int sprite_id);
+#endif // ENABLE_SVG_ICONS
#if !ENABLE_IMGUI
virtual void create_external_gizmo_widgets(wxWindow *parent);
diff --git a/src/slic3r/GUI/GLTexture.cpp b/src/slic3r/GUI/GLTexture.cpp
index e7e20b27e..9679680d0 100644
--- a/src/slic3r/GUI/GLTexture.cpp
+++ b/src/slic3r/GUI/GLTexture.cpp
@@ -120,13 +120,13 @@ bool GLTexture::load_from_file(const std::string& filename, bool use_mipmaps)
{
// we manually generate mipmaps because glGenerateMipmap() function is not reliable on all graphics cards
unsigned int levels_count = generate_mipmaps(image);
- ::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 1 + levels_count);
+ ::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, levels_count);
::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
}
else
{
::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
- ::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 1);
+ ::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
}
::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
@@ -137,6 +137,106 @@ bool GLTexture::load_from_file(const std::string& filename, bool use_mipmaps)
}
#endif // ENABLE_TEXTURES_FROM_SVG
+#if ENABLE_SVG_ICONS
+bool GLTexture::load_from_svg_files_as_sprites_array(const std::vector& filenames, unsigned int num_states, unsigned int sprite_size_px)
+{
+ static int pass = 0;
+ ++pass;
+
+ reset();
+
+ if (filenames.empty() || (num_states == 0) || (sprite_size_px == 0))
+ return false;
+
+ m_width = (int)sprite_size_px * std::max((int)(num_states), (int)(filenames.size()));
+ m_height = m_width;
+ int n_pixels = m_width * m_height;
+
+ if (n_pixels <= 0)
+ {
+ reset();
+ return false;
+ }
+
+ std::vector data(n_pixels * 4, 0);
+ std::vector sprite_data(sprite_size_px * sprite_size_px * 4, 0);
+
+ NSVGrasterizer* rast = nsvgCreateRasterizer();
+ if (rast == nullptr)
+ {
+ reset();
+ return false;
+ }
+
+ int sprite_id = -1;
+ for (const std::string& filename : filenames)
+ {
+ ++sprite_id;
+
+ if (!boost::filesystem::exists(filename))
+ continue;
+
+ if (!boost::algorithm::iends_with(filename, ".svg"))
+ continue;
+
+ NSVGimage* image = nsvgParseFromFile(filename.c_str(), "px", 96.0f);
+ if (image == nullptr)
+ continue;
+
+ float scale = (float)sprite_size_px / std::max(image->width, image->height);
+
+ nsvgRasterize(rast, image, 0, 0, scale, sprite_data.data(), sprite_size_px, sprite_size_px, sprite_size_px * 4);
+
+ int sprite_offset_px = sprite_id * sprite_size_px * m_width;
+ for (unsigned int i = 0; i < num_states; ++i)
+ {
+ int state_offset_px = sprite_offset_px + i * sprite_size_px;
+ for (int j = 0; j < sprite_size_px; ++j)
+ {
+ int data_offset = (state_offset_px + j * m_width) * 4;
+ ::memcpy((void*)&data.data()[data_offset], (const void*)&sprite_data.data()[j * sprite_size_px * 4], sprite_size_px * 4);
+ }
+ }
+
+ nsvgDelete(image);
+ }
+
+ nsvgDeleteRasterizer(rast);
+
+ // sends data to gpu
+ ::glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+ ::glGenTextures(1, &m_id);
+ ::glBindTexture(GL_TEXTURE_2D, m_id);
+ ::glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)m_width, (GLsizei)m_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, (const void*)data.data());
+ ::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ ::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
+ ::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+
+ ::glBindTexture(GL_TEXTURE_2D, 0);
+
+
+ m_source = filenames.front();
+
+ wxImage output(m_width, m_height);
+ output.InitAlpha();
+
+ for (int h = 0; h < m_height; ++h)
+ {
+ for (int w = 0; w < m_width; ++w)
+ {
+ int px = h * m_width + w;
+ int px_byte = px * 4;
+ output.SetRGB(w, h, data.data()[px_byte + 0], data.data()[px_byte + 1], data.data()[px_byte + 2]);
+ output.SetAlpha(w, h, data.data()[px_byte + 3]);
+ }
+ }
+
+ output.SaveFile("C:/prusa/slic3r/svg_icons/temp/test_" + std::to_string(pass) + ".png", wxBITMAP_TYPE_PNG);
+
+ return true;
+}
+#endif // ENABLE_SVG_ICONS
+
void GLTexture::reset()
{
if (m_id != 0)
@@ -265,13 +365,13 @@ bool GLTexture::load_from_png(const std::string& filename, bool use_mipmaps)
{
// we manually generate mipmaps because glGenerateMipmap() function is not reliable on all graphics cards
unsigned int levels_count = generate_mipmaps(image);
- ::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 1 + levels_count);
+ ::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, levels_count);
::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
}
else
{
::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
- ::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 1);
+ ::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
}
::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
@@ -340,13 +440,13 @@ bool GLTexture::load_from_svg(const std::string& filename, bool use_mipmaps, uns
::glTexImage2D(GL_TEXTURE_2D, level, GL_RGBA, (GLsizei)lod_w, (GLsizei)lod_h, 0, GL_RGBA, GL_UNSIGNED_BYTE, (const void*)data.data());
}
- ::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 1 + level);
+ ::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, level);
::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
}
else
{
::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
- ::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 1);
+ ::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
}
::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
diff --git a/src/slic3r/GUI/GLTexture.hpp b/src/slic3r/GUI/GLTexture.hpp
index af41ac342..55e5c4c07 100644
--- a/src/slic3r/GUI/GLTexture.hpp
+++ b/src/slic3r/GUI/GLTexture.hpp
@@ -41,6 +41,9 @@ namespace GUI {
#if ENABLE_TEXTURES_FROM_SVG
bool load_from_svg_file(const std::string& filename, bool use_mipmaps, unsigned int max_size_px);
#endif // ENABLE_TEXTURES_FROM_SVG
+#if ENABLE_SVG_ICONS
+ bool load_from_svg_files_as_sprites_array(const std::vector& filenames, unsigned int num_states, unsigned int sprite_size_px);
+#endif // ENABLE_SVG_ICONS
void reset();
unsigned int get_id() const { return m_id; }
diff --git a/src/slic3r/GUI/GLToolbar.cpp b/src/slic3r/GUI/GLToolbar.cpp
index 4cfa9a879..deb287c6a 100644
--- a/src/slic3r/GUI/GLToolbar.cpp
+++ b/src/slic3r/GUI/GLToolbar.cpp
@@ -32,6 +32,9 @@ wxDEFINE_EVENT(EVT_GLVIEWTOOLBAR_PREVIEW, SimpleEvent);
GLToolbarItem::Data::Data()
: name("")
+#if ENABLE_SVG_ICONS
+ , svg_file("")
+#endif // ENABLE_SVG_ICONS
, tooltip("")
, sprite_id(-1)
, is_toggable(false)
@@ -78,11 +81,13 @@ GLTexture::Quad_UVs GLToolbarItem::get_uvs(unsigned int texture_size, unsigned i
return uvs;
}
+#if !ENABLE_SVG_ICONS
ItemsIconsTexture::Metadata::Metadata()
: filename("")
, icon_size(0)
{
}
+#endif // !ENABLE_SVG_ICONS
BackgroundTexture::Metadata::Metadata()
: filename("")
@@ -93,6 +98,10 @@ BackgroundTexture::Metadata::Metadata()
{
}
+#if ENABLE_SVG_ICONS
+const float GLToolbar::Default_Icons_Size = 64.0f;
+#endif // ENABLE_SVG_ICONS
+
GLToolbar::Layout::Layout()
: type(Horizontal)
, orientation(Center)
@@ -101,7 +110,12 @@ GLToolbar::Layout::Layout()
, border(0.0f)
, separator_size(0.0f)
, gap_size(0.0f)
+#if ENABLE_SVG_ICONS
+ , icons_size(Default_Icons_Size)
+ , scale(1.0f)
+#else
, icons_scale(1.0f)
+#endif // ENABLE_SVG_ICONS
, width(0.0f)
, height(0.0f)
, dirty(true)
@@ -111,6 +125,9 @@ GLToolbar::Layout::Layout()
GLToolbar::GLToolbar(GLToolbar::EType type)
: m_type(type)
, m_enabled(false)
+#if ENABLE_SVG_ICONS
+ , m_icons_texture_dirty(true)
+#endif // ENABLE_SVG_ICONS
{
}
@@ -122,8 +139,19 @@ GLToolbar::~GLToolbar()
}
}
+#if ENABLE_SVG_ICONS
+bool GLToolbar::init(const BackgroundTexture::Metadata& background_texture)
+#else
bool GLToolbar::init(const ItemsIconsTexture::Metadata& icons_texture, const BackgroundTexture::Metadata& background_texture)
+#endif // ENABLE_SVG_ICONS
{
+#if ENABLE_SVG_ICONS
+ if (m_background_texture.texture.get_id() != 0)
+ return true;
+
+ std::string path = resources_dir() + "/icons/";
+ bool res = false;
+#else
if (m_icons_texture.texture.get_id() != 0)
return true;
@@ -131,6 +159,7 @@ bool GLToolbar::init(const ItemsIconsTexture::Metadata& icons_texture, const Bac
bool res = !icons_texture.filename.empty() && m_icons_texture.texture.load_from_file(path + icons_texture.filename, false);
if (res)
m_icons_texture.metadata = icons_texture;
+#endif // ENABLE_SVG_ICONS
if (!background_texture.filename.empty())
res = m_background_texture.texture.load_from_file(path + background_texture.filename, false);
@@ -186,11 +215,33 @@ void GLToolbar::set_gap_size(float size)
m_layout.dirty = true;
}
+#if ENABLE_SVG_ICONS
+void GLToolbar::set_icons_size(float size)
+{
+ if (m_layout.icons_size != size)
+ {
+ m_layout.icons_size = size;
+ m_layout.dirty = true;
+ m_icons_texture_dirty = true;
+ }
+}
+
+void GLToolbar::set_scale(float scale)
+{
+ if (m_layout.scale != scale)
+ {
+ m_layout.scale = scale;
+ m_layout.dirty = true;
+ m_icons_texture_dirty = true;
+ }
+}
+#else
void GLToolbar::set_icons_scale(float scale)
{
m_layout.icons_scale = scale;
m_layout.dirty = true;
}
+#endif // ENABLE_SVG_ICONS
bool GLToolbar::is_enabled() const
{
@@ -411,6 +462,11 @@ void GLToolbar::render(const GLCanvas3D& parent) const
if (!m_enabled || m_items.empty())
return;
+#if ENABLE_SVG_ICONS
+ if (m_icons_texture_dirty)
+ generate_icons_texture();
+#endif // ENABLE_SVG_ICONS
+
::glDisable(GL_DEPTH_TEST);
::glPushMatrix();
@@ -455,12 +511,20 @@ float GLToolbar::get_width_horizontal() const
float GLToolbar::get_width_vertical() const
{
+#if ENABLE_SVG_ICONS
+ return (2.0f * m_layout.border + m_layout.icons_size) * m_layout.scale;
+#else
return 2.0f * m_layout.border * m_layout.icons_scale + m_icons_texture.metadata.icon_size * m_layout.icons_scale;
+#endif // ENABLE_SVG_ICONS
}
float GLToolbar::get_height_horizontal() const
{
+#if ENABLE_SVG_ICONS
+ return (2.0f * m_layout.border + m_layout.icons_size) * m_layout.scale;
+#else
return 2.0f * m_layout.border * m_layout.icons_scale + m_icons_texture.metadata.icon_size * m_layout.icons_scale;
+#endif // ENABLE_SVG_ICONS
}
float GLToolbar::get_height_vertical() const
@@ -470,6 +534,26 @@ float GLToolbar::get_height_vertical() const
float GLToolbar::get_main_size() const
{
+#if ENABLE_SVG_ICONS
+ float size = 2.0f * m_layout.border;
+ for (unsigned int i = 0; i < (unsigned int)m_items.size(); ++i)
+ {
+#if ENABLE_MODE_AWARE_TOOLBAR_ITEMS
+ if (!m_items[i]->is_visible())
+ continue;
+#endif // ENABLE_MODE_AWARE_TOOLBAR_ITEMS
+
+ if (m_items[i]->is_separator())
+ size += m_layout.separator_size;
+ else
+ size += (float)m_layout.icons_size;
+ }
+
+ if (m_items.size() > 1)
+ size += ((float)m_items.size() - 1.0f) * m_layout.gap_size;
+
+ size *= m_layout.scale;
+#else
float size = 2.0f * m_layout.border * m_layout.icons_scale;
for (unsigned int i = 0; i < (unsigned int)m_items.size(); ++i)
{
@@ -486,6 +570,7 @@ float GLToolbar::get_main_size() const
if (m_items.size() > 1)
size += ((float)m_items.size() - 1.0f) * m_layout.gap_size * m_layout.icons_scale;
+#endif // ENABLE_SVG_ICONS
return size;
}
@@ -496,12 +581,20 @@ std::string GLToolbar::update_hover_state_horizontal(const Vec2d& mouse_pos, GLC
float zoom = parent.get_camera_zoom();
float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f;
+#if ENABLE_SVG_ICONS
+ float factor = m_layout.scale * inv_zoom;
+#else
float factor = m_layout.icons_scale * inv_zoom;
+#endif // ENABLE_SVG_ICONS
Size cnv_size = parent.get_canvas_size();
Vec2d scaled_mouse_pos((mouse_pos(0) - 0.5 * (double)cnv_size.get_width()) * inv_zoom, (0.5 * (double)cnv_size.get_height() - mouse_pos(1)) * inv_zoom);
+#if ENABLE_SVG_ICONS
+ float scaled_icons_size = m_layout.icons_size * factor;
+#else
float scaled_icons_size = (float)m_icons_texture.metadata.icon_size * factor;
+#endif // ENABLE_SVG_ICONS
float scaled_separator_size = m_layout.separator_size * factor;
float scaled_gap_size = m_layout.gap_size * factor;
float scaled_border = m_layout.border * factor;
@@ -595,12 +688,20 @@ std::string GLToolbar::update_hover_state_vertical(const Vec2d& mouse_pos, GLCan
float zoom = parent.get_camera_zoom();
float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f;
+#if ENABLE_SVG_ICONS
+ float factor = m_layout.scale * inv_zoom;
+#else
float factor = m_layout.icons_scale * inv_zoom;
+#endif // ENABLE_SVG_ICONS
Size cnv_size = parent.get_canvas_size();
Vec2d scaled_mouse_pos((mouse_pos(0) - 0.5 * (double)cnv_size.get_width()) * inv_zoom, (0.5 * (double)cnv_size.get_height() - mouse_pos(1)) * inv_zoom);
+#if ENABLE_SVG_ICONS
+ float scaled_icons_size = m_layout.icons_size * factor;
+#else
float scaled_icons_size = (float)m_icons_texture.metadata.icon_size * factor;
+#endif // ENABLE_SVG_ICONS
float scaled_separator_size = m_layout.separator_size * factor;
float scaled_gap_size = m_layout.gap_size * factor;
float scaled_border = m_layout.border * factor;
@@ -693,12 +794,20 @@ int GLToolbar::contains_mouse_horizontal(const Vec2d& mouse_pos, const GLCanvas3
float zoom = parent.get_camera_zoom();
float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f;
+#if ENABLE_SVG_ICONS
+ float factor = m_layout.scale * inv_zoom;
+#else
float factor = m_layout.icons_scale * inv_zoom;
+#endif // ENABLE_SVG_ICONS
Size cnv_size = parent.get_canvas_size();
Vec2d scaled_mouse_pos((mouse_pos(0) - 0.5 * (double)cnv_size.get_width()) * inv_zoom, (0.5 * (double)cnv_size.get_height() - mouse_pos(1)) * inv_zoom);
+#if ENABLE_SVG_ICONS
+ float scaled_icons_size = m_layout.icons_size * factor;
+#else
float scaled_icons_size = (float)m_icons_texture.metadata.icon_size * factor;
+#endif // ENABLE_SVG_ICONS
float scaled_separator_size = m_layout.separator_size * factor;
float scaled_gap_size = m_layout.gap_size * factor;
float scaled_border = m_layout.border * factor;
@@ -742,12 +851,20 @@ int GLToolbar::contains_mouse_vertical(const Vec2d& mouse_pos, const GLCanvas3D&
float zoom = parent.get_camera_zoom();
float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f;
+#if ENABLE_SVG_ICONS
+ float factor = m_layout.scale * inv_zoom;
+#else
float factor = m_layout.icons_scale * inv_zoom;
+#endif // ENABLE_SVG_ICONS
Size cnv_size = parent.get_canvas_size();
Vec2d scaled_mouse_pos((mouse_pos(0) - 0.5 * (double)cnv_size.get_width()) * inv_zoom, (0.5 * (double)cnv_size.get_height() - mouse_pos(1)) * inv_zoom);
+#if ENABLE_SVG_ICONS
+ float scaled_icons_size = m_layout.icons_size * factor;
+#else
float scaled_icons_size = (float)m_icons_texture.metadata.icon_size * factor;
+#endif // ENABLE_SVG_ICONS
float scaled_separator_size = m_layout.separator_size * factor;
float scaled_gap_size = m_layout.gap_size * factor;
float scaled_border = m_layout.border * factor;
@@ -788,17 +905,32 @@ int GLToolbar::contains_mouse_vertical(const Vec2d& mouse_pos, const GLCanvas3D&
void GLToolbar::render_horizontal(const GLCanvas3D& parent) const
{
+#if ENABLE_SVG_ICONS
+ unsigned int tex_id = m_icons_texture.get_id();
+ int tex_size = m_icons_texture.get_width();
+#else
unsigned int tex_id = m_icons_texture.texture.get_id();
int tex_size = m_icons_texture.texture.get_width();
+#endif // ENABLE_SVG_ICONS
+#if !ENABLE_SVG_ICONS
if ((tex_id == 0) || (tex_size <= 0))
return;
+#endif // !ENABLE_SVG_ICONS
float zoom = parent.get_camera_zoom();
float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f;
+#if ENABLE_SVG_ICONS
+ float factor = inv_zoom * m_layout.scale;
+#else
float factor = inv_zoom * m_layout.icons_scale;
+#endif // ENABLE_SVG_ICONS
+#if ENABLE_SVG_ICONS
+ float scaled_icons_size = m_layout.icons_size * factor;
+#else
float scaled_icons_size = (float)m_icons_texture.metadata.icon_size * factor;
+#endif // ENABLE_SVG_ICONS
float scaled_separator_size = m_layout.separator_size * factor;
float scaled_gap_size = m_layout.gap_size * factor;
float scaled_border = m_layout.border * factor;
@@ -899,6 +1031,11 @@ void GLToolbar::render_horizontal(const GLCanvas3D& parent) const
left += scaled_border;
top -= scaled_border;
+#if ENABLE_SVG_ICONS
+ if ((tex_id == 0) || (tex_size <= 0))
+ return;
+#endif // ENABLE_SVG_ICONS
+
// renders icons
for (const GLToolbarItem* item : m_items)
{
@@ -911,7 +1048,11 @@ void GLToolbar::render_horizontal(const GLCanvas3D& parent) const
left += separator_stride;
else
{
+#if ENABLE_SVG_ICONS
+ item->render(tex_id, left, left + scaled_icons_size, top - scaled_icons_size, top, (unsigned int)tex_size, (unsigned int)m_layout.icons_size);
+#else
item->render(tex_id, left, left + scaled_icons_size, top - scaled_icons_size, top, (unsigned int)tex_size, m_icons_texture.metadata.icon_size);
+#endif // ENABLE_SVG_ICONS
left += icon_stride;
}
}
@@ -919,17 +1060,30 @@ void GLToolbar::render_horizontal(const GLCanvas3D& parent) const
void GLToolbar::render_vertical(const GLCanvas3D& parent) const
{
+#if ENABLE_SVG_ICONS
+ unsigned int tex_id = m_icons_texture.get_id();
+ int tex_size = m_icons_texture.get_width();
+#else
unsigned int tex_id = m_icons_texture.texture.get_id();
int tex_size = m_icons_texture.texture.get_width();
+#endif // ENABLE_SVG_ICONS
if ((tex_id == 0) || (tex_size <= 0))
return;
float zoom = parent.get_camera_zoom();
float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f;
+#if ENABLE_SVG_ICONS
+ float factor = inv_zoom * m_layout.scale;
+#else
float factor = inv_zoom * m_layout.icons_scale;
+#endif // ENABLE_SVG_ICONS
+#if ENABLE_SVG_ICONS
+ float scaled_icons_size = m_layout.icons_size * factor;
+#else
float scaled_icons_size = (float)m_icons_texture.metadata.icon_size * m_layout.icons_scale * factor;
+#endif // ENABLE_SVG_ICONS
float scaled_separator_size = m_layout.separator_size * factor;
float scaled_gap_size = m_layout.gap_size * factor;
float scaled_border = m_layout.border * factor;
@@ -1042,11 +1196,35 @@ void GLToolbar::render_vertical(const GLCanvas3D& parent) const
top -= separator_stride;
else
{
+#if ENABLE_SVG_ICONS
+ item->render(tex_id, left, left + scaled_icons_size, top - scaled_icons_size, top, (unsigned int)tex_size, (unsigned int)(m_layout.icons_size * m_layout.scale));
+#else
item->render(tex_id, left, left + scaled_icons_size, top - scaled_icons_size, top, (unsigned int)tex_size, m_icons_texture.metadata.icon_size);
+#endif // ENABLE_SVG_ICONS
top -= icon_stride;
}
}
}
+#if ENABLE_SVG_ICONS
+bool GLToolbar::generate_icons_texture() const
+{
+ std::string path = resources_dir() + "/icons/";
+ std::vector filenames;
+ for (GLToolbarItem* item : m_items)
+ {
+ const std::string& svg_file = item->get_svg_file();
+ if (!svg_file.empty())
+ filenames.push_back(path + svg_file);
+ }
+
+ bool res = m_icons_texture.load_from_svg_files_as_sprites_array(filenames, GLToolbarItem::Num_States, (unsigned int)(m_layout.icons_size * m_layout.scale));
+ if (res)
+ m_icons_texture_dirty = false;
+
+ return res;
+}
+#endif // ENABLE_SVG_ICONS
+
} // namespace GUI
} // namespace Slic3r
diff --git a/src/slic3r/GUI/GLToolbar.hpp b/src/slic3r/GUI/GLToolbar.hpp
index 8a9ff783c..b12b2693e 100644
--- a/src/slic3r/GUI/GLToolbar.hpp
+++ b/src/slic3r/GUI/GLToolbar.hpp
@@ -51,6 +51,9 @@ public:
struct Data
{
std::string name;
+#if ENABLE_SVG_ICONS
+ std::string svg_file;
+#endif // ENABLE_SVG_ICONS
std::string tooltip;
unsigned int sprite_id;
bool is_toggable;
@@ -74,6 +77,9 @@ public:
void set_state(EState state) { m_state = state; }
const std::string& get_name() const { return m_data.name; }
+#if ENABLE_SVG_ICONS
+ const std::string& get_svg_file() const { return m_data.svg_file; }
+#endif // ENABLE_SVG_ICONS
const std::string& get_tooltip() const { return m_data.tooltip; }
void do_action(wxEvtHandler *target);
@@ -96,6 +102,7 @@ private:
GLTexture::Quad_UVs get_uvs(unsigned int texture_size, unsigned int icon_size) const;
};
+#if !ENABLE_SVG_ICONS
// items icon textures are assumed to be square and all with the same size in pixels, no internal check is done
// icons are layed-out into the texture starting from the top-left corner in the same order as enum GLToolbarItem::EState
// from left to right
@@ -114,6 +121,7 @@ struct ItemsIconsTexture
GLTexture texture;
Metadata metadata;
};
+#endif // !ENABLE_SVG_ICONS
struct BackgroundTexture
{
@@ -140,6 +148,10 @@ struct BackgroundTexture
class GLToolbar
{
public:
+#if ENABLE_SVG_ICONS
+ static const float Default_Icons_Size;
+#endif // ENABLE_SVG_ICONS
+
enum EType : unsigned char
{
Normal,
@@ -173,7 +185,12 @@ public:
float border;
float separator_size;
float gap_size;
+#if ENABLE_SVG_ICONS
+ float icons_size;
+ float scale;
+#else
float icons_scale;
+#endif // ENABLE_SVG_ICONS
float width;
float height;
@@ -187,7 +204,12 @@ private:
EType m_type;
bool m_enabled;
+#if ENABLE_SVG_ICONS
+ mutable GLTexture m_icons_texture;
+ mutable bool m_icons_texture_dirty;
+#else
ItemsIconsTexture m_icons_texture;
+#endif // ENABLE_SVG_ICONS
BackgroundTexture m_background_texture;
mutable Layout m_layout;
@@ -197,7 +219,11 @@ public:
explicit GLToolbar(EType type);
~GLToolbar();
+#if ENABLE_SVG_ICONS
+ bool init(const BackgroundTexture::Metadata& background_texture);
+#else
bool init(const ItemsIconsTexture::Metadata& icons_texture, const BackgroundTexture::Metadata& background_texture);
+#endif // ENABLE_SVG_ICONS
Layout::EType get_layout_type() const;
void set_layout_type(Layout::EType type);
@@ -208,7 +234,12 @@ public:
void set_border(float border);
void set_separator_size(float size);
void set_gap_size(float size);
+#if ENABLE_SVG_ICONS
+ void set_icons_size(float size);
+ void set_scale(float scale);
+#else
void set_icons_scale(float scale);
+#endif // ENABLE_SVG_ICONS
bool is_enabled() const;
void set_enabled(bool enable);
@@ -253,6 +284,10 @@ private:
void render_horizontal(const GLCanvas3D& parent) const;
void render_vertical(const GLCanvas3D& parent) const;
+
+#if ENABLE_SVG_ICONS
+ bool generate_icons_texture() const;
+#endif // ENABLE_SVG_ICONS
};
} // namespace GUI
diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp
index 76d5f849a..eb02d622c 100644
--- a/src/slic3r/GUI/GUI_App.cpp
+++ b/src/slic3r/GUI/GUI_App.cpp
@@ -56,7 +56,7 @@ wxString file_wildcards(FileType file_type, const std::string &custom_extension)
/* FT_INI */ "INI files (*.ini)|*.ini;*.INI",
/* FT_SVG */ "SVG files (*.svg)|*.svg;*.SVG",
- /* FT_PNGZIP */"Zipped PNG files (*.dwz)|*.dwz;*.DWZ", // This is lame, but that's what we use for SLA
+ /* FT_PNGZIP */"Masked SLA files (*.sl1)|*.sl1;*.SL1",
};
std::string out = defaults[file_type];
diff --git a/src/slic3r/GUI/ImGuiWrapper.cpp b/src/slic3r/GUI/ImGuiWrapper.cpp
index 61baf352b..7f95b6c28 100644
--- a/src/slic3r/GUI/ImGuiWrapper.cpp
+++ b/src/slic3r/GUI/ImGuiWrapper.cpp
@@ -405,8 +405,8 @@ void ImGuiWrapper::init_style()
static const unsigned COL_GREY_DARK = 0x444444ff;
static const unsigned COL_GREY_LIGHT = 0x666666ff;
- static const unsigned COL_ORANGE_DARK = 0xba5418ff;
- static const unsigned COL_ORANGE_LIGHT = 0xff6f22ff;
+ static const unsigned COL_ORANGE_DARK = 0xc16737ff;
+ static const unsigned COL_ORANGE_LIGHT = 0xff7d38ff;
// Generics
set_color(ImGuiCol_TitleBgActive, COL_ORANGE_DARK);
diff --git a/src/slic3r/GUI/MainFrame.cpp b/src/slic3r/GUI/MainFrame.cpp
index 456811051..cddf081eb 100644
--- a/src/slic3r/GUI/MainFrame.cpp
+++ b/src/slic3r/GUI/MainFrame.cpp
@@ -557,9 +557,6 @@ void MainFrame::quick_slice(const int qs)
}
else if (qs & qsSaveAs) {
// The following line may die if the output_filename_format template substitution fails.
-// output_file = sprint->output_filepath;
-// if (export_svg)
-// output_file = ~s / \.[gG][cC][oO][dD][eE]$ / .svg /;
auto dlg = new wxFileDialog(this, _(L("Save ")) + (qs & qsExportSVG ? _(L("SVG")) : _(L("G-code"))) + _(L(" file as:")),
wxGetApp().app_config->get_last_output_dir(get_dir_name(output_file)), get_base_name(input_file),
qs & qsExportSVG ? file_wildcards(FT_SVG) : file_wildcards(FT_GCODE),
@@ -575,11 +572,9 @@ void MainFrame::quick_slice(const int qs)
wxGetApp().app_config->update_last_output_dir(get_dir_name(output_file));
}
else if (qs & qsExportPNG) {
-// output_file = sprint->output_filepath;
-// output_file = ~s / \.[gG][cC][oO][dD][eE]$ / .zip / ;
auto dlg = new wxFileDialog(this, _(L("Save zip file as:")),
wxGetApp().app_config->get_last_output_dir(get_dir_name(output_file)),
- get_base_name(output_file), "*.zip", wxFD_SAVE | wxFD_OVERWRITE_PROMPT);
+ get_base_name(output_file), "*.sl1", wxFD_SAVE | wxFD_OVERWRITE_PROMPT);
if (dlg->ShowModal() != wxID_OK) {
dlg->Destroy();
return;
diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp
index 256fc3a79..d17cce97d 100644
--- a/src/slic3r/GUI/Plater.cpp
+++ b/src/slic3r/GUI/Plater.cpp
@@ -2142,6 +2142,8 @@ void Plater::priv::export_gcode(fs::path output_path, PrintHostJob upload_job)
background_process.schedule_upload(std::move(upload_job));
}
+ // If the SLA processing of just a single object's supports is running, restart slicing for the whole object.
+ this->background_process.set_task(PrintBase::TaskParams());
this->restart_background_process(priv::UPDATE_BACKGROUND_PROCESS_FORCE_EXPORT);
}
@@ -2449,8 +2451,15 @@ void Plater::priv::on_right_click(Vec2dEvent& evt)
sidebar->obj_list()->append_menu_item_settings(menu);
- if (q != nullptr)
+ if (q != nullptr) {
+#ifdef __linux__
+ // For some reason on Linux the menu isn't displayed if position is specified
+ // (even though the position is sane).
+ q->PopupMenu(menu);
+#else
q->PopupMenu(menu, (int)evt.data.x(), (int)evt.data.y());
+#endif
+ }
}
void Plater::priv::on_wipetower_moved(Vec3dEvent &evt)
@@ -2614,9 +2623,11 @@ bool Plater::priv::complit_init_part_menu()
void Plater::priv::init_view_toolbar()
{
+#if !ENABLE_SVG_ICONS
ItemsIconsTexture::Metadata icons_data;
icons_data.filename = "view_toolbar.png";
icons_data.icon_size = 64;
+#endif // !ENABLE_SVG_ICONS
BackgroundTexture::Metadata background_data;
background_data.filename = "toolbar_background.png";
@@ -2625,7 +2636,11 @@ void Plater::priv::init_view_toolbar()
background_data.right = 16;
background_data.bottom = 16;
+#if ENABLE_SVG_ICONS
+ if (!view_toolbar.init(background_data))
+#else
if (!view_toolbar.init(icons_data, background_data))
+#endif // ENABLE_SVG_ICONS
return;
view_toolbar.set_layout_orientation(GLToolbar::Layout::Bottom);
@@ -2635,6 +2650,9 @@ void Plater::priv::init_view_toolbar()
GLToolbarItem::Data item;
item.name = "3D";
+#if ENABLE_SVG_ICONS
+ item.svg_file = "add.svg";
+#endif // ENABLE_SVG_ICONS
item.tooltip = GUI::L_str("3D editor view") + " [" + GUI::shortkey_ctrl_prefix() + "5]";
item.sprite_id = 0;
item.action_event = EVT_GLVIEWTOOLBAR_3D;
@@ -2643,6 +2661,9 @@ void Plater::priv::init_view_toolbar()
return;
item.name = "Preview";
+#if ENABLE_SVG_ICONS
+ item.svg_file = "remove.svg";
+#endif // ENABLE_SVG_ICONS
item.tooltip = GUI::L_str("Preview") + " [" + GUI::shortkey_ctrl_prefix() + "6]";
item.sprite_id = 1;
item.action_event = EVT_GLVIEWTOOLBAR_PREVIEW;
@@ -3066,6 +3087,8 @@ void Plater::reslice()
unsigned int state = this->p->update_background_process(true);
if (state & priv::UPDATE_BACKGROUND_PROCESS_REFRESH_SCENE)
this->p->view3D->reload_scene(false);
+ // If the SLA processing of just a single object's supports is running, restart slicing for the whole object.
+ this->p->background_process.set_task(PrintBase::TaskParams());
// Only restarts if the state is valid.
this->p->restart_background_process(state | priv::UPDATE_BACKGROUND_PROCESS_FORCE_RESTART);
}
diff --git a/src/slic3r/GUI/Preset.cpp b/src/slic3r/GUI/Preset.cpp
index 86d5db2a7..ccccf7626 100644
--- a/src/slic3r/GUI/Preset.cpp
+++ b/src/slic3r/GUI/Preset.cpp
@@ -465,6 +465,7 @@ const std::vector& Preset::sla_print_options()
"pad_wall_height",
"pad_max_merge_distance",
"pad_edge_radius",
+ "pad_wall_slope",
"output_filename_format",
"default_sla_print_profile",
"compatible_printers",
diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp
index 7e9a0c3a2..b52ddbf48 100644
--- a/src/slic3r/GUI/Tab.cpp
+++ b/src/slic3r/GUI/Tab.cpp
@@ -3288,7 +3288,9 @@ void TabSLAPrint::build()
optgroup->append_single_option_line("pad_wall_thickness");
optgroup->append_single_option_line("pad_wall_height");
optgroup->append_single_option_line("pad_max_merge_distance");
- optgroup->append_single_option_line("pad_edge_radius");
+ // TODO: Disabling this parameter for the beta release
+// optgroup->append_single_option_line("pad_edge_radius");
+ optgroup->append_single_option_line("pad_wall_slope");
page = add_options_page(_(L("Output options")), "page_white_go.png");
optgroup = page->new_optgroup(_(L("Output file")));