Fixed conflicts after merge with master

This commit is contained in:
Enrico Turri 2019-04-02 15:13:26 +02:00
commit 89a0c84c83
26 changed files with 368 additions and 256 deletions

View File

@ -246,6 +246,7 @@ public:
const Vec3d& get_mirror() const { return m_mirror; }
double get_mirror(Axis axis) const { return m_mirror(axis); }
bool is_left_handed() const { return m_mirror.x() * m_mirror.y() * m_mirror.z() < 0.; }
void set_mirror(const Vec3d& mirror);
void set_mirror(Axis axis, double mirror);

View File

@ -258,13 +258,18 @@ void LayerRegion::process_external_surfaces(const Layer* lower_layer)
#ifdef SLIC3R_DEBUG
printf("Processing bridge at layer " PRINTF_ZU ":\n", this->layer()->id());
#endif
if (bd.detect_angle(Geometry::deg2rad(this->region()->config().bridge_angle.value))) {
double custom_angle = Geometry::deg2rad(this->region()->config().bridge_angle.value);
if (bd.detect_angle(custom_angle)) {
bridges[idx_last].bridge_angle = bd.angle;
if (this->layer()->object()->config().support_material) {
polygons_append(this->bridged, bd.coverage());
this->unsupported_bridge_edges.append(bd.unsupported_edges());
}
}
} else if (custom_angle > 0) {
// Bridge was not detected (likely it is only supported at one side). Still it is a surface filled in
// using a bridging flow, therefore it makes sense to respect the custom bridging direction.
bridges[idx_last].bridge_angle = custom_angle;
}
// without safety offset, artifacts are generated (GH #2494)
surfaces_append(bottom, union_ex(grown, true), bridges[idx_last]);
}

View File

@ -394,6 +394,7 @@ public:
const Vec3d& get_mirror() const { return m_transformation.get_mirror(); }
double get_mirror(Axis axis) const { return m_transformation.get_mirror(axis); }
bool is_left_handed() const { return m_transformation.is_left_handed(); }
void set_mirror(const Vec3d& mirror) { m_transformation.set_mirror(mirror); }
void set_mirror(Axis axis, double mirror) { m_transformation.set_mirror(axis, mirror); }
@ -498,6 +499,7 @@ public:
const Vec3d& get_mirror() const { return m_transformation.get_mirror(); }
double get_mirror(Axis axis) const { return m_transformation.get_mirror(axis); }
bool is_left_handed() const { return m_transformation.is_left_handed(); }
void set_mirror(const Vec3d& mirror) { m_transformation.set_mirror(mirror); }
void set_mirror(Axis axis, double mirror) { m_transformation.set_mirror(axis, mirror); }

View File

@ -6,7 +6,7 @@
#include <vector>
#include <cstdint>
namespace ClipperLib { class Polygon; }
namespace ClipperLib { struct Polygon; }
namespace Slic3r {

View File

@ -49,8 +49,8 @@ float SLAAutoSupports::distance_limit(float angle) const
}*/
SLAAutoSupports::SLAAutoSupports(const TriangleMesh& mesh, const sla::EigenMesh3D& emesh, const std::vector<ExPolygons>& slices, const std::vector<float>& heights,
const Config& config, std::function<void(void)> throw_on_cancel)
: m_config(config), m_emesh(emesh), m_throw_on_cancel(throw_on_cancel)
const Config& config, std::function<void(void)> throw_on_cancel, std::function<void(int)> statusfn)
: m_config(config), m_emesh(emesh), m_throw_on_cancel(throw_on_cancel), m_statusfn(statusfn)
{
process(slices, heights);
project_onto_mesh(m_output);
@ -197,6 +197,9 @@ void SLAAutoSupports::process(const std::vector<ExPolygons>& slices, const std::
PointGrid3D point_grid;
point_grid.cell_size = Vec3f(10.f, 10.f, 10.f);
double increment = 100.0 / layers.size();
double status = 0;
for (unsigned int layer_id = 0; layer_id < layers.size(); ++ layer_id) {
SLAAutoSupports::MyLayer *layer_top = &layers[layer_id];
SLAAutoSupports::MyLayer *layer_bottom = (layer_id > 0) ? &layers[layer_id - 1] : nullptr;
@ -252,6 +255,9 @@ void SLAAutoSupports::process(const std::vector<ExPolygons>& slices, const std::
m_throw_on_cancel();
status += increment;
m_statusfn(int(std::round(status)));
#ifdef SLA_AUTOSUPPORTS_DEBUG
/*std::string layer_num_str = std::string((i<10 ? "0" : "")) + std::string((i<100 ? "0" : "")) + std::to_string(i);
output_expolygons(expolys_top, "top" + layer_num_str + ".svg");

View File

@ -24,7 +24,7 @@ public:
};
SLAAutoSupports(const TriangleMesh& mesh, const sla::EigenMesh3D& emesh, const std::vector<ExPolygons>& slices,
const std::vector<float>& heights, const Config& config, std::function<void(void)> throw_on_cancel);
const std::vector<float>& heights, const Config& config, std::function<void(void)> throw_on_cancel, std::function<void(int)> statusfn);
const std::vector<sla::SupportPoint>& output() { return m_output; }
struct MyLayer;
@ -196,12 +196,13 @@ private:
static void output_structures(const std::vector<Structure> &structures);
#endif // SLA_AUTOSUPPORTS_DEBUG
std::function<void(void)> m_throw_on_cancel;
const sla::EigenMesh3D& m_emesh;
std::function<void(void)> m_throw_on_cancel;
std::function<void(int)> m_statusfn;
};
} // namespace Slic3r
#endif // SLAAUTOSUPPORTS_HPP_
#endif // SLAAUTOSUPPORTS_HPP_

View File

@ -42,17 +42,17 @@ namespace {
// should add up to 100 (%)
const std::array<unsigned, slaposCount> OBJ_STEP_LEVELS =
{
10, // slaposObjectSlice,
30, // slaposSupportPoints,
25, // slaposSupportTree,
25, // slaposBasePool,
10, // slaposSliceSupports,
30, // slaposObjectSlice,
20, // slaposSupportPoints,
10, // slaposSupportTree,
10, // slaposBasePool,
30, // slaposSliceSupports,
};
const std::array<std::string, slaposCount> OBJ_STEP_LABELS =
{
L("Slicing model"), // slaposObjectSlice,
L("Generating support points"), // slaposSupportPoints,
L("Generating support points"), // slaposSupportPoints,
L("Generating support tree"), // slaposSupportTree,
L("Generating pad"), // slaposBasePool,
L("Slicing supports"), // slaposSliceSupports,
@ -61,8 +61,8 @@ const std::array<std::string, slaposCount> OBJ_STEP_LABELS =
// Should also add up to 100 (%)
const std::array<unsigned, slapsCount> PRINT_STEP_LEVELS =
{
5, // slapsStats
95, // slapsRasterize
10, // slapsMergeSlicesAndEval
90, // slapsRasterize
};
const std::array<std::string, slapsCount> PRINT_STEP_LABELS =
@ -93,7 +93,10 @@ static Transform3d sla_trafo(const ModelObject &model_object)
offset(0) = 0.;
offset(1) = 0.;
rotation(2) = 0.;
return Geometry::assemble_transform(offset, rotation, model_instance.get_scaling_factor(), model_instance.get_mirror());
Transform3d trafo = Geometry::assemble_transform(offset, rotation, model_instance.get_scaling_factor(), model_instance.get_mirror());
if (model_instance.is_left_handed())
trafo = Eigen::Scaling(Vec3d(-1., 1., 1.)) * trafo;
return trafo;
}
// List of instances, where the ModelInstance transformation is a composite of sla_trafo and the transformation defined by SLAPrintObject::Instance.
@ -399,7 +402,7 @@ SLAPrint::ApplyStatus SLAPrint::apply(const Model &model, const DynamicPrintConf
// FIXME: this invalidates the transformed mesh in SLAPrintObject
// which is expensive to calculate (especially the raw_mesh() call)
print_object->set_trafo(sla_trafo(model_object));
print_object->set_trafo(sla_trafo(model_object), model_object.instances.front()->is_left_handed());
print_object->set_instances(new_instances);
print_object->config_apply(config, true);
@ -619,14 +622,6 @@ bool SLAPrint::invalidate_step(SLAPrintStep step)
return invalidated;
}
template<class...Args>
void report_status(SLAPrint& p, int st, const std::string& msg, Args&&...args)
{
BOOST_LOG_TRIVIAL(info) << st << "% " << msg;
p.set_status(st, msg, std::forward<Args>(args)...);
}
void SLAPrint::process()
{
using namespace sla;
@ -645,7 +640,7 @@ void SLAPrint::process()
const size_t objcount = m_objects.size();
const unsigned min_objstatus = 0; // where the per object operations start
const unsigned max_objstatus = PRINT_STEP_LEVELS[slapsMergeSlicesAndEval]; // where the per object operations end
const unsigned max_objstatus = 50; // where the per object operations end
// the coefficient that multiplies the per object status values which
// are set up for <0, 100>. They need to be scaled into the whole process
@ -720,7 +715,7 @@ void SLAPrint::process()
// In this step we check the slices, identify island and cover them with
// support points. Then we sprinkle the rest of the mesh.
auto support_points = [this](SLAPrintObject& po) {
auto support_points = [this, ostepd](SLAPrintObject& po) {
const ModelObject& mo = *po.m_model_object;
po.m_supportdata.reset(
new SLAPrintObject::SupportData(po.transformed_mesh()) );
@ -754,6 +749,19 @@ void SLAPrint::process()
config.minimal_distance = float(cfg.support_points_minimal_distance);
config.head_diameter = float(cfg.support_head_front_diameter);
// scaling for the sub operations
double d = ostepd * OBJ_STEP_LEVELS[slaposSupportPoints] / 100.0;
double init = m_report_status.status();
auto statuscb = [this, d, init](unsigned st)
{
double current = init + st * d;
if(std::round(m_report_status.status()) < std::round(current))
m_report_status(*this, current,
OBJ_STEP_LABELS[slaposSupportPoints]);
};
// Construction of this object does the calculation.
this->throw_if_canceled();
SLAAutoSupports auto_supports(po.transformed_mesh(),
@ -761,7 +769,8 @@ void SLAPrint::process()
po.get_model_slices(),
heights,
config,
[this]() { throw_if_canceled(); });
[this]() { throw_if_canceled(); },
statuscb);
// Now let's extract the result.
const std::vector<sla::SupportPoint>& points = auto_supports.output();
@ -772,7 +781,7 @@ void SLAPrint::process()
<< po.m_supportdata->support_points.size();
// Using RELOAD_SLA_SUPPORT_POINTS to tell the Plater to pass the update status to GLGizmoSlaSupports
report_status(*this, -1, L("Generating support points"), SlicingStatus::RELOAD_SLA_SUPPORT_POINTS);
m_report_status(*this, -1, L("Generating support points"), SlicingStatus::RELOAD_SLA_SUPPORT_POINTS);
}
else {
// There are either some points on the front-end, or the user removed them on purpose. No calculation will be done.
@ -781,7 +790,8 @@ void SLAPrint::process()
};
// In this step we create the supports
auto support_tree = [this, objcount, ostepd](SLAPrintObject& po) {
auto support_tree = [this, ostepd](SLAPrintObject& po)
{
if(!po.m_supportdata) return;
if(!po.m_config.supports_enable.getBool()) {
@ -793,22 +803,17 @@ void SLAPrint::process()
sla::SupportConfig scfg = make_support_cfg(po.m_config);
sla::Controller ctl;
// some magic to scale the status values coming from the support
// tree creation into the whole print process
auto stfirst = OBJ_STEP_LEVELS.begin();
auto stthis = stfirst + slaposSupportTree;
// we need to add up the status portions until this operation
int init = std::accumulate(stfirst, stthis, 0);
init = int(init * ostepd); // scale the init portion
// scaling for the sub operations
double d = *stthis / (objcount * 100.0);
double d = ostepd * OBJ_STEP_LEVELS[slaposSupportTree] / 100.0;
double init = m_report_status.status();
ctl.statuscb = [this, init, d](unsigned st, const std::string& msg)
ctl.statuscb = [this, d, init](unsigned st, const std::string&)
{
//FIXME this status line scaling does not seem to be correct.
// How does it account for an increasing object index?
report_status(*this, int(init + st*d), msg);
double current = init + st * d;
if(std::round(m_report_status.status()) < std::round(current))
m_report_status(*this, current,
OBJ_STEP_LABELS[slaposSupportTree]);
};
ctl.stopcondition = [this](){ return canceled(); };
@ -824,7 +829,7 @@ void SLAPrint::process()
auto rc = SlicingStatus::RELOAD_SCENE;
// This is to prevent "Done." being displayed during merged_mesh()
report_status(*this, -1, L("Visualizing supports"));
m_report_status(*this, -1, L("Visualizing supports"));
po.m_supportdata->support_tree_ptr->merged_mesh();
BOOST_LOG_TRIVIAL(debug) << "Processed support point count "
@ -834,8 +839,7 @@ void SLAPrint::process()
if(po.support_mesh().empty())
BOOST_LOG_TRIVIAL(warning) << "Support mesh is empty";
report_status(*this, -1, L("Visualizing supports"), rc);
m_report_status(*this, -1, L("Visualizing supports"), rc);
};
// This step generates the sla base pad
@ -883,7 +887,7 @@ void SLAPrint::process()
po.throw_if_canceled();
auto rc = SlicingStatus::RELOAD_SCENE;
report_status(*this, -1, L("Visualizing supports"), rc);
m_report_status(*this, -1, L("Visualizing supports"), rc);
};
// Slicing the support geometries similarly to the model slicing procedure.
@ -914,7 +918,7 @@ void SLAPrint::process()
}
// Using RELOAD_SLA_PREVIEW to tell the Plater to pass the update status to the 3D preview to load the SLA slices.
report_status(*this, -2, "", SlicingStatus::RELOAD_SLA_PREVIEW);
m_report_status(*this, -2, "", SlicingStatus::RELOAD_SLA_PREVIEW);
};
// Merging the slices from all the print objects into one slice grid and
@ -1213,7 +1217,7 @@ void SLAPrint::process()
m_print_statistics.fast_layers_count = fast_layers;
m_print_statistics.slow_layers_count = slow_layers;
report_status(*this, -2, "", SlicingStatus::RELOAD_SLA_PREVIEW);
m_report_status(*this, -2, "", SlicingStatus::RELOAD_SLA_PREVIEW);
};
// Rasterizing the model objects, and their supports
@ -1252,18 +1256,24 @@ void SLAPrint::process()
auto lvlcnt = unsigned(m_printer_input.size());
printer.layers(lvlcnt);
// slot is the portion of 100% that is realted to rasterization
unsigned slot = PRINT_STEP_LEVELS[slapsRasterize];
// ist: initial state; pst: previous state
unsigned ist = max_objstatus, pst = ist;
// coefficient to map the rasterization state (0-99) to the allocated
// portion (slot) of the process state
double sd = (100 - ist) / 100.0;
double sd = (100 - max_objstatus) / 100.0;
// slot is the portion of 100% that is realted to rasterization
unsigned slot = PRINT_STEP_LEVELS[slapsRasterize];
// pst: previous state
double pst = m_report_status.status();
double increment = (slot * sd) / m_printer_input.size();
double dstatus = m_report_status.status();
SpinMutex slck;
// procedure to process one height level. This will run in parallel
auto lvlfn =
[this, &slck, &printer, slot, sd, ist, &pst]
[this, &slck, &printer, increment, &dstatus, &pst]
(unsigned level_id)
{
if(canceled()) return;
@ -1280,12 +1290,13 @@ void SLAPrint::process()
printer.finish_layer(level_id);
// Status indication guarded with the spinlock
auto st = ist + unsigned(sd*level_id*slot/m_printer_input.size());
{
std::lock_guard<SpinMutex> lck(slck);
if( st > pst) {
report_status(*this, int(st),
PRINT_STEP_LABELS[slapsRasterize]);
dstatus += increment;
double st = std::round(dstatus);
if(st > pst) {
m_report_status(*this, st,
PRINT_STEP_LABELS[slapsRasterize]);
pst = st;
}
}
@ -1326,7 +1337,7 @@ void SLAPrint::process()
rasterize
};
unsigned st = min_objstatus;
double st = min_objstatus;
unsigned incr = 0;
BOOST_LOG_TRIVIAL(info) << "Start slicing process.";
@ -1340,18 +1351,18 @@ void SLAPrint::process()
BOOST_LOG_TRIVIAL(info) << "Slicing object " << po->model_object()->name;
for (int s = (int)step_ranges[idx_range]; s < (int)step_ranges[idx_range + 1]; ++s) {
auto currentstep = (SLAPrintObjectStep)s;
for (int s = int(step_ranges[idx_range]); s < int(step_ranges[idx_range + 1]); ++s) {
auto currentstep = static_cast<SLAPrintObjectStep>(s);
// Cancellation checking. Each step will check for cancellation
// on its own and return earlier gracefully. Just after it returns
// execution gets to this point and throws the canceled signal.
throw_if_canceled();
st += unsigned(incr * ostepd);
st += incr * ostepd;
if(po->m_stepmask[currentstep] && po->set_started(currentstep)) {
report_status(*this, int(st), OBJ_STEP_LABELS[currentstep]);
m_report_status(*this, st, OBJ_STEP_LABELS[currentstep]);
pobj_program[currentstep](*po);
throw_if_canceled();
po->set_done(currentstep);
@ -1378,17 +1389,17 @@ void SLAPrint::process()
if(m_stepmask[currentstep] && set_started(currentstep))
{
report_status(*this, int(st), PRINT_STEP_LABELS[currentstep]);
m_report_status(*this, st, PRINT_STEP_LABELS[currentstep]);
print_program[currentstep]();
throw_if_canceled();
set_done(currentstep);
}
st += unsigned(PRINT_STEP_LEVELS[currentstep] * pstd);
st += PRINT_STEP_LEVELS[currentstep] * pstd;
}
// If everything vent well
report_status(*this, 100, L("Slicing done"));
m_report_status(*this, 100, L("Slicing done"));
}
bool SLAPrint::invalidate_state_by_config_options(const std::vector<t_config_option_key> &opt_keys)
@ -1712,7 +1723,8 @@ DynamicConfig SLAPrintStatistics::placeholders()
"print_time", "total_cost", "total_weight",
"objects_used_material", "support_used_material" })
config.set_key_value(key, new ConfigOptionString(std::string("{") + key + "}"));
return config;
return config;
}
std::string SLAPrintStatistics::finalize_output_path(const std::string &path_in) const
@ -1732,4 +1744,12 @@ std::string SLAPrintStatistics::finalize_output_path(const std::string &path_in)
return final_path;
}
void SLAPrint::StatusReporter::operator()(
SLAPrint &p, double st, const std::string &msg, unsigned flags)
{
m_st = st;
BOOST_LOG_TRIVIAL(info) << st << "% " << msg;
p.set_status(int(std::round(st)), msg, flags);
}
} // namespace Slic3r

View File

@ -51,6 +51,7 @@ public:
const SLAPrintObjectConfig& config() const { return m_config; }
const Transform3d& trafo() const { return m_trafo; }
bool is_left_handed() const { return m_left_handed; }
struct Instance {
Instance(ModelID instance_id, const Point &shift, float rotation) : instance_id(instance_id), shift(shift), rotation(rotation) {}
@ -241,8 +242,8 @@ protected:
void config_apply_only(const ConfigBase &other, const t_config_option_keys &keys, bool ignore_nonexistent = false)
{ this->m_config.apply_only(other, keys, ignore_nonexistent); }
void set_trafo(const Transform3d& trafo) {
m_transformed_rmesh.invalidate([this, &trafo](){ m_trafo = trafo; });
void set_trafo(const Transform3d& trafo, bool left_handed) {
m_transformed_rmesh.invalidate([this, &trafo, left_handed](){ m_trafo = trafo; m_left_handed = left_handed; });
}
void set_instances(const std::vector<Instance> &instances) { m_instances = instances; }
@ -262,6 +263,8 @@ private:
// Translation in Z + Rotation by Y and Z + Scaling / Mirroring.
Transform3d m_trafo = Transform3d::Identity();
// m_trafo is left handed -> 3x3 affine transformation has negative determinant.
bool m_left_handed = false;
std::vector<Instance> m_instances;
@ -471,6 +474,15 @@ private:
// Estimated print time, material consumed.
SLAPrintStatistics m_print_statistics;
class StatusReporter {
double m_st = 0;
public:
void operator() (SLAPrint& p, double st, const std::string& msg,
unsigned flags = SlicingStatus::DEFAULT);
double status() const { return m_st; }
} m_report_status;
friend SLAPrintObject;
};

View File

@ -343,7 +343,7 @@ void TriangleMesh::rotate(double angle, Point* center)
*/
bool TriangleMesh::is_splittable() const
{
std::vector<bool> visited;
std::vector<unsigned char> visited;
find_unvisited_neighbors(visited);
// Try finding an unvisited facet. If there are none, the mesh is not splittable.
@ -359,36 +359,37 @@ bool TriangleMesh::is_splittable() const
* facet with the same index has been visited.
* @return A deque with all newly visited facets.
*/
std::deque<uint32_t> TriangleMesh::find_unvisited_neighbors(std::vector<bool> &facet_visited) const
std::deque<uint32_t> TriangleMesh::find_unvisited_neighbors(std::vector<unsigned char> &facet_visited) const
{
// Make sure we're not operating on a broken mesh.
if (!this->repaired)
throw std::runtime_error("split() requires repair()");
throw std::runtime_error("find_unvisited_neighbors() requires repair()");
// If the visited list is empty, populate it with false for every facet.
if (facet_visited.empty()) {
facet_visited = std::vector<bool>(this->stl.stats.number_of_facets, false);
}
if (facet_visited.empty())
facet_visited = std::vector<unsigned char>(this->stl.stats.number_of_facets, false);
// Find the first unvisited facet.
std::queue<int> facet_queue;
std::queue<uint32_t> facet_queue;
std::deque<uint32_t> facets;
auto facet = std::find(facet_visited.begin(), facet_visited.end(), false);
if (facet != facet_visited.end())
facet_queue.push(facet - facet_visited.begin());
if (facet != facet_visited.end()) {
uint32_t idx = uint32_t(facet - facet_visited.begin());
facet_queue.push(idx);
facet_visited[idx] = true;
facets.emplace_back(idx);
}
// Traverse all reachable neighbors and mark them as visited.
std::deque<uint32_t> facets;
while (!facet_queue.empty()) {
int facet_idx = facet_queue.front();
while (! facet_queue.empty()) {
uint32_t facet_idx = facet_queue.front();
facet_queue.pop();
if (facet_idx != -1 && !facet_visited[facet_idx]) {
facet_visited[facet_idx] = true;
facets.emplace_back(facet_idx);
for (int facet : this->stl.neighbors_start[facet_idx].neighbor)
facet_queue.push(facet);
}
for (int neighbor_idx : this->stl.neighbors_start[facet_idx].neighbor)
if (neighbor_idx != -1 && ! facet_visited[neighbor_idx]) {
facet_queue.push(uint32_t(neighbor_idx));
facet_visited[neighbor_idx] = true;
facets.emplace_back(uint32_t(neighbor_idx));
}
}
return facets;
@ -402,7 +403,7 @@ std::deque<uint32_t> TriangleMesh::find_unvisited_neighbors(std::vector<bool> &f
TriangleMeshPtrs TriangleMesh::split() const
{
// Loop while we have remaining facets.
std::vector<bool> facet_visited;
std::vector<unsigned char> facet_visited;
TriangleMeshPtrs meshes;
for (;;) {
std::deque<uint32_t> facets = find_unvisited_neighbors(facet_visited);

View File

@ -69,13 +69,13 @@ public:
bool empty() const { return this->facets_count() == 0; }
bool is_splittable() const;
std::deque<uint32_t> find_unvisited_neighbors(std::vector<bool> &facet_visited) const;
stl_file stl;
bool repaired;
private:
void require_shared_vertices();
std::deque<uint32_t> find_unvisited_neighbors(std::vector<unsigned char> &facet_visited) const;
friend class TriangleMeshSlicer;
};

View File

@ -334,6 +334,13 @@ Transform3d GLVolume::world_matrix() const
return m;
}
bool GLVolume::is_left_handed() const
{
const Vec3d &m1 = m_instance_transformation.get_mirror();
const Vec3d &m2 = m_volume_transformation.get_mirror();
return m1.x() * m1.y() * m1.z() * m2.x() * m2.y() * m2.z() < 0.;
}
const BoundingBoxf3& GLVolume::transformed_bounding_box() const
{
assert(bounding_box.defined || bounding_box.min(0) >= bounding_box.max(0) || bounding_box.min(1) >= bounding_box.max(1) || bounding_box.min(2) >= bounding_box.max(2));
@ -402,6 +409,8 @@ void GLVolume::render() const
if (!is_active)
return;
if (this->is_left_handed())
glFrontFace(GL_CW);
glsafe(::glCullFace(GL_BACK));
glsafe(::glPushMatrix());
@ -411,6 +420,8 @@ void GLVolume::render() const
else
this->indexed_vertex_array.render();
glsafe(::glPopMatrix());
if (this->is_left_handed())
glFrontFace(GL_CCW);
}
void GLVolume::render_VBOs(int color_id, int detection_id, int worldmatrix_id) const
@ -421,6 +432,9 @@ void GLVolume::render_VBOs(int color_id, int detection_id, int worldmatrix_id) c
if (!indexed_vertex_array.vertices_and_normals_interleaved_VBO_id)
return;
if (this->is_left_handed())
glFrontFace(GL_CW);
GLsizei n_triangles = GLsizei(std::min(indexed_vertex_array.triangle_indices_size, tverts_range.second - tverts_range.first));
GLsizei n_quads = GLsizei(std::min(indexed_vertex_array.quad_indices_size, qverts_range.second - qverts_range.first));
if (n_triangles + n_quads == 0)
@ -482,6 +496,9 @@ void GLVolume::render_VBOs(int color_id, int detection_id, int worldmatrix_id) c
}
glsafe(::glPopMatrix());
if (this->is_left_handed())
glFrontFace(GL_CCW);
}
void GLVolume::render_legacy() const
@ -490,6 +507,9 @@ void GLVolume::render_legacy() const
if (!is_active)
return;
if (this->is_left_handed())
glFrontFace(GL_CW);
GLsizei n_triangles = GLsizei(std::min(indexed_vertex_array.triangle_indices_size, tverts_range.second - tverts_range.first));
GLsizei n_quads = GLsizei(std::min(indexed_vertex_array.quad_indices_size, qverts_range.second - qverts_range.first));
if (n_triangles + n_quads == 0)
@ -521,6 +541,9 @@ void GLVolume::render_legacy() const
glsafe(::glDrawElements(GL_QUADS, n_quads, GL_UNSIGNED_INT, indexed_vertex_array.quad_indices.data() + qverts_range.first));
glsafe(::glPopMatrix());
if (this->is_left_handed())
glFrontFace(GL_CCW);
}
std::vector<int> GLVolumeCollection::load_object(

View File

@ -390,6 +390,7 @@ public:
int instance_idx() const { return this->composite_id.instance_id; }
Transform3d world_matrix() const;
bool is_left_handed() const;
const BoundingBoxf3& transformed_bounding_box() const;
const BoundingBoxf3& transformed_convex_hull_bounding_box() const;

View File

@ -59,6 +59,8 @@ enum {
USB_PID_MK3 = 2,
USB_PID_MMU_BOOT = 3,
USB_PID_MMU_APP = 4,
USB_PID_CW1_BOOT = 7,
USB_PID_CW1_APP = 8,
};
// This enum discriminates the kind of information in EVT_AVRDUDE,
@ -77,6 +79,13 @@ wxDEFINE_EVENT(EVT_AVRDUDE, wxCommandEvent);
wxDECLARE_EVENT(EVT_ASYNC_DIALOG, wxCommandEvent);
wxDEFINE_EVENT(EVT_ASYNC_DIALOG, wxCommandEvent);
struct Avr109Pid
{
unsigned boot;
unsigned app;
Avr109Pid(unsigned boot, unsigned app) : boot(boot), app(app) {}
};
// Private
@ -146,24 +155,40 @@ struct FirmwareDialog::priv
void flashing_done(AvrDudeComplete complete);
void enable_port_picker(bool enable);
void load_hex_file(const wxString &path);
void queue_status(wxString message);
void queue_error(const wxString &message);
void queue_event(AvrdudeEvent aevt, wxString message);
bool ask_model_id_mismatch(const std::string &printer_model);
bool check_model_id();
void wait_for_mmu_bootloader(unsigned retries);
void mmu_reboot(const SerialPortInfo &port);
void lookup_port_mmu();
void avr109_wait_for_bootloader(Avr109Pid usb_pid, unsigned retries);
void avr109_reboot(const SerialPortInfo &port);
void avr109_lookup_port(Avr109Pid usb_pid);
void prepare_common();
void prepare_mk2();
void prepare_mk3();
void prepare_mm_control();
void prepare_avr109(Avr109Pid usb_pid);
void perform_upload();
void user_cancel();
void on_avrdude(const wxCommandEvent &evt);
void on_async_dialog(const wxCommandEvent &evt);
void ensure_joined();
void queue_status(wxString message) { queue_event(AE_STATUS, std::move(message)); }
template<class ...Args> void queue_message(const wxString &format, Args... args) {
auto message = wxString::Format(format, args...);
BOOST_LOG_TRIVIAL(info) << message;
message.Append('\n');
queue_event(AE_MESSAGE, std::move(message));
}
template<class ...Args> void queue_error(const wxString &format, Args... args) {
queue_message(format, args...);
queue_event(AE_STATUS, _(L("Flashing failed: ")) + wxString::Format(format, args...));
avrdude->cancel();
}
static const char* avr109_dev_name(Avr109Pid usb_pid);
};
void FirmwareDialog::priv::find_serial_ports()
@ -259,26 +284,18 @@ void FirmwareDialog::priv::enable_port_picker(bool enable)
void FirmwareDialog::priv::load_hex_file(const wxString &path)
{
hex_file = HexFile(path.wx_str());
enable_port_picker(hex_file.device != HexFile::DEV_MM_CONTROL);
const bool auto_lookup = hex_file.device == HexFile::DEV_MM_CONTROL || hex_file.device == HexFile::DEV_CW1;
enable_port_picker(! auto_lookup);
}
void FirmwareDialog::priv::queue_status(wxString message)
void FirmwareDialog::priv::queue_event(AvrdudeEvent aevt, wxString message)
{
auto evt = new wxCommandEvent(EVT_AVRDUDE, this->q->GetId());
evt->SetExtraLong(AE_STATUS);
evt->SetExtraLong(aevt);
evt->SetString(std::move(message));
wxQueueEvent(this->q, evt);
}
void FirmwareDialog::priv::queue_error(const wxString &message)
{
auto evt = new wxCommandEvent(EVT_AVRDUDE, this->q->GetId());
evt->SetExtraLong(AE_STATUS);
evt->SetString(wxString::Format(_(L("Flashing failed: %s")), message));
wxQueueEvent(this->q, evt); avrdude->cancel();
}
bool FirmwareDialog::priv::ask_model_id_mismatch(const std::string &printer_model)
{
// model_id in the hex file doesn't match what the printer repoted.
@ -356,7 +373,7 @@ bool FirmwareDialog::priv::check_model_id()
// return false;
}
void FirmwareDialog::priv::wait_for_mmu_bootloader(unsigned retries)
void FirmwareDialog::priv::avr109_wait_for_bootloader(Avr109Pid usb_pid, unsigned retries)
{
enum {
SLEEP_MS = 500,
@ -367,61 +384,63 @@ void FirmwareDialog::priv::wait_for_mmu_bootloader(unsigned retries)
auto ports = Utils::scan_serial_ports_extended();
ports.erase(std::remove_if(ports.begin(), ports.end(), [=](const SerialPortInfo &port ) {
return port.id_vendor != USB_VID_PRUSA || port.id_product != USB_PID_MMU_BOOT;
return port.id_vendor != USB_VID_PRUSA || port.id_product != usb_pid.boot;
}), ports.end());
if (ports.size() == 1) {
port = ports[0];
return;
} else if (ports.size() > 1) {
BOOST_LOG_TRIVIAL(error) << "Several VID/PID 0x2c99/3 devices found";
queue_error(_(L("Multiple Original Prusa i3 MMU 2.0 devices found. Please only connect one at a time for flashing.")));
queue_message("Several VID/PID 0x2c99/%u devices found", usb_pid.boot);
queue_error(_(L("Multiple %s devices found. Please only connect one at a time for flashing.")), avr109_dev_name(usb_pid));
return;
}
}
}
void FirmwareDialog::priv::mmu_reboot(const SerialPortInfo &port)
void FirmwareDialog::priv::avr109_reboot(const SerialPortInfo &port)
{
asio::io_service io;
Serial serial(io, port.port, 1200);
std::this_thread::sleep_for(std::chrono::milliseconds(50));
}
void FirmwareDialog::priv::lookup_port_mmu()
void FirmwareDialog::priv::avr109_lookup_port(Avr109Pid usb_pid)
{
static const auto msg_not_found =
"The Multi Material Control device was not found.\n"
"If the device is connected, please press the Reset button next to the USB connector ...";
const char *dev_name = avr109_dev_name(usb_pid);
const wxString msg_not_found = wxString::Format(
_(L("The %s device was not found.\n"
"If the device is connected, please press the Reset button next to the USB connector ...")),
dev_name);
BOOST_LOG_TRIVIAL(info) << "Flashing MMU 2.0, looking for VID/PID 0x2c99/3 or 0x2c99/4 ...";
queue_message("Flashing %s, looking for VID/PID 0x2c99/%u or 0x2c99/%u ...", dev_name, usb_pid.boot, usb_pid.app);
auto ports = Utils::scan_serial_ports_extended();
ports.erase(std::remove_if(ports.begin(), ports.end(), [=](const SerialPortInfo &port ) {
return port.id_vendor != USB_VID_PRUSA ||
port.id_product != USB_PID_MMU_BOOT &&
port.id_product != USB_PID_MMU_APP;
port.id_product != usb_pid.boot &&
port.id_product != usb_pid.app;
}), ports.end());
if (ports.size() == 0) {
BOOST_LOG_TRIVIAL(info) << "MMU 2.0 device not found, asking the user to press Reset and waiting for the device to show up ...";
queue_status(_(L(msg_not_found)));
wait_for_mmu_bootloader(30);
queue_message("The %s device was not found.", dev_name);
queue_status(msg_not_found);
avr109_wait_for_bootloader(usb_pid, 30);
} else if (ports.size() > 1) {
BOOST_LOG_TRIVIAL(error) << "Several VID/PID 0x2c99/3 devices found";
queue_error(_(L("Multiple Original Prusa i3 MMU 2.0 devices found. Please only connect one at a time for flashing.")));
queue_message("Several VID/PID 0x2c99/%u devices found", usb_pid.boot);
queue_error(_(L("Multiple %s devices found. Please only connect one at a time for flashing.")), dev_name);
} else {
if (ports[0].id_product == USB_PID_MMU_APP) {
if (ports[0].id_product == usb_pid.app) {
// The device needs to be rebooted into the bootloader mode
BOOST_LOG_TRIVIAL(info) << boost::format("Found VID/PID 0x2c99/4 at `%1%`, rebooting the device ...") % ports[0].port;
mmu_reboot(ports[0]);
wait_for_mmu_bootloader(10);
queue_message("Found VID/PID 0x2c99/%u at `%s`, rebooting the device ...", usb_pid.app, ports[0].port);
avr109_reboot(ports[0]);
avr109_wait_for_bootloader(usb_pid, 10);
if (! port) {
// The device in bootloader mode was not found, inform the user and wait some more...
BOOST_LOG_TRIVIAL(info) << "MMU 2.0 bootloader device not found after reboot, asking the user to press Reset and waiting for the device to show up ...";
queue_status(_(L(msg_not_found)));
wait_for_mmu_bootloader(30);
queue_message("%s device not found after reboot", dev_name);
queue_status(msg_not_found);
avr109_wait_for_bootloader(usb_pid, 30);
}
} else {
port = ports[0];
@ -498,16 +517,16 @@ void FirmwareDialog::priv::prepare_mk3()
avrdude->push_args(std::move(args));
}
void FirmwareDialog::priv::prepare_mm_control()
void FirmwareDialog::priv::prepare_avr109(Avr109Pid usb_pid)
{
port = boost::none;
lookup_port_mmu();
avr109_lookup_port(usb_pid);
if (! port) {
queue_error(_(L("The device could not have been found")));
queue_error(_(L("The %s device could not have been found")), avr109_dev_name(usb_pid));
return;
}
BOOST_LOG_TRIVIAL(info) << boost::format("Found VID/PID 0x2c99/3 at `%1%`, flashing ...") % port->port;
queue_message("Found VID/PID 0x2c99/%u at `%s`, flashing ...", usb_pid.boot, port->port);
queue_status(label_status_flashing);
std::vector<std::string> args {{
@ -568,7 +587,11 @@ void FirmwareDialog::priv::perform_upload()
break;
case HexFile::DEV_MM_CONTROL:
this->prepare_mm_control();
this->prepare_avr109(Avr109Pid(USB_PID_MMU_BOOT, USB_PID_MMU_APP));
break;
case HexFile::DEV_CW1:
this->prepare_avr109(Avr109Pid(USB_PID_CW1_BOOT, USB_PID_CW1_APP));
break;
default:
@ -576,7 +599,11 @@ void FirmwareDialog::priv::perform_upload()
break;
}
} catch (const std::exception &ex) {
queue_error(wxString::Format(_(L("Error accessing port at %s: %s")), port->port, ex.what()));
if (port) {
queue_error(_(L("Error accessing port at %s: %s")), port->port, ex.what());
} else {
queue_error(_(L("Error: %s")), ex.what());
}
}
})
.on_message(std::move([q, extra_verbose](const char *msg, unsigned /* size */) {
@ -688,6 +715,19 @@ void FirmwareDialog::priv::ensure_joined()
avrdude.reset();
}
const char* FirmwareDialog::priv::avr109_dev_name(Avr109Pid usb_pid) {
switch (usb_pid.boot) {
case USB_PID_MMU_BOOT:
return "Prusa MMU 2.0 Control";
break;
case USB_PID_CW1_BOOT:
return "Prusa CurWa";
break;
default: throw std::runtime_error((boost::format("Invalid avr109 device USB PID: %1%") % usb_pid.boot).str());
}
}
// Public
@ -757,7 +797,7 @@ FirmwareDialog::FirmwareDialog(wxWindow *parent) :
vsizer->Add(grid, 0, wxEXPAND | wxTOP | wxBOTTOM, SPACING);
p->spoiler = new wxCollapsiblePane(panel, wxID_ANY, _(L("Advanced: avrdude output log")), wxDefaultPosition, wxDefaultSize, wxCP_DEFAULT_STYLE | wxCP_NO_TLW_RESIZE);
p->spoiler = new wxCollapsiblePane(panel, wxID_ANY, _(L("Advanced: Output log")), wxDefaultPosition, wxDefaultSize, wxCP_DEFAULT_STYLE | wxCP_NO_TLW_RESIZE);
auto *spoiler_pane = p->spoiler->GetPane();
auto *spoiler_sizer = new wxBoxSizer(wxVERTICAL);
p->txt_stdout = new wxTextCtrl(spoiler_pane, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_MULTILINE | wxTE_READONLY);

View File

@ -3304,12 +3304,14 @@ void GLCanvas3D::_resize(unsigned int w, unsigned int h)
if ((m_canvas == nullptr) && (m_context == nullptr))
return;
wxGetApp().imgui()->set_display_size((float)w, (float)h);
auto *imgui = wxGetApp().imgui();
imgui->set_display_size((float)w, (float)h);
#if ENABLE_RETINA_GL
wxGetApp().imgui()->set_style_scaling(m_retina_helper->get_scale_factor());
const float scaling = m_retina_helper->get_scale_factor();
#else
wxGetApp().imgui()->set_style_scaling(m_canvas->GetContentScaleFactor());
const float scaling = m_canvas->GetContentScaleFactor();
#endif
imgui->set_scaling(m_canvas->GetFont().GetPixelSize().y, scaling);
// ensures that this canvas is current
_set_current();
@ -3865,6 +3867,9 @@ void GLCanvas3D::_render_sla_slices() const
{
const SLAPrintObject* obj = print_objects[i];
if (!obj->is_step_done(slaposSliceSupports))
continue;
SlaCap::ObjectIdToTrianglesMap::iterator it_caps_bottom = m_sla_caps[0].triangles.find(i);
SlaCap::ObjectIdToTrianglesMap::iterator it_caps_top = m_sla_caps[1].triangles.find(i);
{
@ -3888,24 +3893,12 @@ void GLCanvas3D::_render_sla_slices() const
Pointf3s &top_obj_triangles = it_caps_top->second.object;
Pointf3s &top_sup_triangles = it_caps_top->second.supports;
const std::vector<SLAPrintObject::Instance>& instances = obj->instances();
struct InstanceTransform
{
Vec3d offset;
float rotation;
};
std::vector<InstanceTransform> instance_transforms;
for (const SLAPrintObject::Instance& inst : instances)
{
instance_transforms.push_back({ to_3d(unscale(inst.shift), 0.), Geometry::rad2deg(inst.rotation) });
}
if ((bottom_obj_triangles.empty() || bottom_sup_triangles.empty() || top_obj_triangles.empty() || top_sup_triangles.empty()) &&
obj->is_step_done(slaposSliceSupports) && !obj->get_slice_index().empty())
!obj->get_slice_index().empty())
{
double layer_height = print->default_object_config().layer_height.value;
double initial_layer_height = print->material_config().initial_layer_height.value;
bool left_handed = obj->is_left_handed();
coord_t key_zero = obj->get_slice_index().front().print_level();
// Slice at the center of the slab starting at clip_min_z will be rendered for the lower plane.
@ -3924,10 +3917,10 @@ void GLCanvas3D::_render_sla_slices() const
const ExPolygons& sup_bottom = slice_low.get_slice(soSupport);
// calculate model bottom cap
if (bottom_obj_triangles.empty() && !obj_bottom.empty())
bottom_obj_triangles = triangulate_expolygons_3d(obj_bottom, clip_min_z - plane_shift_z, true);
bottom_obj_triangles = triangulate_expolygons_3d(obj_bottom, clip_min_z - plane_shift_z, ! left_handed);
// calculate support bottom cap
if (bottom_sup_triangles.empty() && !sup_bottom.empty())
bottom_sup_triangles = triangulate_expolygons_3d(sup_bottom, clip_min_z - plane_shift_z, true);
bottom_sup_triangles = triangulate_expolygons_3d(sup_bottom, clip_min_z - plane_shift_z, ! left_handed);
}
if (slice_high.is_valid()) {
@ -3935,49 +3928,35 @@ void GLCanvas3D::_render_sla_slices() const
const ExPolygons& sup_top = slice_high.get_slice(soSupport);
// calculate model top cap
if (top_obj_triangles.empty() && !obj_top.empty())
top_obj_triangles = triangulate_expolygons_3d(obj_top, clip_max_z + plane_shift_z, false);
top_obj_triangles = triangulate_expolygons_3d(obj_top, clip_max_z + plane_shift_z, left_handed);
// calculate support top cap
if (top_sup_triangles.empty() && !sup_top.empty())
top_sup_triangles = triangulate_expolygons_3d(sup_top, clip_max_z + plane_shift_z, false);
top_sup_triangles = triangulate_expolygons_3d(sup_top, clip_max_z + plane_shift_z, left_handed);
}
}
if (!bottom_obj_triangles.empty() || !top_obj_triangles.empty() || !bottom_sup_triangles.empty() || !top_sup_triangles.empty())
{
for (const InstanceTransform& inst : instance_transforms)
for (const SLAPrintObject::Instance& inst : obj->instances())
{
glsafe(::glPushMatrix());
glsafe(::glTranslated(inst.offset(0), inst.offset(1), inst.offset(2)));
glsafe(::glRotatef(inst.rotation, 0.0, 0.0, 1.0));
::glBegin(GL_TRIANGLES);
::glColor3f(1.0f, 0.37f, 0.0f);
for (const Vec3d& v : bottom_obj_triangles)
{
::glVertex3dv((GLdouble*)v.data());
}
for (const Vec3d& v : top_obj_triangles)
{
::glVertex3dv((GLdouble*)v.data());
}
::glColor3f(1.0f, 0.0f, 0.37f);
for (const Vec3d& v : bottom_sup_triangles)
{
::glVertex3dv((GLdouble*)v.data());
}
for (const Vec3d& v : top_sup_triangles)
{
::glVertex3dv((GLdouble*)v.data());
}
glsafe(::glEnd());
glsafe(::glTranslated(unscale<double>(inst.shift.x()), unscale<double>(inst.shift.y()), 0));
glsafe(::glRotatef(Geometry::rad2deg(inst.rotation), 0.0, 0.0, 1.0));
if (obj->is_left_handed())
// The polygons are mirrored by X.
glsafe(::glScalef(-1.0, 1.0, 1.0));
glsafe(::glColor3f(1.0f, 0.37f, 0.0f));
glsafe(::glEnableClientState(GL_VERTEX_ARRAY));
glsafe(::glVertexPointer(3, GL_DOUBLE, 0, (GLdouble*)bottom_obj_triangles.front().data()));
glsafe(::glDrawArrays(GL_TRIANGLES, 0, bottom_obj_triangles.size()));
glsafe(::glVertexPointer(3, GL_DOUBLE, 0, (GLdouble*)top_obj_triangles.front().data()));
glsafe(::glDrawArrays(GL_TRIANGLES, 0, top_obj_triangles.size()));
glsafe(::glColor3f(1.0f, 0.0f, 0.37f));
glsafe(::glVertexPointer(3, GL_DOUBLE, 0, (GLdouble*)bottom_sup_triangles.front().data()));
glsafe(::glDrawArrays(GL_TRIANGLES, 0, bottom_sup_triangles.size()));
glsafe(::glVertexPointer(3, GL_DOUBLE, 0, (GLdouble*)top_sup_triangles.front().data()));
glsafe(::glDrawArrays(GL_TRIANGLES, 0, top_sup_triangles.size()));
glsafe(::glDisableClientState(GL_VERTEX_ARRAY));
glsafe(::glPopMatrix());
}
}
@ -5044,6 +5023,8 @@ void GLCanvas3D::_load_shells_fff()
void GLCanvas3D::_load_shells_sla()
{
//FIXME use reload_scene
#if 1
const SLAPrint* print = this->sla_print();
if (print->objects().empty())
// nothing to render, return
@ -5058,18 +5039,25 @@ void GLCanvas3D::_load_shells_sla()
unsigned int initial_volumes_count = (unsigned int)m_volumes.volumes.size();
// selects only instances which were sliced
const ModelObject* model_obj = obj->model_object();
std::vector<int> instance_idxs(model_obj->instances.size());
for (int i = 0; i < (int)model_obj->instances.size(); ++i)
const std::vector<SLAPrintObject::Instance>& sla_instances = obj->instances();
std::vector<int> instances_model_idxs(sla_instances.size());
for (int i = 0; i < (int)sla_instances.size(); ++i)
{
instance_idxs[i] = i;
instances_model_idxs[i] = (int)sla_instances[i].instance_id.id;
}
m_volumes.load_object(model_obj, obj_idx, instance_idxs, "object", m_use_VBOs && m_initialized);
std::vector<int> sliced_instance_idxs;
for (int i = 0; i < (int)model_obj->instances.size(); ++i)
{
if (std::find(instances_model_idxs.begin(), instances_model_idxs.end(), (int)model_obj->instances[i]->id().id) != instances_model_idxs.end())
sliced_instance_idxs.push_back(i);
}
const std::vector<SLAPrintObject::Instance>& instances = obj->instances();
m_volumes.load_object(model_obj, obj_idx, sliced_instance_idxs, "object", m_use_VBOs && m_initialized);
for (const SLAPrintObject::Instance& instance : instances)
for (const SLAPrintObject::Instance& instance : sla_instances)
{
Vec3d offset = unscale(instance.shift(0), instance.shift(1), 0);
Vec3d rotation(0.0, 0.0, (double)instance.rotation);
@ -5092,6 +5080,7 @@ void GLCanvas3D::_load_shells_sla()
v.composite_id.volume_id = -1;
v.set_instance_offset(offset);
v.set_instance_rotation(rotation);
v.set_instance_mirror(X, obj->is_left_handed() ? -1. : 1.);
}
// add pad
@ -5110,6 +5099,7 @@ void GLCanvas3D::_load_shells_sla()
v.composite_id.volume_id = -1;
v.set_instance_offset(offset);
v.set_instance_rotation(rotation);
v.set_instance_mirror(X, obj->is_left_handed() ? -1. : 1.);
}
// finalize volumes and sends geometry to gpu
@ -5132,6 +5122,9 @@ void GLCanvas3D::_load_shells_sla()
}
update_volumes_colors_by_extruder();
#else
this->reload_scene(true, true);
#endif
}
void GLCanvas3D::_update_gcode_volumes_visibility(const GCodePreviewData& preview_data)

View File

@ -479,6 +479,7 @@ public:
m_sla_caps[id].reset();
}
}
void reset_clipping_planes_cache() { m_sla_caps[0].triangles.clear(); m_sla_caps[1].triangles.clear(); }
void set_use_clipping_planes(bool use) { m_use_clipping_planes = use; }
void set_color_by(const std::string& value);

View File

@ -81,7 +81,7 @@ IMPLEMENT_APP(GUI_App)
GUI_App::GUI_App()
: wxApp()
, m_em_unit(10)
, m_imgui(nullptr)
, m_imgui(new ImGuiWrapper())
{}
bool GUI_App::OnInit()
@ -138,7 +138,6 @@ bool GUI_App::OnInit()
// initialize label colors and fonts
init_label_colours();
init_fonts();
m_imgui.reset(new ImGuiWrapper(m_normal_font.GetPixelSize().y));
load_language();

View File

@ -27,7 +27,7 @@
namespace Slic3r {
namespace GUI {
View3D::View3D(wxWindow* parent, Bed3D& bed, Camera& camera, GLToolbar& view_toolbar, Model* model, DynamicPrintConfig* config, BackgroundSlicingProcess* process)
View3D::View3D(wxWindow* parent, Bed3D& bed, Camera& camera, GLToolbar& view_toolbar, Model* model, DynamicPrintConfig* config, BackgroundSlicingProcess* process)
: m_canvas_widget(nullptr)
, m_canvas(nullptr)
{
@ -155,7 +155,9 @@ void View3D::render()
m_canvas->set_as_dirty();
}
Preview::Preview(wxWindow* parent, Bed3D& bed, Camera& camera, GLToolbar& view_toolbar, DynamicPrintConfig* config, BackgroundSlicingProcess* process, GCodePreviewData* gcode_preview_data, std::function<void()> schedule_background_process_func)
Preview::Preview(
wxWindow* parent, Bed3D& bed, Camera& camera, GLToolbar& view_toolbar, Model* model, DynamicPrintConfig* config,
BackgroundSlicingProcess* process, GCodePreviewData* gcode_preview_data, std::function<void()> schedule_background_process_func)
: m_canvas_widget(nullptr)
, m_canvas(nullptr)
, m_double_slider_sizer(nullptr)
@ -179,14 +181,14 @@ Preview::Preview(wxWindow* parent, Bed3D& bed, Camera& camera, GLToolbar& view_t
, m_volumes_cleanup_required(false)
#endif // __linux__
{
if (init(parent, bed, camera, view_toolbar))
if (init(parent, bed, camera, view_toolbar, model))
{
show_hide_ui_elements("none");
load_print();
}
}
bool Preview::init(wxWindow* parent, Bed3D& bed, Camera& camera, GLToolbar& view_toolbar)
bool Preview::init(wxWindow* parent, Bed3D& bed, Camera& camera, GLToolbar& view_toolbar, Model* model)
{
if (!Create(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0 /* disable wxTAB_TRAVERSAL */))
return false;
@ -196,6 +198,7 @@ bool Preview::init(wxWindow* parent, Bed3D& bed, Camera& camera, GLToolbar& view
m_canvas = _3DScene::get_canvas(this->m_canvas_widget);
m_canvas->allow_multisample(GLCanvas3DManager::can_multisample());
m_canvas->set_config(m_config);
m_canvas->set_model(model);
m_canvas->set_process(m_process);
m_canvas->enable_legend_texture(true);
m_canvas->enable_dynamic_background(true);
@ -781,6 +784,8 @@ void Preview::load_print_as_sla()
}
sort_remove_duplicates(zs);
m_canvas->reset_clipping_planes_cache();
n_layers = (unsigned int)zs.size();
if (n_layers == 0)
{

View File

@ -102,7 +102,8 @@ class Preview : public wxPanel
PrusaDoubleSlider* m_slider {nullptr};
public:
Preview(wxWindow* parent, Bed3D& bed, Camera& camera, GLToolbar& view_toolbar, DynamicPrintConfig* config, BackgroundSlicingProcess* process, GCodePreviewData* gcode_preview_data, std::function<void()> schedule_background_process = [](){});
Preview(wxWindow* parent, Bed3D& bed, Camera& camera, GLToolbar& view_toolbar, Model* model, DynamicPrintConfig* config,
BackgroundSlicingProcess* process, GCodePreviewData* gcode_preview_data, std::function<void()> schedule_background_process = [](){});
virtual ~Preview();
wxGLCanvas* get_wxglcanvas() { return m_canvas_widget; }
@ -120,7 +121,7 @@ public:
void refresh_print();
private:
bool init(wxWindow* parent, Bed3D& bed, Camera& camera, GLToolbar& view_toolbar);
bool init(wxWindow* parent, Bed3D& bed, Camera& camera, GLToolbar& view_toolbar, Model* model);
void bind_event_handlers();
void unbind_event_handlers();

View File

@ -186,7 +186,10 @@ void GLGizmoCut::on_render_for_picking(const Selection& selection) const
void GLGizmoCut::on_render_input_window(float x, float y, float bottom_limit, const Selection& selection)
{
const float approx_height = m_imgui->scaled(11.0f);
y = std::min(y, bottom_limit - approx_height);
m_imgui->set_next_window_pos(x, y, ImGuiCond_Always);
m_imgui->set_next_window_bg_alpha(0.5f);
m_imgui->begin(_(L("Cut")), ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse);

View File

@ -562,8 +562,7 @@ void GLGizmoSlaSupports::on_render_input_window(float x, float y, float bottom_l
RENDER_AGAIN:
m_imgui->set_next_window_pos(x, y, ImGuiCond_Always);
const float scaling = m_imgui->get_style_scaling();
const ImVec2 window_size(285.f * scaling, 300.f * scaling);
const ImVec2 window_size(m_imgui->scaled(15.f, 16.5f));
ImGui::SetNextWindowPos(ImVec2(x, y - std::max(0.f, y+window_size.y-bottom_limit) ));
ImGui::SetNextWindowSize(ImVec2(window_size));
@ -814,7 +813,7 @@ void GLGizmoSlaSupports::editing_mode_apply_changes()
// Recalculate support structures once the editing mode is left.
// m_parent.post_event(SimpleEvent(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS));
// m_parent.post_event(SimpleEvent(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS));
wxGetApp().plater()->reslice_SLA_supports(*m_model_object);
wxGetApp().CallAfter([this]() { wxGetApp().plater()->reslice_SLA_supports(*m_model_object); });
}
m_editing_mode = false;
m_unsaved_changes = false;
@ -867,7 +866,7 @@ void GLGizmoSlaSupports::auto_generate()
m_model_object->sla_support_points.clear();
m_model_object->sla_points_status = sla::PointsStatus::Generating;
m_editing_mode_cache.clear();
wxGetApp().plater()->reslice_SLA_supports(*m_model_object);
wxGetApp().CallAfter([this]() { wxGetApp().plater()->reslice_SLA_supports(*m_model_object); });
}
}

View File

@ -26,9 +26,9 @@ namespace Slic3r {
namespace GUI {
ImGuiWrapper::ImGuiWrapper(float font_size)
ImGuiWrapper::ImGuiWrapper()
: m_glyph_ranges(nullptr)
, m_font_size(font_size)
, m_font_size(18.0)
, m_font_texture(0)
, m_style_scaling(1.0)
, m_mouse_buttons(0)
@ -37,7 +37,6 @@ ImGuiWrapper::ImGuiWrapper(float font_size)
{
ImGui::CreateContext();
init_default_font();
init_input();
init_style();
@ -46,7 +45,7 @@ ImGuiWrapper::ImGuiWrapper(float font_size)
ImGuiWrapper::~ImGuiWrapper()
{
destroy_device_objects();
destroy_font();
ImGui::DestroyContext();
}
@ -83,7 +82,7 @@ void ImGuiWrapper::set_language(const std::string &language)
if (ranges != m_glyph_ranges) {
m_glyph_ranges = ranges;
init_default_font();
destroy_font();
}
}
@ -94,13 +93,18 @@ void ImGuiWrapper::set_display_size(float w, float h)
io.DisplayFramebufferScale = ImVec2(1.0f, 1.0f);
}
void ImGuiWrapper::set_style_scaling(float scaling)
void ImGuiWrapper::set_scaling(float font_size, float scaling)
{
if (!std::isnan(scaling) && !std::isinf(scaling) && scaling != m_style_scaling) {
ImGui::GetStyle().ScaleAllSizes(scaling / m_style_scaling);
m_style_scaling = scaling;
init_default_font();
if (m_font_size == font_size && m_style_scaling == scaling) {
return;
}
m_font_size = font_size;
ImGui::GetStyle().ScaleAllSizes(scaling / m_style_scaling);
m_style_scaling = scaling;
destroy_font();
}
bool ImGuiWrapper::update_mouse_data(wxMouseEvent& evt)
@ -161,8 +165,9 @@ void ImGuiWrapper::new_frame()
return;
}
if (m_font_texture == 0)
create_device_objects();
if (m_font_texture == 0) {
init_font();
}
ImGui::NewFrame();
m_new_frame_open = true;
@ -175,6 +180,12 @@ void ImGuiWrapper::render()
m_new_frame_open = false;
}
ImVec2 ImGuiWrapper::calc_text_size(const wxString &text)
{
auto text_utf8 = into_u8(text);
return ImGui::CalcTextSize(text_utf8.c_str());
}
void ImGuiWrapper::set_next_window_pos(float x, float y, int flag)
{
ImGui::SetNextWindowPos(ImVec2(x, y), (ImGuiCond)flag);
@ -255,7 +266,8 @@ void ImGuiWrapper::text(const std::string &label)
void ImGuiWrapper::text(const wxString &label)
{
this->text(into_u8(label).c_str());
auto label_utf8 = into_u8(label);
this->text(label_utf8.c_str());
}
bool ImGuiWrapper::combo(const wxString& label, const std::vector<std::string>& options, int& selection)
@ -324,11 +336,11 @@ bool ImGuiWrapper::want_any_input() const
return io.WantCaptureMouse || io.WantCaptureKeyboard || io.WantTextInput;
}
void ImGuiWrapper::init_default_font()
void ImGuiWrapper::init_font()
{
const float font_size = m_font_size * m_style_scaling;
destroy_fonts_texture();
destroy_font();
ImGuiIO& io = ImGui::GetIO();
io.Fonts->Clear();
@ -339,17 +351,8 @@ void ImGuiWrapper::init_default_font()
throw std::runtime_error("ImGui: Could not load deafult font");
}
}
}
void ImGuiWrapper::create_device_objects()
{
create_fonts_texture();
}
void ImGuiWrapper::create_fonts_texture()
{
// Build texture atlas
ImGuiIO& io = ImGui::GetIO();
unsigned char* pixels;
int width, height;
io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height); // Load as RGBA 32-bits (75% of the memory is wasted, but default font is so small) because it is more likely to be compatible with user's existing shaders. If your ImTextureId represent a higher-level concept than just a GL texture id, consider calling GetTexDataAsAlpha8() instead to save on GPU memory.
@ -555,14 +558,9 @@ bool ImGuiWrapper::display_initialized() const
return io.DisplaySize.x >= 0.0f && io.DisplaySize.y >= 0.0f;
}
void ImGuiWrapper::destroy_device_objects()
void ImGuiWrapper::destroy_font()
{
destroy_fonts_texture();
}
void ImGuiWrapper::destroy_fonts_texture()
{
if (m_font_texture) {
if (m_font_texture != 0) {
ImGuiIO& io = ImGui::GetIO();
io.Fonts->TexID = 0;
glsafe(::glDeleteTextures(1, &m_font_texture));

View File

@ -18,9 +18,6 @@ namespace GUI {
class ImGuiWrapper
{
typedef std::map<std::string, ImFont*> FontsMap;
FontsMap m_fonts;
const ImWchar *m_glyph_ranges;
float m_font_size;
unsigned m_font_texture;
@ -31,22 +28,27 @@ class ImGuiWrapper
std::string m_clipboard_text;
public:
ImGuiWrapper(float font_size);
ImGuiWrapper();
~ImGuiWrapper();
void read_glsl_version();
void set_language(const std::string &language);
void set_display_size(float w, float h);
void set_style_scaling(float scaling);
void set_scaling(float font_size, float scaling);
bool update_mouse_data(wxMouseEvent &evt);
bool update_key_data(wxKeyEvent &evt);
float get_font_size() const { return m_font_size; }
float get_style_scaling() const { return m_style_scaling; }
void new_frame();
void render();
float scaled(float x) const { return x * m_font_size * m_style_scaling; }
ImVec2 scaled(float x, float y) const { return ImVec2(x * m_font_size * m_style_scaling, y * m_font_size * m_style_scaling); }
ImVec2 calc_text_size(const wxString &text);
void set_next_window_pos(float x, float y, int flag);
void set_next_window_bg_alpha(float alpha);
@ -73,15 +75,12 @@ public:
bool want_any_input() const;
private:
void init_default_font();
void create_device_objects();
void create_fonts_texture();
void init_font();
void init_input();
void init_style();
void render_draw_data(ImDrawData *draw_data);
bool display_initialized() const;
void destroy_device_objects();
void destroy_fonts_texture();
void destroy_font();
static const char* clipboard_get(void* user_data);
static void clipboard_set(void* user_data, const char* text);

View File

@ -1350,7 +1350,7 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame)
this->q->Bind(EVT_SLICING_UPDATE, &priv::on_slicing_update, this);
view3D = new View3D(q, bed, camera, view_toolbar, &model, config, &background_process);
preview = new Preview(q, bed, camera, view_toolbar, config, &background_process, &gcode_preview_data, [this](){ schedule_background_process(); });
preview = new Preview(q, bed, camera, view_toolbar, &model, config, &background_process, &gcode_preview_data, [this](){ schedule_background_process(); });
panels.push_back(view3D);
panels.push_back(preview);

View File

@ -1704,7 +1704,7 @@ bool Selection::is_from_fully_selected_instance(unsigned int volume_idx) const
GLVolumePtrs& volumes;
SameInstance(int obj_idx, int inst_idx, GLVolumePtrs& volumes) : obj_idx(obj_idx), inst_idx(inst_idx), volumes(volumes) {}
bool operator () (unsigned int i) { return (volumes[i]->object_idx() == obj_idx) && (volumes[i]->instance_idx() == inst_idx); }
bool operator () (unsigned int i) { return (volumes[i]->volume_idx() >= 0) && (volumes[i]->object_idx() == obj_idx) && (volumes[i]->instance_idx() == inst_idx); }
};
if ((unsigned int)m_volumes->size() <= volume_idx)

View File

@ -18,6 +18,7 @@ static HexFile::DeviceKind parse_device_kind(const std::string &str)
if (str == "mk2") { return HexFile::DEV_MK2; }
else if (str == "mk3") { return HexFile::DEV_MK3; }
else if (str == "mm-control") { return HexFile::DEV_MM_CONTROL; }
else if (str == "cw1") { return HexFile::DEV_CW1; }
else { return HexFile::DEV_GENERIC; }
}

View File

@ -16,6 +16,7 @@ struct HexFile
DEV_MK2,
DEV_MK3,
DEV_MM_CONTROL,
DEV_CW1,
};
boost::filesystem::path path;