Merge branch 'et_world_coordinates' into fs_emboss_with_CGAL_5_4
# Conflicts: # src/libslic3r/Technologies.hpp # src/slic3r/GUI/Gizmos/GLGizmoBase.hpp # src/slic3r/GUI/Gizmos/GLGizmosManager.cpp
This commit is contained in:
commit
70b94d592b
94 changed files with 22001 additions and 19538 deletions
|
@ -523,21 +523,28 @@ add_custom_target(gettext_make_pot
|
|||
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
|
||||
COMMENT "Generate pot file from strings in the source tree"
|
||||
)
|
||||
add_custom_target(gettext_merge_po_with_pot
|
||||
|
||||
add_custom_target(gettext_merge_community_po_with_pot
|
||||
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
|
||||
COMMENT "Merge localization po with new generted pot file"
|
||||
COMMENT "Merge community po with new generated pot file"
|
||||
)
|
||||
file(GLOB L10N_PO_FILES "${L10N_DIR}/*/PrusaSlicer*.po")
|
||||
# list of names of directories, which are licalized by PS internally
|
||||
list(APPEND PS_L10N_DIRS "cs" "de" "es" "fr" "it" "ja" "pl")
|
||||
foreach(po_file ${L10N_PO_FILES})
|
||||
#GET_FILENAME_COMPONENT(po_dir "${po_file}" DIRECTORY)
|
||||
#SET(po_new_file "${po_dir}/PrusaSlicer_.po")
|
||||
add_custom_command(
|
||||
TARGET gettext_merge_po_with_pot PRE_BUILD
|
||||
COMMAND msgmerge -N -o ${po_file} ${po_file} "${L10N_DIR}/PrusaSlicer.pot"
|
||||
# delete obsolete lines from resulting PO to avoid conflicts after a merging of it with wxWidgets.po
|
||||
COMMAND msgattrib --no-obsolete -o ${po_file} ${po_file}
|
||||
DEPENDS ${po_file}
|
||||
)
|
||||
GET_FILENAME_COMPONENT(po_dir "${po_file}" DIRECTORY)
|
||||
GET_FILENAME_COMPONENT(po_dir_name "${po_dir}" NAME)
|
||||
list(FIND PS_L10N_DIRS ${po_dir_name} found_dir_id)
|
||||
# found_dir_id==-1 means that po_dir_name wasn't found in PS_L10N_DIRS
|
||||
if(found_dir_id LESS 0)
|
||||
add_custom_command(
|
||||
TARGET gettext_merge_community_po_with_pot PRE_BUILD
|
||||
COMMAND msgmerge -N -o ${po_file} ${po_file} "${L10N_DIR}/PrusaSlicer.pot"
|
||||
# delete obsolete lines from resulting PO to avoid conflicts after a merging of it with wxWidgets.po
|
||||
COMMAND msgattrib --no-obsolete -o ${po_file} ${po_file}
|
||||
DEPENDS ${po_file}
|
||||
)
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
add_custom_target(gettext_concat_wx_po_with_po
|
||||
|
@ -545,7 +552,6 @@ add_custom_target(gettext_concat_wx_po_with_po
|
|||
COMMENT "Concatenate and merge wxWidgets localization po with PrusaSlicer po file"
|
||||
)
|
||||
file(GLOB L10N_PO_FILES "${L10N_DIR}/*/PrusaSlicer*.po")
|
||||
file(GLOB L10N_WX_PO_FILES "${L10N_DIR}/*/PrusaSlicer*.po")
|
||||
foreach(po_file ${L10N_PO_FILES})
|
||||
GET_FILENAME_COMPONENT(po_dir "${po_file}" DIRECTORY)
|
||||
GET_FILENAME_COMPONENT(po_dir_name "${po_dir}" NAME)
|
||||
|
|
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
Binary file not shown.
File diff suppressed because it is too large
Load diff
Binary file not shown.
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
Binary file not shown.
File diff suppressed because it is too large
Load diff
Binary file not shown.
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
Binary file not shown.
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
Binary file not shown.
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
@ -10,7 +10,10 @@
|
|||
#include <algorithm>
|
||||
#include <numeric>
|
||||
#include <unordered_set>
|
||||
#include <mutex>
|
||||
|
||||
#include <tbb/parallel_for.h>
|
||||
#include <boost/thread/lock_guard.hpp>
|
||||
|
||||
#ifndef NDEBUG
|
||||
// #define BRIM_DEBUG_TO_SVG
|
||||
|
@ -200,20 +203,94 @@ static ExPolygons top_level_outer_brim_area(const Print &print
|
|||
return diff_ex(brim_area, no_brim_area);
|
||||
}
|
||||
|
||||
static ExPolygons inner_brim_area(const Print &print,
|
||||
const ConstPrintObjectPtrs &top_level_objects_with_brim,
|
||||
const std::vector<ExPolygons> &bottom_layers_expolygons,
|
||||
const float no_brim_offset)
|
||||
// Return vector of booleans indicated if polygons from bottom_layers_expolygons contain another polygon or not.
|
||||
// Every ExPolygon is counted as several Polygons (contour and holes). Contour polygon is always processed before holes.
|
||||
static std::vector<bool> has_polygons_nothing_inside(const Print &print, const std::vector<ExPolygons> &bottom_layers_expolygons)
|
||||
{
|
||||
assert(print.objects().size() == bottom_layers_expolygons.size());
|
||||
Polygons islands;
|
||||
for(size_t print_object_idx = 0; print_object_idx < print.objects().size(); ++print_object_idx) {
|
||||
const PrintObject *object = print.objects()[print_object_idx];
|
||||
const Polygons islands_object = to_polygons(bottom_layers_expolygons[print_object_idx]);
|
||||
|
||||
islands.reserve(islands.size() + object->instances().size() * islands_object.size());
|
||||
for (const PrintInstance &instance : object->instances())
|
||||
append_and_translate(islands, islands_object, instance);
|
||||
}
|
||||
|
||||
ClipperLib_Z::Paths islands_clip;
|
||||
islands_clip.reserve(islands.size());
|
||||
for (const Polygon &poly : islands) {
|
||||
size_t island_idx = &poly - &islands.front();
|
||||
ClipperLib_Z::Path island_clip;
|
||||
for (const Point &pt : poly.points)
|
||||
island_clip.emplace_back(pt.x(), pt.y(), island_idx + 1);
|
||||
islands_clip.emplace_back(island_clip);
|
||||
}
|
||||
|
||||
ClipperLib_Z::Clipper clipper;
|
||||
// Always assign zero to detect cases when two polygons are overlapping.
|
||||
clipper.ZFillFunction([](const ClipperLib_Z::IntPoint &e1bot, const ClipperLib_Z::IntPoint &e1top, const ClipperLib_Z::IntPoint &e2bot, const ClipperLib_Z::IntPoint &e2top, ClipperLib_Z::IntPoint &pt) {
|
||||
pt.z() = 0;
|
||||
});
|
||||
|
||||
clipper.AddPaths(islands_clip, ClipperLib_Z::ptSubject, true);
|
||||
ClipperLib_Z::PolyTree islands_polytree;
|
||||
clipper.Execute(ClipperLib_Z::ctUnion, islands_polytree, ClipperLib_Z::pftEvenOdd, ClipperLib_Z::pftEvenOdd);
|
||||
|
||||
std::vector<bool> has_nothing_inside(islands.size());
|
||||
std::function<void(const ClipperLib_Z::PolyNode&)> check_contours = [&check_contours, &has_nothing_inside](const ClipperLib_Z::PolyNode &parent_node)->void {
|
||||
if (!parent_node.Childs.empty())
|
||||
for(const ClipperLib_Z::PolyNode *child_node : parent_node.Childs)
|
||||
check_contours(*child_node);
|
||||
|
||||
if (parent_node.Childs.empty() && !parent_node.Contour.empty() && parent_node.Contour.front().z() != 0) {
|
||||
int polygon_idx = parent_node.Contour.front().z();
|
||||
assert(polygon_idx > 0 && polygon_idx <= int(has_nothing_inside.size()));
|
||||
|
||||
// The whole contour must have the same ID. In other cases, some counters overlap.
|
||||
for (const ClipperLib_Z::IntPoint &point : parent_node.Contour)
|
||||
if (polygon_idx != point.z())
|
||||
return;
|
||||
|
||||
has_nothing_inside[polygon_idx - 1] = true;
|
||||
}
|
||||
};
|
||||
|
||||
check_contours(islands_polytree);
|
||||
return has_nothing_inside;
|
||||
}
|
||||
|
||||
// INNERMOST means that ExPolygon doesn't contain any other ExPolygons.
|
||||
// NORMAL is for other cases.
|
||||
enum class InnerBrimType {NORMAL, INNERMOST};
|
||||
|
||||
struct InnerBrimExPolygons
|
||||
{
|
||||
ExPolygons brim_area;
|
||||
InnerBrimType type = InnerBrimType::NORMAL;
|
||||
double brim_width = 0.;
|
||||
};
|
||||
|
||||
static std::vector<InnerBrimExPolygons> inner_brim_area(const Print &print,
|
||||
const ConstPrintObjectPtrs &top_level_objects_with_brim,
|
||||
const std::vector<ExPolygons> &bottom_layers_expolygons,
|
||||
const float no_brim_offset)
|
||||
{
|
||||
assert(print.objects().size() == bottom_layers_expolygons.size());
|
||||
std::vector<bool> has_nothing_inside = has_polygons_nothing_inside(print, bottom_layers_expolygons);
|
||||
std::unordered_set<size_t> top_level_objects_idx;
|
||||
top_level_objects_idx.reserve(top_level_objects_with_brim.size());
|
||||
for (const PrintObject *object : top_level_objects_with_brim)
|
||||
top_level_objects_idx.insert(object->id().id);
|
||||
|
||||
ExPolygons brim_area;
|
||||
ExPolygons no_brim_area;
|
||||
Polygons holes;
|
||||
std::vector<ExPolygons> brim_area_innermost(print.objects().size());
|
||||
ExPolygons brim_area;
|
||||
ExPolygons no_brim_area;
|
||||
Polygons holes_reversed;
|
||||
|
||||
// polygon_idx must correspond to idx generated inside has_polygons_nothing_inside()
|
||||
size_t polygon_idx = 0;
|
||||
for(size_t print_object_idx = 0; print_object_idx < print.objects().size(); ++print_object_idx) {
|
||||
const PrintObject *object = print.objects()[print_object_idx];
|
||||
const BrimType brim_type = object->config().brim_type.value;
|
||||
|
@ -221,9 +298,10 @@ static ExPolygons inner_brim_area(const Print &print,
|
|||
const float brim_width = scale_(object->config().brim_width.value);
|
||||
const bool top_outer_brim = top_level_objects_idx.find(object->id().id) != top_level_objects_idx.end();
|
||||
|
||||
ExPolygons brim_area_innermost_object;
|
||||
ExPolygons brim_area_object;
|
||||
ExPolygons no_brim_area_object;
|
||||
Polygons holes_object;
|
||||
Polygons holes_reversed_object;
|
||||
for (const ExPolygon &ex_poly : bottom_layers_expolygons[print_object_idx]) {
|
||||
if (brim_type == BrimType::btOuterOnly || brim_type == BrimType::btOuterAndInner) {
|
||||
if (top_outer_brim)
|
||||
|
@ -235,8 +313,20 @@ static ExPolygons inner_brim_area(const Print &print,
|
|||
// After 7ff76d07684858fd937ef2f5d863f105a10f798e offset and shrink don't work with CW polygons (holes), so let's make it CCW.
|
||||
Polygons ex_poly_holes_reversed = ex_poly.holes;
|
||||
polygons_reverse(ex_poly_holes_reversed);
|
||||
if (brim_type == BrimType::btInnerOnly || brim_type == BrimType::btOuterAndInner)
|
||||
append(brim_area_object, diff_ex(shrink_ex(ex_poly_holes_reversed, brim_separation, ClipperLib::jtSquare), shrink_ex(ex_poly_holes_reversed, brim_width + brim_separation, ClipperLib::jtSquare)));
|
||||
for (const PrintInstance &instance : object->instances()) {
|
||||
++polygon_idx; // Increase idx because of the contour of the ExPolygon.
|
||||
|
||||
if (brim_type == BrimType::btInnerOnly || brim_type == BrimType::btOuterAndInner)
|
||||
for(const Polygon &hole : ex_poly_holes_reversed) {
|
||||
size_t hole_idx = &hole - &ex_poly_holes_reversed.front();
|
||||
if (has_nothing_inside[polygon_idx + hole_idx])
|
||||
append(brim_area_innermost_object, shrink_ex({hole}, brim_separation, ClipperLib::jtSquare));
|
||||
else
|
||||
append(brim_area_object, diff_ex(shrink_ex({hole}, brim_separation, ClipperLib::jtSquare), shrink_ex({hole}, brim_width + brim_separation, ClipperLib::jtSquare)));
|
||||
}
|
||||
|
||||
polygon_idx += ex_poly.holes.size(); // Increase idx for every hole of the ExPolygon.
|
||||
}
|
||||
|
||||
if (brim_type == BrimType::btInnerOnly || brim_type == BrimType::btNoBrim)
|
||||
append(no_brim_area_object, diff_ex(offset(ex_poly.contour, no_brim_offset, ClipperLib::jtSquare), ex_poly_holes_reversed));
|
||||
|
@ -244,18 +334,34 @@ static ExPolygons inner_brim_area(const Print &print,
|
|||
if (brim_type == BrimType::btOuterOnly || brim_type == BrimType::btNoBrim)
|
||||
append(no_brim_area_object, diff_ex(ExPolygon(ex_poly.contour), shrink_ex(ex_poly_holes_reversed, no_brim_offset, ClipperLib::jtSquare)));
|
||||
|
||||
append(holes_object, ex_poly_holes_reversed);
|
||||
append(holes_reversed_object, ex_poly_holes_reversed);
|
||||
}
|
||||
append(no_brim_area_object, offset_ex(bottom_layers_expolygons[print_object_idx], brim_separation, ClipperLib::jtSquare));
|
||||
|
||||
for (const PrintInstance &instance : object->instances()) {
|
||||
append_and_translate(brim_area_innermost[print_object_idx], brim_area_innermost_object, instance);
|
||||
append_and_translate(brim_area, brim_area_object, instance);
|
||||
append_and_translate(no_brim_area, no_brim_area_object, instance);
|
||||
append_and_translate(holes, holes_object, instance);
|
||||
append_and_translate(holes_reversed, holes_reversed_object, instance);
|
||||
}
|
||||
}
|
||||
assert(polygon_idx == has_nothing_inside.size());
|
||||
|
||||
return diff_ex(intersection_ex(to_polygons(std::move(brim_area)), holes), no_brim_area);
|
||||
ExPolygons brim_area_innermost_merged;
|
||||
// Append all innermost brim areas.
|
||||
std::vector<InnerBrimExPolygons> brim_area_out;
|
||||
for (size_t print_object_idx = 0; print_object_idx < print.objects().size(); ++print_object_idx)
|
||||
if (const double brim_width = print.objects()[print_object_idx]->config().brim_width.value; !brim_area_innermost[print_object_idx].empty()) {
|
||||
append(brim_area_innermost_merged, brim_area_innermost[print_object_idx]);
|
||||
brim_area_out.push_back({std::move(brim_area_innermost[print_object_idx]), InnerBrimType::INNERMOST, brim_width});
|
||||
}
|
||||
|
||||
// Append all normal brim areas.
|
||||
brim_area_out.push_back({diff_ex(intersection_ex(to_polygons(std::move(brim_area)), holes_reversed), no_brim_area), InnerBrimType::NORMAL});
|
||||
|
||||
// Cut out a huge brim areas that overflows into the INNERMOST holes.
|
||||
brim_area_out.back().brim_area = diff_ex(brim_area_out.back().brim_area, brim_area_innermost_merged);
|
||||
return brim_area_out;
|
||||
}
|
||||
|
||||
// Flip orientation of open polylines to minimize travel distance.
|
||||
|
@ -359,17 +465,28 @@ static void make_inner_brim(const Print &print,
|
|||
ExtrusionEntityCollection &brim)
|
||||
{
|
||||
assert(print.objects().size() == bottom_layers_expolygons.size());
|
||||
const auto scaled_resolution = scaled<double>(print.config().gcode_resolution.value);
|
||||
Flow flow = print.brim_flow();
|
||||
ExPolygons islands_ex = inner_brim_area(print, top_level_objects_with_brim, bottom_layers_expolygons, float(flow.scaled_spacing()));
|
||||
Polygons loops;
|
||||
islands_ex = offset_ex(islands_ex, -0.5f * float(flow.scaled_spacing()), ClipperLib::jtSquare);
|
||||
for (size_t i = 0; !islands_ex.empty(); ++i) {
|
||||
for (ExPolygon &poly_ex : islands_ex)
|
||||
poly_ex.douglas_peucker(scaled_resolution);
|
||||
polygons_append(loops, to_polygons(islands_ex));
|
||||
islands_ex = offset_ex(islands_ex, -float(flow.scaled_spacing()), ClipperLib::jtSquare);
|
||||
}
|
||||
const auto scaled_resolution = scaled<double>(print.config().gcode_resolution.value);
|
||||
Flow flow = print.brim_flow();
|
||||
std::vector<InnerBrimExPolygons> inner_brims_ex = inner_brim_area(print, top_level_objects_with_brim, bottom_layers_expolygons, float(flow.scaled_spacing()));
|
||||
Polygons loops;
|
||||
std::mutex loops_mutex;
|
||||
tbb::parallel_for(tbb::blocked_range<size_t>(0, inner_brims_ex.size()), [&inner_brims_ex, &flow, &scaled_resolution, &loops, &loops_mutex](const tbb::blocked_range<size_t> &range) {
|
||||
for (size_t brim_idx = range.begin(); brim_idx < range.end(); ++brim_idx) {
|
||||
const InnerBrimExPolygons &inner_brim_ex = inner_brims_ex[brim_idx];
|
||||
auto num_loops = size_t(floor(inner_brim_ex.brim_width / flow.spacing()));
|
||||
ExPolygons islands_ex = offset_ex(inner_brim_ex.brim_area, -0.5f * float(flow.scaled_spacing()), ClipperLib::jtSquare);
|
||||
for (size_t i = 0; (inner_brim_ex.type == InnerBrimType::INNERMOST ? i < num_loops : !islands_ex.empty()); ++i) {
|
||||
for (ExPolygon &poly_ex : islands_ex)
|
||||
poly_ex.douglas_peucker(scaled_resolution);
|
||||
|
||||
{
|
||||
boost::lock_guard<std::mutex> lock(loops_mutex);
|
||||
polygons_append(loops, to_polygons(islands_ex));
|
||||
}
|
||||
islands_ex = offset_ex(islands_ex, -float(flow.scaled_spacing()), ClipperLib::jtSquare);
|
||||
}
|
||||
}
|
||||
}); // end of parallel_for
|
||||
|
||||
loops = union_pt_chained_outside_in(loops);
|
||||
std::reverse(loops.begin(), loops.end());
|
||||
|
|
|
@ -94,6 +94,12 @@ public:
|
|||
// Called on initial G-code preview on OpenGL vertex buffer interleaved normals and vertices.
|
||||
bool all_paths_inside_vertices_and_normals_interleaved(const std::vector<float>& paths, const Eigen::AlignedBox<float, 3>& bbox, bool ignore_bottom = true) const;
|
||||
|
||||
|
||||
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
const std::pair<std::vector<Vec2d>, std::vector<Vec2d>>& top_bottom_convex_hull_decomposition_scene() const { return m_top_bottom_convex_hull_decomposition_scene; }
|
||||
const std::pair<std::vector<Vec2d>, std::vector<Vec2d>>& top_bottom_convex_hull_decomposition_bed() const { return m_top_bottom_convex_hull_decomposition_bed; }
|
||||
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
|
||||
private:
|
||||
// Source definition of the print bed geometry (PrintConfig::bed_shape)
|
||||
std::vector<Vec2d> m_bed_shape;
|
||||
|
|
|
@ -274,7 +274,6 @@ namespace Slic3r {
|
|||
// Otherwise, leave control to the user completely.
|
||||
std::string toolchange_gcode_str;
|
||||
const std::string& toolchange_gcode = gcodegen.config().toolchange_gcode.value;
|
||||
// m_max_layer_z = std::max(m_max_layer_z, tcr.print_z);
|
||||
if (! toolchange_gcode.empty()) {
|
||||
DynamicConfig config;
|
||||
int previous_extruder_id = gcodegen.writer().extruder() ? (int)gcodegen.writer().extruder()->id() : -1;
|
||||
|
@ -283,7 +282,7 @@ namespace Slic3r {
|
|||
config.set_key_value("layer_num", new ConfigOptionInt(gcodegen.m_layer_index));
|
||||
config.set_key_value("layer_z", new ConfigOptionFloat(tcr.print_z));
|
||||
config.set_key_value("toolchange_z", new ConfigOptionFloat(z));
|
||||
// config.set_key_value("max_layer_z", new ConfigOptionFloat(m_max_layer_z));
|
||||
config.set_key_value("max_layer_z", new ConfigOptionFloat(gcodegen.m_max_layer_z));
|
||||
toolchange_gcode_str = gcodegen.placeholder_parser_process("toolchange_gcode", toolchange_gcode, new_extruder_id, &config);
|
||||
check_add_eol(toolchange_gcode_str);
|
||||
}
|
||||
|
@ -305,6 +304,9 @@ namespace Slic3r {
|
|||
if (!start_filament_gcode.empty()) {
|
||||
// Process the start_filament_gcode for the active filament only.
|
||||
DynamicConfig config;
|
||||
config.set_key_value("layer_num", new ConfigOptionInt(gcodegen.m_layer_index));
|
||||
config.set_key_value("layer_z", new ConfigOptionFloat(gcodegen.writer().get_position()(2) - gcodegen.m_config.z_offset.value));
|
||||
config.set_key_value("max_layer_z", new ConfigOptionFloat(gcodegen.m_max_layer_z));
|
||||
config.set_key_value("filament_extruder_id", new ConfigOptionInt(new_extruder_id));
|
||||
start_filament_gcode_str = gcodegen.placeholder_parser_process("start_filament_gcode", start_filament_gcode, new_extruder_id, &config);
|
||||
check_add_eol(start_filament_gcode_str);
|
||||
|
@ -1045,7 +1047,7 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato
|
|||
|
||||
if (! print.config().gcode_substitutions.values.empty()) {
|
||||
m_find_replace = make_unique<GCodeFindReplace>(print.config());
|
||||
file.set_find_replace(m_find_replace.get());
|
||||
file.set_find_replace(m_find_replace.get(), false);
|
||||
}
|
||||
|
||||
// resets analyzer's tracking data
|
||||
|
@ -1153,6 +1155,9 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato
|
|||
}
|
||||
print.throw_if_canceled();
|
||||
|
||||
// Starting now, the G-code find / replace post-processor will be enabled.
|
||||
file.find_replace_enable();
|
||||
|
||||
// adds tags for time estimators
|
||||
if (print.config().remaining_times.value)
|
||||
file.write_format(";%s\n", GCodeProcessor::reserved_tag(GCodeProcessor::ETags::First_Line_M73_Placeholder).c_str());
|
||||
|
@ -1274,15 +1279,6 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato
|
|||
// Write the custom start G-code
|
||||
file.writeln(start_gcode);
|
||||
|
||||
// Process filament-specific gcode.
|
||||
/* if (has_wipe_tower) {
|
||||
// Wipe tower will control the extruder switching, it will call the start_filament_gcode.
|
||||
} else {
|
||||
DynamicConfig config;
|
||||
config.set_key_value("filament_extruder_id", new ConfigOptionInt(int(initial_extruder_id)));
|
||||
file.writeln(this->placeholder_parser_process("start_filament_gcode", print.config().start_filament_gcode.values[initial_extruder_id], initial_extruder_id, &config));
|
||||
}
|
||||
*/
|
||||
this->_print_first_layer_extruder_temperatures(file, print, start_gcode, initial_extruder_id, true);
|
||||
print.throw_if_canceled();
|
||||
|
||||
|
@ -1468,6 +1464,10 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato
|
|||
file.write_format("; total toolchanges = %i\n", print.m_print_statistics.total_toolchanges);
|
||||
file.write_format(";%s\n", GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Estimated_Printing_Time_Placeholder).c_str());
|
||||
|
||||
// From now to the end of G-code, the G-code find / replace post-processor will be disabled.
|
||||
// Thus the PrusaSlicer generated config will NOT be processed by the G-code post-processor, see GH issue #7952.
|
||||
file.find_replace_supress();
|
||||
|
||||
// Append full config, delimited by two 'phony' configuration keys prusaslicer_config = begin and prusaslicer_config = end.
|
||||
// The delimiters are structured as configuration key / value pairs to be parsable by older versions of PrusaSlicer G-code viewer.
|
||||
{
|
||||
|
@ -1525,7 +1525,7 @@ void GCode::process_layers(
|
|||
);
|
||||
|
||||
// The pipeline elements are joined using const references, thus no copying is performed.
|
||||
output_stream.set_find_replace(nullptr);
|
||||
output_stream.find_replace_supress();
|
||||
if (m_spiral_vase && m_find_replace)
|
||||
tbb::parallel_pipeline(12, generator & spiral_vase & cooling & find_replace & output);
|
||||
else if (m_spiral_vase)
|
||||
|
@ -1534,7 +1534,7 @@ void GCode::process_layers(
|
|||
tbb::parallel_pipeline(12, generator & cooling & find_replace & output);
|
||||
else
|
||||
tbb::parallel_pipeline(12, generator & cooling & output);
|
||||
output_stream.set_find_replace(m_find_replace.get());
|
||||
output_stream.find_replace_enable();
|
||||
}
|
||||
|
||||
// Process all layers of a single object instance (sequential mode) with a parallel pipeline:
|
||||
|
@ -1578,7 +1578,7 @@ void GCode::process_layers(
|
|||
);
|
||||
|
||||
// The pipeline elements are joined using const references, thus no copying is performed.
|
||||
output_stream.set_find_replace(nullptr);
|
||||
output_stream.find_replace_supress();
|
||||
if (m_spiral_vase && m_find_replace)
|
||||
tbb::parallel_pipeline(12, generator & spiral_vase & cooling & find_replace & output);
|
||||
else if (m_spiral_vase)
|
||||
|
@ -1587,7 +1587,7 @@ void GCode::process_layers(
|
|||
tbb::parallel_pipeline(12, generator & cooling & find_replace & output);
|
||||
else
|
||||
tbb::parallel_pipeline(12, generator & cooling & output);
|
||||
output_stream.set_find_replace(m_find_replace.get());
|
||||
output_stream.find_replace_enable();
|
||||
}
|
||||
|
||||
std::string GCode::placeholder_parser_process(const std::string &name, const std::string &templ, unsigned int current_extruder_id, const DynamicConfig *config_override)
|
||||
|
@ -1899,6 +1899,8 @@ namespace ProcessLayer
|
|||
// && !MMU1
|
||||
) {
|
||||
//! FIXME_in_fw show message during print pause
|
||||
// FIXME: Why is pause_print_gcode here? Why is it supplied "color_change_extruder"? Why is that not
|
||||
// passed to color_change_gcode below?
|
||||
DynamicConfig cfg;
|
||||
cfg.set_key_value("color_change_extruder", new ConfigOptionInt(m600_extruder_before_layer));
|
||||
gcode += gcodegen.placeholder_parser_process("pause_print_gcode", config.pause_print_gcode, current_extruder_id, &cfg);
|
||||
|
@ -2109,10 +2111,10 @@ GCode::LayerResult GCode::process_layer(
|
|||
DynamicConfig config;
|
||||
config.set_key_value("layer_num", new ConfigOptionInt(m_layer_index));
|
||||
config.set_key_value("layer_z", new ConfigOptionFloat(print_z));
|
||||
config.set_key_value("max_layer_z", new ConfigOptionFloat(m_max_layer_z));
|
||||
gcode += this->placeholder_parser_process("layer_gcode",
|
||||
print.config().layer_gcode.value, m_writer.extruder()->id(), &config)
|
||||
+ "\n";
|
||||
config.set_key_value("max_layer_z", new ConfigOptionFloat(m_max_layer_z));
|
||||
}
|
||||
|
||||
if (! first_layer && ! m_second_layer_things_done) {
|
||||
|
@ -3146,7 +3148,9 @@ std::string GCode::set_extruder(unsigned int extruder_id, double print_z)
|
|||
const std::string &start_filament_gcode = m_config.start_filament_gcode.get_at(extruder_id);
|
||||
if (! start_filament_gcode.empty()) {
|
||||
// Process the start_filament_gcode for the filament.
|
||||
gcode += this->placeholder_parser_process("start_filament_gcode", start_filament_gcode, extruder_id);
|
||||
DynamicConfig config;
|
||||
config.set_key_value("filament_extruder_id", new ConfigOptionInt(int(extruder_id)));
|
||||
gcode += this->placeholder_parser_process("start_filament_gcode", start_filament_gcode, extruder_id, &config);
|
||||
check_add_eol(gcode);
|
||||
}
|
||||
gcode += m_writer.toolchange(extruder_id);
|
||||
|
@ -3215,7 +3219,9 @@ std::string GCode::set_extruder(unsigned int extruder_id, double print_z)
|
|||
const std::string &start_filament_gcode = m_config.start_filament_gcode.get_at(extruder_id);
|
||||
if (! start_filament_gcode.empty()) {
|
||||
// Process the start_filament_gcode for the new filament.
|
||||
gcode += this->placeholder_parser_process("start_filament_gcode", start_filament_gcode, extruder_id);
|
||||
DynamicConfig config;
|
||||
config.set_key_value("filament_extruder_id", new ConfigOptionInt(int(extruder_id)));
|
||||
gcode += this->placeholder_parser_process("start_filament_gcode", start_filament_gcode, extruder_id, &config);
|
||||
check_add_eol(gcode);
|
||||
}
|
||||
// Set the new extruder to the operating temperature.
|
||||
|
|
|
@ -196,7 +196,9 @@ private:
|
|||
// Set a find-replace post-processor to modify the G-code before GCodePostProcessor.
|
||||
// It is being set to null inside process_layers(), because the find-replace process
|
||||
// is being called on a secondary thread to improve performance.
|
||||
void set_find_replace(GCodeFindReplace *find_replace) { m_find_replace = find_replace; }
|
||||
void set_find_replace(GCodeFindReplace *find_replace, bool enabled) { m_find_replace_backup = find_replace; m_find_replace = enabled ? find_replace : nullptr; }
|
||||
void find_replace_enable() { m_find_replace = m_find_replace_backup; }
|
||||
void find_replace_supress() { m_find_replace = nullptr; }
|
||||
|
||||
bool is_open() const { return f; }
|
||||
bool is_error() const;
|
||||
|
@ -220,6 +222,8 @@ private:
|
|||
FILE *f { nullptr };
|
||||
// Find-replace post-processor to be called before GCodePostProcessor.
|
||||
GCodeFindReplace *m_find_replace { nullptr };
|
||||
// If suppressed, the backoup holds m_find_replace.
|
||||
GCodeFindReplace *m_find_replace_backup { nullptr };
|
||||
GCodeProcessor &m_processor;
|
||||
};
|
||||
void _do_export(Print &print, GCodeOutputStream &file, ThumbnailsGeneratorCallback thumbnail_cb);
|
||||
|
|
|
@ -1412,9 +1412,11 @@ void ModelObject::bake_xy_rotation_into_meshes(size_t instance_idx)
|
|||
assert(instance_idx < this->instances.size());
|
||||
|
||||
const Geometry::Transformation reference_trafo = this->instances[instance_idx]->get_transformation();
|
||||
#if !ENABLE_WORLD_COORDINATE_SCALE_REVISITED
|
||||
if (Geometry::is_rotation_ninety_degrees(reference_trafo.get_rotation()))
|
||||
// nothing to do, scaling in the world coordinate space is possible in the representation of Geometry::Transformation.
|
||||
return;
|
||||
#endif // !ENABLE_WORLD_COORDINATE_SCALE_REVISITED
|
||||
|
||||
bool left_handed = reference_trafo.is_left_handed();
|
||||
bool has_mirrorring = ! reference_trafo.get_mirror().isApprox(Vec3d(1., 1., 1.));
|
||||
|
|
|
@ -605,7 +605,7 @@ struct MMU_Graph
|
|||
if (arcs[arc_idx].to_idx == to_idx)
|
||||
return;
|
||||
for (const size_t &arc_idx : this->nodes[to_idx].arc_idxs)
|
||||
if (arcs[arc_idx].to_idx == to_idx)
|
||||
if (arcs[arc_idx].to_idx == from_idx)
|
||||
return;
|
||||
|
||||
this->nodes[from_idx].arc_idxs.push_back(this->arcs.size());
|
||||
|
@ -1201,7 +1201,7 @@ static inline double compute_edge_length(const MMU_Graph &graph, const size_t st
|
|||
used_arcs[start_arc_idx] = true;
|
||||
const MMU_Graph::Arc *arc = &graph.arcs[start_arc_idx];
|
||||
size_t idx = start_idx;
|
||||
double line_total_length = (graph.nodes[arc->to_idx].point - graph.nodes[idx].point).norm();;
|
||||
double line_total_length = (graph.nodes[arc->to_idx].point - graph.nodes[idx].point).norm();
|
||||
while (graph.nodes[arc->to_idx].arc_idxs.size() == 2) {
|
||||
bool found = false;
|
||||
for (const size_t &arc_idx : graph.nodes[arc->to_idx].arc_idxs) {
|
||||
|
@ -1711,7 +1711,7 @@ std::vector<std::vector<ExPolygons>> multi_material_segmentation_by_painting(con
|
|||
// Such close points sometimes caused that the Voronoi diagram has self-intersecting edges around these vertices.
|
||||
// This consequently leads to issues with the extraction of colored segments by function extract_colored_segments.
|
||||
// Calling expolygons_simplify fixed these issues.
|
||||
input_expolygons[layer_idx] = smooth_outward(expolygons_simplify(offset_ex(ex_polygons, -10.f * float(SCALED_EPSILON)), 5 * SCALED_EPSILON), 10 * coord_t(SCALED_EPSILON));
|
||||
input_expolygons[layer_idx] = remove_duplicates(expolygons_simplify(offset_ex(ex_polygons, -10.f * float(SCALED_EPSILON)), 5 * SCALED_EPSILON), scaled<coord_t>(0.01), PI/6);
|
||||
|
||||
#ifdef MMU_SEGMENTATION_DEBUG_INPUT
|
||||
{
|
||||
|
|
|
@ -37,6 +37,36 @@ void remove_duplicates(MutablePolygon &polygon, double eps)
|
|||
}
|
||||
}
|
||||
|
||||
// Remove nearly duplicate points. If a distance between two points is less than scaled_eps
|
||||
// and if the angle between its surrounding lines is less than max_angle, the point will be removed.
|
||||
// May reduce the polygon down to empty polygon.
|
||||
void remove_duplicates(MutablePolygon &polygon, coord_t scaled_eps, const double max_angle)
|
||||
{
|
||||
if (polygon.size() >= 3) {
|
||||
auto cos_max_angle_2 = Slic3r::sqr<double>(cos(max_angle));
|
||||
auto scaled_eps_sqr = Slic3r::sqr<int64_t>(scaled_eps);
|
||||
auto begin = polygon.begin();
|
||||
auto it = begin;
|
||||
for (++it; it != begin;) {
|
||||
auto prev = it.prev();
|
||||
auto next = it.next();
|
||||
Vec2i64 v1 = (*it - *prev).cast<int64_t>();
|
||||
int64_t v1_sqr_norm = v1.squaredNorm();
|
||||
if (v1_sqr_norm < scaled_eps_sqr) {
|
||||
if (Vec2i64 v2 = (*next - *prev).cast<int64_t>();
|
||||
Slic3r::sqr<double>(double(v1.dot(v2))) > cos_max_angle_2 * double(v1_sqr_norm) * double(v2.squaredNorm())) {
|
||||
it = it.remove();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
it = next;
|
||||
}
|
||||
}
|
||||
|
||||
if (polygon.size() < 3)
|
||||
polygon.clear();
|
||||
}
|
||||
|
||||
// Adapted from Cura ConstPolygonRef::smooth_corner_complex() by Tim Kuipers.
|
||||
// A concave corner at it1 with position p1 has been removed by the caller between it0 and it2, where |p2 - p0| < shortcut_length.
|
||||
// Now try to close a concave crack by walking left from it0 and right from it2 as long as the new clipping edge is smaller than shortcut_length
|
||||
|
|
|
@ -309,6 +309,28 @@ inline bool operator!=(const MutablePolygon &p1, const MutablePolygon &p2) { ret
|
|||
void remove_duplicates(MutablePolygon &polygon);
|
||||
void remove_duplicates(MutablePolygon &polygon, double eps);
|
||||
|
||||
// Remove nearly duplicate points. If a distance between two points is less than scaled_eps
|
||||
// and if the angle between its surrounding lines is less than max_angle, the point will be removed.
|
||||
// May reduce the polygon down to empty polygon.
|
||||
void remove_duplicates(MutablePolygon &polygon, coord_t scaled_eps, const double max_angle);
|
||||
inline ExPolygons remove_duplicates(ExPolygons expolygons, coord_t scaled_eps, double max_angle)
|
||||
{
|
||||
MutablePolygon mp;
|
||||
for (ExPolygon &expolygon : expolygons) {
|
||||
mp.assign(expolygon.contour, expolygon.contour.size() * 2);
|
||||
remove_duplicates(mp, scaled_eps, max_angle);
|
||||
mp.polygon(expolygon.contour);
|
||||
for (Polygon &hole : expolygon.holes) {
|
||||
mp.assign(hole, hole.size() * 2);
|
||||
remove_duplicates(mp, scaled_eps, max_angle);
|
||||
mp.polygon(hole);
|
||||
}
|
||||
expolygon.holes.erase(std::remove_if(expolygon.holes.begin(), expolygon.holes.end(), [](const auto &p) { return p.empty(); }), expolygon.holes.end());
|
||||
}
|
||||
expolygons.erase(std::remove_if(expolygons.begin(), expolygons.end(), [](const auto &p) { return p.empty(); }), expolygons.end());
|
||||
return expolygons;
|
||||
}
|
||||
|
||||
void smooth_outward(MutablePolygon &polygon, coord_t clip_dist_scaled);
|
||||
|
||||
inline Polygon smooth_outward(Polygon polygon, coord_t clip_dist_scaled)
|
||||
|
|
|
@ -412,6 +412,8 @@ void Preset::set_visible_from_appconfig(const AppConfig &app_config)
|
|||
for (auto it = this->renamed_from.begin(); ! is_visible && it != this->renamed_from.end(); ++ it)
|
||||
is_visible = has(*it);
|
||||
}
|
||||
else
|
||||
is_visible = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -791,7 +793,8 @@ std::pair<Preset*, bool> PresetCollection::load_external_preset(
|
|||
// The source config may contain keys from many possible preset types. Just copy those that relate to this preset.
|
||||
this->get_edited_preset().config.apply_only(combined_config, keys, true);
|
||||
this->update_dirty();
|
||||
update_saved_preset_from_current_preset();
|
||||
// Don't save the newly loaded project as a "saved into project" state.
|
||||
//update_saved_preset_from_current_preset();
|
||||
assert(this->get_edited_preset().is_dirty);
|
||||
return std::make_pair(&(*it), this->get_edited_preset().is_dirty);
|
||||
}
|
||||
|
@ -1226,7 +1229,6 @@ Preset& PresetCollection::select_preset(size_t idx)
|
|||
idx = first_visible_idx();
|
||||
m_idx_selected = idx;
|
||||
m_edited_preset = m_presets[idx];
|
||||
update_saved_preset_from_current_preset();
|
||||
bool default_visible = ! m_default_suppressed || m_idx_selected < m_num_default_presets;
|
||||
for (size_t i = 0; i < m_num_default_presets; ++i)
|
||||
m_presets[i].is_visible = default_visible;
|
||||
|
|
|
@ -397,6 +397,7 @@ public:
|
|||
void discard_current_changes() {
|
||||
m_presets[m_idx_selected].reset_dirty();
|
||||
m_edited_preset = m_presets[m_idx_selected];
|
||||
// Don't save the resetted preset state as a "saved into project" state.
|
||||
// update_saved_preset_from_current_preset();
|
||||
}
|
||||
|
||||
|
|
|
@ -660,7 +660,8 @@ std::string Print::validate(std::string* warning) const
|
|||
bool layer_gcode_resets_extruder = boost::regex_search(m_config.layer_gcode.value, regex_g92e0);
|
||||
if (m_config.use_relative_e_distances) {
|
||||
// See GH issues #6336 #5073
|
||||
if (! before_layer_gcode_resets_extruder && ! layer_gcode_resets_extruder)
|
||||
if ((m_config.gcode_flavor == gcfMarlinLegacy || m_config.gcode_flavor == gcfMarlinFirmware) &&
|
||||
! before_layer_gcode_resets_extruder && ! layer_gcode_resets_extruder)
|
||||
return L("Relative extruder addressing requires resetting the extruder position at each layer to prevent loss of floating point accuracy. Add \"G92 E0\" to layer_gcode.");
|
||||
} else if (before_layer_gcode_resets_extruder)
|
||||
return L("\"G92 E0\" was found in before_layer_gcode, which is incompatible with absolute extruder addressing.");
|
||||
|
|
|
@ -74,12 +74,20 @@
|
|||
#define ENABLE_SHOW_NON_MANIFOLD_EDGES (1 && ENABLE_2_5_0_ALPHA1)
|
||||
// Enable rework of Reload from disk command
|
||||
#define ENABLE_RELOAD_FROM_DISK_REWORK (1 && ENABLE_2_5_0_ALPHA1)
|
||||
// Enable showing toolpaths center of gravity
|
||||
#define ENABLE_SHOW_TOOLPATHS_COG (1 && ENABLE_2_5_0_ALPHA1)
|
||||
// Enable recalculating toolpaths when switching to/from volumetric rate visualization
|
||||
#define ENABLE_VOLUMETRIC_RATE_TOOLPATHS_RECALC (1 && ENABLE_2_5_0_ALPHA1)
|
||||
// Enable editing volumes transformation in world coordinates and instances in local coordinates
|
||||
#define ENABLE_WORLD_COORDINATE (1 && ENABLE_2_5_0_ALPHA1)
|
||||
// Enable showing world coordinates of volumes' offset relative to the instance containing them
|
||||
#define ENABLE_WORLD_COORDINATE_VOLUMES_LOCAL_OFFSET (0 && ENABLE_WORLD_COORDINATE)
|
||||
// Enable editing instance coordinates of volumes
|
||||
#define ENABLE_INSTANCE_COORDINATES_FOR_VOLUMES (1 && ENABLE_WORLD_COORDINATE)
|
||||
// Enable rendering the selection bounding box in the current reference system
|
||||
#define ENABLE_COORDINATE_DEPENDENT_SELECTION_BOX (1 && ENABLE_WORLD_COORDINATE)
|
||||
// Enable showing the axes of the current reference system when sidebar hints are active
|
||||
#define ENABLE_WORLD_COORDINATE_SHOW_AXES (1 && ENABLE_WORLD_COORDINATE)
|
||||
// Enable alternate implementation of manipulating scale for instances and volumes
|
||||
#define ENABLE_WORLD_COORDINATE_SCALE_REVISITED (1 && ENABLE_WORLD_COORDINATE)
|
||||
|
||||
|
||||
#endif // _prusaslicer_technologies_h_
|
||||
|
|
|
@ -133,6 +133,8 @@ set(SLIC3R_GUI_SOURCES
|
|||
GUI/2DBed.hpp
|
||||
GUI/3DBed.cpp
|
||||
GUI/3DBed.hpp
|
||||
GUI/CoordAxes.cpp
|
||||
GUI/CoordAxes.hpp
|
||||
GUI/Camera.cpp
|
||||
GUI/Camera.hpp
|
||||
GUI/CameraUtils.cpp
|
||||
|
|
|
@ -98,6 +98,7 @@ const float* GeometryBuffer::get_vertices_data() const
|
|||
}
|
||||
#endif // !ENABLE_GLBEGIN_GLEND_REMOVAL
|
||||
|
||||
#if !ENABLE_WORLD_COORDINATE_SHOW_AXES
|
||||
const float Bed3D::Axes::DefaultStemRadius = 0.5f;
|
||||
const float Bed3D::Axes::DefaultStemLength = 25.0f;
|
||||
const float Bed3D::Axes::DefaultTipRadius = 2.5f * Bed3D::Axes::DefaultStemRadius;
|
||||
|
@ -152,6 +153,7 @@ void Bed3D::Axes::render()
|
|||
|
||||
glsafe(::glDisable(GL_DEPTH_TEST));
|
||||
}
|
||||
#endif // !ENABLE_WORLD_COORDINATE_SHOW_AXES
|
||||
|
||||
bool Bed3D::set_shape(const Pointfs& bed_shape, const double max_print_height, const std::string& custom_texture, const std::string& custom_model, bool force_as_custom)
|
||||
{
|
||||
|
@ -288,7 +290,11 @@ BoundingBoxf3 Bed3D::calc_extended_bounding_box() const
|
|||
out.max.z() = 0.0;
|
||||
// extend to contain axes
|
||||
out.merge(m_axes.get_origin() + m_axes.get_total_length() * Vec3d::Ones());
|
||||
#if ENABLE_WORLD_COORDINATE_SHOW_AXES
|
||||
out.merge(out.min + Vec3d(-m_axes.get_tip_radius(), -m_axes.get_tip_radius(), out.max.z()));
|
||||
#else
|
||||
out.merge(out.min + Vec3d(-Axes::DefaultTipRadius, -Axes::DefaultTipRadius, out.max.z()));
|
||||
#endif // ENABLE_WORLD_COORDINATE_SHOW_AXES
|
||||
// extend to contain model, if any
|
||||
BoundingBoxf3 model_bb = m_model.get_bounding_box();
|
||||
if (model_bb.defined) {
|
||||
|
@ -458,7 +464,11 @@ std::tuple<Bed3D::Type, std::string, std::string> Bed3D::detect_type(const Point
|
|||
void Bed3D::render_axes()
|
||||
{
|
||||
if (m_build_volume.valid())
|
||||
#if ENABLE_WORLD_COORDINATE_SHOW_AXES
|
||||
m_axes.render(0.25f);
|
||||
#else
|
||||
m_axes.render();
|
||||
#endif // ENABLE_WORLD_COORDINATE_SHOW_AXES
|
||||
}
|
||||
|
||||
void Bed3D::render_system(GLCanvas3D& canvas, bool bottom, bool show_texture)
|
||||
|
|
|
@ -3,7 +3,11 @@
|
|||
|
||||
#include "GLTexture.hpp"
|
||||
#include "3DScene.hpp"
|
||||
#if ENABLE_WORLD_COORDINATE_SHOW_AXES
|
||||
#include "CoordAxes.hpp"
|
||||
#else
|
||||
#include "GLModel.hpp"
|
||||
#endif // ENABLE_WORLD_COORDINATE_SHOW_AXES
|
||||
|
||||
#include "libslic3r/BuildVolume.hpp"
|
||||
#if ENABLE_GLBEGIN_GLEND_REMOVAL
|
||||
|
@ -44,6 +48,7 @@ public:
|
|||
|
||||
class Bed3D
|
||||
{
|
||||
#if !ENABLE_WORLD_COORDINATE_SHOW_AXES
|
||||
class Axes
|
||||
{
|
||||
public:
|
||||
|
@ -67,6 +72,7 @@ class Bed3D
|
|||
float get_total_length() const { return m_stem_length + DefaultTipLength; }
|
||||
void render();
|
||||
};
|
||||
#endif // !ENABLE_WORLD_COORDINATE_SHOW_AXES
|
||||
|
||||
public:
|
||||
enum class Type : unsigned char
|
||||
|
@ -105,7 +111,11 @@ private:
|
|||
#if !ENABLE_GLBEGIN_GLEND_REMOVAL
|
||||
unsigned int m_vbo_id{ 0 };
|
||||
#endif // !ENABLE_GLBEGIN_GLEND_REMOVAL
|
||||
#if ENABLE_WORLD_COORDINATE_SHOW_AXES
|
||||
CoordAxes m_axes;
|
||||
#else
|
||||
Axes m_axes;
|
||||
#endif // ENABLE_WORLD_COORDINATE_SHOW_AXES
|
||||
|
||||
float m_scale_factor{ 1.0f };
|
||||
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
#include <GL/glew.h>
|
||||
|
||||
#if !ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
#if ENABLE_SMOOTH_NORMALS
|
||||
#include <igl/per_face_normals.h>
|
||||
#include <igl/per_corner_normals.h>
|
||||
#include <igl/per_vertex_normals.h>
|
||||
#endif // ENABLE_SMOOTH_NORMALS
|
||||
#endif // !ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
|
||||
#include "3DScene.hpp"
|
||||
#include "GLShader.hpp"
|
||||
|
@ -69,6 +71,7 @@ void glAssertRecentCallImpl(const char* file_name, unsigned int line, const char
|
|||
|
||||
namespace Slic3r {
|
||||
|
||||
#if !ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
#if ENABLE_SMOOTH_NORMALS
|
||||
static void smooth_normals_corner(TriangleMesh& mesh, std::vector<stl_normal>& normals)
|
||||
{
|
||||
|
@ -287,6 +290,7 @@ void GLIndexedVertexArray::render(
|
|||
|
||||
glsafe(::glBindBuffer(GL_ARRAY_BUFFER, 0));
|
||||
}
|
||||
#endif // !ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
|
||||
const float GLVolume::SinkingContours::HalfWidth = 0.25f;
|
||||
|
||||
|
@ -483,7 +487,9 @@ GLVolume::GLVolume(float r, float g, float b, float a)
|
|||
, force_neutral_color(false)
|
||||
, force_sinking_contours(false)
|
||||
, tverts_range(0, size_t(-1))
|
||||
#if !ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
, qverts_range(0, size_t(-1))
|
||||
#endif // !ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
{
|
||||
color = { r, g, b, a };
|
||||
set_render_color(color);
|
||||
|
@ -599,6 +605,36 @@ const BoundingBoxf3& GLVolume::transformed_non_sinking_bounding_box() const
|
|||
return *m_transformed_non_sinking_bounding_box;
|
||||
}
|
||||
|
||||
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
void GLVolume::set_range(double min_z, double max_z)
|
||||
{
|
||||
this->tverts_range.first = 0;
|
||||
this->tverts_range.second = this->model.indices_count();
|
||||
|
||||
if (!this->print_zs.empty()) {
|
||||
// The Z layer range is specified.
|
||||
// First test whether the Z span of this object is not out of (min_z, max_z) completely.
|
||||
if (this->print_zs.front() > max_z || this->print_zs.back() < min_z)
|
||||
this->tverts_range.second = 0;
|
||||
else {
|
||||
// Then find the lowest layer to be displayed.
|
||||
size_t i = 0;
|
||||
for (; i < this->print_zs.size() && this->print_zs[i] < min_z; ++i);
|
||||
if (i == this->print_zs.size())
|
||||
// This shall not happen.
|
||||
this->tverts_range.second = 0;
|
||||
else {
|
||||
// Remember start of the layer.
|
||||
this->tverts_range.first = this->offsets[i];
|
||||
// Some layers are above $min_z. Which?
|
||||
for (; i < this->print_zs.size() && this->print_zs[i] <= max_z; ++i);
|
||||
if (i < this->print_zs.size())
|
||||
this->tverts_range.second = this->offsets[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
void GLVolume::set_range(double min_z, double max_z)
|
||||
{
|
||||
this->qverts_range.first = 0;
|
||||
|
@ -611,7 +647,8 @@ void GLVolume::set_range(double min_z, double max_z)
|
|||
if (this->print_zs.front() > max_z || this->print_zs.back() < min_z) {
|
||||
this->qverts_range.second = 0;
|
||||
this->tverts_range.second = 0;
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
// Then find the lowest layer to be displayed.
|
||||
size_t i = 0;
|
||||
for (; i < this->print_zs.size() && this->print_zs[i] < min_z; ++ i);
|
||||
|
@ -619,7 +656,8 @@ void GLVolume::set_range(double min_z, double max_z)
|
|||
// This shall not happen.
|
||||
this->qverts_range.second = 0;
|
||||
this->tverts_range.second = 0;
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
// Remember start of the layer.
|
||||
this->qverts_range.first = this->offsets[i * 2];
|
||||
this->tverts_range.first = this->offsets[i * 2 + 1];
|
||||
|
@ -633,8 +671,9 @@ void GLVolume::set_range(double min_z, double max_z)
|
|||
}
|
||||
}
|
||||
}
|
||||
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
|
||||
void GLVolume::render() const
|
||||
void GLVolume::render()
|
||||
{
|
||||
if (!is_active)
|
||||
return;
|
||||
|
@ -645,7 +684,14 @@ void GLVolume::render() const
|
|||
glsafe(::glPushMatrix());
|
||||
glsafe(::glMultMatrixd(world_matrix().data()));
|
||||
|
||||
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
if (tverts_range == std::make_pair<size_t, size_t>(0, -1))
|
||||
model.render();
|
||||
else
|
||||
model.render(this->tverts_range);
|
||||
#else
|
||||
this->indexed_vertex_array.render(this->tverts_range, this->qverts_range);
|
||||
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
|
||||
glsafe(::glPopMatrix());
|
||||
if (this->is_left_handed())
|
||||
|
@ -680,25 +726,44 @@ void GLVolume::render_non_manifold_edges()
|
|||
}
|
||||
#endif // ENABLE_SHOW_NON_MANIFOLD_EDGES
|
||||
|
||||
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
std::vector<int> GLVolumeCollection::load_object(
|
||||
const ModelObject* model_object,
|
||||
int obj_idx,
|
||||
const std::vector<int>& instance_idxs)
|
||||
#else
|
||||
std::vector<int> GLVolumeCollection::load_object(
|
||||
const ModelObject *model_object,
|
||||
int obj_idx,
|
||||
const std::vector<int> &instance_idxs,
|
||||
bool opengl_initialized)
|
||||
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
{
|
||||
std::vector<int> volumes_idx;
|
||||
for (int volume_idx = 0; volume_idx < int(model_object->volumes.size()); ++volume_idx)
|
||||
for (int instance_idx : instance_idxs)
|
||||
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
volumes_idx.emplace_back(this->GLVolumeCollection::load_object_volume(model_object, obj_idx, volume_idx, instance_idx));
|
||||
#else
|
||||
volumes_idx.emplace_back(this->GLVolumeCollection::load_object_volume(model_object, obj_idx, volume_idx, instance_idx, opengl_initialized));
|
||||
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
return volumes_idx;
|
||||
}
|
||||
|
||||
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
int GLVolumeCollection::load_object_volume(
|
||||
const ModelObject* model_object,
|
||||
int obj_idx,
|
||||
int volume_idx,
|
||||
int instance_idx)
|
||||
#else
|
||||
int GLVolumeCollection::load_object_volume(
|
||||
const ModelObject *model_object,
|
||||
int obj_idx,
|
||||
int volume_idx,
|
||||
int instance_idx,
|
||||
bool opengl_initialized)
|
||||
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
{
|
||||
const ModelVolume *model_volume = model_object->volumes[volume_idx];
|
||||
const int extruder_id = model_volume->extruder_id();
|
||||
|
@ -707,15 +772,22 @@ int GLVolumeCollection::load_object_volume(
|
|||
this->volumes.emplace_back(new GLVolume());
|
||||
GLVolume& v = *this->volumes.back();
|
||||
v.set_color(color_from_model_volume(*model_volume));
|
||||
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
#if ENABLE_SMOOTH_NORMALS
|
||||
v.model.init_from(mesh, true);
|
||||
#else
|
||||
v.model.init_from(mesh);
|
||||
#endif // ENABLE_SMOOTH_NORMALS
|
||||
#else
|
||||
#if ENABLE_SMOOTH_NORMALS
|
||||
v.indexed_vertex_array.load_mesh(mesh, true);
|
||||
#else
|
||||
v.indexed_vertex_array.load_mesh(mesh);
|
||||
#endif // ENABLE_SMOOTH_NORMALS
|
||||
v.indexed_vertex_array.finalize_geometry(opengl_initialized);
|
||||
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
v.composite_id = GLVolume::CompositeID(obj_idx, volume_idx, instance_idx);
|
||||
if (model_volume->is_model_part())
|
||||
{
|
||||
if (model_volume->is_model_part()) {
|
||||
// GLVolume will reference a convex hull from model_volume!
|
||||
v.set_convex_hull(model_volume->get_convex_hull_shared_ptr());
|
||||
if (extruder_id != -1)
|
||||
|
@ -732,6 +804,16 @@ int GLVolumeCollection::load_object_volume(
|
|||
// Load SLA auxiliary GLVolumes (for support trees or pad).
|
||||
// This function produces volumes for multiple instances in a single shot,
|
||||
// as some object specific mesh conversions may be expensive.
|
||||
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
void GLVolumeCollection::load_object_auxiliary(
|
||||
const SLAPrintObject* print_object,
|
||||
int obj_idx,
|
||||
// pairs of <instance_idx, print_instance_idx>
|
||||
const std::vector<std::pair<size_t, size_t>>& instances,
|
||||
SLAPrintObjectStep milestone,
|
||||
// Timestamp of the last change of the milestone
|
||||
size_t timestamp)
|
||||
#else
|
||||
void GLVolumeCollection::load_object_auxiliary(
|
||||
const SLAPrintObject *print_object,
|
||||
int obj_idx,
|
||||
|
@ -741,6 +823,7 @@ void GLVolumeCollection::load_object_auxiliary(
|
|||
// Timestamp of the last change of the milestone
|
||||
size_t timestamp,
|
||||
bool opengl_initialized)
|
||||
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
{
|
||||
assert(print_object->is_step_done(milestone));
|
||||
Transform3d mesh_trafo_inv = print_object->trafo().inverse();
|
||||
|
@ -753,12 +836,21 @@ void GLVolumeCollection::load_object_auxiliary(
|
|||
const ModelInstance& model_instance = *print_object->model_object()->instances[instance_idx.first];
|
||||
this->volumes.emplace_back(new GLVolume((milestone == slaposPad) ? GLVolume::SLA_PAD_COLOR : GLVolume::SLA_SUPPORT_COLOR));
|
||||
GLVolume& v = *this->volumes.back();
|
||||
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
#if ENABLE_SMOOTH_NORMALS
|
||||
v.model.init_from(mesh, true);
|
||||
#else
|
||||
v.model.init_from(mesh);
|
||||
#endif // ENABLE_SMOOTH_NORMALS
|
||||
v.model.set_color((milestone == slaposPad) ? GLVolume::SLA_PAD_COLOR : GLVolume::SLA_SUPPORT_COLOR);
|
||||
#else
|
||||
#if ENABLE_SMOOTH_NORMALS
|
||||
v.indexed_vertex_array.load_mesh(mesh, true);
|
||||
#else
|
||||
v.indexed_vertex_array.load_mesh(mesh);
|
||||
#endif // ENABLE_SMOOTH_NORMALS
|
||||
v.indexed_vertex_array.finalize_geometry(opengl_initialized);
|
||||
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
v.composite_id = GLVolume::CompositeID(obj_idx, -int(milestone), (int)instance_idx.first);
|
||||
v.geometry_id = std::pair<size_t, size_t>(timestamp, model_instance.id().id);
|
||||
// Create a copy of the convex hull mesh for each instance. Use a move operator on the last instance.
|
||||
|
@ -774,6 +866,17 @@ void GLVolumeCollection::load_object_auxiliary(
|
|||
}
|
||||
}
|
||||
|
||||
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
#if ENABLE_WIPETOWER_OBJECTID_1000_REMOVAL
|
||||
int GLVolumeCollection::load_wipe_tower_preview(
|
||||
float pos_x, float pos_y, float width, float depth, float height,
|
||||
float rotation_angle, bool size_unknown, float brim_width)
|
||||
#else
|
||||
int GLVolumeCollection::load_wipe_tower_preview(
|
||||
int obj_idx, float pos_x, float pos_y, float width, float depth, float height,
|
||||
float rotation_angle, bool size_unknown, float brim_width)
|
||||
#endif // ENABLE_WIPETOWER_OBJECTID_1000_REMOVAL
|
||||
#else
|
||||
#if ENABLE_WIPETOWER_OBJECTID_1000_REMOVAL
|
||||
int GLVolumeCollection::load_wipe_tower_preview(
|
||||
float pos_x, float pos_y, float width, float depth, float height,
|
||||
|
@ -783,6 +886,7 @@ int GLVolumeCollection::load_wipe_tower_preview(
|
|||
int obj_idx, float pos_x, float pos_y, float width, float depth, float height,
|
||||
float rotation_angle, bool size_unknown, float brim_width, bool opengl_initialized)
|
||||
#endif // ENABLE_WIPETOWER_OBJECTID_1000_REMOVAL
|
||||
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
{
|
||||
if (depth < 0.01f)
|
||||
return int(this->volumes.size() - 1);
|
||||
|
@ -839,9 +943,16 @@ int GLVolumeCollection::load_wipe_tower_preview(
|
|||
|
||||
volumes.emplace_back(new GLVolume(color));
|
||||
GLVolume& v = *volumes.back();
|
||||
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
v.model.init_from(mesh);
|
||||
v.model.set_color(color);
|
||||
#else
|
||||
v.indexed_vertex_array.load_mesh(mesh);
|
||||
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
v.set_convex_hull(mesh.convex_hull_3d());
|
||||
#if !ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
v.indexed_vertex_array.finalize_geometry(opengl_initialized);
|
||||
#endif // !ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
v.set_volume_offset(Vec3d(pos_x, pos_y, 0.0));
|
||||
v.set_volume_rotation(Vec3d(0., 0., (M_PI / 180.) * rotation_angle));
|
||||
#if ENABLE_WIPETOWER_OBJECTID_1000_REMOVAL
|
||||
|
@ -856,6 +967,22 @@ int GLVolumeCollection::load_wipe_tower_preview(
|
|||
return int(volumes.size() - 1);
|
||||
}
|
||||
|
||||
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
GLVolume* GLVolumeCollection::new_toolpath_volume(const ColorRGBA& rgba)
|
||||
{
|
||||
GLVolume* out = new_nontoolpath_volume(rgba);
|
||||
out->is_extrusion_path = true;
|
||||
return out;
|
||||
}
|
||||
|
||||
GLVolume* GLVolumeCollection::new_nontoolpath_volume(const ColorRGBA& rgba)
|
||||
{
|
||||
GLVolume* out = new GLVolume(rgba);
|
||||
out->is_extrusion_path = false;
|
||||
this->volumes.emplace_back(out);
|
||||
return out;
|
||||
}
|
||||
#else
|
||||
GLVolume* GLVolumeCollection::new_toolpath_volume(const ColorRGBA& rgba, size_t reserve_vbo_floats)
|
||||
{
|
||||
GLVolume *out = new_nontoolpath_volume(rgba, reserve_vbo_floats);
|
||||
|
@ -872,6 +999,7 @@ GLVolume* GLVolumeCollection::new_nontoolpath_volume(const ColorRGBA& rgba, size
|
|||
this->volumes.emplace_back(out);
|
||||
return out;
|
||||
}
|
||||
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
|
||||
GLVolumeWithIdAndZList volumes_to_render(const GLVolumePtrs& volumes, GLVolumeCollection::ERenderType type, const Transform3d& view_matrix, std::function<bool(const GLVolume&)> filter_func)
|
||||
{
|
||||
|
@ -960,7 +1088,10 @@ void GLVolumeCollection::render(GLVolumeCollection::ERenderType type, bool disab
|
|||
glsafe(::glEnableClientState(GL_VERTEX_ARRAY));
|
||||
glsafe(::glEnableClientState(GL_NORMAL_ARRAY));
|
||||
|
||||
shader->set_uniform("uniform_color", volume.first->render_color);
|
||||
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
if (!volume.first->model.is_initialized())
|
||||
#endif // !ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
shader->set_uniform("uniform_color", volume.first->render_color);
|
||||
shader->set_uniform("z_range", m_z_range, 2);
|
||||
shader->set_uniform("clipping_plane", m_clipping_plane, 4);
|
||||
shader->set_uniform("print_volume.type", static_cast<int>(m_print_volume.type));
|
||||
|
@ -980,6 +1111,9 @@ void GLVolumeCollection::render(GLVolumeCollection::ERenderType type, bool disab
|
|||
#endif // ENABLE_ENVIRONMENT_MAP
|
||||
glcheck();
|
||||
|
||||
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
volume.first->model.set_color(volume.first->render_color);
|
||||
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
volume.first->render();
|
||||
|
||||
#if ENABLE_ENVIRONMENT_MAP
|
||||
|
@ -1215,6 +1349,466 @@ std::string GLVolumeCollection::log_memory_info() const
|
|||
return " (GLVolumeCollection RAM: " + format_memsize_MB(this->cpu_memory_used()) + " GPU: " + format_memsize_MB(this->gpu_memory_used()) + " Both: " + format_memsize_MB(this->gpu_memory_used()) + ")";
|
||||
}
|
||||
|
||||
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
static void thick_lines_to_geometry(
|
||||
const Lines& lines,
|
||||
const std::vector<double>& widths,
|
||||
const std::vector<double>& heights,
|
||||
bool closed,
|
||||
double top_z,
|
||||
GUI::GLModel::Geometry& geometry)
|
||||
{
|
||||
assert(!lines.empty());
|
||||
if (lines.empty())
|
||||
return;
|
||||
|
||||
enum Direction : unsigned char
|
||||
{
|
||||
Left,
|
||||
Right,
|
||||
Top,
|
||||
Bottom
|
||||
};
|
||||
|
||||
// right, left, top, bottom
|
||||
std::array<int, 4> idx_prev = { -1, -1, -1, -1 };
|
||||
std::array<int, 4> idx_initial = { -1, -1, -1, -1 };
|
||||
|
||||
double bottom_z_prev = 0.0;
|
||||
Vec2d b1_prev(Vec2d::Zero());
|
||||
Vec2d v_prev(Vec2d::Zero());
|
||||
double len_prev = 0.0;
|
||||
double width_initial = 0.0;
|
||||
double bottom_z_initial = 0.0;
|
||||
|
||||
// loop once more in case of closed loops
|
||||
const size_t lines_end = closed ? (lines.size() + 1) : lines.size();
|
||||
for (size_t ii = 0; ii < lines_end; ++ii) {
|
||||
const size_t i = (ii == lines.size()) ? 0 : ii;
|
||||
const Line& line = lines[i];
|
||||
const double bottom_z = top_z - heights[i];
|
||||
const double middle_z = 0.5 * (top_z + bottom_z);
|
||||
const double width = widths[i];
|
||||
|
||||
const bool is_first = (ii == 0);
|
||||
const bool is_last = (ii == lines_end - 1);
|
||||
const bool is_closing = closed && is_last;
|
||||
|
||||
const Vec2d v = unscale(line.vector()).normalized();
|
||||
const double len = unscale<double>(line.length());
|
||||
|
||||
const Vec2d a = unscale(line.a);
|
||||
const Vec2d b = unscale(line.b);
|
||||
Vec2d a1 = a;
|
||||
Vec2d a2 = a;
|
||||
Vec2d b1 = b;
|
||||
Vec2d b2 = b;
|
||||
{
|
||||
const double dist = 0.5 * width; // scaled
|
||||
const double dx = dist * v.x();
|
||||
const double dy = dist * v.y();
|
||||
a1 += Vec2d(+dy, -dx);
|
||||
a2 += Vec2d(-dy, +dx);
|
||||
b1 += Vec2d(+dy, -dx);
|
||||
b2 += Vec2d(-dy, +dx);
|
||||
}
|
||||
|
||||
// calculate new XY normals
|
||||
const Vec2d xy_right_normal = unscale(line.normal()).normalized();
|
||||
|
||||
std::array<int, 4> idx_a = { 0, 0, 0, 0 };
|
||||
std::array<int, 4> idx_b = { 0, 0, 0, 0 };
|
||||
int idx_last = int(geometry.vertices_count());
|
||||
|
||||
const bool bottom_z_different = bottom_z_prev != bottom_z;
|
||||
bottom_z_prev = bottom_z;
|
||||
|
||||
if (!is_first && bottom_z_different) {
|
||||
// Found a change of the layer thickness -> Add a cap at the end of the previous segment.
|
||||
geometry.add_uint_triangle(idx_b[Bottom], idx_b[Left], idx_b[Top]);
|
||||
geometry.add_uint_triangle(idx_b[Bottom], idx_b[Top], idx_b[Right]);
|
||||
}
|
||||
|
||||
// Share top / bottom vertices if possible.
|
||||
if (is_first) {
|
||||
idx_a[Top] = idx_last++;
|
||||
geometry.add_vertex(Vec3f(a.x(), a.y(), top_z), Vec3f(0.0f, 0.0f, 1.0f));
|
||||
}
|
||||
else
|
||||
idx_a[Top] = idx_prev[Top];
|
||||
|
||||
if (is_first || bottom_z_different) {
|
||||
// Start of the 1st line segment or a change of the layer thickness while maintaining the print_z.
|
||||
idx_a[Bottom] = idx_last++;
|
||||
geometry.add_vertex(Vec3f(a.x(), a.y(), bottom_z), Vec3f(0.0f, 0.0f, -1.0f));
|
||||
idx_a[Left] = idx_last++;
|
||||
geometry.add_vertex(Vec3f(a2.x(), a2.y(), middle_z), Vec3f(-xy_right_normal.x(), -xy_right_normal.y(), 0.0f));
|
||||
idx_a[Right] = idx_last++;
|
||||
geometry.add_vertex(Vec3f(a1.x(), a1.y(), middle_z), Vec3f(xy_right_normal.x(), xy_right_normal.y(), 0.0f));
|
||||
}
|
||||
else
|
||||
idx_a[Bottom] = idx_prev[Bottom];
|
||||
|
||||
if (is_first) {
|
||||
// Start of the 1st line segment.
|
||||
width_initial = width;
|
||||
bottom_z_initial = bottom_z;
|
||||
idx_initial = idx_a;
|
||||
}
|
||||
else {
|
||||
// Continuing a previous segment.
|
||||
// Share left / right vertices if possible.
|
||||
const double v_dot = v_prev.dot(v);
|
||||
// To reduce gpu memory usage, we try to reuse vertices
|
||||
// To reduce the visual artifacts, due to averaged normals, we allow to reuse vertices only when any of two adjacent edges
|
||||
// is longer than a fixed threshold.
|
||||
// The following value is arbitrary, it comes from tests made on a bunch of models showing the visual artifacts
|
||||
const double len_threshold = 2.5;
|
||||
|
||||
// Generate new vertices if the angle between adjacent edges is greater than 45 degrees or thresholds conditions are met
|
||||
const bool sharp = (v_dot < 0.707) || (len_prev > len_threshold) || (len > len_threshold);
|
||||
if (sharp) {
|
||||
if (!bottom_z_different) {
|
||||
// Allocate new left / right points for the start of this segment as these points will receive their own normals to indicate a sharp turn.
|
||||
idx_a[Right] = idx_last++;
|
||||
geometry.add_vertex(Vec3f(a1.x(), a1.y(), middle_z), Vec3f(xy_right_normal.x(), xy_right_normal.y(), 0.0f));
|
||||
idx_a[Left] = idx_last++;
|
||||
geometry.add_vertex(Vec3f(a2.x(), a2.y(), middle_z), Vec3f(-xy_right_normal.x(), -xy_right_normal.y(), 0.0f));
|
||||
if (cross2(v_prev, v) > 0.0) {
|
||||
// Right turn. Fill in the right turn wedge.
|
||||
geometry.add_uint_triangle(idx_prev[Right], idx_a[Right], idx_prev[Top]);
|
||||
geometry.add_uint_triangle(idx_prev[Right], idx_prev[Bottom], idx_a[Right]);
|
||||
}
|
||||
else {
|
||||
// Left turn. Fill in the left turn wedge.
|
||||
geometry.add_uint_triangle(idx_prev[Left], idx_prev[Top], idx_a[Left]);
|
||||
geometry.add_uint_triangle(idx_prev[Left], idx_a[Left], idx_prev[Bottom]);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (!bottom_z_different) {
|
||||
// The two successive segments are nearly collinear.
|
||||
idx_a[Left] = idx_prev[Left];
|
||||
idx_a[Right] = idx_prev[Right];
|
||||
}
|
||||
}
|
||||
if (is_closing) {
|
||||
if (!sharp) {
|
||||
if (!bottom_z_different) {
|
||||
// Closing a loop with smooth transition. Unify the closing left / right vertices.
|
||||
geometry.set_vertex(idx_initial[Left], geometry.extract_position_3(idx_prev[Left]), geometry.extract_normal_3(idx_prev[Left]));
|
||||
geometry.set_vertex(idx_initial[Right], geometry.extract_position_3(idx_prev[Right]), geometry.extract_normal_3(idx_prev[Right]));
|
||||
geometry.remove_vertex(geometry.vertices_count() - 1);
|
||||
geometry.remove_vertex(geometry.vertices_count() - 1);
|
||||
// Replace the left / right vertex indices to point to the start of the loop.
|
||||
const size_t indices_count = geometry.indices_count();
|
||||
for (size_t u = indices_count - 24; u < indices_count; ++u) {
|
||||
const unsigned int id = geometry.extract_uint_index(u);
|
||||
if (id == (unsigned int)idx_prev[Left])
|
||||
geometry.set_uint_index(u, (unsigned int)idx_initial[Left]);
|
||||
else if (id == (unsigned int)idx_prev[Right])
|
||||
geometry.set_uint_index(u, (unsigned int)idx_initial[Right]);
|
||||
}
|
||||
}
|
||||
}
|
||||
// This is the last iteration, only required to solve the transition.
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Only new allocate top / bottom vertices, if not closing a loop.
|
||||
if (is_closing)
|
||||
idx_b[Top] = idx_initial[Top];
|
||||
else {
|
||||
idx_b[Top] = idx_last++;
|
||||
geometry.add_vertex(Vec3f(b.x(), b.y(), top_z), Vec3f(0.0f, 0.0f, 1.0f));
|
||||
}
|
||||
|
||||
if (is_closing && width == width_initial && bottom_z == bottom_z_initial)
|
||||
idx_b[Bottom] = idx_initial[Bottom];
|
||||
else {
|
||||
idx_b[Bottom] = idx_last++;
|
||||
geometry.add_vertex(Vec3f(b.x(), b.y(), bottom_z), Vec3f(0.0f, 0.0f, -1.0f));
|
||||
}
|
||||
// Generate new vertices for the end of this line segment.
|
||||
idx_b[Left] = idx_last++;
|
||||
geometry.add_vertex(Vec3f(b2.x(), b2.y(), middle_z), Vec3f(-xy_right_normal.x(), -xy_right_normal.y(), 0.0f));
|
||||
idx_b[Right] = idx_last++;
|
||||
geometry.add_vertex(Vec3f(b1.x(), b1.y(), middle_z), Vec3f(xy_right_normal.x(), xy_right_normal.y(), 0.0f));
|
||||
|
||||
idx_prev = idx_b;
|
||||
bottom_z_prev = bottom_z;
|
||||
b1_prev = b1;
|
||||
v_prev = v;
|
||||
len_prev = len;
|
||||
|
||||
if (bottom_z_different && (closed || (!is_first && !is_last))) {
|
||||
// Found a change of the layer thickness -> Add a cap at the beginning of this segment.
|
||||
geometry.add_uint_triangle(idx_a[Bottom], idx_a[Right], idx_a[Top]);
|
||||
geometry.add_uint_triangle(idx_a[Bottom], idx_a[Top], idx_a[Left]);
|
||||
}
|
||||
|
||||
if (!closed) {
|
||||
// Terminate open paths with caps.
|
||||
if (is_first) {
|
||||
geometry.add_uint_triangle(idx_a[Bottom], idx_a[Right], idx_a[Top]);
|
||||
geometry.add_uint_triangle(idx_a[Bottom], idx_a[Top], idx_a[Left]);
|
||||
}
|
||||
// We don't use 'else' because both cases are true if we have only one line.
|
||||
if (is_last) {
|
||||
geometry.add_uint_triangle(idx_b[Bottom], idx_b[Left], idx_b[Top]);
|
||||
geometry.add_uint_triangle(idx_b[Bottom], idx_b[Top], idx_b[Right]);
|
||||
}
|
||||
}
|
||||
|
||||
// Add quads for a straight hollow tube-like segment.
|
||||
// bottom-right face
|
||||
geometry.add_uint_triangle(idx_a[Bottom], idx_b[Bottom], idx_b[Right]);
|
||||
geometry.add_uint_triangle(idx_a[Bottom], idx_b[Right], idx_a[Right]);
|
||||
// top-right face
|
||||
geometry.add_uint_triangle(idx_a[Right], idx_b[Right], idx_b[Top]);
|
||||
geometry.add_uint_triangle(idx_a[Right], idx_b[Top], idx_a[Top]);
|
||||
// top-left face
|
||||
geometry.add_uint_triangle(idx_a[Top], idx_b[Top], idx_b[Left]);
|
||||
geometry.add_uint_triangle(idx_a[Top], idx_b[Left], idx_a[Left]);
|
||||
// bottom-left face
|
||||
geometry.add_uint_triangle(idx_a[Left], idx_b[Left], idx_b[Bottom]);
|
||||
geometry.add_uint_triangle(idx_a[Left], idx_b[Bottom], idx_a[Bottom]);
|
||||
}
|
||||
}
|
||||
|
||||
// caller is responsible for supplying NO lines with zero length
|
||||
static void thick_lines_to_geometry(
|
||||
const Lines3& lines,
|
||||
const std::vector<double>& widths,
|
||||
const std::vector<double>& heights,
|
||||
bool closed,
|
||||
GUI::GLModel::Geometry& geometry)
|
||||
{
|
||||
assert(!lines.empty());
|
||||
if (lines.empty())
|
||||
return;
|
||||
|
||||
enum Direction : unsigned char
|
||||
{
|
||||
Left,
|
||||
Right,
|
||||
Top,
|
||||
Bottom
|
||||
};
|
||||
|
||||
// left, right, top, bottom
|
||||
std::array<int, 4> idx_prev = { -1, -1, -1, -1 };
|
||||
std::array<int, 4> idx_initial = { -1, -1, -1, -1 };
|
||||
|
||||
double z_prev = 0.0;
|
||||
double len_prev = 0.0;
|
||||
Vec3d n_right_prev = Vec3d::Zero();
|
||||
Vec3d n_top_prev = Vec3d::Zero();
|
||||
Vec3d unit_v_prev = Vec3d::Zero();
|
||||
double width_initial = 0.0;
|
||||
|
||||
// new vertices around the line endpoints
|
||||
// left, right, top, bottom
|
||||
std::array<Vec3d, 4> a = { Vec3d::Zero(), Vec3d::Zero(), Vec3d::Zero(), Vec3d::Zero() };
|
||||
std::array<Vec3d, 4> b = { Vec3d::Zero(), Vec3d::Zero(), Vec3d::Zero(), Vec3d::Zero() };
|
||||
|
||||
// loop once more in case of closed loops
|
||||
const size_t lines_end = closed ? (lines.size() + 1) : lines.size();
|
||||
for (size_t ii = 0; ii < lines_end; ++ii) {
|
||||
const size_t i = (ii == lines.size()) ? 0 : ii;
|
||||
|
||||
const Line3& line = lines[i];
|
||||
const double height = heights[i];
|
||||
const double width = widths[i];
|
||||
|
||||
const Vec3d unit_v = unscale(line.vector()).normalized();
|
||||
const double len = unscale<double>(line.length());
|
||||
|
||||
Vec3d n_top = Vec3d::Zero();
|
||||
Vec3d n_right = Vec3d::Zero();
|
||||
|
||||
if (line.a.x() == line.b.x() && line.a.y() == line.b.y()) {
|
||||
// vertical segment
|
||||
n_top = Vec3d::UnitY();
|
||||
n_right = Vec3d::UnitX();
|
||||
if (line.a.z() < line.b.z())
|
||||
n_right = -n_right;
|
||||
}
|
||||
else {
|
||||
// horizontal segment
|
||||
n_right = unit_v.cross(Vec3d::UnitZ()).normalized();
|
||||
n_top = n_right.cross(unit_v).normalized();
|
||||
}
|
||||
|
||||
const Vec3d rl_displacement = 0.5 * width * n_right;
|
||||
const Vec3d tb_displacement = 0.5 * height * n_top;
|
||||
const Vec3d l_a = unscale(line.a);
|
||||
const Vec3d l_b = unscale(line.b);
|
||||
|
||||
a[Right] = l_a + rl_displacement;
|
||||
a[Left] = l_a - rl_displacement;
|
||||
a[Top] = l_a + tb_displacement;
|
||||
a[Bottom] = l_a - tb_displacement;
|
||||
b[Right] = l_b + rl_displacement;
|
||||
b[Left] = l_b - rl_displacement;
|
||||
b[Top] = l_b + tb_displacement;
|
||||
b[Bottom] = l_b - tb_displacement;
|
||||
|
||||
const Vec3d n_bottom = -n_top;
|
||||
const Vec3d n_left = -n_right;
|
||||
|
||||
std::array<int, 4> idx_a = { 0, 0, 0, 0};
|
||||
std::array<int, 4> idx_b = { 0, 0, 0, 0 };
|
||||
int idx_last = int(geometry.vertices_count());
|
||||
|
||||
const bool z_different = (z_prev != l_a.z());
|
||||
z_prev = l_b.z();
|
||||
|
||||
// Share top / bottom vertices if possible.
|
||||
if (ii == 0) {
|
||||
idx_a[Top] = idx_last++;
|
||||
geometry.add_vertex((Vec3f)a[Top].cast<float>(), (Vec3f)n_top.cast<float>());
|
||||
}
|
||||
else
|
||||
idx_a[Top] = idx_prev[Top];
|
||||
|
||||
if (ii == 0 || z_different) {
|
||||
// Start of the 1st line segment or a change of the layer thickness while maintaining the print_z.
|
||||
idx_a[Bottom] = idx_last++;
|
||||
geometry.add_vertex((Vec3f)a[Bottom].cast<float>(), (Vec3f)n_bottom.cast<float>());
|
||||
idx_a[Left] = idx_last++;
|
||||
geometry.add_vertex((Vec3f)a[Left].cast<float>(), (Vec3f)n_left.cast<float>());
|
||||
idx_a[Right] = idx_last++;
|
||||
geometry.add_vertex((Vec3f)a[Right].cast<float>(), (Vec3f)n_right.cast<float>());
|
||||
}
|
||||
else
|
||||
idx_a[Bottom] = idx_prev[Bottom];
|
||||
|
||||
if (ii == 0) {
|
||||
// Start of the 1st line segment.
|
||||
width_initial = width;
|
||||
idx_initial = idx_a;
|
||||
}
|
||||
else {
|
||||
// Continuing a previous segment.
|
||||
// Share left / right vertices if possible.
|
||||
const double v_dot = unit_v_prev.dot(unit_v);
|
||||
const bool is_right_turn = n_top_prev.dot(unit_v_prev.cross(unit_v)) > 0.0;
|
||||
|
||||
// To reduce gpu memory usage, we try to reuse vertices
|
||||
// To reduce the visual artifacts, due to averaged normals, we allow to reuse vertices only when any of two adjacent edges
|
||||
// is longer than a fixed threshold.
|
||||
// The following value is arbitrary, it comes from tests made on a bunch of models showing the visual artifacts
|
||||
const double len_threshold = 2.5;
|
||||
|
||||
// Generate new vertices if the angle between adjacent edges is greater than 45 degrees or thresholds conditions are met
|
||||
const bool is_sharp = v_dot < 0.707 || len_prev > len_threshold || len > len_threshold;
|
||||
if (is_sharp) {
|
||||
// Allocate new left / right points for the start of this segment as these points will receive their own normals to indicate a sharp turn.
|
||||
idx_a[Right] = idx_last++;
|
||||
geometry.add_vertex((Vec3f)a[Right].cast<float>(), (Vec3f)n_right.cast<float>());
|
||||
idx_a[Left] = idx_last++;
|
||||
geometry.add_vertex((Vec3f)a[Left].cast<float>(), (Vec3f)n_left.cast<float>());
|
||||
|
||||
if (is_right_turn) {
|
||||
// Right turn. Fill in the right turn wedge.
|
||||
geometry.add_uint_triangle(idx_prev[Right], idx_a[Right], idx_prev[Top]);
|
||||
geometry.add_uint_triangle(idx_prev[Right], idx_prev[Bottom], idx_a[Right]);
|
||||
}
|
||||
else {
|
||||
// Left turn. Fill in the left turn wedge.
|
||||
geometry.add_uint_triangle(idx_prev[Left], idx_prev[Top], idx_a[Left]);
|
||||
geometry.add_uint_triangle(idx_prev[Left], idx_a[Left], idx_prev[Bottom]);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// The two successive segments are nearly collinear.
|
||||
idx_a[Left] = idx_prev[Left];
|
||||
idx_a[Right] = idx_prev[Right];
|
||||
}
|
||||
|
||||
if (ii == lines.size()) {
|
||||
if (!is_sharp) {
|
||||
// Closing a loop with smooth transition. Unify the closing left / right vertices.
|
||||
geometry.set_vertex(idx_initial[Left], geometry.extract_position_3(idx_prev[Left]), geometry.extract_normal_3(idx_prev[Left]));
|
||||
geometry.set_vertex(idx_initial[Right], geometry.extract_position_3(idx_prev[Right]), geometry.extract_normal_3(idx_prev[Right]));
|
||||
geometry.remove_vertex(geometry.vertices_count() - 1);
|
||||
geometry.remove_vertex(geometry.vertices_count() - 1);
|
||||
// Replace the left / right vertex indices to point to the start of the loop.
|
||||
const size_t indices_count = geometry.indices_count();
|
||||
for (size_t u = indices_count - 24; u < indices_count; ++u) {
|
||||
const unsigned int id = geometry.extract_uint_index(u);
|
||||
if (id == (unsigned int)idx_prev[Left])
|
||||
geometry.set_uint_index(u, (unsigned int)idx_initial[Left]);
|
||||
else if (id == (unsigned int)idx_prev[Right])
|
||||
geometry.set_uint_index(u, (unsigned int)idx_initial[Right]);
|
||||
}
|
||||
}
|
||||
|
||||
// This is the last iteration, only required to solve the transition.
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Only new allocate top / bottom vertices, if not closing a loop.
|
||||
if (closed && ii + 1 == lines.size())
|
||||
idx_b[Top] = idx_initial[Top];
|
||||
else {
|
||||
idx_b[Top] = idx_last++;
|
||||
geometry.add_vertex((Vec3f)b[Top].cast<float>(), (Vec3f)n_top.cast<float>());
|
||||
}
|
||||
|
||||
if (closed && ii + 1 == lines.size() && width == width_initial)
|
||||
idx_b[Bottom] = idx_initial[Bottom];
|
||||
else {
|
||||
idx_b[Bottom] = idx_last++;
|
||||
geometry.add_vertex((Vec3f)b[Bottom].cast<float>(), (Vec3f)n_bottom.cast<float>());
|
||||
}
|
||||
|
||||
// Generate new vertices for the end of this line segment.
|
||||
idx_b[Left] = idx_last++;
|
||||
geometry.add_vertex((Vec3f)b[Left].cast<float>(), (Vec3f)n_left.cast<float>());
|
||||
idx_b[Right] = idx_last++;
|
||||
geometry.add_vertex((Vec3f)b[Right].cast<float>(), (Vec3f)n_right.cast<float>());
|
||||
|
||||
idx_prev = idx_b;
|
||||
n_right_prev = n_right;
|
||||
n_top_prev = n_top;
|
||||
unit_v_prev = unit_v;
|
||||
len_prev = len;
|
||||
|
||||
if (!closed) {
|
||||
// Terminate open paths with caps.
|
||||
if (i == 0) {
|
||||
geometry.add_uint_triangle(idx_a[Bottom], idx_a[Right], idx_a[Top]);
|
||||
geometry.add_uint_triangle(idx_a[Bottom], idx_a[Top], idx_a[Left]);
|
||||
}
|
||||
|
||||
// We don't use 'else' because both cases are true if we have only one line.
|
||||
if (i + 1 == lines.size()) {
|
||||
geometry.add_uint_triangle(idx_b[Bottom], idx_b[Left], idx_b[Top]);
|
||||
geometry.add_uint_triangle(idx_b[Bottom], idx_b[Top], idx_b[Right]);
|
||||
}
|
||||
}
|
||||
|
||||
// Add quads for a straight hollow tube-like segment.
|
||||
// bottom-right face
|
||||
geometry.add_uint_triangle(idx_a[Bottom], idx_b[Bottom], idx_b[Right]);
|
||||
geometry.add_uint_triangle(idx_a[Bottom], idx_b[Right], idx_a[Right]);
|
||||
// top-right face
|
||||
geometry.add_uint_triangle(idx_a[Right], idx_b[Right], idx_b[Top]);
|
||||
geometry.add_uint_triangle(idx_a[Right], idx_b[Top], idx_a[Top]);
|
||||
// top-left face
|
||||
geometry.add_uint_triangle(idx_a[Top], idx_b[Top], idx_b[Left]);
|
||||
geometry.add_uint_triangle(idx_a[Top], idx_b[Left], idx_a[Left]);
|
||||
// bottom-left face
|
||||
geometry.add_uint_triangle(idx_a[Left], idx_b[Left], idx_b[Bottom]);
|
||||
geometry.add_uint_triangle(idx_a[Left], idx_b[Bottom], idx_a[Bottom]);
|
||||
}
|
||||
}
|
||||
#else
|
||||
// caller is responsible for supplying NO lines with zero length
|
||||
static void thick_lines_to_indexed_vertex_array(
|
||||
const Lines &lines,
|
||||
|
@ -1724,7 +2318,30 @@ static void point_to_indexed_vertex_array(const Vec3crd& point,
|
|||
volume.push_triangle(idxs[3], idxs[1], idxs[4]);
|
||||
volume.push_triangle(idxs[0], idxs[3], idxs[4]);
|
||||
}
|
||||
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
|
||||
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
void _3DScene::thick_lines_to_verts(
|
||||
const Lines& lines,
|
||||
const std::vector<double>& widths,
|
||||
const std::vector<double>& heights,
|
||||
bool closed,
|
||||
double top_z,
|
||||
GUI::GLModel::Geometry& geometry)
|
||||
{
|
||||
thick_lines_to_geometry(lines, widths, heights, closed, top_z, geometry);
|
||||
}
|
||||
|
||||
void _3DScene::thick_lines_to_verts(
|
||||
const Lines3& lines,
|
||||
const std::vector<double>& widths,
|
||||
const std::vector<double>& heights,
|
||||
bool closed,
|
||||
GUI::GLModel::Geometry& geometry)
|
||||
{
|
||||
thick_lines_to_geometry(lines, widths, heights, closed, geometry);
|
||||
}
|
||||
#else
|
||||
void _3DScene::thick_lines_to_verts(
|
||||
const Lines &lines,
|
||||
const std::vector<double> &widths,
|
||||
|
@ -1766,8 +2383,21 @@ void _3DScene::extrusionentity_to_verts(const ExtrusionPath &extrusion_path, flo
|
|||
{
|
||||
extrusionentity_to_verts(extrusion_path.polyline, extrusion_path.width, extrusion_path.height, print_z, volume);
|
||||
}
|
||||
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
|
||||
// Fill in the qverts and tverts with quads and triangles for the extrusion_path.
|
||||
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
void _3DScene::extrusionentity_to_verts(const ExtrusionPath& extrusion_path, float print_z, const Point& copy, GUI::GLModel::Geometry& geometry)
|
||||
{
|
||||
Polyline polyline = extrusion_path.polyline;
|
||||
polyline.remove_duplicate_points();
|
||||
polyline.translate(copy);
|
||||
const Lines lines = polyline.lines();
|
||||
std::vector<double> widths(lines.size(), extrusion_path.width);
|
||||
std::vector<double> heights(lines.size(), extrusion_path.height);
|
||||
thick_lines_to_verts(lines, widths, heights, false, print_z, geometry);
|
||||
}
|
||||
#else
|
||||
void _3DScene::extrusionentity_to_verts(const ExtrusionPath &extrusion_path, float print_z, const Point ©, GLVolume &volume)
|
||||
{
|
||||
Polyline polyline = extrusion_path.polyline;
|
||||
|
@ -1778,8 +2408,27 @@ void _3DScene::extrusionentity_to_verts(const ExtrusionPath &extrusion_path, flo
|
|||
std::vector<double> heights(lines.size(), extrusion_path.height);
|
||||
thick_lines_to_verts(lines, widths, heights, false, print_z, volume);
|
||||
}
|
||||
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
|
||||
// Fill in the qverts and tverts with quads and triangles for the extrusion_loop.
|
||||
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
void _3DScene::extrusionentity_to_verts(const ExtrusionLoop& extrusion_loop, float print_z, const Point& copy, GUI::GLModel::Geometry& geometry)
|
||||
{
|
||||
Lines lines;
|
||||
std::vector<double> widths;
|
||||
std::vector<double> heights;
|
||||
for (const ExtrusionPath& extrusion_path : extrusion_loop.paths) {
|
||||
Polyline polyline = extrusion_path.polyline;
|
||||
polyline.remove_duplicate_points();
|
||||
polyline.translate(copy);
|
||||
const Lines lines_this = polyline.lines();
|
||||
append(lines, lines_this);
|
||||
widths.insert(widths.end(), lines_this.size(), extrusion_path.width);
|
||||
heights.insert(heights.end(), lines_this.size(), extrusion_path.height);
|
||||
}
|
||||
thick_lines_to_verts(lines, widths, heights, true, print_z, geometry);
|
||||
}
|
||||
#else
|
||||
void _3DScene::extrusionentity_to_verts(const ExtrusionLoop &extrusion_loop, float print_z, const Point ©, GLVolume &volume)
|
||||
{
|
||||
Lines lines;
|
||||
|
@ -1796,8 +2445,27 @@ void _3DScene::extrusionentity_to_verts(const ExtrusionLoop &extrusion_loop, flo
|
|||
}
|
||||
thick_lines_to_verts(lines, widths, heights, true, print_z, volume);
|
||||
}
|
||||
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
|
||||
// Fill in the qverts and tverts with quads and triangles for the extrusion_multi_path.
|
||||
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
void _3DScene::extrusionentity_to_verts(const ExtrusionMultiPath& extrusion_multi_path, float print_z, const Point& copy, GUI::GLModel::Geometry& geometry)
|
||||
{
|
||||
Lines lines;
|
||||
std::vector<double> widths;
|
||||
std::vector<double> heights;
|
||||
for (const ExtrusionPath& extrusion_path : extrusion_multi_path.paths) {
|
||||
Polyline polyline = extrusion_path.polyline;
|
||||
polyline.remove_duplicate_points();
|
||||
polyline.translate(copy);
|
||||
const Lines lines_this = polyline.lines();
|
||||
append(lines, lines_this);
|
||||
widths.insert(widths.end(), lines_this.size(), extrusion_path.width);
|
||||
heights.insert(heights.end(), lines_this.size(), extrusion_path.height);
|
||||
}
|
||||
thick_lines_to_verts(lines, widths, heights, false, print_z, geometry);
|
||||
}
|
||||
#else
|
||||
void _3DScene::extrusionentity_to_verts(const ExtrusionMultiPath &extrusion_multi_path, float print_z, const Point ©, GLVolume &volume)
|
||||
{
|
||||
Lines lines;
|
||||
|
@ -1814,13 +2482,49 @@ void _3DScene::extrusionentity_to_verts(const ExtrusionMultiPath &extrusion_mult
|
|||
}
|
||||
thick_lines_to_verts(lines, widths, heights, false, print_z, volume);
|
||||
}
|
||||
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
|
||||
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
void _3DScene::extrusionentity_to_verts(const ExtrusionEntityCollection& extrusion_entity_collection, float print_z, const Point& copy, GUI::GLModel::Geometry& geometry)
|
||||
{
|
||||
for (const ExtrusionEntity* extrusion_entity : extrusion_entity_collection.entities)
|
||||
extrusionentity_to_verts(extrusion_entity, print_z, copy, geometry);
|
||||
}
|
||||
#else
|
||||
void _3DScene::extrusionentity_to_verts(const ExtrusionEntityCollection &extrusion_entity_collection, float print_z, const Point ©, GLVolume &volume)
|
||||
{
|
||||
for (const ExtrusionEntity *extrusion_entity : extrusion_entity_collection.entities)
|
||||
extrusionentity_to_verts(extrusion_entity, print_z, copy, volume);
|
||||
}
|
||||
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
|
||||
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
void _3DScene::extrusionentity_to_verts(const ExtrusionEntity* extrusion_entity, float print_z, const Point& copy, GUI::GLModel::Geometry& geometry)
|
||||
{
|
||||
if (extrusion_entity != nullptr) {
|
||||
auto* extrusion_path = dynamic_cast<const ExtrusionPath*>(extrusion_entity);
|
||||
if (extrusion_path != nullptr)
|
||||
extrusionentity_to_verts(*extrusion_path, print_z, copy, geometry);
|
||||
else {
|
||||
auto* extrusion_loop = dynamic_cast<const ExtrusionLoop*>(extrusion_entity);
|
||||
if (extrusion_loop != nullptr)
|
||||
extrusionentity_to_verts(*extrusion_loop, print_z, copy, geometry);
|
||||
else {
|
||||
auto* extrusion_multi_path = dynamic_cast<const ExtrusionMultiPath*>(extrusion_entity);
|
||||
if (extrusion_multi_path != nullptr)
|
||||
extrusionentity_to_verts(*extrusion_multi_path, print_z, copy, geometry);
|
||||
else {
|
||||
auto* extrusion_entity_collection = dynamic_cast<const ExtrusionEntityCollection*>(extrusion_entity);
|
||||
if (extrusion_entity_collection != nullptr)
|
||||
extrusionentity_to_verts(*extrusion_entity_collection, print_z, copy, geometry);
|
||||
else
|
||||
throw Slic3r::RuntimeError("Unexpected extrusion_entity type in to_verts()");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
void _3DScene::extrusionentity_to_verts(const ExtrusionEntity *extrusion_entity, float print_z, const Point ©, GLVolume &volume)
|
||||
{
|
||||
if (extrusion_entity != nullptr) {
|
||||
|
@ -1839,9 +2543,8 @@ void _3DScene::extrusionentity_to_verts(const ExtrusionEntity *extrusion_entity,
|
|||
auto *extrusion_entity_collection = dynamic_cast<const ExtrusionEntityCollection*>(extrusion_entity);
|
||||
if (extrusion_entity_collection != nullptr)
|
||||
extrusionentity_to_verts(*extrusion_entity_collection, print_z, copy, volume);
|
||||
else {
|
||||
else
|
||||
throw Slic3r::RuntimeError("Unexpected extrusion_entity type in to_verts()");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1860,5 +2563,6 @@ void _3DScene::point3_to_verts(const Vec3crd& point, double width, double height
|
|||
{
|
||||
thick_point_to_verts(point, width, height, volume);
|
||||
}
|
||||
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
|
||||
} // namespace Slic3r
|
||||
|
|
|
@ -46,6 +46,7 @@ enum ModelInstanceEPrintVolumeState : unsigned char;
|
|||
// Return appropriate color based on the ModelVolume.
|
||||
extern ColorRGBA color_from_model_volume(const ModelVolume& model_volume);
|
||||
|
||||
#if !ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
// A container for interleaved arrays of 3D vertices and normals,
|
||||
// possibly indexed by triangles and / or quads.
|
||||
class GLIndexedVertexArray {
|
||||
|
@ -246,6 +247,7 @@ public:
|
|||
private:
|
||||
BoundingBox m_bounding_box;
|
||||
};
|
||||
#endif // !ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
|
||||
class GLVolume {
|
||||
public:
|
||||
|
@ -388,11 +390,17 @@ public:
|
|||
// Is mouse or rectangle selection over this object to select/deselect it ?
|
||||
EHoverState hover;
|
||||
|
||||
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
GUI::GLModel model;
|
||||
#else
|
||||
// Interleaved triangles & normals with indexed triangles & quads.
|
||||
GLIndexedVertexArray indexed_vertex_array;
|
||||
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
// Ranges of triangle and quad indices to be rendered.
|
||||
std::pair<size_t, size_t> tverts_range;
|
||||
#if !ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
std::pair<size_t, size_t> qverts_range;
|
||||
#endif // !ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
|
||||
// If the qverts or tverts contain thick extrusions, then offsets keeps pointers of the starts
|
||||
// of the extrusions per layer.
|
||||
|
@ -402,13 +410,17 @@ public:
|
|||
|
||||
// Bounding box of this volume, in unscaled coordinates.
|
||||
BoundingBoxf3 bounding_box() const {
|
||||
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
return this->model.get_bounding_box();
|
||||
#else
|
||||
BoundingBoxf3 out;
|
||||
if (! this->indexed_vertex_array.bounding_box().isEmpty()) {
|
||||
if (!this->indexed_vertex_array.bounding_box().isEmpty()) {
|
||||
out.min = this->indexed_vertex_array.bounding_box().min().cast<double>();
|
||||
out.max = this->indexed_vertex_array.bounding_box().max().cast<double>();
|
||||
out.defined = true;
|
||||
};
|
||||
}
|
||||
return out;
|
||||
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
}
|
||||
|
||||
void set_color(const ColorRGBA& rgba) { color = rgba; }
|
||||
|
@ -498,14 +510,20 @@ public:
|
|||
// convex hull
|
||||
const TriangleMesh* convex_hull() const { return m_convex_hull.get(); }
|
||||
|
||||
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
bool empty() const { return this->model.is_empty(); }
|
||||
#else
|
||||
bool empty() const { return this->indexed_vertex_array.empty(); }
|
||||
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
|
||||
void set_range(double low, double high);
|
||||
|
||||
void render() const;
|
||||
void render();
|
||||
|
||||
#if !ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
void finalize_geometry(bool opengl_initialized) { this->indexed_vertex_array.finalize_geometry(opengl_initialized); }
|
||||
void release_geometry() { this->indexed_vertex_array.release_geometry(); }
|
||||
#endif // !ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
|
||||
void set_bounding_boxes_as_dirty() {
|
||||
m_transformed_bounding_box.reset();
|
||||
|
@ -524,12 +542,20 @@ public:
|
|||
#endif // ENABLE_SHOW_NON_MANIFOLD_EDGES
|
||||
|
||||
// Return an estimate of the memory consumed by this class.
|
||||
size_t cpu_memory_used() const {
|
||||
//FIXME what to do wih m_convex_hull?
|
||||
size_t cpu_memory_used() const {
|
||||
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
return sizeof(*this) + this->model.cpu_memory_used() + this->print_zs.capacity() * sizeof(coordf_t) +
|
||||
this->offsets.capacity() * sizeof(size_t);
|
||||
}
|
||||
// Return an estimate of the memory held by GPU vertex buffers.
|
||||
size_t gpu_memory_used() const { return this->model.gpu_memory_used(); }
|
||||
#else
|
||||
//FIXME what to do wih m_convex_hull?
|
||||
return sizeof(*this) - sizeof(this->indexed_vertex_array) + this->indexed_vertex_array.cpu_memory_used() + this->print_zs.capacity() * sizeof(coordf_t) + this->offsets.capacity() * sizeof(size_t);
|
||||
}
|
||||
// Return an estimate of the memory held by GPU vertex buffers.
|
||||
size_t gpu_memory_used() const { return this->indexed_vertex_array.gpu_memory_used(); }
|
||||
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
size_t total_memory_used() const { return this->cpu_memory_used() + this->gpu_memory_used(); }
|
||||
};
|
||||
|
||||
|
@ -589,6 +615,36 @@ public:
|
|||
GLVolumeCollection() { set_default_slope_normal_z(); }
|
||||
~GLVolumeCollection() { clear(); }
|
||||
|
||||
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
std::vector<int> load_object(
|
||||
const ModelObject* model_object,
|
||||
int obj_idx,
|
||||
const std::vector<int>& instance_idxs);
|
||||
|
||||
int load_object_volume(
|
||||
const ModelObject* model_object,
|
||||
int obj_idx,
|
||||
int volume_idx,
|
||||
int instance_idx);
|
||||
|
||||
// Load SLA auxiliary GLVolumes (for support trees or pad).
|
||||
void load_object_auxiliary(
|
||||
const SLAPrintObject* print_object,
|
||||
int obj_idx,
|
||||
// pairs of <instance_idx, print_instance_idx>
|
||||
const std::vector<std::pair<size_t, size_t>>& instances,
|
||||
SLAPrintObjectStep milestone,
|
||||
// Timestamp of the last change of the milestone
|
||||
size_t timestamp);
|
||||
|
||||
#if ENABLE_WIPETOWER_OBJECTID_1000_REMOVAL
|
||||
int load_wipe_tower_preview(
|
||||
float pos_x, float pos_y, float width, float depth, float height, float rotation_angle, bool size_unknown, float brim_width);
|
||||
#else
|
||||
int load_wipe_tower_preview(
|
||||
int obj_idx, float pos_x, float pos_y, float width, float depth, float height, float rotation_angle, bool size_unknown, float brim_width);
|
||||
#endif // ENABLE_WIPETOWER_OBJECTID_1000_REMOVAL
|
||||
#else
|
||||
std::vector<int> load_object(
|
||||
const ModelObject *model_object,
|
||||
int obj_idx,
|
||||
|
@ -620,13 +676,20 @@ public:
|
|||
int load_wipe_tower_preview(
|
||||
int obj_idx, float pos_x, float pos_y, float width, float depth, float height, float rotation_angle, bool size_unknown, float brim_width, bool opengl_initialized);
|
||||
#endif // ENABLE_WIPETOWER_OBJECTID_1000_REMOVAL
|
||||
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
|
||||
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
GLVolume* new_toolpath_volume(const ColorRGBA& rgba);
|
||||
GLVolume* new_nontoolpath_volume(const ColorRGBA& rgba);
|
||||
#else
|
||||
GLVolume* new_toolpath_volume(const ColorRGBA& rgba, size_t reserve_vbo_floats = 0);
|
||||
GLVolume* new_nontoolpath_volume(const ColorRGBA& rgba, size_t reserve_vbo_floats = 0);
|
||||
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
|
||||
// Render the volumes by OpenGL.
|
||||
void render(ERenderType type, bool disable_cullface, const Transform3d& view_matrix, std::function<bool(const GLVolume&)> filter_func = std::function<bool(const GLVolume&)>()) const;
|
||||
|
||||
#if !ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
// Finalize the initialization of the geometry & indices,
|
||||
// upload the geometry and indices to OpenGL VBO objects
|
||||
// and shrink the allocated data, possibly relasing it if it has been loaded into the VBOs.
|
||||
|
@ -634,11 +697,12 @@ public:
|
|||
// Release the geometry data assigned to the volumes.
|
||||
// If OpenGL VBOs were allocated, an OpenGL context has to be active to release them.
|
||||
void release_geometry() { for (auto *v : volumes) v->release_geometry(); }
|
||||
#endif // !ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
// Clear the geometry
|
||||
void clear() { for (auto *v : volumes) delete v; volumes.clear(); }
|
||||
|
||||
bool empty() const { return volumes.empty(); }
|
||||
void set_range(double low, double high) { for (GLVolume *vol : this->volumes) vol->set_range(low, high); }
|
||||
void set_range(double low, double high) { for (GLVolume* vol : this->volumes) vol->set_range(low, high); }
|
||||
|
||||
void set_print_volume(const PrintVolume& print_volume) { m_print_volume = print_volume; }
|
||||
|
||||
|
@ -683,9 +747,18 @@ GLVolumeWithIdAndZList volumes_to_render(const GLVolumePtrs& volumes, GLVolumeCo
|
|||
|
||||
struct _3DScene
|
||||
{
|
||||
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
static void thick_lines_to_verts(const Lines& lines, const std::vector<double>& widths, const std::vector<double>& heights, bool closed, double top_z, GUI::GLModel::Geometry& geometry);
|
||||
static void thick_lines_to_verts(const Lines3& lines, const std::vector<double>& widths, const std::vector<double>& heights, bool closed, GUI::GLModel::Geometry& geometry);
|
||||
static void extrusionentity_to_verts(const ExtrusionPath& extrusion_path, float print_z, const Point& copy, GUI::GLModel::Geometry& geometry);
|
||||
static void extrusionentity_to_verts(const ExtrusionLoop& extrusion_loop, float print_z, const Point& copy, GUI::GLModel::Geometry& geometry);
|
||||
static void extrusionentity_to_verts(const ExtrusionMultiPath& extrusion_multi_path, float print_z, const Point& copy, GUI::GLModel::Geometry& geometry);
|
||||
static void extrusionentity_to_verts(const ExtrusionEntityCollection& extrusion_entity_collection, float print_z, const Point& copy, GUI::GLModel::Geometry& geometry);
|
||||
static void extrusionentity_to_verts(const ExtrusionEntity* extrusion_entity, float print_z, const Point& copy, GUI::GLModel::Geometry& geometry);
|
||||
#else
|
||||
static void thick_lines_to_verts(const Lines& lines, const std::vector<double>& widths, const std::vector<double>& heights, bool closed, double top_z, GLVolume& volume);
|
||||
static void thick_lines_to_verts(const Lines3& lines, const std::vector<double>& widths, const std::vector<double>& heights, bool closed, GLVolume& volume);
|
||||
static void extrusionentity_to_verts(const Polyline &polyline, float width, float height, float print_z, GLVolume& volume);
|
||||
static void extrusionentity_to_verts(const Polyline& polyline, float width, float height, float print_z, GLVolume& volume);
|
||||
static void extrusionentity_to_verts(const ExtrusionPath& extrusion_path, float print_z, GLVolume& volume);
|
||||
static void extrusionentity_to_verts(const ExtrusionPath& extrusion_path, float print_z, const Point& copy, GLVolume& volume);
|
||||
static void extrusionentity_to_verts(const ExtrusionLoop& extrusion_loop, float print_z, const Point& copy, GLVolume& volume);
|
||||
|
@ -694,6 +767,7 @@ struct _3DScene
|
|||
static void extrusionentity_to_verts(const ExtrusionEntity* extrusion_entity, float print_z, const Point& copy, GLVolume& volume);
|
||||
static void polyline3_to_verts(const Polyline3& polyline, double width, double height, GLVolume& volume);
|
||||
static void point3_to_verts(const Vec3crd& point, double width, double height, GLVolume& volume);
|
||||
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
};
|
||||
|
||||
}
|
||||
|
|
79
src/slic3r/GUI/CoordAxes.cpp
Normal file
79
src/slic3r/GUI/CoordAxes.cpp
Normal file
|
@ -0,0 +1,79 @@
|
|||
#include "libslic3r/libslic3r.h"
|
||||
|
||||
#include "CoordAxes.hpp"
|
||||
#include "GUI_App.hpp"
|
||||
#include "3DScene.hpp"
|
||||
|
||||
#include <GL/glew.h>
|
||||
|
||||
#if ENABLE_WORLD_COORDINATE_SHOW_AXES
|
||||
|
||||
namespace Slic3r {
|
||||
namespace GUI {
|
||||
|
||||
const float CoordAxes::DefaultStemRadius = 0.5f;
|
||||
const float CoordAxes::DefaultStemLength = 25.0f;
|
||||
const float CoordAxes::DefaultTipRadius = 2.5f * CoordAxes::DefaultStemRadius;
|
||||
const float CoordAxes::DefaultTipLength = 5.0f;
|
||||
|
||||
void CoordAxes::render(float emission_factor)
|
||||
{
|
||||
auto render_axis = [this](const Transform3f& transform) {
|
||||
glsafe(::glPushMatrix());
|
||||
glsafe(::glMultMatrixf(transform.data()));
|
||||
m_arrow.render();
|
||||
glsafe(::glPopMatrix());
|
||||
};
|
||||
|
||||
if (!m_arrow.is_initialized())
|
||||
m_arrow.init_from(stilized_arrow(16, m_tip_radius, m_tip_length, m_stem_radius, m_stem_length));
|
||||
|
||||
GLShaderProgram* curr_shader = wxGetApp().get_current_shader();
|
||||
bool shader_differs = (curr_shader == nullptr || curr_shader->get_name() != "gouraud_light");
|
||||
|
||||
GLShaderProgram* shader = wxGetApp().get_shader("gouraud_light");
|
||||
if (shader == nullptr)
|
||||
return;
|
||||
|
||||
if (shader_differs) {
|
||||
if (curr_shader != nullptr)
|
||||
curr_shader->stop_using();
|
||||
shader->start_using();
|
||||
}
|
||||
shader->set_uniform("emission_factor", emission_factor);
|
||||
|
||||
// x axis
|
||||
#if ENABLE_GLBEGIN_GLEND_REMOVAL
|
||||
m_arrow.set_color(ColorRGBA::X());
|
||||
#else
|
||||
m_arrow.set_color(-1, ColorRGBA::X());
|
||||
#endif // ENABLE_GLBEGIN_GLEND_REMOVAL
|
||||
render_axis(Geometry::assemble_transform(m_origin, { 0.0, 0.5 * M_PI, 0.0 }).cast<float>());
|
||||
|
||||
// y axis
|
||||
#if ENABLE_GLBEGIN_GLEND_REMOVAL
|
||||
m_arrow.set_color(ColorRGBA::Y());
|
||||
#else
|
||||
m_arrow.set_color(-1, ColorRGBA::Y());
|
||||
#endif // ENABLE_GLBEGIN_GLEND_REMOVAL
|
||||
render_axis(Geometry::assemble_transform(m_origin, { -0.5 * M_PI, 0.0, 0.0 }).cast<float>());
|
||||
|
||||
// z axis
|
||||
#if ENABLE_GLBEGIN_GLEND_REMOVAL
|
||||
m_arrow.set_color(ColorRGBA::Z());
|
||||
#else
|
||||
m_arrow.set_color(-1, ColorRGBA::Z());
|
||||
#endif // ENABLE_GLBEGIN_GLEND_REMOVAL
|
||||
render_axis(Geometry::assemble_transform(m_origin).cast<float>());
|
||||
|
||||
if (shader_differs) {
|
||||
shader->stop_using();
|
||||
if (curr_shader != nullptr)
|
||||
curr_shader->start_using();
|
||||
}
|
||||
}
|
||||
|
||||
} // GUI
|
||||
} // Slic3r
|
||||
|
||||
#endif // ENABLE_WORLD_COORDINATE_SHOW_AXES
|
59
src/slic3r/GUI/CoordAxes.hpp
Normal file
59
src/slic3r/GUI/CoordAxes.hpp
Normal file
|
@ -0,0 +1,59 @@
|
|||
#ifndef slic3r_CoordAxes_hpp_
|
||||
#define slic3r_CoordAxes_hpp_
|
||||
|
||||
#if ENABLE_WORLD_COORDINATE_SHOW_AXES
|
||||
#include "GLModel.hpp"
|
||||
|
||||
namespace Slic3r {
|
||||
namespace GUI {
|
||||
|
||||
class CoordAxes
|
||||
{
|
||||
public:
|
||||
static const float DefaultStemRadius;
|
||||
static const float DefaultStemLength;
|
||||
static const float DefaultTipRadius;
|
||||
static const float DefaultTipLength;
|
||||
|
||||
private:
|
||||
Vec3d m_origin{ Vec3d::Zero() };
|
||||
float m_stem_radius{ DefaultStemRadius };
|
||||
float m_stem_length{ DefaultStemLength };
|
||||
float m_tip_radius{ DefaultTipRadius };
|
||||
float m_tip_length{ DefaultTipLength };
|
||||
GLModel m_arrow;
|
||||
|
||||
public:
|
||||
const Vec3d& get_origin() const { return m_origin; }
|
||||
void set_origin(const Vec3d& origin) { m_origin = origin; }
|
||||
void set_stem_radius(float radius) {
|
||||
m_stem_radius = radius;
|
||||
m_arrow.reset();
|
||||
}
|
||||
void set_stem_length(float length) {
|
||||
m_stem_length = length;
|
||||
m_arrow.reset();
|
||||
}
|
||||
void set_tip_radius(float radius) {
|
||||
m_tip_radius = radius;
|
||||
m_arrow.reset();
|
||||
}
|
||||
void set_tip_length(float length) {
|
||||
m_tip_length = length;
|
||||
m_arrow.reset();
|
||||
}
|
||||
|
||||
float get_stem_radius() const { return m_stem_radius; }
|
||||
float get_stem_length() const { return m_stem_length; }
|
||||
float get_tip_radius() const { return m_tip_radius; }
|
||||
float get_tip_length() const { return m_tip_length; }
|
||||
float get_total_length() const { return m_stem_length + m_tip_length; }
|
||||
void render(float emission_factor = 0.0f);
|
||||
};
|
||||
|
||||
} // GUI
|
||||
} // Slic3r
|
||||
|
||||
#endif // ENABLE_WORLD_COORDINATE_SHOW_AXES
|
||||
|
||||
#endif // slic3r_CoordAxes_hpp_
|
|
@ -711,7 +711,11 @@ void GCodeViewer::init()
|
|||
m_gl_data_initialized = true;
|
||||
}
|
||||
|
||||
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
void GCodeViewer::load(const GCodeProcessorResult& gcode_result, const Print& print)
|
||||
#else
|
||||
void GCodeViewer::load(const GCodeProcessorResult& gcode_result, const Print& print, bool initialized)
|
||||
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
{
|
||||
// avoid processing if called with the same gcode_result
|
||||
#if ENABLE_VOLUMETRIC_RATE_TOOLPATHS_RECALC
|
||||
|
@ -750,7 +754,11 @@ void GCodeViewer::load(const GCodeProcessorResult& gcode_result, const Print& pr
|
|||
m_filament_densities = gcode_result.filament_densities;
|
||||
|
||||
if (wxGetApp().is_editor())
|
||||
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
load_shells(print);
|
||||
#else
|
||||
load_shells(print, initialized);
|
||||
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
else {
|
||||
Pointfs bed_shape;
|
||||
std::string texture;
|
||||
|
@ -2289,7 +2297,11 @@ void GCodeViewer::load_toolpaths(const GCodeProcessorResult& gcode_result)
|
|||
progress_dialog->Destroy();
|
||||
}
|
||||
|
||||
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
void GCodeViewer::load_shells(const Print& print)
|
||||
#else
|
||||
void GCodeViewer::load_shells(const Print& print, bool initialized)
|
||||
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
{
|
||||
if (print.objects().empty())
|
||||
// no shells, return
|
||||
|
@ -2306,7 +2318,11 @@ void GCodeViewer::load_shells(const Print& print, bool initialized)
|
|||
}
|
||||
|
||||
size_t current_volumes_count = m_shells.volumes.volumes.size();
|
||||
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
m_shells.volumes.load_object(model_obj, object_id, instance_ids);
|
||||
#else
|
||||
m_shells.volumes.load_object(model_obj, object_id, instance_ids, initialized);
|
||||
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
|
||||
// adjust shells' z if raft is present
|
||||
const SlicingParameters& slicing_parameters = obj->slicing_parameters();
|
||||
|
@ -2330,6 +2346,15 @@ void GCodeViewer::load_shells(const Print& print, bool initialized)
|
|||
const float depth = print.wipe_tower_data(extruders_count).depth;
|
||||
const float brim_width = print.wipe_tower_data(extruders_count).brim_width;
|
||||
|
||||
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
#if ENABLE_WIPETOWER_OBJECTID_1000_REMOVAL
|
||||
m_shells.volumes.load_wipe_tower_preview(config.wipe_tower_x, config.wipe_tower_y, config.wipe_tower_width, depth, max_z, config.wipe_tower_rotation_angle,
|
||||
!print.is_step_done(psWipeTower), brim_width);
|
||||
#else
|
||||
m_shells.volumes.load_wipe_tower_preview(1000, config.wipe_tower_x, config.wipe_tower_y, config.wipe_tower_width, depth, max_z, config.wipe_tower_rotation_angle,
|
||||
!print.is_step_done(psWipeTower), brim_width);
|
||||
#endif // ENABLE_WIPETOWER_OBJECTID_1000_REMOVAL
|
||||
#else
|
||||
#if ENABLE_WIPETOWER_OBJECTID_1000_REMOVAL
|
||||
m_shells.volumes.load_wipe_tower_preview(config.wipe_tower_x, config.wipe_tower_y, config.wipe_tower_width, depth, max_z, config.wipe_tower_rotation_angle,
|
||||
!print.is_step_done(psWipeTower), brim_width, initialized);
|
||||
|
@ -2337,6 +2362,7 @@ void GCodeViewer::load_shells(const Print& print, bool initialized)
|
|||
m_shells.volumes.load_wipe_tower_preview(1000, config.wipe_tower_x, config.wipe_tower_y, config.wipe_tower_width, depth, max_z, config.wipe_tower_rotation_angle,
|
||||
!print.is_step_done(psWipeTower), brim_width, initialized);
|
||||
#endif // ENABLE_WIPETOWER_OBJECTID_1000_REMOVAL
|
||||
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3199,6 +3225,7 @@ void GCodeViewer::render_shells()
|
|||
if (shader == nullptr)
|
||||
return;
|
||||
|
||||
#if !ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
// when the background processing is enabled, it may happen that the shells data have been loaded
|
||||
// before opengl has been initialized for the preview canvas.
|
||||
// when this happens, the volumes' data have not been sent to gpu yet.
|
||||
|
@ -3206,6 +3233,7 @@ void GCodeViewer::render_shells()
|
|||
if (!v->indexed_vertex_array.has_VBOs())
|
||||
v->finalize_geometry(true);
|
||||
}
|
||||
#endif // !ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
|
||||
// glsafe(::glDepthMask(GL_FALSE));
|
||||
|
||||
|
|
|
@ -823,7 +823,11 @@ public:
|
|||
void init();
|
||||
|
||||
// extract rendering data from the given parameters
|
||||
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
void load(const GCodeProcessorResult& gcode_result, const Print& print);
|
||||
#else
|
||||
void load(const GCodeProcessorResult& gcode_result, const Print& print, bool initialized);
|
||||
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
// recalculate ranges in dependence of what is visible and sets tool/print colors
|
||||
void refresh(const GCodeProcessorResult& gcode_result, const std::vector<std::string>& str_tool_colors);
|
||||
#if ENABLE_PREVIEW_LAYOUT
|
||||
|
@ -883,7 +887,11 @@ public:
|
|||
|
||||
private:
|
||||
void load_toolpaths(const GCodeProcessorResult& gcode_result);
|
||||
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
void load_shells(const Print& print);
|
||||
#else
|
||||
void load_shells(const Print& print, bool initialized);
|
||||
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
#if !ENABLE_PREVIEW_LAYOUT
|
||||
void refresh_render_paths(bool keep_sequential_current_first, bool keep_sequential_current_last) const;
|
||||
#endif // !ENABLE_PREVIEW_LAYOUT
|
||||
|
|
|
@ -87,9 +87,11 @@ static const Slic3r::ColorRGB ERROR_BG_LIGHT_COLOR = { 0.753f, 0.192f, 0.039f
|
|||
// Number of floats
|
||||
static constexpr const size_t MAX_VERTEX_BUFFER_SIZE = 131072 * 6; // 3.15MB
|
||||
// Reserve size in number of floats.
|
||||
#if !ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
static constexpr const size_t VERTEX_BUFFER_RESERVE_SIZE = 131072 * 2; // 1.05MB
|
||||
// Reserve size in number of floats, maximum sum of all preallocated buffers.
|
||||
//static constexpr const size_t VERTEX_BUFFER_RESERVE_SIZE_SUM_MAX = 1024 * 1024 * 128 / 4; // 128MB
|
||||
#endif // !ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
|
||||
namespace Slic3r {
|
||||
namespace GUI {
|
||||
|
@ -526,7 +528,7 @@ void GLCanvas3D::LayersEditing::render_volumes(const GLCanvas3D& canvas, const G
|
|||
glsafe(::glTexImage2D(GL_TEXTURE_2D, 1, GL_RGBA, half_w, half_h, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0));
|
||||
glsafe(::glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, m_layers_texture.data.data()));
|
||||
glsafe(::glTexSubImage2D(GL_TEXTURE_2D, 1, 0, 0, half_w, half_h, GL_RGBA, GL_UNSIGNED_BYTE, m_layers_texture.data.data() + m_layers_texture.width * m_layers_texture.height * 4));
|
||||
for (const GLVolume* glvolume : volumes.volumes) {
|
||||
for (GLVolume* glvolume : volumes.volumes) {
|
||||
// Render the object using the layer editing shader and texture.
|
||||
if (!glvolume->is_active || glvolume->composite_id.object_id != this->last_object_id || glvolume->is_modifier)
|
||||
continue;
|
||||
|
@ -1192,9 +1194,11 @@ bool GLCanvas3D::init()
|
|||
if (m_main_toolbar.is_enabled())
|
||||
m_layers_editing.init();
|
||||
|
||||
#if !ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
// on linux the gl context is not valid until the canvas is not shown on screen
|
||||
// we defer the geometry finalization of volumes until the first call to render()
|
||||
m_volumes.finalize_geometry(true);
|
||||
#endif // !ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
|
||||
if (m_gizmos.is_enabled() && !m_gizmos.init())
|
||||
std::cout << "Unable to initialize gizmos: please, check that all the required textures are available" << std::endl;
|
||||
|
@ -1799,7 +1803,11 @@ std::vector<int> GLCanvas3D::load_object(const ModelObject& model_object, int ob
|
|||
instance_idxs.emplace_back(i);
|
||||
}
|
||||
}
|
||||
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
return m_volumes.load_object(&model_object, obj_idx, instance_idxs);
|
||||
#else
|
||||
return m_volumes.load_object(&model_object, obj_idx, instance_idxs, m_initialized);
|
||||
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
}
|
||||
|
||||
std::vector<int> GLCanvas3D::load_object(const Model& model, int obj_idx)
|
||||
|
@ -2024,7 +2032,11 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re
|
|||
// Note the index of the loaded volume, so that we can reload the main model GLVolume with the hollowed mesh
|
||||
// later in this function.
|
||||
it->volume_idx = m_volumes.volumes.size();
|
||||
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
m_volumes.load_object_volume(&model_object, obj_idx, volume_idx, instance_idx);
|
||||
#else
|
||||
m_volumes.load_object_volume(&model_object, obj_idx, volume_idx, instance_idx, m_initialized);
|
||||
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
m_volumes.volumes.back()->geometry_id = key.geometry_id;
|
||||
update_object_list = true;
|
||||
} else {
|
||||
|
@ -2081,31 +2093,55 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re
|
|||
GLVolume &volume = *m_volumes.volumes[it->volume_idx];
|
||||
if (! volume.offsets.empty() && state.step[istep].timestamp != volume.offsets.front()) {
|
||||
// The backend either produced a new hollowed mesh, or it invalidated the one that the front end has seen.
|
||||
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
volume.model.reset();
|
||||
#else
|
||||
volume.indexed_vertex_array.release_geometry();
|
||||
if (state.step[istep].state == PrintStateBase::DONE) {
|
||||
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
if (state.step[istep].state == PrintStateBase::DONE) {
|
||||
TriangleMesh mesh = print_object->get_mesh(slaposDrillHoles);
|
||||
assert(! mesh.empty());
|
||||
mesh.transform(sla_print->sla_trafo(*m_model->objects[volume.object_idx()]).inverse());
|
||||
#if ENABLE_SMOOTH_NORMALS
|
||||
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
volume.model.init_from(mesh, true);
|
||||
#else
|
||||
volume.indexed_vertex_array.load_mesh(mesh, true);
|
||||
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
#else
|
||||
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
volume.model.init_from(mesh);
|
||||
#else
|
||||
volume.indexed_vertex_array.load_mesh(mesh);
|
||||
#endif // ENABLE_SMOOTH_NORMALS
|
||||
} else {
|
||||
// Reload the original volume.
|
||||
#if ENABLE_SMOOTH_NORMALS
|
||||
volume.indexed_vertex_array.load_mesh(m_model->objects[volume.object_idx()]->volumes[volume.volume_idx()]->mesh(), true);
|
||||
#else
|
||||
volume.indexed_vertex_array.load_mesh(m_model->objects[volume.object_idx()]->volumes[volume.volume_idx()]->mesh());
|
||||
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
#endif // ENABLE_SMOOTH_NORMALS
|
||||
}
|
||||
else {
|
||||
// Reload the original volume.
|
||||
#if ENABLE_SMOOTH_NORMALS
|
||||
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
volume.model.init_from(m_model->objects[volume.object_idx()]->volumes[volume.volume_idx()]->mesh(), true);
|
||||
#else
|
||||
volume.indexed_vertex_array.load_mesh(m_model->objects[volume.object_idx()]->volumes[volume.volume_idx()]->mesh(), true);
|
||||
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
#else
|
||||
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
volume.model.init_from(m_model->objects[volume.object_idx()]->volumes[volume.volume_idx()]->mesh());
|
||||
#else
|
||||
volume.indexed_vertex_array.load_mesh(m_model->objects[volume.object_idx()]->volumes[volume.volume_idx()]->mesh());
|
||||
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
#endif // ENABLE_SMOOTH_NORMALS
|
||||
}
|
||||
#if !ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
volume.finalize_geometry(true);
|
||||
}
|
||||
#endif // !ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
}
|
||||
//FIXME it is an ugly hack to write the timestamp into the "offsets" field to not have to add another member variable
|
||||
// to the GLVolume. We should refactor GLVolume significantly, so that the GLVolume will not contain member variables
|
||||
// of various concenrs (model vs. 3D print path).
|
||||
volume.offsets = { state.step[istep].timestamp };
|
||||
} else if (state.step[istep].state == PrintStateBase::DONE) {
|
||||
}
|
||||
else if (state.step[istep].state == PrintStateBase::DONE) {
|
||||
// Check whether there is an existing auxiliary volume to be updated, or a new auxiliary volume to be created.
|
||||
ModelVolumeState key(state.step[istep].timestamp, instance.instance_id.id);
|
||||
auto it = std::lower_bound(aux_volume_state.begin(), aux_volume_state.end(), key, model_volume_state_lower);
|
||||
|
@ -2117,7 +2153,8 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re
|
|||
instances[istep].emplace_back(std::pair<size_t, size_t>(instance_idx, print_instance_idx));
|
||||
else
|
||||
shift_zs[object_idx] = 0.;
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
// Recycling an old GLVolume. Update the Object/Instance indices into the current Model.
|
||||
m_volumes.volumes[it->volume_idx]->composite_id = GLVolume::CompositeID(object_idx, m_volumes.volumes[it->volume_idx]->volume_idx(), instance_idx);
|
||||
m_volumes.volumes[it->volume_idx]->set_instance_transformation(model_object->instances[instance_idx]->get_transformation());
|
||||
|
@ -2127,7 +2164,11 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re
|
|||
|
||||
for (size_t istep = 0; istep < sla_steps.size(); ++istep)
|
||||
if (!instances[istep].empty())
|
||||
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
m_volumes.load_object_auxiliary(print_object, object_idx, instances[istep], sla_steps[istep], state.step[istep].timestamp);
|
||||
#else
|
||||
m_volumes.load_object_auxiliary(print_object, object_idx, instances[istep], sla_steps[istep], state.step[istep].timestamp, m_initialized);
|
||||
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
}
|
||||
|
||||
// Shift-up all volumes of the object so that it has the right elevation with respect to the print bed
|
||||
|
@ -2157,6 +2198,17 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re
|
|||
float depth = print->wipe_tower_data(extruders_count).depth;
|
||||
float brim_width = print->wipe_tower_data(extruders_count).brim_width;
|
||||
|
||||
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
#if ENABLE_WIPETOWER_OBJECTID_1000_REMOVAL
|
||||
int volume_idx_wipe_tower_new = m_volumes.load_wipe_tower_preview(
|
||||
x, y, w, depth, (float)height, a, !print->is_step_done(psWipeTower),
|
||||
brim_width);
|
||||
#else
|
||||
int volume_idx_wipe_tower_new = m_volumes.load_wipe_tower_preview(
|
||||
1000, x, y, w, depth, (float)height, a, !print->is_step_done(psWipeTower),
|
||||
brim_width);
|
||||
#endif // ENABLE_WIPETOWER_OBJECTID_1000_REMOVAL
|
||||
#else
|
||||
#if ENABLE_WIPETOWER_OBJECTID_1000_REMOVAL
|
||||
int volume_idx_wipe_tower_new = m_volumes.load_wipe_tower_preview(
|
||||
x, y, w, depth, (float)height, a, !print->is_step_done(psWipeTower),
|
||||
|
@ -2166,6 +2218,7 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re
|
|||
1000, x, y, w, depth, (float)height, a, !print->is_step_done(psWipeTower),
|
||||
brim_width, m_initialized);
|
||||
#endif // ENABLE_WIPETOWER_OBJECTID_1000_REMOVAL
|
||||
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
if (volume_idx_wipe_tower_old != -1)
|
||||
map_glvolume_old_to_new[volume_idx_wipe_tower_old] = volume_idx_wipe_tower_new;
|
||||
}
|
||||
|
@ -2225,9 +2278,10 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re
|
|||
m_dirty = true;
|
||||
}
|
||||
|
||||
#if !ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
static void reserve_new_volume_finalize_old_volume(GLVolume& vol_new, GLVolume& vol_old, bool gl_initialized, size_t prealloc_size = VERTEX_BUFFER_RESERVE_SIZE)
|
||||
{
|
||||
// Assign the large pre-allocated buffers to the new GLVolume.
|
||||
// Assign the large pre-allocated buffers to the new GLVolume.
|
||||
vol_new.indexed_vertex_array = std::move(vol_old.indexed_vertex_array);
|
||||
// Copy the content back to the old GLVolume.
|
||||
vol_old.indexed_vertex_array = vol_new.indexed_vertex_array;
|
||||
|
@ -2239,10 +2293,15 @@ static void reserve_new_volume_finalize_old_volume(GLVolume& vol_new, GLVolume&
|
|||
// Finalize the old geometry, possibly move data to the graphics card.
|
||||
vol_old.finalize_geometry(gl_initialized);
|
||||
}
|
||||
#endif // !ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
|
||||
void GLCanvas3D::load_gcode_preview(const GCodeProcessorResult& gcode_result, const std::vector<std::string>& str_tool_colors)
|
||||
{
|
||||
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
m_gcode_viewer.load(gcode_result, *this->fff_print());
|
||||
#else
|
||||
m_gcode_viewer.load(gcode_result, *this->fff_print(), m_initialized);
|
||||
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
|
||||
if (wxGetApp().is_editor()) {
|
||||
m_gcode_viewer.update_shells_color_by_extruder(m_config);
|
||||
|
@ -2715,7 +2774,7 @@ void GLCanvas3D::on_key(wxKeyEvent& evt)
|
|||
m_dirty = true;
|
||||
},
|
||||
[this](const Vec3d& direction, bool slow, bool camera_space) {
|
||||
m_selection.start_dragging();
|
||||
m_selection.setup_cache();
|
||||
double multiplier = slow ? 1.0 : 10.0;
|
||||
|
||||
Vec3d displacement;
|
||||
|
@ -2728,7 +2787,6 @@ void GLCanvas3D::on_key(wxKeyEvent& evt)
|
|||
displacement = multiplier * direction;
|
||||
|
||||
m_selection.translate(displacement);
|
||||
m_selection.stop_dragging();
|
||||
m_dirty = true;
|
||||
}
|
||||
);
|
||||
|
@ -2825,9 +2883,8 @@ void GLCanvas3D::on_key(wxKeyEvent& evt)
|
|||
m_dirty = true;
|
||||
else if (m_gizmos.is_enabled() && !m_selection.is_empty()) {
|
||||
auto do_rotate = [this](double angle_z_rad) {
|
||||
m_selection.start_dragging();
|
||||
m_selection.setup_cache();
|
||||
m_selection.rotate(Vec3d(0.0, 0.0, angle_z_rad), TransformationType(TransformationType::World_Relative_Joint));
|
||||
m_selection.stop_dragging();
|
||||
m_dirty = true;
|
||||
// wxGetApp().obj_manipul()->set_dirty();
|
||||
};
|
||||
|
@ -3135,30 +3192,21 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
|
|||
m_mouse.set_start_position_3D_as_invalid();
|
||||
m_mouse.position = pos.cast<double>();
|
||||
|
||||
if (evt.Dragging() && current_printer_technology() == ptFFF && fff_print()->config().complete_objects) {
|
||||
switch (m_gizmos.get_current_type())
|
||||
{
|
||||
case GLGizmosManager::EType::Move:
|
||||
case GLGizmosManager::EType::Scale:
|
||||
case GLGizmosManager::EType::Rotate:
|
||||
{
|
||||
update_sequential_clearance();
|
||||
break;
|
||||
}
|
||||
default: { break; }
|
||||
}
|
||||
}
|
||||
else if (evt.Dragging()) {
|
||||
switch (m_gizmos.get_current_type())
|
||||
{
|
||||
case GLGizmosManager::EType::Move:
|
||||
case GLGizmosManager::EType::Scale:
|
||||
case GLGizmosManager::EType::Rotate:
|
||||
{
|
||||
show_sinking_contours();
|
||||
break;
|
||||
}
|
||||
default: { break; }
|
||||
// It should be detection of volume change
|
||||
// Not only detection of some modifiers !!!
|
||||
if (evt.Dragging()) {
|
||||
GLGizmosManager::EType c = m_gizmos.get_current_type();
|
||||
if (current_printer_technology() == ptFFF &&
|
||||
fff_print()->config().complete_objects){
|
||||
if (c == GLGizmosManager::EType::Move ||
|
||||
c == GLGizmosManager::EType::Scale ||
|
||||
c == GLGizmosManager::EType::Rotate )
|
||||
update_sequential_clearance();
|
||||
} else {
|
||||
if (c == GLGizmosManager::EType::Move ||
|
||||
c == GLGizmosManager::EType::Scale ||
|
||||
c == GLGizmosManager::EType::Rotate)
|
||||
show_sinking_contours();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3302,7 +3350,7 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
|
|||
m_volumes.volumes[volume_idx]->hover = GLVolume::HS_None;
|
||||
// The dragging operation is initiated.
|
||||
m_mouse.drag.move_volume_idx = volume_idx;
|
||||
m_selection.start_dragging();
|
||||
m_selection.setup_cache();
|
||||
m_mouse.drag.start_position_3D = m_mouse.scene_position;
|
||||
m_sequential_print_clearance_first_displacement = true;
|
||||
m_moving = true;
|
||||
|
@ -3414,9 +3462,6 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
|
|||
}
|
||||
}
|
||||
else if (evt.LeftUp() || evt.MiddleUp() || evt.RightUp()) {
|
||||
if (evt.LeftUp())
|
||||
m_selection.stop_dragging();
|
||||
|
||||
if (m_layers_editing.state != LayersEditing::Unknown) {
|
||||
m_layers_editing.state = LayersEditing::Unknown;
|
||||
_stop_timer();
|
||||
|
@ -3785,15 +3830,6 @@ void GLCanvas3D::do_scale(const std::string& snapshot_type)
|
|||
m_dirty = true;
|
||||
}
|
||||
|
||||
void GLCanvas3D::do_flatten(const Vec3d& normal, const std::string& snapshot_type)
|
||||
{
|
||||
if (!snapshot_type.empty())
|
||||
wxGetApp().plater()->take_snapshot(_(snapshot_type));
|
||||
|
||||
m_selection.flattening_rotate(normal);
|
||||
do_rotate(""); // avoid taking another snapshot
|
||||
}
|
||||
|
||||
void GLCanvas3D::do_mirror(const std::string& snapshot_type)
|
||||
{
|
||||
if (m_model == nullptr)
|
||||
|
@ -4364,7 +4400,11 @@ void GLCanvas3D::_render_thumbnail_internal(ThumbnailData& thumbnail_data, const
|
|||
shader->set_uniform("emission_factor", 0.0f);
|
||||
|
||||
for (GLVolume* vol : visible_volumes) {
|
||||
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
vol->model.set_color((vol->printable && !vol->is_outside) ? (current_printer_technology() == ptSLA ? vol->color : ColorRGBA::ORANGE()) : ColorRGBA::GRAY());
|
||||
#else
|
||||
shader->set_uniform("uniform_color", (vol->printable && !vol->is_outside) ? (current_printer_technology() == ptSLA ? vol->color : ColorRGBA::ORANGE()) : ColorRGBA::GRAY());
|
||||
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
// the volume may have been deactivated by an active gizmo
|
||||
bool is_active = vol->is_active;
|
||||
vol->is_active = true;
|
||||
|
@ -5570,6 +5610,12 @@ void GLCanvas3D::_render_overlays()
|
|||
|
||||
void GLCanvas3D::_render_volumes_for_picking() const
|
||||
{
|
||||
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
GLShaderProgram* shader = wxGetApp().get_shader("flat");
|
||||
if (shader == nullptr)
|
||||
return;
|
||||
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
|
||||
// do not cull backfaces to show broken geometry, if any
|
||||
glsafe(::glDisable(GL_CULL_FACE));
|
||||
|
||||
|
@ -5585,9 +5631,17 @@ void GLCanvas3D::_render_volumes_for_picking() const
|
|||
// we reserve color = (0,0,0) for occluders (as the printbed)
|
||||
// so we shift volumes' id by 1 to get the proper color
|
||||
const unsigned int id = 1 + volume.second.first;
|
||||
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
volume.first->model.set_color(picking_decode(id));
|
||||
shader->start_using();
|
||||
#else
|
||||
glsafe(::glColor4fv(picking_decode(id).data()));
|
||||
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
volume.first->render();
|
||||
}
|
||||
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
shader->stop_using();
|
||||
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
}
|
||||
}
|
||||
|
||||
glsafe(::glDisableClientState(GL_NORMAL_ARRAY));
|
||||
|
@ -6173,23 +6227,48 @@ void GLCanvas3D::_load_print_toolpaths(const BuildVolume &build_volume)
|
|||
skirt_height = std::min(skirt_height, print_zs.size());
|
||||
print_zs.erase(print_zs.begin() + skirt_height, print_zs.end());
|
||||
|
||||
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
GLVolume* volume = m_volumes.new_toolpath_volume(color);
|
||||
GLModel::Geometry init_data;
|
||||
init_data.format = { GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3N3, GLModel::Geometry::EIndexType::UINT };
|
||||
#else
|
||||
GLVolume *volume = m_volumes.new_toolpath_volume(color, VERTEX_BUFFER_RESERVE_SIZE);
|
||||
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
for (size_t i = 0; i < skirt_height; ++ i) {
|
||||
volume->print_zs.emplace_back(print_zs[i]);
|
||||
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
volume->offsets.emplace_back(init_data.indices_count());
|
||||
if (i == 0)
|
||||
_3DScene::extrusionentity_to_verts(print->brim(), print_zs[i], Point(0, 0), init_data);
|
||||
_3DScene::extrusionentity_to_verts(print->skirt(), print_zs[i], Point(0, 0), init_data);
|
||||
#else
|
||||
volume->offsets.emplace_back(volume->indexed_vertex_array.quad_indices.size());
|
||||
volume->offsets.emplace_back(volume->indexed_vertex_array.triangle_indices.size());
|
||||
if (i == 0)
|
||||
_3DScene::extrusionentity_to_verts(print->brim(), print_zs[i], Point(0, 0), *volume);
|
||||
_3DScene::extrusionentity_to_verts(print->skirt(), print_zs[i], Point(0, 0), *volume);
|
||||
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
// Ensure that no volume grows over the limits. If the volume is too large, allocate a new one.
|
||||
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
if (init_data.vertices_size_bytes() > MAX_VERTEX_BUFFER_SIZE) {
|
||||
volume->model.init_from(std::move(init_data));
|
||||
#else
|
||||
if (volume->indexed_vertex_array.vertices_and_normals_interleaved.size() > MAX_VERTEX_BUFFER_SIZE) {
|
||||
GLVolume &vol = *volume;
|
||||
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
GLVolume &vol = *volume;
|
||||
volume = m_volumes.new_toolpath_volume(vol.color);
|
||||
#if !ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
reserve_new_volume_finalize_old_volume(*volume, vol, m_initialized);
|
||||
#endif // !ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
}
|
||||
}
|
||||
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
volume->model.init_from(std::move(init_data));
|
||||
volume->is_outside = !contains(build_volume, volume->model);
|
||||
#else
|
||||
volume->is_outside = ! build_volume.all_paths_inside_vertices_and_normals_interleaved(volume->indexed_vertex_array.vertices_and_normals_interleaved, volume->indexed_vertex_array.bounding_box());
|
||||
volume->indexed_vertex_array.finalize_geometry(m_initialized);
|
||||
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
}
|
||||
|
||||
void GLCanvas3D::_load_print_object_toolpaths(const PrintObject& print_object, const BuildVolume& build_volume, const std::vector<std::string>& str_tool_colors, const std::vector<CustomGCode::Item>& color_print_values)
|
||||
|
@ -6361,7 +6440,12 @@ void GLCanvas3D::_load_print_object_toolpaths(const PrintObject& print_object, c
|
|||
// Allocate the volume before locking.
|
||||
GLVolume *volume = new GLVolume(color);
|
||||
volume->is_extrusion_path = true;
|
||||
tbb::spin_mutex::scoped_lock lock;
|
||||
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
// to prevent sending data to gpu (in the main thread) while
|
||||
// editing the model geometry
|
||||
volume->model.disable_render();
|
||||
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
tbb::spin_mutex::scoped_lock lock;
|
||||
// Lock by ROII, so if the emplace_back() fails, the lock will be released.
|
||||
lock.acquire(new_volume_mutex);
|
||||
m_volumes.volumes.emplace_back(volume);
|
||||
|
@ -6373,31 +6457,57 @@ void GLCanvas3D::_load_print_object_toolpaths(const PrintObject& print_object, c
|
|||
tbb::blocked_range<size_t>(0, ctxt.layers.size(), grain_size),
|
||||
[&ctxt, &new_volume, is_selected_separate_extruder, this](const tbb::blocked_range<size_t>& range) {
|
||||
GLVolumePtrs vols;
|
||||
auto volume = [&ctxt, &vols](size_t layer_idx, int extruder, int feature) -> GLVolume& {
|
||||
return *vols[ctxt.color_by_color_print()?
|
||||
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
std::vector<GLModel::Geometry> geometries;
|
||||
auto select_geometry = [&ctxt, &geometries](size_t layer_idx, int extruder, int feature) -> GLModel::Geometry& {
|
||||
return geometries[ctxt.color_by_color_print() ?
|
||||
ctxt.color_print_color_idx_by_layer_idx_and_extruder(layer_idx, extruder) :
|
||||
ctxt.color_by_tool() ?
|
||||
std::min<int>(ctxt.number_tools() - 1, std::max<int>(extruder - 1, 0)) :
|
||||
feature
|
||||
];
|
||||
ctxt.color_by_tool() ?
|
||||
std::min<int>(ctxt.number_tools() - 1, std::max<int>(extruder - 1, 0)) :
|
||||
feature
|
||||
];
|
||||
};
|
||||
#else
|
||||
auto volume = [&ctxt, &vols](size_t layer_idx, int extruder, int feature) -> GLVolume& {
|
||||
return *vols[ctxt.color_by_color_print() ?
|
||||
ctxt.color_print_color_idx_by_layer_idx_and_extruder(layer_idx, extruder) :
|
||||
ctxt.color_by_tool() ?
|
||||
std::min<int>(ctxt.number_tools() - 1, std::max<int>(extruder - 1, 0)) :
|
||||
feature
|
||||
];
|
||||
};
|
||||
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
if (ctxt.color_by_color_print() || ctxt.color_by_tool()) {
|
||||
for (size_t i = 0; i < ctxt.number_tools(); ++i)
|
||||
for (size_t i = 0; i < ctxt.number_tools(); ++i) {
|
||||
vols.emplace_back(new_volume(ctxt.color_tool(i)));
|
||||
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
geometries.emplace_back(GLModel::Geometry());
|
||||
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
}
|
||||
}
|
||||
else
|
||||
else {
|
||||
vols = { new_volume(ctxt.color_perimeters()), new_volume(ctxt.color_infill()), new_volume(ctxt.color_support()) };
|
||||
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
geometries = { GLModel::Geometry(), GLModel::Geometry(), GLModel::Geometry() };
|
||||
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
}
|
||||
|
||||
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
assert(vols.size() == geometries.size());
|
||||
for (GLModel::Geometry& g : geometries) {
|
||||
g.format = { GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3N3, GLModel::Geometry::EIndexType::UINT };
|
||||
}
|
||||
#else
|
||||
for (GLVolume *vol : vols)
|
||||
// Reserving number of vertices (3x position + 3x color)
|
||||
vol->indexed_vertex_array.reserve(VERTEX_BUFFER_RESERVE_SIZE / 6);
|
||||
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
for (size_t idx_layer = range.begin(); idx_layer < range.end(); ++ idx_layer) {
|
||||
const Layer *layer = ctxt.layers[idx_layer];
|
||||
|
||||
if (is_selected_separate_extruder)
|
||||
{
|
||||
if (is_selected_separate_extruder) {
|
||||
bool at_least_one_has_correct_extruder = false;
|
||||
for (const LayerRegion* layerm : layer->regions())
|
||||
{
|
||||
for (const LayerRegion* layerm : layer->regions()) {
|
||||
if (layerm->slices.surfaces.empty())
|
||||
continue;
|
||||
const PrintRegionConfig& cfg = layerm->region().config();
|
||||
|
@ -6412,17 +6522,27 @@ void GLCanvas3D::_load_print_object_toolpaths(const PrintObject& print_object, c
|
|||
continue;
|
||||
}
|
||||
|
||||
for (GLVolume *vol : vols)
|
||||
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
for (size_t i = 0; i < vols.size(); ++i) {
|
||||
GLVolume* vol = vols[i];
|
||||
if (vol->print_zs.empty() || vol->print_zs.back() != layer->print_z) {
|
||||
vol->print_zs.emplace_back(layer->print_z);
|
||||
vol->offsets.emplace_back(geometries[i].indices_count());
|
||||
}
|
||||
}
|
||||
#else
|
||||
for (GLVolume* vol : vols)
|
||||
if (vol->print_zs.empty() || vol->print_zs.back() != layer->print_z) {
|
||||
vol->print_zs.emplace_back(layer->print_z);
|
||||
vol->offsets.emplace_back(vol->indexed_vertex_array.quad_indices.size());
|
||||
vol->offsets.emplace_back(vol->indexed_vertex_array.triangle_indices.size());
|
||||
}
|
||||
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
|
||||
for (const PrintInstance &instance : *ctxt.shifted_copies) {
|
||||
const Point © = instance.shift;
|
||||
for (const LayerRegion *layerm : layer->regions()) {
|
||||
if (is_selected_separate_extruder)
|
||||
{
|
||||
if (is_selected_separate_extruder) {
|
||||
const PrintRegionConfig& cfg = layerm->region().config();
|
||||
if (cfg.perimeter_extruder.value != m_selected_extruder ||
|
||||
cfg.infill_extruder.value != m_selected_extruder ||
|
||||
|
@ -6430,19 +6550,31 @@ void GLCanvas3D::_load_print_object_toolpaths(const PrintObject& print_object, c
|
|||
continue;
|
||||
}
|
||||
if (ctxt.has_perimeters)
|
||||
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
_3DScene::extrusionentity_to_verts(layerm->perimeters, float(layer->print_z), copy,
|
||||
select_geometry(idx_layer, layerm->region().config().perimeter_extruder.value, 0));
|
||||
#else
|
||||
_3DScene::extrusionentity_to_verts(layerm->perimeters, float(layer->print_z), copy,
|
||||
volume(idx_layer, layerm->region().config().perimeter_extruder.value, 0));
|
||||
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
if (ctxt.has_infill) {
|
||||
for (const ExtrusionEntity *ee : layerm->fills.entities) {
|
||||
// fill represents infill extrusions of a single island.
|
||||
const auto *fill = dynamic_cast<const ExtrusionEntityCollection*>(ee);
|
||||
if (! fill->entities.empty())
|
||||
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
_3DScene::extrusionentity_to_verts(*fill, float(layer->print_z), copy,
|
||||
select_geometry(idx_layer, is_solid_infill(fill->entities.front()->role()) ?
|
||||
layerm->region().config().solid_infill_extruder :
|
||||
layerm->region().config().infill_extruder, 1));
|
||||
#else
|
||||
_3DScene::extrusionentity_to_verts(*fill, float(layer->print_z), copy,
|
||||
volume(idx_layer,
|
||||
is_solid_infill(fill->entities.front()->role()) ?
|
||||
layerm->region().config().solid_infill_extruder :
|
||||
layerm->region().config().infill_extruder,
|
||||
1));
|
||||
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -6450,28 +6582,50 @@ void GLCanvas3D::_load_print_object_toolpaths(const PrintObject& print_object, c
|
|||
const SupportLayer *support_layer = dynamic_cast<const SupportLayer*>(layer);
|
||||
if (support_layer) {
|
||||
for (const ExtrusionEntity *extrusion_entity : support_layer->support_fills.entities)
|
||||
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
_3DScene::extrusionentity_to_verts(extrusion_entity, float(layer->print_z), copy,
|
||||
select_geometry(idx_layer, (extrusion_entity->role() == erSupportMaterial) ?
|
||||
support_layer->object()->config().support_material_extruder :
|
||||
support_layer->object()->config().support_material_interface_extruder, 2));
|
||||
#else
|
||||
_3DScene::extrusionentity_to_verts(extrusion_entity, float(layer->print_z), copy,
|
||||
volume(idx_layer,
|
||||
(extrusion_entity->role() == erSupportMaterial) ?
|
||||
support_layer->object()->config().support_material_extruder :
|
||||
support_layer->object()->config().support_material_interface_extruder,
|
||||
2));
|
||||
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
}
|
||||
}
|
||||
}
|
||||
// Ensure that no volume grows over the limits. If the volume is too large, allocate a new one.
|
||||
for (size_t i = 0; i < vols.size(); ++i) {
|
||||
GLVolume &vol = *vols[i];
|
||||
if (vol.indexed_vertex_array.vertices_and_normals_interleaved.size() > MAX_VERTEX_BUFFER_SIZE) {
|
||||
vols[i] = new_volume(vol.color);
|
||||
reserve_new_volume_finalize_old_volume(*vols[i], vol, false);
|
||||
}
|
||||
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
if (geometries[i].vertices_size_bytes() > MAX_VERTEX_BUFFER_SIZE) {
|
||||
vol.model.init_from(std::move(geometries[i]));
|
||||
#else
|
||||
if (vol.indexed_vertex_array.vertices_and_normals_interleaved.size() > MAX_VERTEX_BUFFER_SIZE) {
|
||||
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
vols[i] = new_volume(vol.color);
|
||||
#if !ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
reserve_new_volume_finalize_old_volume(*vols[i], vol, false);
|
||||
#endif // !ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
for (size_t i = 0; i < vols.size(); ++i) {
|
||||
if (!geometries[i].is_empty())
|
||||
vols[i]->model.init_from(std::move(geometries[i]));
|
||||
}
|
||||
#else
|
||||
for (GLVolume *vol : vols)
|
||||
// Ideally one would call vol->indexed_vertex_array.finalize() here to move the buffers to the OpenGL driver,
|
||||
// but this code runs in parallel and the OpenGL driver is not thread safe.
|
||||
vol->indexed_vertex_array.shrink_to_fit();
|
||||
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
});
|
||||
|
||||
BOOST_LOG_TRIVIAL(debug) << "Loading print object toolpaths in parallel - finalizing results" << m_volumes.log_memory_info() << log_memory_info();
|
||||
|
@ -6486,8 +6640,14 @@ void GLCanvas3D::_load_print_object_toolpaths(const PrintObject& print_object, c
|
|||
}
|
||||
for (size_t i = volumes_cnt_initial; i < m_volumes.volumes.size(); ++i) {
|
||||
GLVolume* v = m_volumes.volumes[i];
|
||||
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
v->is_outside = !contains(build_volume, v->model);
|
||||
// We are done editinig the model, now it can be sent to gpu
|
||||
v->model.enable_render();
|
||||
#else
|
||||
v->is_outside = ! build_volume.all_paths_inside_vertices_and_normals_interleaved(v->indexed_vertex_array.vertices_and_normals_interleaved, v->indexed_vertex_array.bounding_box());
|
||||
v->indexed_vertex_array.finalize_geometry(m_initialized);
|
||||
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
}
|
||||
|
||||
BOOST_LOG_TRIVIAL(debug) << "Loading print object toolpaths in parallel - end" << m_volumes.log_memory_info() << log_memory_info();
|
||||
|
@ -6507,10 +6667,10 @@ void GLCanvas3D::_load_wipe_tower_toolpaths(const BuildVolume& build_volume, con
|
|||
|
||||
struct Ctxt
|
||||
{
|
||||
const Print *print;
|
||||
const std::vector<ColorRGBA>* tool_colors;
|
||||
Vec2f wipe_tower_pos;
|
||||
float wipe_tower_angle;
|
||||
const Print *print;
|
||||
const std::vector<ColorRGBA> *tool_colors;
|
||||
Vec2f wipe_tower_pos;
|
||||
float wipe_tower_angle;
|
||||
|
||||
static ColorRGBA color_support() { return ColorRGBA::GREENISH(); }
|
||||
|
||||
|
@ -6552,6 +6712,11 @@ void GLCanvas3D::_load_wipe_tower_toolpaths(const BuildVolume& build_volume, con
|
|||
auto new_volume = [this, &new_volume_mutex](const ColorRGBA& color) {
|
||||
auto *volume = new GLVolume(color);
|
||||
volume->is_extrusion_path = true;
|
||||
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
// to prevent sending data to gpu (in the main thread) while
|
||||
// editing the model geometry
|
||||
volume->model.disable_render();
|
||||
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
tbb::spin_mutex::scoped_lock lock;
|
||||
lock.acquire(new_volume_mutex);
|
||||
m_volumes.volumes.emplace_back(volume);
|
||||
|
@ -6565,23 +6730,46 @@ void GLCanvas3D::_load_wipe_tower_toolpaths(const BuildVolume& build_volume, con
|
|||
[&ctxt, &new_volume](const tbb::blocked_range<size_t>& range) {
|
||||
// Bounding box of this slab of a wipe tower.
|
||||
GLVolumePtrs vols;
|
||||
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
std::vector<GLModel::Geometry> geometries;
|
||||
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
if (ctxt.color_by_tool()) {
|
||||
for (size_t i = 0; i < ctxt.number_tools(); ++i)
|
||||
for (size_t i = 0; i < ctxt.number_tools(); ++i) {
|
||||
vols.emplace_back(new_volume(ctxt.color_tool(i)));
|
||||
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
geometries.emplace_back(GLModel::Geometry());
|
||||
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
}
|
||||
}
|
||||
else
|
||||
else {
|
||||
vols = { new_volume(ctxt.color_support()) };
|
||||
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
geometries = { GLModel::Geometry() };
|
||||
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
}
|
||||
|
||||
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
assert(vols.size() == geometries.size());
|
||||
for (GLModel::Geometry& g : geometries) {
|
||||
g.format = { GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3N3, GLModel::Geometry::EIndexType::UINT };
|
||||
}
|
||||
#else
|
||||
for (GLVolume *volume : vols)
|
||||
// Reserving number of vertices (3x position + 3x color)
|
||||
volume->indexed_vertex_array.reserve(VERTEX_BUFFER_RESERVE_SIZE / 6);
|
||||
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
for (size_t idx_layer = range.begin(); idx_layer < range.end(); ++idx_layer) {
|
||||
const std::vector<WipeTower::ToolChangeResult> &layer = ctxt.tool_change(idx_layer);
|
||||
for (size_t i = 0; i < vols.size(); ++i) {
|
||||
GLVolume &vol = *vols[i];
|
||||
if (vol.print_zs.empty() || vol.print_zs.back() != layer.front().print_z) {
|
||||
vol.print_zs.emplace_back(layer.front().print_z);
|
||||
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
vol.offsets.emplace_back(geometries[i].indices_count());
|
||||
#else
|
||||
vol.offsets.emplace_back(vol.indexed_vertex_array.quad_indices.size());
|
||||
vol.offsets.emplace_back(vol.indexed_vertex_array.triangle_indices.size());
|
||||
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
}
|
||||
}
|
||||
for (const WipeTower::ToolChangeResult &extrusions : layer) {
|
||||
|
@ -6623,21 +6811,42 @@ void GLCanvas3D::_load_wipe_tower_toolpaths(const BuildVolume& build_volume, con
|
|||
|
||||
e_prev = e;
|
||||
}
|
||||
|
||||
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
_3DScene::thick_lines_to_verts(lines, widths, heights, lines.front().a == lines.back().b, extrusions.print_z,
|
||||
geometries[ctxt.volume_idx(e.tool, 0)]);
|
||||
#else
|
||||
_3DScene::thick_lines_to_verts(lines, widths, heights, lines.front().a == lines.back().b, extrusions.print_z,
|
||||
*vols[ctxt.volume_idx(e.tool, 0)]);
|
||||
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
}
|
||||
}
|
||||
}
|
||||
for (size_t i = 0; i < vols.size(); ++i) {
|
||||
GLVolume &vol = *vols[i];
|
||||
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
if (geometries[i].vertices_size_bytes() > MAX_VERTEX_BUFFER_SIZE) {
|
||||
vol.model.init_from(std::move(geometries[i]));
|
||||
#else
|
||||
if (vol.indexed_vertex_array.vertices_and_normals_interleaved.size() > MAX_VERTEX_BUFFER_SIZE) {
|
||||
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
vols[i] = new_volume(vol.color);
|
||||
#if !ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
reserve_new_volume_finalize_old_volume(*vols[i], vol, false);
|
||||
#endif // !ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
}
|
||||
}
|
||||
|
||||
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
for (size_t i = 0; i < vols.size(); ++i) {
|
||||
if (!geometries[i].is_empty())
|
||||
vols[i]->model.init_from(std::move(geometries[i]));
|
||||
}
|
||||
#else
|
||||
for (GLVolume *vol : vols)
|
||||
vol->indexed_vertex_array.shrink_to_fit();
|
||||
});
|
||||
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
});
|
||||
|
||||
BOOST_LOG_TRIVIAL(debug) << "Loading wipe tower toolpaths in parallel - finalizing results" << m_volumes.log_memory_info() << log_memory_info();
|
||||
// Remove empty volumes from the newly added volumes.
|
||||
|
@ -6651,8 +6860,14 @@ void GLCanvas3D::_load_wipe_tower_toolpaths(const BuildVolume& build_volume, con
|
|||
}
|
||||
for (size_t i = volumes_cnt_initial; i < m_volumes.volumes.size(); ++i) {
|
||||
GLVolume* v = m_volumes.volumes[i];
|
||||
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
v->is_outside = !contains(build_volume, v->model);
|
||||
// We are done editinig the model, now it can be sent to gpu
|
||||
v->model.enable_render();
|
||||
#else
|
||||
v->is_outside = ! build_volume.all_paths_inside_vertices_and_normals_interleaved(v->indexed_vertex_array.vertices_and_normals_interleaved, v->indexed_vertex_array.bounding_box());
|
||||
v->indexed_vertex_array.finalize_geometry(m_initialized);
|
||||
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
}
|
||||
|
||||
BOOST_LOG_TRIVIAL(debug) << "Loading wipe tower toolpaths in parallel - end" << m_volumes.log_memory_info() << log_memory_info();
|
||||
|
@ -6676,11 +6891,21 @@ void GLCanvas3D::_load_sla_shells()
|
|||
m_volumes.volumes.emplace_back(new GLVolume(color));
|
||||
GLVolume& v = *m_volumes.volumes.back();
|
||||
#if ENABLE_SMOOTH_NORMALS
|
||||
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
v.model.init_from(mesh, true);
|
||||
#else
|
||||
v.indexed_vertex_array.load_mesh(mesh, true);
|
||||
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
#else
|
||||
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
v.model.init_from(mesh);
|
||||
#else
|
||||
v.indexed_vertex_array.load_mesh(mesh);
|
||||
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
#endif // ENABLE_SMOOTH_NORMALS
|
||||
#if !ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
v.indexed_vertex_array.finalize_geometry(m_initialized);
|
||||
#endif // !ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
v.shader_outside_printer_detection_enabled = outside_printer_detection_enabled;
|
||||
v.composite_id.volume_id = volume_id;
|
||||
v.set_instance_offset(unscale(instance.shift.x(), instance.shift.y(), 0.0));
|
||||
|
|
|
@ -799,7 +799,6 @@ public:
|
|||
void do_move(const std::string& snapshot_type);
|
||||
void do_rotate(const std::string& snapshot_type);
|
||||
void do_scale(const std::string& snapshot_type);
|
||||
void do_flatten(const Vec3d& normal, const std::string& snapshot_type);
|
||||
void do_mirror(const std::string& snapshot_type);
|
||||
|
||||
void update_gizmos_on_off_state();
|
||||
|
|
|
@ -8,15 +8,56 @@
|
|||
#include "libslic3r/TriangleMesh.hpp"
|
||||
#include "libslic3r/Model.hpp"
|
||||
#include "libslic3r/Polygon.hpp"
|
||||
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
#include "libslic3r/BuildVolume.hpp"
|
||||
#include "libslic3r/Geometry/ConvexHull.hpp"
|
||||
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
|
||||
#include <boost/filesystem/operations.hpp>
|
||||
#include <boost/algorithm/string/predicate.hpp>
|
||||
|
||||
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
#if ENABLE_SMOOTH_NORMALS
|
||||
#include <igl/per_face_normals.h>
|
||||
#include <igl/per_corner_normals.h>
|
||||
#include <igl/per_vertex_normals.h>
|
||||
#endif // ENABLE_SMOOTH_NORMALS
|
||||
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
|
||||
#include <GL/glew.h>
|
||||
|
||||
namespace Slic3r {
|
||||
namespace GUI {
|
||||
|
||||
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
#if ENABLE_SMOOTH_NORMALS
|
||||
static void smooth_normals_corner(const TriangleMesh& mesh, std::vector<stl_normal>& normals)
|
||||
{
|
||||
using MapMatrixXfUnaligned = Eigen::Map<const Eigen::Matrix<float, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor | Eigen::DontAlign>>;
|
||||
using MapMatrixXiUnaligned = Eigen::Map<const Eigen::Matrix<int, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor | Eigen::DontAlign>>;
|
||||
|
||||
std::vector<Vec3f> face_normals = its_face_normals(mesh.its);
|
||||
|
||||
Eigen::MatrixXd vertices = MapMatrixXfUnaligned(mesh.its.vertices.front().data(),
|
||||
Eigen::Index(mesh.its.vertices.size()), 3).cast<double>();
|
||||
Eigen::MatrixXi indices = MapMatrixXiUnaligned(mesh.its.indices.front().data(),
|
||||
Eigen::Index(mesh.its.indices.size()), 3);
|
||||
Eigen::MatrixXd in_normals = MapMatrixXfUnaligned(face_normals.front().data(),
|
||||
Eigen::Index(face_normals.size()), 3).cast<double>();
|
||||
Eigen::MatrixXd out_normals;
|
||||
|
||||
igl::per_corner_normals(vertices, indices, in_normals, 1.0, out_normals);
|
||||
|
||||
normals = std::vector<stl_normal>(mesh.its.vertices.size());
|
||||
for (size_t i = 0; i < mesh.its.indices.size(); ++i) {
|
||||
for (size_t j = 0; j < 3; ++j) {
|
||||
normals[mesh.its.indices[i][j]] = out_normals.row(i * 3 + j).cast<float>();
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif // ENABLE_SMOOTH_NORMALS
|
||||
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
|
||||
#if ENABLE_GLBEGIN_GLEND_REMOVAL
|
||||
void GLModel::Geometry::reserve_vertices(size_t vertices_count)
|
||||
{
|
||||
|
@ -207,6 +248,37 @@ Vec2f GLModel::Geometry::extract_tex_coord_2(size_t id) const
|
|||
return { *(start + 0), *(start + 1) };
|
||||
}
|
||||
|
||||
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
void GLModel::Geometry::set_vertex(size_t id, const Vec3f& position, const Vec3f& normal)
|
||||
{
|
||||
assert(format.vertex_layout == EVertexLayout::P3N3);
|
||||
assert(id < vertices_count());
|
||||
if (id < vertices_count()) {
|
||||
float* start = &vertices[id * vertex_stride_floats(format)];
|
||||
*(start + 0) = position.x();
|
||||
*(start + 1) = position.y();
|
||||
*(start + 2) = position.z();
|
||||
*(start + 3) = normal.x();
|
||||
*(start + 4) = normal.y();
|
||||
*(start + 5) = normal.z();
|
||||
}
|
||||
}
|
||||
|
||||
void GLModel::Geometry::set_ushort_index(size_t id, unsigned short index)
|
||||
{
|
||||
assert(id < indices_count());
|
||||
if (id < indices_count())
|
||||
::memcpy(indices.data() + id * sizeof(unsigned short), &index, sizeof(unsigned short));
|
||||
}
|
||||
|
||||
void GLModel::Geometry::set_uint_index(size_t id, unsigned int index)
|
||||
{
|
||||
assert(id < indices_count());
|
||||
if (id < indices_count())
|
||||
::memcpy(indices.data() + id * sizeof(unsigned int), &index, sizeof(unsigned int));
|
||||
}
|
||||
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
|
||||
unsigned int GLModel::Geometry::extract_uint_index(size_t id) const
|
||||
{
|
||||
if (format.index_type != EIndexType::UINT) {
|
||||
|
@ -219,7 +291,7 @@ unsigned int GLModel::Geometry::extract_uint_index(size_t id) const
|
|||
return -1;
|
||||
}
|
||||
|
||||
unsigned int ret = -1;
|
||||
unsigned int ret = (unsigned int)-1;
|
||||
::memcpy(&ret, indices.data() + id * index_stride_bytes(format), sizeof(unsigned int));
|
||||
return ret;
|
||||
}
|
||||
|
@ -236,11 +308,23 @@ unsigned short GLModel::Geometry::extract_ushort_index(size_t id) const
|
|||
return -1;
|
||||
}
|
||||
|
||||
unsigned short ret = -1;
|
||||
unsigned short ret = (unsigned short)-1;
|
||||
::memcpy(&ret, indices.data() + id * index_stride_bytes(format), sizeof(unsigned short));
|
||||
return ret;
|
||||
}
|
||||
|
||||
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
void GLModel::Geometry::remove_vertex(size_t id)
|
||||
{
|
||||
assert(id < vertices_count());
|
||||
if (id < vertices_count()) {
|
||||
size_t stride = vertex_stride_floats(format);
|
||||
std::vector<float>::iterator it = vertices.begin() + id * stride;
|
||||
vertices.erase(it, it + stride);
|
||||
}
|
||||
}
|
||||
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
|
||||
size_t GLModel::Geometry::vertex_stride_floats(const Format& format)
|
||||
{
|
||||
switch (format.vertex_layout)
|
||||
|
@ -461,10 +545,58 @@ void GLModel::init_from(const Geometry& data)
|
|||
}
|
||||
|
||||
#if ENABLE_GLBEGIN_GLEND_REMOVAL
|
||||
#if ENABLE_SMOOTH_NORMALS
|
||||
void GLModel::init_from(const TriangleMesh& mesh, bool smooth_normals)
|
||||
{
|
||||
if (smooth_normals) {
|
||||
if (is_initialized()) {
|
||||
// call reset() if you want to reuse this model
|
||||
assert(false);
|
||||
return;
|
||||
}
|
||||
|
||||
if (mesh.its.vertices.empty() || mesh.its.indices.empty()) {
|
||||
assert(false);
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<stl_normal> normals;
|
||||
smooth_normals_corner(mesh, normals);
|
||||
|
||||
const indexed_triangle_set& its = mesh.its;
|
||||
Geometry& data = m_render_data.geometry;
|
||||
data.format = { Geometry::EPrimitiveType::Triangles, Geometry::EVertexLayout::P3N3, GLModel::Geometry::index_type(3 * its.indices.size()) };
|
||||
data.reserve_vertices(3 * its.indices.size());
|
||||
data.reserve_indices(3 * its.indices.size());
|
||||
|
||||
// vertices
|
||||
for (size_t i = 0; i < its.vertices.size(); ++i) {
|
||||
data.add_vertex(its.vertices[i], normals[i]);
|
||||
}
|
||||
|
||||
// indices
|
||||
for (size_t i = 0; i < its.indices.size(); ++i) {
|
||||
const stl_triangle_vertex_indices& idx = its.indices[i];
|
||||
if (data.format.index_type == GLModel::Geometry::EIndexType::USHORT)
|
||||
data.add_ushort_triangle((unsigned short)idx(0), (unsigned short)idx(1), (unsigned short)idx(2));
|
||||
else
|
||||
data.add_uint_triangle((unsigned int)idx(0), (unsigned int)idx(1), (unsigned int)idx(2));
|
||||
}
|
||||
|
||||
// update bounding box
|
||||
for (size_t i = 0; i < vertices_count(); ++i) {
|
||||
m_bounding_box.merge(m_render_data.geometry.extract_position_3(i).cast<double>());
|
||||
}
|
||||
}
|
||||
else
|
||||
init_from(mesh.its);
|
||||
}
|
||||
#else
|
||||
void GLModel::init_from(const TriangleMesh& mesh)
|
||||
{
|
||||
init_from(mesh.its);
|
||||
}
|
||||
#endif // ENABLE_SMOOTH_NORMALS
|
||||
|
||||
void GLModel::init_from(const indexed_triangle_set& its)
|
||||
#else
|
||||
|
@ -484,21 +616,24 @@ void GLModel::init_from(const indexed_triangle_set& its, const BoundingBoxf3 &bb
|
|||
}
|
||||
|
||||
Geometry& data = m_render_data.geometry;
|
||||
data.format = { Geometry::EPrimitiveType::Triangles, Geometry::EVertexLayout::P3N3, Geometry::EIndexType::UINT };
|
||||
data.format = { Geometry::EPrimitiveType::Triangles, Geometry::EVertexLayout::P3N3, GLModel::Geometry::index_type(3 * its.indices.size()) };
|
||||
data.reserve_vertices(3 * its.indices.size());
|
||||
data.reserve_indices(3 * its.indices.size());
|
||||
|
||||
// vertices + indices
|
||||
unsigned int vertices_counter = 0;
|
||||
for (uint32_t i = 0; i < its.indices.size(); ++i) {
|
||||
stl_triangle_vertex_indices face = its.indices[i];
|
||||
stl_vertex vertex[3] = { its.vertices[face[0]], its.vertices[face[1]], its.vertices[face[2]] };
|
||||
stl_vertex n = face_normal_normalized(vertex);
|
||||
const stl_triangle_vertex_indices face = its.indices[i];
|
||||
const stl_vertex vertex[3] = { its.vertices[face[0]], its.vertices[face[1]], its.vertices[face[2]] };
|
||||
const stl_vertex n = face_normal_normalized(vertex);
|
||||
for (size_t j = 0; j < 3; ++j) {
|
||||
data.add_vertex(vertex[j], n);
|
||||
}
|
||||
vertices_counter += 3;
|
||||
data.add_uint_triangle(vertices_counter - 3, vertices_counter - 2, vertices_counter - 1);
|
||||
if (data.format.index_type == GLModel::Geometry::EIndexType::USHORT)
|
||||
data.add_ushort_triangle((unsigned short)vertices_counter - 3, (unsigned short)vertices_counter - 2, (unsigned short)vertices_counter - 1);
|
||||
else
|
||||
data.add_uint_triangle(vertices_counter - 3, vertices_counter - 2, vertices_counter - 1);
|
||||
}
|
||||
|
||||
// update bounding box
|
||||
|
@ -721,6 +856,9 @@ void GLModel::render()
|
|||
void GLModel::render() const
|
||||
#endif // ENABLE_GLBEGIN_GLEND_REMOVAL
|
||||
{
|
||||
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
render(std::make_pair<size_t, size_t>(0, indices_count()));
|
||||
#else
|
||||
GLShaderProgram* shader = wxGetApp().get_current_shader();
|
||||
|
||||
#if ENABLE_GLBEGIN_GLEND_REMOVAL
|
||||
|
@ -809,8 +947,71 @@ void GLModel::render() const
|
|||
glsafe(::glBindBuffer(GL_ARRAY_BUFFER, 0));
|
||||
}
|
||||
#endif // ENABLE_GLBEGIN_GLEND_REMOVAL
|
||||
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
}
|
||||
|
||||
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
void GLModel::render(const std::pair<size_t, size_t>& range)
|
||||
{
|
||||
if (m_render_disabled)
|
||||
return;
|
||||
|
||||
if (range.second == range.first)
|
||||
return;
|
||||
|
||||
GLShaderProgram* shader = wxGetApp().get_current_shader();
|
||||
|
||||
if (shader == nullptr)
|
||||
return;
|
||||
|
||||
// sends data to gpu if not done yet
|
||||
if (m_render_data.vbo_id == 0 || m_render_data.ibo_id == 0) {
|
||||
if (m_render_data.geometry.vertices_count() > 0 && m_render_data.geometry.indices_count() > 0 && !send_to_gpu())
|
||||
return;
|
||||
}
|
||||
|
||||
const Geometry& data = m_render_data.geometry;
|
||||
|
||||
const GLenum mode = get_primitive_mode(data.format);
|
||||
const GLenum index_type = get_index_type(data.format);
|
||||
|
||||
const size_t vertex_stride_bytes = Geometry::vertex_stride_bytes(data.format);
|
||||
const bool position = Geometry::has_position(data.format);
|
||||
const bool normal = Geometry::has_normal(data.format);
|
||||
const bool tex_coord = Geometry::has_tex_coord(data.format);
|
||||
|
||||
glsafe(::glBindBuffer(GL_ARRAY_BUFFER, m_render_data.vbo_id));
|
||||
|
||||
if (position) {
|
||||
glsafe(::glVertexPointer(Geometry::position_stride_floats(data.format), GL_FLOAT, vertex_stride_bytes, (const void*)Geometry::position_offset_bytes(data.format)));
|
||||
glsafe(::glEnableClientState(GL_VERTEX_ARRAY));
|
||||
}
|
||||
if (normal) {
|
||||
glsafe(::glNormalPointer(GL_FLOAT, vertex_stride_bytes, (const void*)Geometry::normal_offset_bytes(data.format)));
|
||||
glsafe(::glEnableClientState(GL_NORMAL_ARRAY));
|
||||
}
|
||||
if (tex_coord) {
|
||||
glsafe(::glTexCoordPointer(Geometry::tex_coord_stride_floats(data.format), GL_FLOAT, vertex_stride_bytes, (const void*)Geometry::tex_coord_offset_bytes(data.format)));
|
||||
glsafe(::glEnableClientState(GL_TEXTURE_COORD_ARRAY));
|
||||
}
|
||||
|
||||
shader->set_uniform("uniform_color", data.color);
|
||||
|
||||
glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_render_data.ibo_id));
|
||||
glsafe(::glDrawElements(mode, range.second - range.first + 1, index_type, (const void*)(range.first * Geometry::index_stride_bytes(data.format))));
|
||||
glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0));
|
||||
|
||||
if (tex_coord)
|
||||
glsafe(::glDisableClientState(GL_TEXTURE_COORD_ARRAY));
|
||||
if (normal)
|
||||
glsafe(::glDisableClientState(GL_NORMAL_ARRAY));
|
||||
if (position)
|
||||
glsafe(::glDisableClientState(GL_VERTEX_ARRAY));
|
||||
|
||||
glsafe(::glBindBuffer(GL_ARRAY_BUFFER, 0));
|
||||
}
|
||||
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
|
||||
#if ENABLE_GLBEGIN_GLEND_REMOVAL
|
||||
void GLModel::render_instanced(unsigned int instances_vbo, unsigned int instances_count)
|
||||
#else
|
||||
|
@ -1027,6 +1228,62 @@ static void append_triangle(GLModel::Geometry& data, unsigned short v1, unsigned
|
|||
}
|
||||
#endif // ENABLE_GLBEGIN_GLEND_REMOVAL
|
||||
|
||||
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
template<typename Fn>
|
||||
inline bool all_vertices_inside(const GLModel::Geometry& geometry, Fn fn)
|
||||
{
|
||||
const size_t position_stride_floats = geometry.position_stride_floats(geometry.format);
|
||||
const size_t position_offset_floats = geometry.position_offset_floats(geometry.format);
|
||||
assert(position_stride_floats == 3);
|
||||
if (geometry.vertices.empty() || position_stride_floats != 3)
|
||||
return false;
|
||||
|
||||
for (auto it = geometry.vertices.begin(); it != geometry.vertices.end(); ) {
|
||||
it += position_offset_floats;
|
||||
if (!fn({ *it, *(it + 1), *(it + 2) }))
|
||||
return false;
|
||||
it += (geometry.vertex_stride_floats(geometry.format) - position_offset_floats - position_stride_floats);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool contains(const BuildVolume& volume, const GLModel& model, bool ignore_bottom)
|
||||
{
|
||||
static constexpr const double epsilon = BuildVolume::BedEpsilon;
|
||||
switch (volume.type()) {
|
||||
case BuildVolume::Type::Rectangle:
|
||||
{
|
||||
BoundingBox3Base<Vec3d> build_volume = volume.bounding_volume().inflated(epsilon);
|
||||
if (volume.max_print_height() == 0.0)
|
||||
build_volume.max.z() = std::numeric_limits<double>::max();
|
||||
if (ignore_bottom)
|
||||
build_volume.min.z() = -std::numeric_limits<double>::max();
|
||||
const BoundingBoxf3& model_box = model.get_bounding_box();
|
||||
return build_volume.contains(model_box.min) && build_volume.contains(model_box.max);
|
||||
}
|
||||
case BuildVolume::Type::Circle:
|
||||
{
|
||||
const Geometry::Circled& circle = volume.circle();
|
||||
const Vec2f c = unscaled<float>(circle.center);
|
||||
const float r = unscaled<double>(circle.radius) + float(epsilon);
|
||||
const float r2 = sqr(r);
|
||||
return volume.max_print_height() == 0.0 ?
|
||||
all_vertices_inside(model.get_geometry(), [c, r2](const Vec3f& p) { return (to_2d(p) - c).squaredNorm() <= r2; }) :
|
||||
|
||||
all_vertices_inside(model.get_geometry(), [c, r2, z = volume.max_print_height() + epsilon](const Vec3f& p) { return (to_2d(p) - c).squaredNorm() <= r2 && p.z() <= z; });
|
||||
}
|
||||
case BuildVolume::Type::Convex:
|
||||
//FIXME doing test on convex hull until we learn to do test on non-convex polygons efficiently.
|
||||
case BuildVolume::Type::Custom:
|
||||
return volume.max_print_height() == 0.0 ?
|
||||
all_vertices_inside(model.get_geometry(), [&volume](const Vec3f& p) { return Geometry::inside_convex_polygon(volume.top_bottom_convex_hull_decomposition_bed(), to_2d(p).cast<double>()); }) :
|
||||
all_vertices_inside(model.get_geometry(), [&volume, z = volume.max_print_height() + epsilon](const Vec3f& p) { return Geometry::inside_convex_polygon(volume.top_bottom_convex_hull_decomposition_bed(), to_2d(p).cast<double>()) && p.z() <= z; });
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
|
||||
GLModel::Geometry stilized_arrow(unsigned short resolution, float tip_radius, float tip_height, float stem_radius, float stem_height)
|
||||
{
|
||||
#if !ENABLE_GLBEGIN_GLEND_REMOVAL
|
||||
|
|
|
@ -14,6 +14,9 @@ namespace Slic3r {
|
|||
class TriangleMesh;
|
||||
class Polygon;
|
||||
using Polygons = std::vector<Polygon>;
|
||||
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
class BuildVolume;
|
||||
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
|
||||
namespace GUI {
|
||||
|
||||
|
@ -89,6 +92,13 @@ namespace GUI {
|
|||
void add_vertex(const Vec3f& position, const Vec2f& tex_coord); // EVertexLayout::P3T2
|
||||
void add_vertex(const Vec3f& position, const Vec3f& normal); // EVertexLayout::P3N3
|
||||
|
||||
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
void set_vertex(size_t id, const Vec3f& position, const Vec3f& normal); // EVertexLayout::P3N3
|
||||
|
||||
void set_ushort_index(size_t id, unsigned short index);
|
||||
void set_uint_index(size_t id, unsigned int index);
|
||||
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
|
||||
void add_ushort_index(unsigned short id);
|
||||
void add_uint_index(unsigned int id);
|
||||
|
||||
|
@ -106,7 +116,11 @@ namespace GUI {
|
|||
unsigned int extract_uint_index(size_t id) const;
|
||||
unsigned short extract_ushort_index(size_t id) const;
|
||||
|
||||
bool is_empty() const { return vertices.empty() || indices.empty(); }
|
||||
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
void remove_vertex(size_t id);
|
||||
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
|
||||
bool is_empty() const { return vertices_count() == 0 || indices_count() == 0; }
|
||||
|
||||
size_t vertices_count() const { return vertices.size() / vertex_stride_floats(format); }
|
||||
size_t indices_count() const { return indices.size() / index_stride_bytes(format); }
|
||||
|
@ -179,6 +193,16 @@ namespace GUI {
|
|||
std::vector<RenderData> m_render_data;
|
||||
#endif // ENABLE_GLBEGIN_GLEND_REMOVAL
|
||||
|
||||
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
// By default the vertex and index buffers data are sent to gpu at the first call to render() method.
|
||||
// If you need to initialize a model from outside the main thread, so that a call to render() may happen
|
||||
// before the initialization is complete, use the methods:
|
||||
// disable_render()
|
||||
// ... do your initialization ...
|
||||
// enable_render()
|
||||
// to keep the data on cpu side until needed.
|
||||
bool m_render_disabled{ false };
|
||||
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
BoundingBoxf3 m_bounding_box;
|
||||
std::string m_filename;
|
||||
|
||||
|
@ -197,8 +221,16 @@ namespace GUI {
|
|||
|
||||
size_t indices_size_bytes() const { return indices_count() * Geometry::index_stride_bytes(m_render_data.geometry.format); }
|
||||
|
||||
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
const Geometry& get_geometry() const { return m_render_data.geometry; }
|
||||
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
|
||||
void init_from(Geometry&& data);
|
||||
#if ENABLE_SMOOTH_NORMALS
|
||||
void init_from(const TriangleMesh& mesh, bool smooth_normals = false);
|
||||
#else
|
||||
void init_from(const TriangleMesh& mesh);
|
||||
#endif // ENABLE_SMOOTH_NORMALS
|
||||
#else
|
||||
void init_from(const Geometry& data);
|
||||
void init_from(const indexed_triangle_set& its, const BoundingBoxf3& bbox);
|
||||
|
@ -219,9 +251,15 @@ namespace GUI {
|
|||
void reset();
|
||||
#if ENABLE_GLBEGIN_GLEND_REMOVAL
|
||||
void render();
|
||||
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
void render(const std::pair<size_t, size_t>& range);
|
||||
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
void render_instanced(unsigned int instances_vbo, unsigned int instances_count);
|
||||
|
||||
bool is_initialized() const { return vertices_count() > 0 && indices_count() > 0; }
|
||||
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
bool is_empty() const { return m_render_data.geometry.is_empty(); }
|
||||
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
#else
|
||||
void render() const;
|
||||
void render_instanced(unsigned int instances_vbo, unsigned int instances_count) const;
|
||||
|
@ -232,6 +270,29 @@ namespace GUI {
|
|||
const BoundingBoxf3& get_bounding_box() const { return m_bounding_box; }
|
||||
const std::string& get_filename() const { return m_filename; }
|
||||
|
||||
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
bool is_render_disabled() const { return m_render_disabled; }
|
||||
void enable_render() { m_render_disabled = false; }
|
||||
void disable_render() { m_render_disabled = true; }
|
||||
|
||||
size_t cpu_memory_used() const {
|
||||
size_t ret = 0;
|
||||
if (!m_render_data.geometry.vertices.empty())
|
||||
ret += vertices_size_bytes();
|
||||
if (!m_render_data.geometry.indices.empty())
|
||||
ret += indices_size_bytes();
|
||||
return ret;
|
||||
}
|
||||
size_t gpu_memory_used() const {
|
||||
size_t ret = 0;
|
||||
if (m_render_data.geometry.vertices.empty())
|
||||
ret += vertices_size_bytes();
|
||||
if (m_render_data.geometry.indices.empty())
|
||||
ret += indices_size_bytes();
|
||||
return ret;
|
||||
}
|
||||
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
|
||||
private:
|
||||
#if ENABLE_GLBEGIN_GLEND_REMOVAL
|
||||
bool send_to_gpu();
|
||||
|
@ -240,6 +301,10 @@ namespace GUI {
|
|||
#endif // ENABLE_GLBEGIN_GLEND_REMOVAL
|
||||
};
|
||||
|
||||
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
bool contains(const BuildVolume& volume, const GLModel& model, bool ignore_bottom = true);
|
||||
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
|
||||
// create an arrow with cylindrical stem and conical tip, with the given dimensions and resolution
|
||||
// the origin of the arrow is in the center of the stem cap
|
||||
// the arrow has its axis of symmetry along the Z axis and is pointing upward
|
||||
|
|
|
@ -87,7 +87,7 @@ namespace GUI {
|
|||
color[1] = (m_state == Select) ? 1.0f : 0.3f;
|
||||
color[2] = 0.3f;
|
||||
glsafe(::glColor3fv(color));
|
||||
#endif // ENABLE_GLBEGIN_GLEND_REMOVAL
|
||||
#endif // !ENABLE_GLBEGIN_GLEND_REMOVAL
|
||||
|
||||
glsafe(::glDisable(GL_DEPTH_TEST));
|
||||
|
||||
|
|
|
@ -755,7 +755,7 @@ void GUI_App::post_init()
|
|||
if (boost::algorithm::iends_with(filename, ".amf") ||
|
||||
boost::algorithm::iends_with(filename, ".amf.xml") ||
|
||||
boost::algorithm::iends_with(filename, ".3mf"))
|
||||
this->plater()->set_project_filename(filename);
|
||||
this->plater()->set_project_filename(from_u8(filename));
|
||||
}
|
||||
}
|
||||
if (! this->init_params->extra_config.empty())
|
||||
|
@ -1286,8 +1286,13 @@ bool GUI_App::on_init_inner()
|
|||
else
|
||||
load_current_presets();
|
||||
|
||||
// Save the active profiles as a "saved into project".
|
||||
update_saved_preset_from_current_preset();
|
||||
|
||||
if (plater_ != nullptr) {
|
||||
// Save the names of active presets and project specific config into ProjectDirtyStateManager.
|
||||
plater_->reset_project_dirty_initial_presets();
|
||||
// Update Project dirty state, update application title bar.
|
||||
plater_->update_project_dirty_from_presets();
|
||||
}
|
||||
|
||||
|
@ -2448,16 +2453,13 @@ void GUI_App::update_saved_preset_from_current_preset()
|
|||
}
|
||||
}
|
||||
|
||||
std::vector<std::pair<unsigned int, std::string>> GUI_App::get_selected_presets() const
|
||||
std::vector<const PresetCollection*> GUI_App::get_active_preset_collections() const
|
||||
{
|
||||
std::vector<std::pair<unsigned int, std::string>> ret;
|
||||
std::vector<const PresetCollection*> ret;
|
||||
PrinterTechnology printer_technology = preset_bundle->printers.get_edited_preset().printer_technology();
|
||||
for (Tab* tab : tabs_list) {
|
||||
if (tab->supports_printer_technology(printer_technology)) {
|
||||
const PresetCollection* presets = tab->get_presets();
|
||||
ret.push_back({ static_cast<unsigned int>(presets->type()), presets->get_selected_preset_name() });
|
||||
}
|
||||
}
|
||||
for (const Tab* tab : tabs_list)
|
||||
if (tab->supports_printer_technology(printer_technology))
|
||||
ret.push_back(tab->get_presets());
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
|
@ -253,7 +253,7 @@ public:
|
|||
bool has_unsaved_preset_changes() const;
|
||||
bool has_current_preset_changes() const;
|
||||
void update_saved_preset_from_current_preset();
|
||||
std::vector<std::pair<unsigned int, std::string>> get_selected_presets() const;
|
||||
std::vector<const PresetCollection*> get_active_preset_collections() const;
|
||||
bool check_and_save_current_preset_changes(const wxString& caption, const wxString& header, bool remember_choice = true, bool use_dont_save_insted_of_discard = false);
|
||||
void apply_keeped_preset_modifications();
|
||||
bool check_and_keep_current_preset_changes(const wxString& caption, const wxString& header, int action_buttons, bool* postponed_apply_of_keeped_changes = nullptr);
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
namespace Slic3r {
|
||||
namespace GUI {
|
||||
|
||||
#if ENABLE_INSTANCE_COORDINATES_FOR_VOLUMES
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
enum class ECoordinatesType : unsigned char
|
||||
{
|
||||
World,
|
||||
|
@ -72,7 +72,8 @@ private:
|
|||
|
||||
Enum m_value;
|
||||
};
|
||||
#endif // ENABLE_INSTANCE_COORDINATES_FOR_VOLUMES
|
||||
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
||||
} // namespace Slic3r
|
||||
} // namespace GUI
|
||||
|
|
|
@ -52,7 +52,7 @@ static choice_ctrl* create_word_local_combo(wxWindow *parent)
|
|||
temp->SetFont(Slic3r::GUI::wxGetApp().normal_font());
|
||||
if (!wxOSX) temp->SetBackgroundStyle(wxBG_STYLE_PAINT);
|
||||
|
||||
#if ENABLE_INSTANCE_COORDINATES_FOR_VOLUMES
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
temp->Append(ObjectManipulation::coordinate_type_str(ECoordinatesType::World));
|
||||
temp->Append(ObjectManipulation::coordinate_type_str(ECoordinatesType::Instance));
|
||||
temp->Append(ObjectManipulation::coordinate_type_str(ECoordinatesType::Local));
|
||||
|
@ -62,7 +62,7 @@ static choice_ctrl* create_word_local_combo(wxWindow *parent)
|
|||
temp->Append(_L("Local coordinates"));
|
||||
temp->SetSelection(0);
|
||||
temp->SetValue(temp->GetString(0));
|
||||
#endif // ENABLE_INSTANCE_COORDINATES_FOR_VOLUMES
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
||||
temp->SetToolTip(_L("Select coordinate space, in which the transformation will be performed."));
|
||||
return temp;
|
||||
|
@ -88,14 +88,14 @@ void msw_rescale_word_local_combo(choice_ctrl* combo)
|
|||
// Set rescaled size
|
||||
combo->SetSize(size);
|
||||
|
||||
#if ENABLE_INSTANCE_COORDINATES_FOR_VOLUMES
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
combo->Append(ObjectManipulation::coordinate_type_str(ECoordinatesType::World));
|
||||
combo->Append(ObjectManipulation::coordinate_type_str(ECoordinatesType::Instance));
|
||||
combo->Append(ObjectManipulation::coordinate_type_str(ECoordinatesType::Local));
|
||||
#else
|
||||
combo->Append(_L("World coordinates"));
|
||||
combo->Append(_L("Local coordinates"));
|
||||
#endif // ENABLE_INSTANCE_COORDINATES_FOR_VOLUMES
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
||||
combo->SetValue(selection);
|
||||
#else
|
||||
|
@ -171,12 +171,12 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) :
|
|||
// Add world local combobox
|
||||
m_word_local_combo = create_word_local_combo(parent);
|
||||
m_word_local_combo->Bind(wxEVT_COMBOBOX, ([this](wxCommandEvent& evt) {
|
||||
#if ENABLE_INSTANCE_COORDINATES_FOR_VOLUMES
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
this->set_coordinates_type(evt.GetString());
|
||||
#else
|
||||
this->set_world_coordinates(evt.GetSelection() != 1);
|
||||
#endif // ENABLE_INSTANCE_COORDINATES_FOR_VOLUMES
|
||||
}), m_word_local_combo->GetId());
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
}), m_word_local_combo->GetId());
|
||||
|
||||
// Small trick to correct layouting in different view_mode :
|
||||
// Show empty string of a same height as a m_word_local_combo, when m_word_local_combo is hidden
|
||||
|
@ -353,11 +353,7 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) :
|
|||
if (selection.is_single_volume_or_modifier()) {
|
||||
const GLVolume* volume = selection.get_volume(*selection.get_volume_idxs().begin());
|
||||
const double min_z = get_volume_min_z(*volume);
|
||||
#if ENABLE_INSTANCE_COORDINATES_FOR_VOLUMES
|
||||
if (!is_world_coordinates()) {
|
||||
#else
|
||||
if (!m_world_coordinates) {
|
||||
#endif // ENABLE_INSTANCE_COORDINATES_FOR_VOLUMES
|
||||
const Vec3d diff = m_cache.position - volume->get_instance_transformation().get_matrix(true).inverse() * (min_z * Vec3d::UnitZ());
|
||||
|
||||
Plater::TakeSnapshot snapshot(wxGetApp().plater(), _L("Drop to bed"));
|
||||
|
@ -383,11 +379,7 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) :
|
|||
else if (selection.is_single_full_instance()) {
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
const double min_z = selection.get_scaled_instance_bounding_box().min.z();
|
||||
#if ENABLE_INSTANCE_COORDINATES_FOR_VOLUMES
|
||||
if (!is_world_coordinates()) {
|
||||
#else
|
||||
if (!m_world_coordinates) {
|
||||
#endif // ENABLE_INSTANCE_COORDINATES_FOR_VOLUMES
|
||||
const GLVolume* volume = selection.get_volume(*selection.get_volume_idxs().begin());
|
||||
const Vec3d diff = m_cache.position - volume->get_instance_transformation().get_matrix(true).inverse() * (min_z * Vec3d::UnitZ());
|
||||
|
||||
|
@ -428,17 +420,14 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) :
|
|||
Selection& selection = canvas->get_selection();
|
||||
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
if (selection.is_single_volume_or_modifier()) {
|
||||
if (selection.is_single_volume_or_modifier())
|
||||
#else
|
||||
if (selection.is_single_volume() || selection.is_single_modifier()) {
|
||||
if (selection.is_single_volume() || selection.is_single_modifier())
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
GLVolume* volume = const_cast<GLVolume*>(selection.get_volume(*selection.get_volume_idxs().begin()));
|
||||
volume->set_volume_rotation(Vec3d::Zero());
|
||||
}
|
||||
const_cast<GLVolume*>(selection.get_volume(*selection.get_volume_idxs().begin()))->set_volume_rotation(Vec3d::Zero());
|
||||
else if (selection.is_single_full_instance()) {
|
||||
for (unsigned int idx : selection.get_volume_idxs()) {
|
||||
GLVolume* volume = const_cast<GLVolume*>(selection.get_volume(idx));
|
||||
volume->set_instance_rotation(Vec3d::Zero());
|
||||
const_cast<GLVolume*>(selection.get_volume(idx))->set_instance_rotation(Vec3d::Zero());
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -513,7 +502,6 @@ void ObjectManipulation::Show(const bool show)
|
|||
#if ENABLE_WORLD_COORDINATE
|
||||
const Selection& selection = wxGetApp().plater()->canvas3D()->get_selection();
|
||||
bool show_world_local_combo = wxGetApp().get_mode() != comSimple && (selection.is_single_full_instance() || selection.is_single_volume_or_modifier());
|
||||
#if ENABLE_INSTANCE_COORDINATES_FOR_VOLUMES
|
||||
if (selection.is_single_volume_or_modifier() && m_word_local_combo->GetCount() < 3) {
|
||||
#ifdef __linux__
|
||||
m_word_local_combo->Insert(coordinate_type_str(ECoordinatesType::Instance), 1);
|
||||
|
@ -528,7 +516,6 @@ void ObjectManipulation::Show(const bool show)
|
|||
m_word_local_combo->Select((int)ECoordinatesType::World);
|
||||
this->set_coordinates_type(m_word_local_combo->GetString(m_word_local_combo->GetSelection()));
|
||||
}
|
||||
#endif // ENABLE_INSTANCE_COORDINATES_FOR_VOLUMES
|
||||
#else
|
||||
bool show_world_local_combo = wxGetApp().plater()->canvas3D()->get_selection().is_single_full_instance() && wxGetApp().get_mode() != comSimple;
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
@ -576,8 +563,7 @@ void ObjectManipulation::update_ui_from_settings()
|
|||
}
|
||||
m_check_inch->SetValue(m_imperial_units);
|
||||
|
||||
if (m_use_colors != (wxGetApp().app_config->get("color_mapinulation_panel") == "1"))
|
||||
{
|
||||
if (m_use_colors != (wxGetApp().app_config->get("color_mapinulation_panel") == "1")) {
|
||||
m_use_colors = wxGetApp().app_config->get("color_mapinulation_panel") == "1";
|
||||
// update colors for edit-boxes
|
||||
int axis_id = 0;
|
||||
|
@ -609,10 +595,10 @@ void ObjectManipulation::update_settings_value(const Selection& selection)
|
|||
m_new_rotate_label_string = L("Rotation");
|
||||
m_new_scale_label_string = L("Scale factors");
|
||||
|
||||
#if !ENABLE_INSTANCE_COORDINATES_FOR_VOLUMES
|
||||
#if !ENABLE_WORLD_COORDINATE
|
||||
if (wxGetApp().get_mode() == comSimple)
|
||||
m_world_coordinates = true;
|
||||
#endif // !ENABLE_INSTANCE_COORDINATES_FOR_VOLUMES
|
||||
#endif // !ENABLE_WORLD_COORDINATE
|
||||
|
||||
ObjectList* obj_list = wxGetApp().obj_list();
|
||||
if (selection.is_single_full_instance()) {
|
||||
|
@ -623,41 +609,41 @@ void ObjectManipulation::update_settings_value(const Selection& selection)
|
|||
#endif // !ENABLE_WORLD_COORDINATE
|
||||
|
||||
// Verify whether the instance rotation is multiples of 90 degrees, so that the scaling in world coordinates is possible.
|
||||
#if ENABLE_INSTANCE_COORDINATES_FOR_VOLUMES
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
if (is_world_coordinates() && !m_uniform_scale &&
|
||||
#else
|
||||
if (m_world_coordinates && ! m_uniform_scale &&
|
||||
#endif // ENABLE_INSTANCE_COORDINATES_FOR_VOLUMES
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
! Geometry::is_rotation_ninety_degrees(volume->get_instance_rotation())) {
|
||||
// Manipulating an instance in the world coordinate system, rotation is not multiples of ninety degrees, therefore enforce uniform scaling.
|
||||
m_uniform_scale = true;
|
||||
m_lock_bnt->SetLock(true);
|
||||
}
|
||||
|
||||
#if ENABLE_INSTANCE_COORDINATES_FOR_VOLUMES
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
if (is_world_coordinates()) {
|
||||
m_new_position = volume->get_instance_offset();
|
||||
#else
|
||||
if (m_world_coordinates) {
|
||||
#endif // ENABLE_INSTANCE_COORDINATES_FOR_VOLUMES
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
m_new_position = volume->get_instance_offset();
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
m_new_rotate_label_string = L("Rotate");
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
m_new_rotation = volume->get_instance_rotation() * (180.0 / M_PI);
|
||||
#else
|
||||
#if ENABLE_WORLD_COORDINATE_SCALE_REVISITED
|
||||
m_new_scale_label_string = L("Scale");
|
||||
#endif // ENABLE_WORLD_COORDINATE_SCALE_REVISITED
|
||||
m_new_rotation = Vec3d::Zero();
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
m_new_size = selection.get_scaled_instance_bounding_box().size();
|
||||
m_new_scale = m_new_size.cwiseProduct(selection.get_unscaled_instance_bounding_box().size().cwiseInverse()) * 100.0;
|
||||
}
|
||||
#if ENABLE_WORLD_COORDINATE_SCALE_REVISITED
|
||||
m_new_scale = Vec3d(100.0, 100.0, 100.0);
|
||||
#else
|
||||
m_new_scale = m_new_size.cwiseProduct(selection.get_unscaled_instance_bounding_box().size().cwiseInverse()) * 100.0;
|
||||
#endif // ENABLE_WORLD_COORDINATE_SCALE_REVISITED
|
||||
}
|
||||
else {
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
m_new_move_label_string = L("Translate");
|
||||
m_new_position = Vec3d::Zero();
|
||||
m_new_rotation = Vec3d::Zero();
|
||||
#else
|
||||
m_new_rotation = volume->get_instance_rotation() * (180.0 / M_PI);
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
m_new_rotation = volume->get_instance_rotation() * (180.0 / M_PI);
|
||||
m_new_size = volume->get_instance_scaling_factor().cwiseProduct(wxGetApp().model().objects[volume->object_idx()]->raw_mesh_bounding_box().size());
|
||||
m_new_scale = volume->get_instance_scaling_factor() * 100.0;
|
||||
}
|
||||
|
@ -682,11 +668,7 @@ void ObjectManipulation::update_settings_value(const Selection& selection)
|
|||
// the selection contains a single volume
|
||||
const GLVolume* volume = selection.get_volume(*selection.get_volume_idxs().begin());
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
#if ENABLE_INSTANCE_COORDINATES_FOR_VOLUMES
|
||||
if (is_world_coordinates()) {
|
||||
#else
|
||||
if (m_world_coordinates) {
|
||||
#endif // ENABLE_INSTANCE_COORDINATES_FOR_VOLUMES
|
||||
const Geometry::Transformation trafo(volume->world_matrix());
|
||||
|
||||
#if ENABLE_WORLD_COORDINATE_VOLUMES_LOCAL_OFFSET
|
||||
|
@ -694,34 +676,46 @@ void ObjectManipulation::update_settings_value(const Selection& selection)
|
|||
#else
|
||||
const Vec3d& offset = trafo.get_offset();
|
||||
#endif // ENABLE_WORLD_COORDINATE_VOLUMES_LOCAL_OFFSET
|
||||
// const Vec3d& mirror = trafo.get_mirror();
|
||||
|
||||
m_new_position = offset;
|
||||
m_new_rotation = trafo.get_rotation() * (180.0 / M_PI);
|
||||
m_new_size = volume->transformed_convex_hull_bounding_box(trafo.get_matrix()).size();
|
||||
m_new_scale = m_new_size.cwiseProduct(volume->transformed_convex_hull_bounding_box(volume->get_instance_transformation().get_matrix() * volume->get_volume_transformation().get_matrix(false, false, true, false)).size().cwiseInverse()) * 100.0;
|
||||
}
|
||||
#if ENABLE_INSTANCE_COORDINATES_FOR_VOLUMES
|
||||
else if (is_local_coordinates()) {
|
||||
m_new_position = Vec3d::Zero();
|
||||
m_new_rotate_label_string = L("Rotate");
|
||||
#if ENABLE_WORLD_COORDINATE_SCALE_REVISITED
|
||||
m_new_scale_label_string = L("Scale");
|
||||
#endif // ENABLE_WORLD_COORDINATE_SCALE_REVISITED
|
||||
m_new_rotation = Vec3d::Zero();
|
||||
m_new_size = volume->transformed_convex_hull_bounding_box(trafo.get_matrix()).size();
|
||||
#if ENABLE_WORLD_COORDINATE_SCALE_REVISITED
|
||||
m_new_scale = Vec3d(100.0, 100.0, 100.0);
|
||||
#else
|
||||
m_new_scale = m_new_size.cwiseProduct(volume->transformed_convex_hull_bounding_box(volume->get_instance_transformation().get_matrix() * volume->get_volume_transformation().get_matrix(false, false, true, false)).size().cwiseInverse()) * 100.0;
|
||||
#endif // ENABLE_WORLD_COORDINATE_SCALE_REVISITED
|
||||
}
|
||||
else if (is_local_coordinates()) {
|
||||
m_new_move_label_string = L("Translate");
|
||||
m_new_position = Vec3d::Zero();
|
||||
m_new_rotation = volume->get_volume_rotation() * (180.0 / M_PI);
|
||||
m_new_scale = volume->get_volume_scaling_factor() * 100.0;
|
||||
m_new_size = volume->get_volume_scaling_factor().cwiseProduct(volume->bounding_box().size());
|
||||
}
|
||||
#endif // ENABLE_INSTANCE_COORDINATES_FOR_VOLUMES
|
||||
else {
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
m_new_position = volume->get_volume_offset();
|
||||
m_new_rotation = volume->get_volume_rotation() * (180.0 / M_PI);
|
||||
#if ENABLE_INSTANCE_COORDINATES_FOR_VOLUMES
|
||||
m_new_size = volume->transformed_convex_hull_bounding_box(volume->get_volume_transformation().get_matrix()).size();
|
||||
m_new_scale = m_new_size.cwiseProduct(volume->transformed_convex_hull_bounding_box(volume->get_volume_transformation().get_matrix(false, false, true, false)).size().cwiseInverse()) * 100.0;
|
||||
m_new_rotate_label_string = L("Rotate");
|
||||
#if ENABLE_WORLD_COORDINATE_SCALE_REVISITED
|
||||
m_new_scale_label_string = L("Scale");
|
||||
#endif // ENABLE_WORLD_COORDINATE_SCALE_REVISITED
|
||||
m_new_rotation = Vec3d::Zero();
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
m_new_size = volume->transformed_convex_hull_bounding_box(volume->get_volume_transformation().get_matrix()).size();
|
||||
#if ENABLE_WORLD_COORDINATE_SCALE_REVISITED
|
||||
m_new_scale = Vec3d(100.0, 100.0, 100.0);
|
||||
#else
|
||||
m_new_scale = m_new_size.cwiseProduct(volume->transformed_convex_hull_bounding_box(volume->get_volume_transformation().get_matrix(false, false, true, false)).size().cwiseInverse()) * 100.0;
|
||||
#endif // ENABLE_WORLD_COORDINATE_SCALE_REVISITED
|
||||
}
|
||||
#else
|
||||
m_new_scale = volume->get_volume_scaling_factor() * 100.0;
|
||||
m_new_size = volume->get_instance_scaling_factor().cwiseProduct(volume->get_volume_scaling_factor().cwiseProduct(volume->bounding_box().size()));
|
||||
#endif // ENABLE_INSTANCE_COORDINATES_FOR_VOLUMES
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
}
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
m_new_enabled = true;
|
||||
}
|
||||
|
@ -788,39 +782,43 @@ void ObjectManipulation::update_if_dirty()
|
|||
update(m_cache.rotation, m_cache.rotation_rounded, meRotation, m_new_rotation);
|
||||
}
|
||||
|
||||
#if ENABLE_INSTANCE_COORDINATES_FOR_VOLUMES
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
Selection::EUniformScaleRequiredReason reason;
|
||||
if (selection.requires_uniform_scale(&reason)) {
|
||||
#else
|
||||
if (selection.requires_uniform_scale()) {
|
||||
#endif // ENABLE_INSTANCE_COORDINATES_FOR_VOLUMES
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
#if !ENABLE_WORLD_COORDINATE_SCALE_REVISITED
|
||||
m_lock_bnt->SetLock(true);
|
||||
#endif // !ENABLE_WORLD_COORDINATE_SCALE_REVISITED
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
#if ENABLE_INSTANCE_COORDINATES_FOR_VOLUMES
|
||||
wxString tooltip;
|
||||
if (selection.is_single_volume_or_modifier()) {
|
||||
#if !ENABLE_WORLD_COORDINATE_SCALE_REVISITED
|
||||
if (reason == Selection::EUniformScaleRequiredReason::VolumeNotAxisAligned_Instance)
|
||||
tooltip = _L("You cannot use non-uniform scaling mode for parts non aligned with the instance local axes");
|
||||
else if (reason == Selection::EUniformScaleRequiredReason::VolumeNotAxisAligned_World)
|
||||
tooltip = _L("You cannot use non-uniform scaling mode for parts non aligned with the printer axes");
|
||||
#endif // !ENABLE_WORLD_COORDINATE_SCALE_REVISITED
|
||||
}
|
||||
else if (selection.is_single_full_instance()) {
|
||||
#if !ENABLE_WORLD_COORDINATE_SCALE_REVISITED
|
||||
if (reason == Selection::EUniformScaleRequiredReason::InstanceNotAxisAligned_World)
|
||||
tooltip = _L("You cannot use non-uniform scaling mode for instances non aligned with the printer axes");
|
||||
else if (reason == Selection::EUniformScaleRequiredReason::VolumeNotAxisAligned_Instance)
|
||||
tooltip = _L("You cannot use non-uniform scaling mode for instances containing non locally axis-aligned parts");
|
||||
#endif // !ENABLE_WORLD_COORDINATE_SCALE_REVISITED
|
||||
}
|
||||
else
|
||||
tooltip = _L("You cannot use non-uniform scaling mode for multiple objects/parts selection");
|
||||
|
||||
m_lock_bnt->SetToolTip(tooltip);
|
||||
#else
|
||||
m_lock_bnt->SetToolTip(_L("You cannot use non-uniform scaling mode for multiple objects/parts selection or non axis-aligned objects/parts"));
|
||||
#endif // ENABLE_INSTANCE_COORDINATES_FOR_VOLUMES
|
||||
#else
|
||||
m_lock_bnt->SetToolTip(_L("You cannot use non-uniform scaling mode for multiple objects/parts selection"));
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
#if !ENABLE_WORLD_COORDINATE_SCALE_REVISITED
|
||||
m_lock_bnt->disable();
|
||||
#endif // !ENABLE_WORLD_COORDINATE_SCALE_REVISITED
|
||||
}
|
||||
else {
|
||||
m_lock_bnt->SetLock(m_uniform_scale);
|
||||
|
@ -828,22 +826,22 @@ void ObjectManipulation::update_if_dirty()
|
|||
m_lock_bnt->enable();
|
||||
}
|
||||
|
||||
#if !ENABLE_INSTANCE_COORDINATES_FOR_VOLUMES
|
||||
#if !ENABLE_WORLD_COORDINATE
|
||||
{
|
||||
int new_selection = m_world_coordinates ? 0 : 1;
|
||||
if (m_word_local_combo->GetSelection() != new_selection)
|
||||
m_word_local_combo->SetSelection(new_selection);
|
||||
}
|
||||
#endif // !ENABLE_INSTANCE_COORDINATES_FOR_VOLUMES
|
||||
#endif // !ENABLE_WORLD_COORDINATE
|
||||
|
||||
if (m_new_enabled)
|
||||
m_og->enable();
|
||||
else
|
||||
m_og->disable();
|
||||
|
||||
if (!selection.is_dragging()) {
|
||||
if (!wxGetApp().plater()->canvas3D()->is_dragging()) {
|
||||
update_reset_buttons_visibility();
|
||||
update_mirror_buttons_visibility();
|
||||
update_mirror_buttons_visibility();
|
||||
}
|
||||
|
||||
m_dirty = false;
|
||||
|
@ -863,11 +861,15 @@ void ObjectManipulation::update_reset_buttons_visibility()
|
|||
bool show_drop_to_bed = false;
|
||||
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
#if ENABLE_INSTANCE_COORDINATES_FOR_VOLUMES
|
||||
if (m_coordinates_type != ECoordinatesType::Local && (selection.is_single_full_instance() || selection.is_single_volume_or_modifier())) {
|
||||
#else
|
||||
if (selection.is_single_full_instance() || selection.is_single_volume_or_modifier()) {
|
||||
#endif // ENABLE_INSTANCE_COORDINATES_FOR_VOLUMES
|
||||
if ((m_coordinates_type == ECoordinatesType::World && selection.is_single_full_instance()) ||
|
||||
(m_coordinates_type == ECoordinatesType::Instance && selection.is_single_volume_or_modifier())) {
|
||||
const double min_z = selection.is_single_full_instance() ? selection.get_scaled_instance_bounding_box().min.z() :
|
||||
get_volume_min_z(*selection.get_volume(*selection.get_volume_idxs().begin()));
|
||||
|
||||
show_drop_to_bed = std::abs(min_z) > EPSILON;
|
||||
}
|
||||
|
||||
if (m_coordinates_type == ECoordinatesType::Local && (selection.is_single_full_instance() || selection.is_single_volume_or_modifier())) {
|
||||
const GLVolume* volume = selection.get_volume(*selection.get_volume_idxs().begin());
|
||||
Vec3d rotation = Vec3d::Zero();
|
||||
Vec3d scale = Vec3d::Ones();
|
||||
|
@ -876,26 +878,28 @@ void ObjectManipulation::update_reset_buttons_visibility()
|
|||
const GLVolume* volume = selection.get_volume(*selection.get_volume_idxs().begin());
|
||||
Vec3d rotation;
|
||||
Vec3d scale;
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
double min_z = 0.0;
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
||||
if (selection.is_single_full_instance()) {
|
||||
rotation = volume->get_instance_rotation();
|
||||
scale = volume->get_instance_scaling_factor();
|
||||
#if !ENABLE_WORLD_COORDINATE
|
||||
min_z = selection.get_scaled_instance_bounding_box().min.z();
|
||||
#endif // !ENABLE_WORLD_COORDINATE
|
||||
}
|
||||
else {
|
||||
rotation = volume->get_volume_rotation();
|
||||
scale = volume->get_volume_scaling_factor();
|
||||
#if !ENABLE_WORLD_COORDINATE
|
||||
min_z = get_volume_min_z(*volume);
|
||||
#endif // !ENABLE_WORLD_COORDINATE
|
||||
}
|
||||
show_rotation = !rotation.isApprox(Vec3d::Zero());
|
||||
show_scale = !scale.isApprox(Vec3d::Ones());
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
show_drop_to_bed = std::abs(min_z) > EPSILON;
|
||||
#else
|
||||
#if !ENABLE_WORLD_COORDINATE
|
||||
show_drop_to_bed = std::abs(min_z) > SINKING_Z_THRESHOLD;
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
#endif // !ENABLE_WORLD_COORDINATE
|
||||
}
|
||||
|
||||
wxGetApp().CallAfter([this, show_rotation, show_scale, show_drop_to_bed] {
|
||||
|
@ -925,11 +929,11 @@ void ObjectManipulation::update_mirror_buttons_visibility()
|
|||
Selection& selection = canvas->get_selection();
|
||||
std::array<MirrorButtonState, 3> new_states = {mbHidden, mbHidden, mbHidden};
|
||||
|
||||
#if ENABLE_INSTANCE_COORDINATES_FOR_VOLUMES
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
if (is_local_coordinates()) {
|
||||
#else
|
||||
if (!m_world_coordinates) {
|
||||
#endif // ENABLE_INSTANCE_COORDINATES_FOR_VOLUMES
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
if (selection.is_single_full_instance() || selection.is_single_volume_or_modifier()) {
|
||||
#else
|
||||
|
@ -999,7 +1003,7 @@ void ObjectManipulation::update_warning_icon_state(const MeshErrorsInfo& warning
|
|||
m_fix_throught_netfab_bitmap->SetToolTip(tooltip);
|
||||
}
|
||||
|
||||
#if ENABLE_INSTANCE_COORDINATES_FOR_VOLUMES
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
wxString ObjectManipulation::coordinate_type_str(ECoordinatesType type)
|
||||
{
|
||||
switch (type)
|
||||
|
@ -1010,7 +1014,7 @@ wxString ObjectManipulation::coordinate_type_str(ECoordinatesType type)
|
|||
default: { assert(false); return _L("Unknown"); }
|
||||
}
|
||||
}
|
||||
#endif // ENABLE_INSTANCE_COORDINATES_FOR_VOLUMES
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
||||
void ObjectManipulation::reset_settings_value()
|
||||
{
|
||||
|
@ -1034,17 +1038,12 @@ void ObjectManipulation::change_position_value(int axis, double value)
|
|||
|
||||
auto canvas = wxGetApp().plater()->canvas3D();
|
||||
Selection& selection = canvas->get_selection();
|
||||
selection.start_dragging();
|
||||
selection.setup_cache();
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
#if ENABLE_INSTANCE_COORDINATES_FOR_VOLUMES
|
||||
selection.translate(position - m_cache.position, get_coordinates_type());
|
||||
#else
|
||||
selection.translate(position - m_cache.position, !m_world_coordinates);
|
||||
#endif // ENABLE_INSTANCE_COORDINATES_FOR_VOLUMES
|
||||
#else
|
||||
selection.translate(position - m_cache.position, selection.requires_local_axes());
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
selection.stop_dragging();
|
||||
canvas->do_move(L("Set Position"));
|
||||
|
||||
m_cache.position = position;
|
||||
|
@ -1068,15 +1067,13 @@ void ObjectManipulation::change_rotation_value(int axis, double value)
|
|||
if (selection.is_single_full_instance())
|
||||
transformation_type.set_independent();
|
||||
|
||||
#if ENABLE_INSTANCE_COORDINATES_FOR_VOLUMES
|
||||
if (!is_world_coordinates()) {
|
||||
#else
|
||||
if (!m_world_coordinates) {
|
||||
#endif // ENABLE_INSTANCE_COORDINATES_FOR_VOLUMES
|
||||
//FIXME Selection::rotate() does not process absolute rotations correctly: It does not recognize the axis index, which was changed.
|
||||
// transformation_type.set_absolute();
|
||||
if (is_local_coordinates()) {
|
||||
transformation_type.set_local();
|
||||
transformation_type.set_absolute();
|
||||
}
|
||||
|
||||
if (is_instance_coordinates())
|
||||
transformation_type.set_instance();
|
||||
#else
|
||||
if (selection.is_single_full_instance() || selection.requires_local_axes())
|
||||
transformation_type.set_independent();
|
||||
|
@ -1087,11 +1084,10 @@ void ObjectManipulation::change_rotation_value(int axis, double value)
|
|||
}
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
||||
selection.start_dragging();
|
||||
selection.setup_cache();
|
||||
selection.rotate(
|
||||
(M_PI / 180.0) * (transformation_type.absolute() ? rotation : rotation - m_cache.rotation),
|
||||
transformation_type);
|
||||
selection.stop_dragging();
|
||||
canvas->do_rotate(L("Set Orientation"));
|
||||
|
||||
m_cache.rotation = rotation;
|
||||
|
@ -1146,15 +1142,19 @@ void ObjectManipulation::change_size_value(int axis, double value)
|
|||
ref_size = Vec3d::Ones();
|
||||
}
|
||||
else if (selection.is_single_full_instance())
|
||||
#if ENABLE_INSTANCE_COORDINATES_FOR_VOLUMES
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
ref_size = is_world_coordinates() ?
|
||||
#else
|
||||
ref_size = m_world_coordinates ?
|
||||
#endif // ENABLE_INSTANCE_COORDINATES_FOR_VOLUMES
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
selection.get_unscaled_instance_bounding_box().size() :
|
||||
wxGetApp().model().objects[selection.get_volume(*selection.get_volume_idxs().begin())->object_idx()]->raw_mesh_bounding_box().size();
|
||||
|
||||
#if ENABLE_WORLD_COORDINATE_SCALE_REVISITED
|
||||
this->do_size(axis, size.cwiseQuotient(ref_size));
|
||||
#else
|
||||
this->do_scale(axis, size.cwiseQuotient(ref_size));
|
||||
#endif // ENABLE_WORLD_COORDINATE_SCALE_REVISITED
|
||||
|
||||
m_cache.size = size;
|
||||
m_cache.size_rounded(axis) = DBL_MAX;
|
||||
|
@ -1170,21 +1170,23 @@ void ObjectManipulation::do_scale(int axis, const Vec3d &scale) const
|
|||
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
TransformationType transformation_type;
|
||||
#if ENABLE_INSTANCE_COORDINATES_FOR_VOLUMES
|
||||
if (!is_world_coordinates())
|
||||
#else
|
||||
if (!m_world_coordinates)
|
||||
#endif // ENABLE_INSTANCE_COORDINATES_FOR_VOLUMES
|
||||
#if ENABLE_WORLD_COORDINATE_SCALE_REVISITED
|
||||
if (is_local_coordinates())
|
||||
transformation_type.set_local();
|
||||
else if (is_instance_coordinates())
|
||||
transformation_type.set_instance();
|
||||
|
||||
if (!is_local_coordinates())
|
||||
transformation_type.set_relative();
|
||||
#else
|
||||
if (!is_world_coordinates())
|
||||
transformation_type.set_local();
|
||||
#endif // ENABLE_WORLD_COORDINATE_SCALE_REVISITED
|
||||
|
||||
bool uniform_scale = m_uniform_scale || selection.requires_uniform_scale();
|
||||
Vec3d scaling_factor = uniform_scale ? scale(axis) * Vec3d::Ones() : scale;
|
||||
|
||||
#if ENABLE_INSTANCE_COORDINATES_FOR_VOLUMES
|
||||
if (!uniform_scale && is_world_coordinates()) {
|
||||
#else
|
||||
if (!uniform_scale && m_world_coordinates) {
|
||||
#endif // ENABLE_INSTANCE_COORDINATES_FOR_VOLUMES
|
||||
if (selection.is_single_full_instance())
|
||||
scaling_factor = (Geometry::assemble_transform(Vec3d::Zero(), selection.get_volume(*selection.get_volume_idxs().begin())->get_instance_rotation()).inverse() * scaling_factor).cwiseAbs();
|
||||
else if (selection.is_single_volume_or_modifier()) {
|
||||
|
@ -1205,12 +1207,41 @@ void ObjectManipulation::do_scale(int axis, const Vec3d &scale) const
|
|||
scaling_factor = scale(axis) * Vec3d::Ones();
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
||||
selection.start_dragging();
|
||||
selection.setup_cache();
|
||||
selection.scale(scaling_factor, transformation_type);
|
||||
selection.stop_dragging();
|
||||
wxGetApp().plater()->canvas3D()->do_scale(L("Set Scale"));
|
||||
}
|
||||
|
||||
#if ENABLE_WORLD_COORDINATE_SCALE_REVISITED
|
||||
void ObjectManipulation::do_size(int axis, const Vec3d& scale) const
|
||||
{
|
||||
Selection& selection = wxGetApp().plater()->canvas3D()->get_selection();
|
||||
|
||||
TransformationType transformation_type;
|
||||
if (is_local_coordinates())
|
||||
transformation_type.set_local();
|
||||
else if (is_instance_coordinates())
|
||||
transformation_type.set_instance();
|
||||
|
||||
bool uniform_scale = m_uniform_scale || selection.requires_uniform_scale();
|
||||
Vec3d scaling_factor = uniform_scale ? scale(axis) * Vec3d::Ones() : scale;
|
||||
|
||||
if (!uniform_scale && is_world_coordinates()) {
|
||||
if (selection.is_single_full_instance())
|
||||
scaling_factor = (Geometry::assemble_transform(Vec3d::Zero(), selection.get_volume(*selection.get_volume_idxs().begin())->get_instance_rotation()).inverse() * scaling_factor).cwiseAbs();
|
||||
else if (selection.is_single_volume_or_modifier()) {
|
||||
const Transform3d mi = Geometry::assemble_transform(Vec3d::Zero(), selection.get_volume(*selection.get_volume_idxs().begin())->get_instance_rotation()).inverse();
|
||||
const Transform3d mv = Geometry::assemble_transform(Vec3d::Zero(), selection.get_volume(*selection.get_volume_idxs().begin())->get_volume_rotation()).inverse();
|
||||
scaling_factor = (mv * mi * scaling_factor).cwiseAbs();
|
||||
}
|
||||
}
|
||||
|
||||
selection.setup_cache();
|
||||
selection.scale(scaling_factor, transformation_type);
|
||||
wxGetApp().plater()->canvas3D()->do_scale(L("Set Size"));
|
||||
}
|
||||
#endif // ENABLE_WORLD_COORDINATE_SCALE_REVISITED
|
||||
|
||||
void ObjectManipulation::on_change(const std::string& opt_key, int axis, double new_value)
|
||||
{
|
||||
if (!m_cache.is_valid())
|
||||
|
@ -1245,21 +1276,36 @@ void ObjectManipulation::on_change(const std::string& opt_key, int axis, double
|
|||
}
|
||||
}
|
||||
|
||||
void ObjectManipulation::set_uniform_scaling(const bool new_value)
|
||||
void ObjectManipulation::set_uniform_scaling(const bool use_uniform_scale)
|
||||
{
|
||||
const Selection &selection = wxGetApp().plater()->canvas3D()->get_selection();
|
||||
#if ENABLE_INSTANCE_COORDINATES_FOR_VOLUMES
|
||||
if (selection.is_single_full_instance() && is_world_coordinates() && !new_value) {
|
||||
#if ENABLE_WORLD_COORDINATE_SCALE_REVISITED
|
||||
if (!use_uniform_scale) {
|
||||
int res = selection.bake_transform_if_needed();
|
||||
if (res == -1) {
|
||||
// Enforce uniform scaling.
|
||||
m_lock_bnt->SetLock(true);
|
||||
return;
|
||||
}
|
||||
else if (res == 0)
|
||||
// Recalculate cached values at this panel, refresh the screen.
|
||||
this->UpdateAndShow(true);
|
||||
}
|
||||
|
||||
m_uniform_scale = use_uniform_scale;
|
||||
#else
|
||||
if (selection.is_single_full_instance() && m_world_coordinates && !new_value) {
|
||||
#endif // ENABLE_INSTANCE_COORDINATES_FOR_VOLUMES
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
if (selection.is_single_full_instance() && is_world_coordinates() && !use_uniform_scale) {
|
||||
#else
|
||||
if (selection.is_single_full_instance() && m_world_coordinates && !use_uniform_scale) {
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
// Verify whether the instance rotation is multiples of 90 degrees, so that the scaling in world coordinates is possible.
|
||||
// all volumes in the selection belongs to the same instance, any of them contains the needed instance data, so we take the first one
|
||||
const GLVolume* volume = selection.get_volume(*selection.get_volume_idxs().begin());
|
||||
// Is the angle close to a multiple of 90 degrees?
|
||||
if (! Geometry::is_rotation_ninety_degrees(volume->get_instance_rotation())) {
|
||||
if (!Geometry::is_rotation_ninety_degrees(volume->get_instance_rotation())) {
|
||||
// Cannot apply scaling in the world coordinate system.
|
||||
//wxMessageDialog dlg(GUI::wxGetApp().mainframe,
|
||||
//wxMessageDialog dlg(GUI::wxGetApp().mainframe,
|
||||
MessageDialog dlg(GUI::wxGetApp().mainframe,
|
||||
_L("The currently manipulated object is tilted (rotation angles are not multiples of 90°).\n"
|
||||
"Non-uniform scaling of tilted objects is only possible in the World coordinate system,\n"
|
||||
|
@ -1267,7 +1313,7 @@ void ObjectManipulation::set_uniform_scaling(const bool new_value)
|
|||
_L("This operation is irreversible.\n"
|
||||
"Do you want to proceed?"),
|
||||
SLIC3R_APP_NAME,
|
||||
wxYES_NO | wxCANCEL | wxCANCEL_DEFAULT | wxICON_QUESTION);
|
||||
wxYES_NO | wxCANCEL | wxCANCEL_DEFAULT | wxICON_QUESTION);
|
||||
if (dlg.ShowModal() != wxID_YES) {
|
||||
// Enforce uniform scaling.
|
||||
m_lock_bnt->SetLock(true);
|
||||
|
@ -1281,11 +1327,12 @@ void ObjectManipulation::set_uniform_scaling(const bool new_value)
|
|||
this->UpdateAndShow(true);
|
||||
}
|
||||
}
|
||||
m_uniform_scale = new_value;
|
||||
|
||||
m_uniform_scale = use_uniform_scale;
|
||||
#endif // ENABLE_WORLD_COORDINATE_SCALE_REVISITED
|
||||
}
|
||||
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
#if ENABLE_INSTANCE_COORDINATES_FOR_VOLUMES
|
||||
void ObjectManipulation::set_coordinates_type(ECoordinatesType type)
|
||||
{
|
||||
if (wxGetApp().get_mode() == comSimple)
|
||||
|
@ -1301,24 +1348,6 @@ void ObjectManipulation::set_coordinates_type(ECoordinatesType type)
|
|||
canvas->set_as_dirty();
|
||||
canvas->request_extra_frame();
|
||||
}
|
||||
#else
|
||||
void ObjectManipulation::set_world_coordinates(const bool world_coordinates)
|
||||
{
|
||||
m_world_coordinates = world_coordinates;
|
||||
this->UpdateAndShow(true);
|
||||
GLCanvas3D* canvas = wxGetApp().plater()->canvas3D();
|
||||
canvas->get_gizmos_manager().update_data();
|
||||
canvas->set_as_dirty();
|
||||
canvas->request_extra_frame();
|
||||
}
|
||||
|
||||
bool ObjectManipulation::get_world_coordinates() const
|
||||
{
|
||||
const Selection& selection = wxGetApp().plater()->canvas3D()->get_selection();
|
||||
return wxGetApp().get_mode() != comSimple && (selection.is_single_full_instance() || selection.is_single_volume() || selection.is_single_modifier()) ?
|
||||
m_world_coordinates : true;
|
||||
}
|
||||
#endif // ENABLE_INSTANCE_COORDINATES_FOR_VOLUMES
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
||||
void ObjectManipulation::msw_rescale()
|
||||
|
@ -1384,7 +1413,7 @@ void ObjectManipulation::sys_color_changed()
|
|||
m_mirror_buttons[id].first->msw_rescale();
|
||||
}
|
||||
|
||||
#if ENABLE_INSTANCE_COORDINATES_FOR_VOLUMES
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
void ObjectManipulation::set_coordinates_type(const wxString& type_string)
|
||||
{
|
||||
ECoordinatesType type = ECoordinatesType::World;
|
||||
|
@ -1395,7 +1424,7 @@ void ObjectManipulation::set_coordinates_type(const wxString& type_string)
|
|||
|
||||
this->set_coordinates_type(type);
|
||||
}
|
||||
#endif // ENABLE_INSTANCE_COORDINATES_FOR_VOLUMES
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
||||
static const char axes[] = { 'x', 'y', 'z' };
|
||||
ManipulationEditor::ManipulationEditor(ObjectManipulation* parent,
|
||||
|
@ -1438,8 +1467,8 @@ ManipulationEditor::ManipulationEditor(ObjectManipulation* parent,
|
|||
parent->set_focused_editor(nullptr);
|
||||
|
||||
#if ENABLE_OBJECT_MANIPULATOR_FOCUS
|
||||
// if the widgets exchanging focus are both manipulator fields, call kill_focus
|
||||
if (dynamic_cast<ManipulationEditor*>(e.GetEventObject()) != nullptr && dynamic_cast<ManipulationEditor*>(e.GetWindow()) != nullptr)
|
||||
// if the widgets loosing focus is a manipulator field, call kill_focus
|
||||
if (dynamic_cast<ManipulationEditor*>(e.GetEventObject()) != nullptr)
|
||||
#else
|
||||
if (!m_enter_pressed)
|
||||
#endif // ENABLE_OBJECT_MANIPULATOR_FOCUS
|
||||
|
|
|
@ -5,9 +5,9 @@
|
|||
|
||||
#include "GUI_ObjectSettings.hpp"
|
||||
#include "GUI_ObjectList.hpp"
|
||||
#if ENABLE_INSTANCE_COORDINATES_FOR_VOLUMES
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
#include "GUI_Geometry.hpp"
|
||||
#endif // ENABLE_INSTANCE_COORDINATES_FOR_VOLUMES
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
#include "libslic3r/Point.hpp"
|
||||
#include <float.h>
|
||||
|
||||
|
@ -151,12 +151,12 @@ private:
|
|||
Vec3d m_new_size;
|
||||
bool m_new_enabled {true};
|
||||
bool m_uniform_scale {true};
|
||||
#if ENABLE_INSTANCE_COORDINATES_FOR_VOLUMES
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
ECoordinatesType m_coordinates_type{ ECoordinatesType::World };
|
||||
#else
|
||||
// Does the object manipulation panel work in World or Local coordinates?
|
||||
bool m_world_coordinates = true;
|
||||
#endif // ENABLE_INSTANCE_COORDINATES_FOR_VOLUMES
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
LockButton* m_lock_bnt{ nullptr };
|
||||
choice_ctrl* m_word_local_combo { nullptr };
|
||||
|
||||
|
@ -196,20 +196,14 @@ public:
|
|||
// Called from the App to update the UI if dirty.
|
||||
void update_if_dirty();
|
||||
|
||||
void set_uniform_scaling(const bool uniform_scale);
|
||||
void set_uniform_scaling(const bool use_uniform_scale);
|
||||
bool get_uniform_scaling() const { return m_uniform_scale; }
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
#if ENABLE_INSTANCE_COORDINATES_FOR_VOLUMES
|
||||
void set_coordinates_type(ECoordinatesType type);
|
||||
ECoordinatesType get_coordinates_type() const { return m_coordinates_type; }
|
||||
bool is_world_coordinates() const { return m_coordinates_type == ECoordinatesType::World; }
|
||||
bool is_instance_coordinates() const { return m_coordinates_type == ECoordinatesType::Instance; }
|
||||
bool is_local_coordinates() const { return m_coordinates_type == ECoordinatesType::Local; }
|
||||
#else
|
||||
// Does the object manipulation panel work in World or Local coordinates?
|
||||
void set_world_coordinates(const bool world_coordinates);
|
||||
bool get_world_coordinates() const;
|
||||
#endif // ENABLE_INSTANCE_COORDINATES_FOR_VOLUMES
|
||||
#else
|
||||
// Does the object manipulation panel work in World or Local coordinates?
|
||||
void set_world_coordinates(const bool world_coordinates) { m_world_coordinates = world_coordinates; this->UpdateAndShow(true); }
|
||||
|
@ -243,9 +237,9 @@ public:
|
|||
ManipulationEditor* get_focused_editor() { return m_focused_editor; }
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
||||
#if ENABLE_INSTANCE_COORDINATES_FOR_VOLUMES
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
static wxString coordinate_type_str(ECoordinatesType type);
|
||||
#endif // ENABLE_INSTANCE_COORDINATES_FOR_VOLUMES
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
||||
private:
|
||||
void reset_settings_value();
|
||||
|
@ -262,10 +256,13 @@ private:
|
|||
void change_scale_value(int axis, double value);
|
||||
void change_size_value(int axis, double value);
|
||||
void do_scale(int axis, const Vec3d &scale) const;
|
||||
#if ENABLE_WORLD_COORDINATE_SCALE_REVISITED
|
||||
void do_size(int axis, const Vec3d& scale) const;
|
||||
#endif // ENABLE_WORLD_COORDINATE_SCALE_REVISITED
|
||||
|
||||
#if ENABLE_INSTANCE_COORDINATES_FOR_VOLUMES
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
void set_coordinates_type(const wxString& type_string);
|
||||
#endif // ENABLE_INSTANCE_COORDINATES_FOR_VOLUMES
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
};
|
||||
|
||||
}}
|
||||
|
|
|
@ -141,6 +141,8 @@ bool ObjectSettings::update_settings_list()
|
|||
{
|
||||
Option option = optgroup->get_option(opt);
|
||||
option.opt.width = 12;
|
||||
if (!option.opt.full_label.empty())
|
||||
option.opt.label = option.opt.full_label;
|
||||
if (is_extruders_cat)
|
||||
option.opt.max = wxGetApp().extruders_edited_cnt();
|
||||
optgroup->append_single_option_line(option);
|
||||
|
|
|
@ -274,9 +274,13 @@ static void generate_thumbnail_from_model(const std::string& filename)
|
|||
|
||||
GLVolumeCollection volumes;
|
||||
volumes.volumes.push_back(new GLVolume());
|
||||
GLVolume* volume = volumes.volumes[0];
|
||||
GLVolume* volume = volumes.volumes.back();
|
||||
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
volume->model.init_from(model.mesh());
|
||||
#else
|
||||
volume->indexed_vertex_array.load_mesh(model.mesh());
|
||||
volume->indexed_vertex_array.finalize_geometry(true);
|
||||
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
volume->set_instance_transformation(model.objects[0]->instances[0]->get_transformation());
|
||||
volume->set_volume_transformation(model.objects[0]->volumes[0]->get_transformation());
|
||||
|
||||
|
|
|
@ -5,6 +5,8 @@
|
|||
|
||||
#include "slic3r/GUI/GUI_App.hpp"
|
||||
|
||||
#include "slic3r/GUI/GUI_ObjectManipulation.hpp"
|
||||
|
||||
// TODO: Display tooltips quicker on Linux
|
||||
|
||||
namespace Slic3r {
|
||||
|
@ -74,63 +76,19 @@ GLGizmoBase::GLGizmoBase(GLCanvas3D& parent, const std::string& icon_filename, u
|
|||
, m_first_input_window_render(true)
|
||||
, m_dirty(false)
|
||||
{
|
||||
m_base_color = DEFAULT_BASE_COLOR;
|
||||
m_drag_color = DEFAULT_DRAG_COLOR;
|
||||
m_highlight_color = DEFAULT_HIGHLIGHT_COLOR;
|
||||
}
|
||||
|
||||
void GLGizmoBase::set_hover_id(int id)
|
||||
{
|
||||
if (m_grabbers.empty() || id < (int)m_grabbers.size()) {
|
||||
m_hover_id = id;
|
||||
on_set_hover_id();
|
||||
}
|
||||
}
|
||||
// do not change hover id during dragging
|
||||
assert(!m_dragging);
|
||||
|
||||
void GLGizmoBase::enable_grabber(unsigned int id)
|
||||
{
|
||||
if (id < m_grabbers.size())
|
||||
m_grabbers[id].enabled = true;
|
||||
|
||||
on_enable_grabber(id);
|
||||
}
|
||||
|
||||
void GLGizmoBase::disable_grabber(unsigned int id)
|
||||
{
|
||||
if (id < m_grabbers.size())
|
||||
m_grabbers[id].enabled = false;
|
||||
|
||||
on_disable_grabber(id);
|
||||
}
|
||||
|
||||
void GLGizmoBase::start_dragging()
|
||||
{
|
||||
m_dragging = true;
|
||||
|
||||
for (int i = 0; i < (int)m_grabbers.size(); ++i)
|
||||
{
|
||||
m_grabbers[i].dragging = (m_hover_id == i);
|
||||
}
|
||||
|
||||
on_start_dragging();
|
||||
}
|
||||
|
||||
void GLGizmoBase::stop_dragging()
|
||||
{
|
||||
m_dragging = false;
|
||||
|
||||
for (int i = 0; i < (int)m_grabbers.size(); ++i)
|
||||
{
|
||||
m_grabbers[i].dragging = false;
|
||||
}
|
||||
|
||||
on_stop_dragging();
|
||||
}
|
||||
|
||||
void GLGizmoBase::update(const UpdateData& data)
|
||||
{
|
||||
if (m_hover_id != -1)
|
||||
on_update(data);
|
||||
// allow empty grabbers when not using grabbers but use hover_id - flatten, rotate
|
||||
if (!m_grabbers.empty() && id >= (int) m_grabbers.size())
|
||||
return;
|
||||
|
||||
m_hover_id = id;
|
||||
on_set_hover_id();
|
||||
}
|
||||
|
||||
bool GLGizmoBase::update_items_state()
|
||||
|
@ -138,7 +96,7 @@ bool GLGizmoBase::update_items_state()
|
|||
bool res = m_dirty;
|
||||
m_dirty = false;
|
||||
return res;
|
||||
};
|
||||
}
|
||||
|
||||
ColorRGBA GLGizmoBase::picking_color_component(unsigned int id) const
|
||||
{
|
||||
|
@ -189,6 +147,113 @@ void GLGizmoBase::render_grabbers_for_picking(const BoundingBoxf3& box) const
|
|||
#endif // ENABLE_GLBEGIN_GLEND_REMOVAL
|
||||
}
|
||||
|
||||
// help function to process grabbers
|
||||
// call start_dragging, stop_dragging, on_dragging
|
||||
bool GLGizmoBase::use_grabbers(const wxMouseEvent &mouse_event) {
|
||||
bool is_dragging_finished = false;
|
||||
if (mouse_event.Moving()) {
|
||||
// it should not happen but for sure
|
||||
assert(!m_dragging);
|
||||
if (m_dragging) is_dragging_finished = true;
|
||||
else return false;
|
||||
}
|
||||
|
||||
if (mouse_event.LeftDown()) {
|
||||
Selection &selection = m_parent.get_selection();
|
||||
if (!selection.is_empty() && m_hover_id != -1 &&
|
||||
(m_grabbers.empty() || m_hover_id < static_cast<int>(m_grabbers.size()))) {
|
||||
selection.setup_cache();
|
||||
|
||||
m_dragging = true;
|
||||
for (auto &grabber : m_grabbers) grabber.dragging = false;
|
||||
if (!m_grabbers.empty() && m_hover_id < int(m_grabbers.size()))
|
||||
m_grabbers[m_hover_id].dragging = true;
|
||||
|
||||
// prevent change of hover_id during dragging
|
||||
m_parent.set_mouse_as_dragging();
|
||||
on_start_dragging();
|
||||
|
||||
// Let the plater know that the dragging started
|
||||
m_parent.post_event(SimpleEvent(EVT_GLCANVAS_MOUSE_DRAGGING_STARTED));
|
||||
m_parent.set_as_dirty();
|
||||
return true;
|
||||
}
|
||||
} else if (m_dragging) {
|
||||
// when mouse cursor leave window than finish actual dragging operation
|
||||
bool is_leaving = mouse_event.Leaving();
|
||||
if (mouse_event.Dragging()) {
|
||||
m_parent.set_mouse_as_dragging();
|
||||
Point mouse_coord(mouse_event.GetX(), mouse_event.GetY());
|
||||
auto ray = m_parent.mouse_ray(mouse_coord);
|
||||
UpdateData data(ray, mouse_coord);
|
||||
|
||||
on_dragging(data);
|
||||
|
||||
wxGetApp().obj_manipul()->set_dirty();
|
||||
m_parent.set_as_dirty();
|
||||
return true;
|
||||
}
|
||||
else if (mouse_event.LeftUp() || is_leaving || is_dragging_finished) {
|
||||
#if ENABLE_WORLD_COORDINATE_SCALE_REVISITED
|
||||
do_stop_dragging(is_leaving);
|
||||
#else
|
||||
for (auto &grabber : m_grabbers) grabber.dragging = false;
|
||||
m_dragging = false;
|
||||
|
||||
// NOTE: This should be part of GLCanvas3D
|
||||
// Reset hover_id when leave window
|
||||
if (is_leaving) m_parent.mouse_up_cleanup();
|
||||
|
||||
on_stop_dragging();
|
||||
|
||||
// There is prediction that after draggign, data are changed
|
||||
// Data are updated twice also by canvas3D::reload_scene.
|
||||
// Should be fixed.
|
||||
m_parent.get_gizmos_manager().update_data();
|
||||
|
||||
wxGetApp().obj_manipul()->set_dirty();
|
||||
|
||||
// Let the plater know that the dragging finished, so a delayed
|
||||
// refresh of the scene with the background processing data should
|
||||
// be performed.
|
||||
m_parent.post_event(SimpleEvent(EVT_GLCANVAS_MOUSE_DRAGGING_FINISHED));
|
||||
// updates camera target constraints
|
||||
m_parent.refresh_camera_scene_box();
|
||||
#endif // ENABLE_WORLD_COORDINATE_SCALE_REVISITED
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
#if ENABLE_WORLD_COORDINATE_SCALE_REVISITED
|
||||
void GLGizmoBase::do_stop_dragging(bool perform_mouse_cleanup)
|
||||
{
|
||||
for (auto& grabber : m_grabbers) grabber.dragging = false;
|
||||
m_dragging = false;
|
||||
|
||||
// NOTE: This should be part of GLCanvas3D
|
||||
// Reset hover_id when leave window
|
||||
if (perform_mouse_cleanup) m_parent.mouse_up_cleanup();
|
||||
|
||||
on_stop_dragging();
|
||||
|
||||
// There is prediction that after draggign, data are changed
|
||||
// Data are updated twice also by canvas3D::reload_scene.
|
||||
// Should be fixed.
|
||||
m_parent.get_gizmos_manager().update_data();
|
||||
|
||||
wxGetApp().obj_manipul()->set_dirty();
|
||||
|
||||
// Let the plater know that the dragging finished, so a delayed
|
||||
// refresh of the scene with the background processing data should
|
||||
// be performed.
|
||||
m_parent.post_event(SimpleEvent(EVT_GLCANVAS_MOUSE_DRAGGING_FINISHED));
|
||||
// updates camera target constraints
|
||||
m_parent.refresh_camera_scene_box();
|
||||
}
|
||||
#endif // ENABLE_WORLD_COORDINATE_SCALE_REVISITED
|
||||
|
||||
std::string GLGizmoBase::format(float value, unsigned int decimals) const
|
||||
{
|
||||
return Slic3r::string_printf("%.*f", decimals, value);
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include <cereal/archives/binary.hpp>
|
||||
|
||||
class wxWindow;
|
||||
class wxMouseEvent;
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
|
@ -29,7 +30,6 @@ class ImGuiWrapper;
|
|||
class GLCanvas3D;
|
||||
enum class CommonGizmosDataID;
|
||||
class CommonGizmosDataPool;
|
||||
class Selection;
|
||||
|
||||
class GLGizmoBase
|
||||
{
|
||||
|
@ -88,28 +88,22 @@ public:
|
|||
|
||||
protected:
|
||||
GLCanvas3D& m_parent;
|
||||
|
||||
int m_group_id;
|
||||
int m_group_id; // TODO: remove only for rotate
|
||||
EState m_state;
|
||||
int m_shortcut_key;
|
||||
std::string m_icon_filename;
|
||||
unsigned int m_sprite_id;
|
||||
int m_hover_id;
|
||||
bool m_dragging;
|
||||
ColorRGBA m_base_color;
|
||||
ColorRGBA m_drag_color;
|
||||
ColorRGBA m_highlight_color;
|
||||
mutable std::vector<Grabber> m_grabbers;
|
||||
ImGuiWrapper* m_imgui;
|
||||
bool m_first_input_window_render;
|
||||
mutable std::string m_tooltip;
|
||||
CommonGizmosDataPool* m_c;
|
||||
|
||||
public:
|
||||
GLGizmoBase(GLCanvas3D& parent,
|
||||
const std::string& icon_filename,
|
||||
unsigned int sprite_id);
|
||||
virtual ~GLGizmoBase() {}
|
||||
virtual ~GLGizmoBase() = default;
|
||||
|
||||
bool init() { return on_init(); }
|
||||
|
||||
|
@ -118,9 +112,6 @@ public:
|
|||
|
||||
std::string get_name(bool include_shortcut = true) const;
|
||||
|
||||
int get_group_id() const { return m_group_id; }
|
||||
void set_group_id(int id) { m_group_id = id; }
|
||||
|
||||
EState get_state() const { return m_state; }
|
||||
void set_state(EState state) { m_state = state; on_set_state(); }
|
||||
|
||||
|
@ -142,36 +133,34 @@ public:
|
|||
int get_hover_id() const { return m_hover_id; }
|
||||
void set_hover_id(int id);
|
||||
|
||||
void set_highlight_color(const ColorRGBA& color) { m_highlight_color = color; }
|
||||
|
||||
void enable_grabber(unsigned int id);
|
||||
void disable_grabber(unsigned int id);
|
||||
|
||||
void start_dragging();
|
||||
void stop_dragging();
|
||||
|
||||
bool is_dragging() const { return m_dragging; }
|
||||
|
||||
void update(const UpdateData& data);
|
||||
|
||||
// returns True when Gizmo changed its state
|
||||
bool update_items_state();
|
||||
|
||||
void render() { m_tooltip.clear(); on_render(); }
|
||||
void render() { on_render(); }
|
||||
void render_for_picking() { on_render_for_picking(); }
|
||||
void render_input_window(float x, float y, float bottom_limit);
|
||||
|
||||
virtual std::string get_tooltip() const { return ""; }
|
||||
|
||||
/// <summary>
|
||||
/// Implement when you want process mouse events in gizmo
|
||||
/// Mouse tooltip text
|
||||
/// </summary>
|
||||
/// <returns>Text to be visible in mouse tooltip</returns>
|
||||
virtual std::string get_tooltip() const { return ""; }
|
||||
|
||||
/// <summary>
|
||||
/// Is called when data (Selection) is changed
|
||||
/// </summary>
|
||||
virtual void data_changed(){};
|
||||
|
||||
/// <summary>
|
||||
/// Implement when want to process mouse events in gizmo
|
||||
/// Click, Right click, move, drag, ...
|
||||
/// </summary>
|
||||
/// <param name="mouse_event">Keep information about mouse + some action key like alt, shift, ...</param>
|
||||
/// <returns>Return True when Gizmo use the information and don't want to propagate it. Otherwise False.</returns>
|
||||
/// <param name="mouse_event">Keep information about mouse click</param>
|
||||
/// <returns>Return True when use the information and don't want to propagate it otherwise False.</returns>
|
||||
virtual bool on_mouse(const wxMouseEvent &mouse_event) { return false; }
|
||||
|
||||
protected:
|
||||
protected:
|
||||
virtual bool on_init() = 0;
|
||||
virtual void on_load(cereal::BinaryInputArchive& ar) {}
|
||||
virtual void on_save(cereal::BinaryOutputArchive& ar) const {}
|
||||
|
@ -183,9 +172,12 @@ public:
|
|||
virtual CommonGizmosDataID on_get_requirements() const { return CommonGizmosDataID(0); }
|
||||
virtual void on_enable_grabber(unsigned int id) {}
|
||||
virtual void on_disable_grabber(unsigned int id) {}
|
||||
|
||||
// called inside use_grabbers
|
||||
virtual void on_start_dragging() {}
|
||||
virtual void on_stop_dragging() {}
|
||||
virtual void on_update(const UpdateData& data) {}
|
||||
virtual void on_dragging(const UpdateData& data) {}
|
||||
|
||||
virtual void on_render() = 0;
|
||||
virtual void on_render_for_picking() = 0;
|
||||
virtual void on_render_input_window(float x, float y, float bottom_limit) {}
|
||||
|
@ -202,6 +194,20 @@ public:
|
|||
|
||||
// Mark gizmo as dirty to Re-Render when idle()
|
||||
void set_dirty();
|
||||
|
||||
/// <summary>
|
||||
/// function which
|
||||
/// Set up m_dragging and call functions
|
||||
/// on_start_dragging / on_dragging / on_stop_dragging
|
||||
/// </summary>
|
||||
/// <param name="mouse_event">Keep information about mouse click</param>
|
||||
/// <returns>same as on_mouse</returns>
|
||||
bool use_grabbers(const wxMouseEvent &mouse_event);
|
||||
|
||||
#if ENABLE_WORLD_COORDINATE_SCALE_REVISITED
|
||||
void do_stop_dragging(bool perform_mouse_cleanup);
|
||||
#endif // ENABLE_WORLD_COORDINATE_SCALE_REVISITED
|
||||
|
||||
private:
|
||||
// Flag for dirty visible state of Gizmo
|
||||
// When True then need new rendering
|
||||
|
|
|
@ -38,6 +38,11 @@ std::string GLGizmoCut::get_tooltip() const
|
|||
return (m_hover_id == 0 || m_grabbers[0].dragging) ? "Z: " + format(cut_z, 2) : "";
|
||||
}
|
||||
|
||||
bool GLGizmoCut::on_mouse(const wxMouseEvent &mouse_event)
|
||||
{
|
||||
return use_grabbers(mouse_event);
|
||||
}
|
||||
|
||||
bool GLGizmoCut::on_init()
|
||||
{
|
||||
m_grabbers.emplace_back();
|
||||
|
@ -53,7 +58,7 @@ std::string GLGizmoCut::on_get_name() const
|
|||
void GLGizmoCut::on_set_state()
|
||||
{
|
||||
// Reset m_cut_z on gizmo activation
|
||||
if (get_state() == On)
|
||||
if (m_state == On)
|
||||
m_cut_z = bounding_box().center().z();
|
||||
}
|
||||
|
||||
|
@ -76,10 +81,10 @@ void GLGizmoCut::on_start_dragging()
|
|||
m_drag_center.z() = m_cut_z;
|
||||
}
|
||||
|
||||
void GLGizmoCut::on_update(const UpdateData& data)
|
||||
void GLGizmoCut::on_dragging(const UpdateData &data)
|
||||
{
|
||||
if (m_hover_id != -1)
|
||||
set_cut_z(m_start_z + calc_projection(data.mouse_ray));
|
||||
assert(m_hover_id != -1);
|
||||
set_cut_z(m_start_z + calc_projection(data.mouse_ray));
|
||||
}
|
||||
|
||||
void GLGizmoCut::on_render()
|
||||
|
@ -105,11 +110,15 @@ void GLGizmoCut::on_render()
|
|||
GLShaderProgram* shader = wxGetApp().get_shader("flat");
|
||||
if (shader != nullptr) {
|
||||
shader->start_using();
|
||||
Vec3d diff = plane_center - m_old_center;
|
||||
// Z changed when move with cut plane
|
||||
// X and Y changed when move with cutted object
|
||||
bool is_changed = std::abs(diff.x()) > EPSILON ||
|
||||
std::abs(diff.y()) > EPSILON ||
|
||||
std::abs(diff.z()) > EPSILON;
|
||||
m_old_center = plane_center;
|
||||
|
||||
const bool z_changed = std::abs(plane_center.z() - m_old_z) > EPSILON;
|
||||
m_old_z = plane_center.z();
|
||||
|
||||
if (!m_plane.is_initialized() || z_changed) {
|
||||
if (!m_plane.is_initialized() || is_changed) {
|
||||
m_plane.reset();
|
||||
|
||||
GLModel::Geometry init_data;
|
||||
|
@ -154,7 +163,7 @@ void GLGizmoCut::on_render()
|
|||
|
||||
glsafe(::glLineWidth(m_hover_id != -1 ? 2.0f : 1.5f));
|
||||
#if ENABLE_GLBEGIN_GLEND_REMOVAL
|
||||
if (!m_grabber_connection.is_initialized() || z_changed) {
|
||||
if (!m_grabber_connection.is_initialized() || is_changed) {
|
||||
m_grabber_connection.reset();
|
||||
|
||||
GLModel::Geometry init_data;
|
||||
|
@ -329,6 +338,8 @@ BoundingBoxf3 GLGizmoCut::bounding_box() const
|
|||
BoundingBoxf3 ret;
|
||||
const Selection& selection = m_parent.get_selection();
|
||||
const Selection::IndicesList& idxs = selection.get_volume_idxs();
|
||||
return selection.get_bounding_box();
|
||||
|
||||
for (unsigned int i : idxs) {
|
||||
const GLVolume* volume = selection.get_volume(i);
|
||||
if (!volume->is_modifier)
|
||||
|
@ -367,6 +378,8 @@ void GLGizmoCut::update_contours()
|
|||
|
||||
MeshSlicingParams slicing_params;
|
||||
slicing_params.trafo = first_glvolume->get_instance_transformation().get_matrix();
|
||||
slicing_params.trafo.pretranslate(Vec3d(0., 0., first_glvolume->get_sla_shift_z()));
|
||||
|
||||
const Polygons polys = slice_mesh(m_cut_contours.mesh.its, m_cut_z, slicing_params);
|
||||
if (!polys.empty()) {
|
||||
m_cut_contours.contours.init_from(polys, static_cast<float>(m_cut_z));
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
|
||||
namespace Slic3r {
|
||||
namespace GUI {
|
||||
class Selection;
|
||||
|
||||
class GLGizmoCut : public GLGizmoBase
|
||||
{
|
||||
|
@ -25,7 +26,7 @@ class GLGizmoCut : public GLGizmoBase
|
|||
#if ENABLE_GLBEGIN_GLEND_REMOVAL
|
||||
GLModel m_plane;
|
||||
GLModel m_grabber_connection;
|
||||
float m_old_z{ 0.0f };
|
||||
Vec3d m_old_center;
|
||||
#endif // ENABLE_GLBEGIN_GLEND_REMOVAL
|
||||
|
||||
struct CutContours
|
||||
|
@ -50,6 +51,13 @@ public:
|
|||
|
||||
std::string get_tooltip() const override;
|
||||
|
||||
/// <summary>
|
||||
/// Drag of plane
|
||||
/// </summary>
|
||||
/// <param name="mouse_event">Keep information about mouse click</param>
|
||||
/// <returns>Return True when use the information otherwise False.</returns>
|
||||
bool on_mouse(const wxMouseEvent &mouse_event) override;
|
||||
|
||||
protected:
|
||||
virtual bool on_init() override;
|
||||
virtual void on_load(cereal::BinaryInputArchive& ar) override { ar(m_cut_z, m_keep_upper, m_keep_lower, m_rotate_lower); }
|
||||
|
@ -58,7 +66,7 @@ protected:
|
|||
virtual void on_set_state() override;
|
||||
virtual bool on_is_activable() const override;
|
||||
virtual void on_start_dragging() override;
|
||||
virtual void on_update(const UpdateData& data) override;
|
||||
virtual void on_dragging(const UpdateData& data) override;
|
||||
virtual void on_render() override;
|
||||
virtual void on_render_for_picking() override;
|
||||
virtual void on_render_input_window(float x, float y, float bottom_limit) override;
|
||||
|
|
|
@ -21,9 +21,52 @@ static const Slic3r::ColorRGBA DEFAULT_HOVER_PLANE_COLOR = { 0.9f, 0.9f, 0.9f, 0
|
|||
|
||||
GLGizmoFlatten::GLGizmoFlatten(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id)
|
||||
: GLGizmoBase(parent, icon_filename, sprite_id)
|
||||
, m_normal(Vec3d::Zero())
|
||||
, m_starting_center(Vec3d::Zero())
|
||||
{}
|
||||
|
||||
bool GLGizmoFlatten::on_mouse(const wxMouseEvent &mouse_event)
|
||||
{
|
||||
if (mouse_event.Moving()) {
|
||||
// only for sure
|
||||
m_mouse_left_down = false;
|
||||
return false;
|
||||
}
|
||||
if (mouse_event.LeftDown()) {
|
||||
if (m_hover_id != -1) {
|
||||
m_mouse_left_down = true;
|
||||
Selection &selection = m_parent.get_selection();
|
||||
if (selection.is_single_full_instance()) {
|
||||
// Rotate the object so the normal points downward:
|
||||
selection.flattening_rotate(m_planes[m_hover_id].normal);
|
||||
m_parent.do_rotate(L("Gizmo-Place on Face"));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// fix: prevent restart gizmo when reselect object
|
||||
// take responsibility for left up
|
||||
if (m_parent.get_first_hover_volume_idx() >= 0) m_mouse_left_down = true;
|
||||
|
||||
} else if (mouse_event.LeftUp()) {
|
||||
if (m_mouse_left_down) {
|
||||
// responsible for mouse left up after selecting plane
|
||||
m_mouse_left_down = false;
|
||||
return true;
|
||||
}
|
||||
} else if (mouse_event.Leaving()) {
|
||||
m_mouse_left_down = false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void GLGizmoFlatten::data_changed()
|
||||
{
|
||||
const Selection & selection = m_parent.get_selection();
|
||||
const ModelObject *model_object = nullptr;
|
||||
if (selection.is_single_full_instance() ||
|
||||
selection.is_from_single_object() ) {
|
||||
model_object = selection.get_model()->objects[selection.get_object_idx()];
|
||||
}
|
||||
set_flattening_data(model_object);
|
||||
}
|
||||
|
||||
bool GLGizmoFlatten::on_init()
|
||||
|
@ -53,15 +96,6 @@ bool GLGizmoFlatten::on_is_activable() const
|
|||
return m_parent.get_selection().is_single_full_instance();
|
||||
}
|
||||
|
||||
void GLGizmoFlatten::on_start_dragging()
|
||||
{
|
||||
if (m_hover_id != -1) {
|
||||
assert(m_planes_valid);
|
||||
m_normal = m_planes[m_hover_id].normal;
|
||||
m_starting_center = m_parent.get_selection().get_bounding_box().center();
|
||||
}
|
||||
}
|
||||
|
||||
void GLGizmoFlatten::on_render()
|
||||
{
|
||||
const Selection& selection = m_parent.get_selection();
|
||||
|
@ -149,7 +183,6 @@ void GLGizmoFlatten::on_render_for_picking()
|
|||
|
||||
void GLGizmoFlatten::set_flattening_data(const ModelObject* model_object)
|
||||
{
|
||||
m_starting_center = Vec3d::Zero();
|
||||
if (model_object != m_old_model_object) {
|
||||
m_planes.clear();
|
||||
m_planes_valid = false;
|
||||
|
@ -415,13 +448,5 @@ bool GLGizmoFlatten::is_plane_update_necessary() const
|
|||
return false;
|
||||
}
|
||||
|
||||
Vec3d GLGizmoFlatten::get_flattening_normal() const
|
||||
{
|
||||
Vec3d out = m_normal;
|
||||
m_normal = Vec3d::Zero();
|
||||
m_starting_center = Vec3d::Zero();
|
||||
return out;
|
||||
}
|
||||
|
||||
} // namespace GUI
|
||||
} // namespace Slic3r
|
||||
|
|
|
@ -22,7 +22,6 @@ class GLGizmoFlatten : public GLGizmoBase
|
|||
// This gizmo does not use grabbers. The m_hover_id relates to polygon managed by the class itself.
|
||||
|
||||
private:
|
||||
mutable Vec3d m_normal;
|
||||
|
||||
struct PlaneData {
|
||||
std::vector<Vec3d> vertices; // should be in fact local in update_planes()
|
||||
|
@ -42,8 +41,8 @@ private:
|
|||
Vec3d m_first_instance_mirror;
|
||||
|
||||
std::vector<PlaneData> m_planes;
|
||||
bool m_mouse_left_down = false; // for detection left_up of this gizmo
|
||||
bool m_planes_valid = false;
|
||||
mutable Vec3d m_starting_center;
|
||||
const ModelObject* m_old_model_object = nullptr;
|
||||
std::vector<const Transform3d*> instances_matrices;
|
||||
|
||||
|
@ -54,17 +53,23 @@ public:
|
|||
GLGizmoFlatten(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id);
|
||||
|
||||
void set_flattening_data(const ModelObject* model_object);
|
||||
Vec3d get_flattening_normal() const;
|
||||
|
||||
/// <summary>
|
||||
/// Apply rotation on select plane
|
||||
/// </summary>
|
||||
/// <param name="mouse_event">Keep information about mouse click</param>
|
||||
/// <returns>Return True when use the information otherwise False.</returns>
|
||||
bool on_mouse(const wxMouseEvent &mouse_event) override;
|
||||
|
||||
void data_changed() override;
|
||||
protected:
|
||||
virtual bool on_init() override;
|
||||
virtual std::string on_get_name() const override;
|
||||
virtual bool on_is_activable() const override;
|
||||
virtual void on_start_dragging() override;
|
||||
virtual void on_render() override;
|
||||
virtual void on_render_for_picking() override;
|
||||
virtual void on_set_state() override;
|
||||
virtual CommonGizmosDataID on_get_requirements() const override;
|
||||
bool on_init() override;
|
||||
std::string on_get_name() const override;
|
||||
bool on_is_activable() const override;
|
||||
void on_render() override;
|
||||
void on_render_for_picking() override;
|
||||
void on_set_state() override;
|
||||
CommonGizmosDataID on_get_requirements() const override;
|
||||
};
|
||||
|
||||
} // namespace GUI
|
||||
|
|
|
@ -42,7 +42,7 @@ bool GLGizmoHollow::on_init()
|
|||
return true;
|
||||
}
|
||||
|
||||
void GLGizmoHollow::set_sla_support_data(ModelObject*, const Selection&)
|
||||
void GLGizmoHollow::data_changed()
|
||||
{
|
||||
if (! m_c->selection_info())
|
||||
return;
|
||||
|
@ -417,20 +417,70 @@ void GLGizmoHollow::delete_selected_points()
|
|||
select_point(NoPoints);
|
||||
}
|
||||
|
||||
void GLGizmoHollow::on_update(const UpdateData& data)
|
||||
bool GLGizmoHollow::on_mouse(const wxMouseEvent &mouse_event)
|
||||
{
|
||||
sla::DrainHoles& drain_holes = m_c->selection_info()->model_object()->sla_drain_holes;
|
||||
if (mouse_event.Moving()) return false;
|
||||
if (use_grabbers(mouse_event)) return true;
|
||||
|
||||
if (m_hover_id != -1) {
|
||||
std::pair<Vec3f, Vec3f> pos_and_normal;
|
||||
if (! unproject_on_mesh(data.mouse_pos.cast<double>(), pos_and_normal))
|
||||
return;
|
||||
drain_holes[m_hover_id].pos = pos_and_normal.first;
|
||||
drain_holes[m_hover_id].normal = -pos_and_normal.second;
|
||||
// wxCoord == int --> wx/types.h
|
||||
Vec2i mouse_coord(mouse_event.GetX(), mouse_event.GetY());
|
||||
Vec2d mouse_pos = mouse_coord.cast<double>();
|
||||
|
||||
static bool pending_right_up = false;
|
||||
if (mouse_event.LeftDown()) {
|
||||
bool control_down = mouse_event.CmdDown();
|
||||
bool grabber_contains_mouse = (get_hover_id() != -1);
|
||||
if ((!control_down || grabber_contains_mouse) &&
|
||||
gizmo_event(SLAGizmoEventType::LeftDown, mouse_pos, mouse_event.ShiftDown(), mouse_event.AltDown(), false))
|
||||
// the gizmo got the event and took some action, there is no need
|
||||
// to do anything more
|
||||
return true;
|
||||
} else if (mouse_event.Dragging()) {
|
||||
if (m_parent.get_move_volume_id() != -1)
|
||||
// don't allow dragging objects with the Sla gizmo on
|
||||
return true;
|
||||
|
||||
bool control_down = mouse_event.CmdDown();
|
||||
if (control_down) {
|
||||
// CTRL has been pressed while already dragging -> stop current action
|
||||
if (mouse_event.LeftIsDown())
|
||||
gizmo_event(SLAGizmoEventType::LeftUp, mouse_pos, mouse_event.ShiftDown(), mouse_event.AltDown(), true);
|
||||
else if (mouse_event.RightIsDown()) {
|
||||
pending_right_up = false;
|
||||
}
|
||||
} else if(gizmo_event(SLAGizmoEventType::Dragging, mouse_pos, mouse_event.ShiftDown(), mouse_event.AltDown(), false)) {
|
||||
// the gizmo got the event and took some action, no need to do
|
||||
// anything more here
|
||||
m_parent.set_as_dirty();
|
||||
return true;
|
||||
}
|
||||
} else if (mouse_event.LeftUp()) {
|
||||
if (!m_parent.is_mouse_dragging()) {
|
||||
bool control_down = mouse_event.CmdDown();
|
||||
// in case gizmo is selected, we just pass the LeftUp event
|
||||
// and stop processing - neither object moving or selecting is
|
||||
// suppressed in that case
|
||||
gizmo_event(SLAGizmoEventType::LeftUp, mouse_pos, mouse_event.ShiftDown(), mouse_event.AltDown(), control_down);
|
||||
return true;
|
||||
}
|
||||
} else if (mouse_event.RightDown()) {
|
||||
if (m_parent.get_selection().get_object_idx() != -1 &&
|
||||
gizmo_event(SLAGizmoEventType::RightDown, mouse_pos, false, false, false)) {
|
||||
// we need to set the following right up as processed to avoid showing
|
||||
// the context menu if the user release the mouse over the object
|
||||
pending_right_up = true;
|
||||
// event was taken care of by the SlaSupports gizmo
|
||||
return true;
|
||||
}
|
||||
} else if (mouse_event.RightUp()) {
|
||||
if (pending_right_up) {
|
||||
pending_right_up = false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void GLGizmoHollow::hollow_mesh(bool postpone_error_messages)
|
||||
{
|
||||
wxGetApp().CallAfter([this, postpone_error_messages]() {
|
||||
|
@ -820,6 +870,17 @@ void GLGizmoHollow::on_stop_dragging()
|
|||
}
|
||||
|
||||
|
||||
void GLGizmoHollow::on_dragging(const UpdateData &data)
|
||||
{
|
||||
assert(m_hover_id != -1);
|
||||
std::pair<Vec3f, Vec3f> pos_and_normal;
|
||||
if (!unproject_on_mesh(data.mouse_pos.cast<double>(), pos_and_normal))
|
||||
return;
|
||||
sla::DrainHoles &drain_holes = m_c->selection_info()->model_object()->sla_drain_holes;
|
||||
drain_holes[m_hover_id].pos = pos_and_normal.first;
|
||||
drain_holes[m_hover_id].normal = -pos_and_normal.second;
|
||||
}
|
||||
|
||||
|
||||
void GLGizmoHollow::on_load(cereal::BinaryInputArchive& ar)
|
||||
{
|
||||
|
|
|
@ -19,7 +19,7 @@ class ConfigOptionDef;
|
|||
namespace GUI {
|
||||
|
||||
enum class SLAGizmoEventType : unsigned char;
|
||||
|
||||
class Selection;
|
||||
class GLGizmoHollow : public GLGizmoBase
|
||||
{
|
||||
private:
|
||||
|
@ -29,16 +29,22 @@ private:
|
|||
public:
|
||||
GLGizmoHollow(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id);
|
||||
virtual ~GLGizmoHollow() = default;
|
||||
void set_sla_support_data(ModelObject* model_object, const Selection& selection);
|
||||
void data_changed() override;
|
||||
bool gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_position, bool shift_down, bool alt_down, bool control_down);
|
||||
void delete_selected_points();
|
||||
bool is_selection_rectangle_dragging() const {
|
||||
return m_selection_rectangle.is_dragging();
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Postpone to Grabber for move
|
||||
/// Detect move of object by dragging
|
||||
/// </summary>
|
||||
/// <param name="mouse_event">Keep information about mouse click</param>
|
||||
/// <returns>Return True when use the information otherwise False.</returns>
|
||||
bool on_mouse(const wxMouseEvent &mouse_event) override;
|
||||
private:
|
||||
bool on_init() override;
|
||||
void on_update(const UpdateData& data) override;
|
||||
void on_render() override;
|
||||
void on_render_for_picking() override;
|
||||
|
||||
|
@ -94,6 +100,7 @@ protected:
|
|||
void on_set_hover_id() override;
|
||||
void on_start_dragging() override;
|
||||
void on_stop_dragging() override;
|
||||
void on_dragging(const UpdateData &data) override;
|
||||
void on_render_input_window(float x, float y, float bottom_limit) override;
|
||||
virtual CommonGizmosDataID on_get_requirements() const override;
|
||||
|
||||
|
|
|
@ -146,10 +146,9 @@ void GLGizmoMmuSegmentation::render_painter_gizmo()
|
|||
glsafe(::glDisable(GL_BLEND));
|
||||
}
|
||||
|
||||
void GLGizmoMmuSegmentation::set_painter_gizmo_data(const Selection &selection)
|
||||
void GLGizmoMmuSegmentation::data_changed()
|
||||
{
|
||||
GLGizmoPainterBase::set_painter_gizmo_data(selection);
|
||||
|
||||
GLGizmoPainterBase::data_changed();
|
||||
if (m_state != On || wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology() != ptFFF || wxGetApp().extruders_edited_cnt() <= 1)
|
||||
return;
|
||||
|
||||
|
|
|
@ -87,7 +87,7 @@ public:
|
|||
|
||||
void render_painter_gizmo() override;
|
||||
|
||||
void set_painter_gizmo_data(const Selection& selection) override;
|
||||
void data_changed() override;
|
||||
|
||||
void render_triangles(const Selection& selection) const override;
|
||||
|
||||
|
|
|
@ -46,6 +46,14 @@ std::string GLGizmoMove3D::get_tooltip() const
|
|||
#endif // ENABLE_WORLD_COORDINATE
|
||||
}
|
||||
|
||||
bool GLGizmoMove3D::on_mouse(const wxMouseEvent &mouse_event) {
|
||||
return use_grabbers(mouse_event);
|
||||
}
|
||||
|
||||
void GLGizmoMove3D::data_changed() {
|
||||
m_grabbers[2].enabled = !m_parent.get_selection().is_wipe_tower();
|
||||
}
|
||||
|
||||
bool GLGizmoMove3D::on_init()
|
||||
{
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
|
@ -69,46 +77,41 @@ bool GLGizmoMove3D::on_is_activable() const
|
|||
|
||||
void GLGizmoMove3D::on_start_dragging()
|
||||
{
|
||||
if (m_hover_id != -1) {
|
||||
m_displacement = Vec3d::Zero();
|
||||
assert(m_hover_id != -1);
|
||||
|
||||
m_displacement = Vec3d::Zero();
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
const Selection& selection = m_parent.get_selection();
|
||||
#if ENABLE_INSTANCE_COORDINATES_FOR_VOLUMES
|
||||
const ECoordinatesType coordinates_type = wxGetApp().obj_manipul()->get_coordinates_type();
|
||||
if (coordinates_type == ECoordinatesType::World)
|
||||
#else
|
||||
if (wxGetApp().obj_manipul()->get_world_coordinates())
|
||||
#endif // ENABLE_INSTANCE_COORDINATES_FOR_VOLUMES
|
||||
m_starting_drag_position = m_center + m_grabbers[m_hover_id].center;
|
||||
#if ENABLE_INSTANCE_COORDINATES_FOR_VOLUMES
|
||||
else if (coordinates_type == ECoordinatesType::Local && selection.is_single_volume_or_modifier()) {
|
||||
const GLVolume& v = *selection.get_volume(*selection.get_volume_idxs().begin());
|
||||
m_starting_drag_position = m_center + Geometry::assemble_transform(Vec3d::Zero(), v.get_instance_rotation()) * Geometry::assemble_transform(Vec3d::Zero(), v.get_volume_rotation()) * m_grabbers[m_hover_id].center;
|
||||
}
|
||||
#endif // ENABLE_INSTANCE_COORDINATES_FOR_VOLUMES
|
||||
else {
|
||||
const GLVolume& v = *selection.get_volume(*selection.get_volume_idxs().begin());
|
||||
m_starting_drag_position = m_center + Geometry::assemble_transform(Vec3d::Zero(), v.get_instance_rotation()) * m_grabbers[m_hover_id].center;
|
||||
}
|
||||
m_starting_box_center = m_center;
|
||||
m_starting_box_bottom_center = m_center;
|
||||
m_starting_box_bottom_center.z() = m_bounding_box.min.z();
|
||||
#else
|
||||
const BoundingBoxf3& box = m_parent.get_selection().get_bounding_box();
|
||||
m_starting_drag_position = m_grabbers[m_hover_id].center;
|
||||
m_starting_box_center = box.center();
|
||||
m_starting_box_bottom_center = box.center();
|
||||
m_starting_box_bottom_center.z() = box.min.z();
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
const Selection& selection = m_parent.get_selection();
|
||||
const ECoordinatesType coordinates_type = wxGetApp().obj_manipul()->get_coordinates_type();
|
||||
if (coordinates_type == ECoordinatesType::World)
|
||||
m_starting_drag_position = m_center + m_grabbers[m_hover_id].center;
|
||||
else if (coordinates_type == ECoordinatesType::Local && selection.is_single_volume_or_modifier()) {
|
||||
const GLVolume& v = *selection.get_volume(*selection.get_volume_idxs().begin());
|
||||
m_starting_drag_position = m_center + Geometry::assemble_transform(Vec3d::Zero(), v.get_instance_rotation()) * Geometry::assemble_transform(Vec3d::Zero(), v.get_volume_rotation()) * m_grabbers[m_hover_id].center;
|
||||
}
|
||||
else {
|
||||
const GLVolume& v = *selection.get_volume(*selection.get_volume_idxs().begin());
|
||||
m_starting_drag_position = m_center + Geometry::assemble_transform(Vec3d::Zero(), v.get_instance_rotation()) * m_grabbers[m_hover_id].center;
|
||||
}
|
||||
m_starting_box_center = m_center;
|
||||
m_starting_box_bottom_center = m_center;
|
||||
m_starting_box_bottom_center.z() = m_bounding_box.min.z();
|
||||
#else
|
||||
const BoundingBoxf3& box = m_parent.get_selection().get_bounding_box();
|
||||
m_starting_drag_position = m_grabbers[m_hover_id].center;
|
||||
m_starting_box_center = box.center();
|
||||
m_starting_box_bottom_center = box.center();
|
||||
m_starting_box_bottom_center.z() = box.min.z();
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
}
|
||||
|
||||
void GLGizmoMove3D::on_stop_dragging()
|
||||
{
|
||||
m_parent.do_move(L("Gizmo-Move"));
|
||||
m_displacement = Vec3d::Zero();
|
||||
}
|
||||
|
||||
void GLGizmoMove3D::on_update(const UpdateData& data)
|
||||
void GLGizmoMove3D::on_dragging(const UpdateData& data)
|
||||
{
|
||||
if (m_hover_id == 0)
|
||||
m_displacement.x() = calc_projection(data);
|
||||
|
@ -116,6 +119,13 @@ void GLGizmoMove3D::on_update(const UpdateData& data)
|
|||
m_displacement.y() = calc_projection(data);
|
||||
else if (m_hover_id == 2)
|
||||
m_displacement.z() = calc_projection(data);
|
||||
|
||||
Selection &selection = m_parent.get_selection();
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
selection.translate(m_displacement, wxGetApp().obj_manipul()->get_coordinates_type());
|
||||
#else
|
||||
selection.translate(m_displacement);
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
}
|
||||
|
||||
void GLGizmoMove3D::on_render()
|
||||
|
@ -397,7 +407,6 @@ void GLGizmoMove3D::transform_to_local(const Selection& selection) const
|
|||
{
|
||||
glsafe(::glTranslated(m_center.x(), m_center.y(), m_center.z()));
|
||||
|
||||
#if ENABLE_INSTANCE_COORDINATES_FOR_VOLUMES
|
||||
if (!wxGetApp().obj_manipul()->is_world_coordinates()) {
|
||||
const GLVolume& v = *selection.get_volume(*selection.get_volume_idxs().begin());
|
||||
Transform3d orient_matrix = v.get_instance_transformation().get_matrix(true, false, true, true);
|
||||
|
@ -405,33 +414,21 @@ void GLGizmoMove3D::transform_to_local(const Selection& selection) const
|
|||
orient_matrix = orient_matrix * v.get_volume_transformation().get_matrix(true, false, true, true);
|
||||
glsafe(::glMultMatrixd(orient_matrix.data()));
|
||||
}
|
||||
#else
|
||||
if (!wxGetApp().obj_manipul()->get_world_coordinates()) {
|
||||
const Transform3d orient_matrix = selection.get_volume(*selection.get_volume_idxs().begin())->get_instance_transformation().get_matrix(true, false, true, true);
|
||||
glsafe(::glMultMatrixd(orient_matrix.data()));
|
||||
}
|
||||
#endif // ENABLE_INSTANCE_COORDINATES_FOR_VOLUMES
|
||||
}
|
||||
|
||||
void GLGizmoMove3D::calc_selection_box_and_center()
|
||||
{
|
||||
const Selection& selection = m_parent.get_selection();
|
||||
#if ENABLE_INSTANCE_COORDINATES_FOR_VOLUMES
|
||||
const ECoordinatesType coordinates_type = wxGetApp().obj_manipul()->get_coordinates_type();
|
||||
if (coordinates_type == ECoordinatesType::World) {
|
||||
#else
|
||||
if (wxGetApp().obj_manipul()->get_world_coordinates()) {
|
||||
#endif // ENABLE_INSTANCE_COORDINATES_FOR_VOLUMES
|
||||
m_bounding_box = selection.get_bounding_box();
|
||||
m_center = m_bounding_box.center();
|
||||
}
|
||||
#if ENABLE_INSTANCE_COORDINATES_FOR_VOLUMES
|
||||
else if (coordinates_type == ECoordinatesType::Local && selection.is_single_volume_or_modifier()) {
|
||||
const GLVolume& v = *selection.get_volume(*selection.get_volume_idxs().begin());
|
||||
m_bounding_box = v.transformed_convex_hull_bounding_box(v.get_instance_transformation().get_matrix(true, true, false, true) * v.get_volume_transformation().get_matrix(true, true, false, true));
|
||||
m_center = v.world_matrix() * m_bounding_box.center();
|
||||
}
|
||||
#endif // ENABLE_INSTANCE_COORDINATES_FOR_VOLUMES
|
||||
else {
|
||||
m_bounding_box.reset();
|
||||
const Selection::IndicesList& ids = selection.get_volume_idxs();
|
||||
|
|
|
@ -7,6 +7,10 @@
|
|||
namespace Slic3r {
|
||||
namespace GUI {
|
||||
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
class Selection;
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
||||
class GLGizmoMove3D : public GLGizmoBase
|
||||
{
|
||||
static const double Offset;
|
||||
|
@ -38,19 +42,28 @@ public:
|
|||
double get_snap_step(double step) const { return m_snap_step; }
|
||||
void set_snap_step(double step) { m_snap_step = step; }
|
||||
|
||||
const Vec3d& get_displacement() const { return m_displacement; }
|
||||
|
||||
std::string get_tooltip() const override;
|
||||
|
||||
/// <summary>
|
||||
/// Postpone to Grabber for move
|
||||
/// </summary>
|
||||
/// <param name="mouse_event">Keep information about mouse click</param>
|
||||
/// <returns>Return True when use the information otherwise False.</returns>
|
||||
bool on_mouse(const wxMouseEvent &mouse_event) override;
|
||||
|
||||
/// <summary>
|
||||
/// Detect reduction of move for wipetover on selection change
|
||||
/// </summary>
|
||||
void data_changed() override;
|
||||
protected:
|
||||
virtual bool on_init() override;
|
||||
virtual std::string on_get_name() const override;
|
||||
virtual bool on_is_activable() const override;
|
||||
virtual void on_start_dragging() override;
|
||||
virtual void on_stop_dragging() override;
|
||||
virtual void on_update(const UpdateData& data) override;
|
||||
virtual void on_render() override;
|
||||
virtual void on_render_for_picking() override;
|
||||
bool on_init() override;
|
||||
std::string on_get_name() const override;
|
||||
bool on_is_activable() const override;
|
||||
void on_start_dragging() override;
|
||||
void on_stop_dragging() override;
|
||||
void on_dragging(const UpdateData& data) override;
|
||||
void on_render() override;
|
||||
void on_render_for_picking() override;
|
||||
|
||||
private:
|
||||
double calc_projection(const UpdateData& data) const;
|
||||
|
|
|
@ -40,13 +40,13 @@ GLGizmoPainterBase::~GLGizmoPainterBase()
|
|||
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||
}
|
||||
|
||||
void GLGizmoPainterBase::set_painter_gizmo_data(const Selection& selection)
|
||||
void GLGizmoPainterBase::data_changed()
|
||||
{
|
||||
if (m_state != On)
|
||||
return;
|
||||
|
||||
const ModelObject* mo = m_c->selection_info() ? m_c->selection_info()->model_object() : nullptr;
|
||||
|
||||
const Selection & selection = m_parent.get_selection();
|
||||
if (mo && selection.is_from_single_instance()
|
||||
&& (m_schedule_update || mo->id() != m_old_mo_id || mo->volumes.size() != m_old_volumes_size))
|
||||
{
|
||||
|
@ -641,7 +641,72 @@ bool GLGizmoPainterBase::gizmo_event(SLAGizmoEventType action, const Vec2d& mous
|
|||
return false;
|
||||
}
|
||||
|
||||
bool GLGizmoPainterBase::on_mouse(const wxMouseEvent &mouse_event)
|
||||
{
|
||||
// wxCoord == int --> wx/types.h
|
||||
Vec2i mouse_coord(mouse_event.GetX(), mouse_event.GetY());
|
||||
Vec2d mouse_pos = mouse_coord.cast<double>();
|
||||
|
||||
if (mouse_event.Moving()) {
|
||||
gizmo_event(SLAGizmoEventType::Moving, mouse_pos, mouse_event.ShiftDown(), mouse_event.AltDown(), false);
|
||||
return false;
|
||||
}
|
||||
|
||||
// when control is down we allow scene pan and rotation even when clicking
|
||||
// over some object
|
||||
bool control_down = mouse_event.CmdDown();
|
||||
bool grabber_contains_mouse = (get_hover_id() != -1);
|
||||
|
||||
const Selection &selection = m_parent.get_selection();
|
||||
int selected_object_idx = selection.get_object_idx();
|
||||
if (mouse_event.LeftDown()) {
|
||||
if ((!control_down || grabber_contains_mouse) &&
|
||||
gizmo_event(SLAGizmoEventType::LeftDown, mouse_pos, mouse_event.ShiftDown(), mouse_event.AltDown(), false))
|
||||
// the gizmo got the event and took some action, there is no need
|
||||
// to do anything more
|
||||
return true;
|
||||
} else if (mouse_event.RightDown()){
|
||||
if (!control_down && selected_object_idx != -1 &&
|
||||
gizmo_event(SLAGizmoEventType::RightDown, mouse_pos, false, false, false))
|
||||
// event was taken care of
|
||||
return true;
|
||||
} else if (mouse_event.Dragging()) {
|
||||
if (m_parent.get_move_volume_id() != -1)
|
||||
// don't allow dragging objects with the Sla gizmo on
|
||||
return true;
|
||||
if (!control_down && gizmo_event(SLAGizmoEventType::Dragging,
|
||||
mouse_pos, mouse_event.ShiftDown(),
|
||||
mouse_event.AltDown(), false)) {
|
||||
// the gizmo got the event and took some action, no need to do
|
||||
// anything more here
|
||||
m_parent.set_as_dirty();
|
||||
return true;
|
||||
}
|
||||
if(control_down && (mouse_event.LeftIsDown() || mouse_event.RightIsDown()))
|
||||
{
|
||||
// CTRL has been pressed while already dragging -> stop current action
|
||||
if (mouse_event.LeftIsDown())
|
||||
gizmo_event(SLAGizmoEventType::LeftUp, mouse_pos, mouse_event.ShiftDown(), mouse_event.AltDown(), true);
|
||||
else if (mouse_event.RightIsDown())
|
||||
gizmo_event(SLAGizmoEventType::RightUp, mouse_pos, mouse_event.ShiftDown(), mouse_event.AltDown(), true);
|
||||
return false;
|
||||
}
|
||||
} else if (mouse_event.LeftUp()) {
|
||||
if (!m_parent.is_mouse_dragging()) {
|
||||
// in case SLA/FDM gizmo is selected, we just pass the LeftUp
|
||||
// event and stop processing - neither object moving or selecting
|
||||
// is suppressed in that case
|
||||
gizmo_event(SLAGizmoEventType::LeftUp, mouse_pos, mouse_event.ShiftDown(), mouse_event.AltDown(), control_down);
|
||||
return true;
|
||||
}
|
||||
} else if (mouse_event.RightUp()) {
|
||||
if (!m_parent.is_mouse_dragging()) {
|
||||
gizmo_event(SLAGizmoEventType::RightUp, mouse_pos, mouse_event.ShiftDown(), mouse_event.AltDown(), control_down);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void GLGizmoPainterBase::update_raycast_cache(const Vec2d& mouse_position,
|
||||
const Camera& camera,
|
||||
|
|
|
@ -25,6 +25,7 @@ enum class SLAGizmoEventType : unsigned char;
|
|||
class ClippingPlane;
|
||||
struct Camera;
|
||||
class GLGizmoMmuSegmentation;
|
||||
class Selection;
|
||||
|
||||
enum class PainterGizmoType {
|
||||
FDM_SUPPORTS,
|
||||
|
@ -135,8 +136,8 @@ private:
|
|||
void on_render_for_picking() override {}
|
||||
public:
|
||||
GLGizmoPainterBase(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id);
|
||||
virtual ~GLGizmoPainterBase() override;
|
||||
virtual void set_painter_gizmo_data(const Selection& selection);
|
||||
~GLGizmoPainterBase() override;
|
||||
void data_changed() override;
|
||||
virtual bool gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_position, bool shift_down, bool alt_down, bool control_down);
|
||||
|
||||
// Following function renders the triangles and cursor. Having this separated
|
||||
|
@ -149,6 +150,15 @@ public:
|
|||
virtual const float get_cursor_radius_max() const { return CursorRadiusMax; }
|
||||
virtual const float get_cursor_radius_step() const { return CursorRadiusStep; }
|
||||
|
||||
/// <summary>
|
||||
/// Implement when want to process mouse events in gizmo
|
||||
/// Click, Right click, move, drag, ...
|
||||
/// </summary>
|
||||
/// <param name="mouse_event">Keep information about mouse click</param>
|
||||
/// <returns>Return True when use the information and don't want to
|
||||
/// propagate it otherwise False.</returns>
|
||||
bool on_mouse(const wxMouseEvent &mouse_event) override;
|
||||
|
||||
protected:
|
||||
virtual void render_triangles(const Selection& selection) const;
|
||||
void render_cursor();
|
||||
|
@ -257,9 +267,6 @@ private:
|
|||
|
||||
protected:
|
||||
void on_set_state() override;
|
||||
void on_start_dragging() override {}
|
||||
void on_stop_dragging() override {}
|
||||
|
||||
virtual void on_opening() = 0;
|
||||
virtual void on_shutdown() = 0;
|
||||
virtual PainterGizmoType get_painter_type() const = 0;
|
||||
|
|
|
@ -31,7 +31,23 @@ const float GLGizmoRotate::GrabberOffset = 0.15f; // in percent of radius
|
|||
GLGizmoRotate::GLGizmoRotate(GLCanvas3D& parent, GLGizmoRotate::Axis axis)
|
||||
: GLGizmoBase(parent, "", -1)
|
||||
, m_axis(axis)
|
||||
{}
|
||||
, m_angle(0.0)
|
||||
, m_center(0.0, 0.0, 0.0)
|
||||
, m_radius(0.0f)
|
||||
, m_snap_coarse_in_radius(0.0f)
|
||||
, m_snap_coarse_out_radius(0.0f)
|
||||
, m_snap_fine_in_radius(0.0f)
|
||||
, m_snap_fine_out_radius(0.0f)
|
||||
, m_drag_color(DEFAULT_DRAG_COLOR)
|
||||
, m_highlight_color(DEFAULT_HIGHLIGHT_COLOR)
|
||||
{
|
||||
m_group_id = static_cast<int>(axis);
|
||||
}
|
||||
|
||||
void GLGizmoRotate::set_highlight_color(const ColorRGBA &color)
|
||||
{
|
||||
m_highlight_color = color;
|
||||
}
|
||||
|
||||
void GLGizmoRotate::set_angle(double angle)
|
||||
{
|
||||
|
@ -53,6 +69,28 @@ std::string GLGizmoRotate::get_tooltip() const
|
|||
return (m_hover_id == 0 || m_grabbers.front().dragging) ? axis + ": " + format(float(Geometry::rad2deg(m_angle)), 4) : "";
|
||||
}
|
||||
|
||||
bool GLGizmoRotate::on_mouse(const wxMouseEvent &mouse_event)
|
||||
{
|
||||
return use_grabbers(mouse_event);
|
||||
}
|
||||
|
||||
void GLGizmoRotate::dragging(const UpdateData &data) { on_dragging(data); }
|
||||
|
||||
void GLGizmoRotate::start_dragging()
|
||||
{
|
||||
m_grabbers[0].dragging = true;
|
||||
on_start_dragging();
|
||||
}
|
||||
|
||||
void GLGizmoRotate::stop_dragging()
|
||||
{
|
||||
m_grabbers[0].dragging = false;
|
||||
on_stop_dragging();
|
||||
}
|
||||
|
||||
void GLGizmoRotate::enable_grabber() { m_grabbers[0].enabled = true; }
|
||||
void GLGizmoRotate::disable_grabber() { m_grabbers[0].enabled = false; }
|
||||
|
||||
bool GLGizmoRotate::on_init()
|
||||
{
|
||||
m_grabbers.push_back(Grabber());
|
||||
|
@ -74,7 +112,7 @@ void GLGizmoRotate::on_start_dragging()
|
|||
#endif // ENABLE_WORLD_COORDINATE
|
||||
}
|
||||
|
||||
void GLGizmoRotate::on_update(const UpdateData& data)
|
||||
void GLGizmoRotate::on_dragging(const UpdateData &data)
|
||||
{
|
||||
const Vec2d mouse_pos = to_2d(mouse_position_in_local_plane(data.mouse_ray, m_parent.get_selection()));
|
||||
|
||||
|
@ -218,22 +256,16 @@ void GLGizmoRotate::on_render_for_picking()
|
|||
#if ENABLE_WORLD_COORDINATE
|
||||
void GLGizmoRotate::init_data_from_selection(const Selection& selection)
|
||||
{
|
||||
#if ENABLE_INSTANCE_COORDINATES_FOR_VOLUMES
|
||||
const ECoordinatesType coordinates_type = wxGetApp().obj_manipul()->get_coordinates_type();
|
||||
if (coordinates_type == ECoordinatesType::World) {
|
||||
#else
|
||||
if (wxGetApp().obj_manipul()->get_world_coordinates()) {
|
||||
#endif // ENABLE_INSTANCE_COORDINATES_FOR_VOLUMES
|
||||
m_bounding_box = selection.get_bounding_box();
|
||||
m_center = m_bounding_box.center();
|
||||
}
|
||||
#if ENABLE_INSTANCE_COORDINATES_FOR_VOLUMES
|
||||
else if (coordinates_type == ECoordinatesType::Local && selection.is_single_volume_or_modifier()) {
|
||||
const GLVolume& v = *selection.get_volume(*selection.get_volume_idxs().begin());
|
||||
m_bounding_box = v.transformed_convex_hull_bounding_box(v.get_instance_transformation().get_matrix(true, true, false, true) * v.get_volume_transformation().get_matrix(true, true, false, true));
|
||||
m_center = v.world_matrix() * m_bounding_box.center();
|
||||
}
|
||||
#endif // ENABLE_INSTANCE_COORDINATES_FOR_VOLUMES
|
||||
else {
|
||||
m_bounding_box.reset();
|
||||
const Selection::IndicesList& ids = selection.get_volume_idxs();
|
||||
|
@ -251,7 +283,6 @@ void GLGizmoRotate::init_data_from_selection(const Selection& selection)
|
|||
m_snap_fine_in_radius = m_radius;
|
||||
m_snap_fine_out_radius = m_snap_fine_in_radius + m_radius * ScaleLongTooth;
|
||||
|
||||
#if ENABLE_INSTANCE_COORDINATES_FOR_VOLUMES
|
||||
if (coordinates_type == ECoordinatesType::World)
|
||||
m_orient_matrix = Transform3d::Identity();
|
||||
else if (coordinates_type == ECoordinatesType::Local && selection.is_single_volume_or_modifier()) {
|
||||
|
@ -262,12 +293,6 @@ void GLGizmoRotate::init_data_from_selection(const Selection& selection)
|
|||
const GLVolume& v = *selection.get_volume(*selection.get_volume_idxs().begin());
|
||||
m_orient_matrix = v.get_instance_transformation().get_matrix(true, false, true, true);
|
||||
}
|
||||
#else
|
||||
if (wxGetApp().obj_manipul()->get_world_coordinates())
|
||||
m_orient_matrix = Transform3d::Identity();
|
||||
else
|
||||
m_orient_matrix = selection.get_volume(*selection.get_volume_idxs().begin())->get_instance_transformation().get_matrix(true, false, true, true);
|
||||
#endif // ENABLE_INSTANCE_COORDINATES_FOR_VOLUMES
|
||||
}
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
||||
|
@ -710,25 +735,60 @@ Vec3d GLGizmoRotate::mouse_position_in_local_plane(const Linef3& mouse_ray, cons
|
|||
|
||||
GLGizmoRotate3D::GLGizmoRotate3D(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id)
|
||||
: GLGizmoBase(parent, icon_filename, sprite_id)
|
||||
, m_gizmos({ GLGizmoRotate(parent, GLGizmoRotate::X), GLGizmoRotate(parent, GLGizmoRotate::Y), GLGizmoRotate(parent, GLGizmoRotate::Z) })
|
||||
{
|
||||
for (unsigned int i = 0; i < 3; ++i) {
|
||||
m_gizmos[i].set_group_id(i);
|
||||
}
|
||||
, m_gizmos({
|
||||
GLGizmoRotate(parent, GLGizmoRotate::X),
|
||||
GLGizmoRotate(parent, GLGizmoRotate::Y),
|
||||
GLGizmoRotate(parent, GLGizmoRotate::Z) })
|
||||
{}
|
||||
|
||||
load_rotoptimize_state();
|
||||
bool GLGizmoRotate3D::on_mouse(const wxMouseEvent &mouse_event)
|
||||
{
|
||||
if (mouse_event.Dragging() && m_dragging) {
|
||||
// Apply new temporary rotations
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
TransformationType transformation_type;
|
||||
switch (wxGetApp().obj_manipul()->get_coordinates_type())
|
||||
{
|
||||
default:
|
||||
case ECoordinatesType::World: { transformation_type = TransformationType::World_Relative_Joint; break; }
|
||||
case ECoordinatesType::Instance: { transformation_type = TransformationType::Instance_Relative_Joint; break; }
|
||||
case ECoordinatesType::Local: { transformation_type = TransformationType::Local_Relative_Joint; break; }
|
||||
}
|
||||
#else
|
||||
TransformationType transformation_type(TransformationType::World_Relative_Joint);
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
if (mouse_event.AltDown()) transformation_type.set_independent();
|
||||
m_parent.get_selection().rotate(get_rotation(), transformation_type);
|
||||
}
|
||||
return use_grabbers(mouse_event);
|
||||
}
|
||||
|
||||
void GLGizmoRotate3D::data_changed() {
|
||||
const Selection &selection = m_parent.get_selection();
|
||||
bool is_wipe_tower = selection.is_wipe_tower();
|
||||
if (is_wipe_tower) {
|
||||
DynamicPrintConfig& config = wxGetApp().preset_bundle->prints.get_edited_preset().config;
|
||||
float wipe_tower_rotation_angle =
|
||||
dynamic_cast<const ConfigOptionFloat *>(
|
||||
config.option("wipe_tower_rotation_angle"))
|
||||
->value;
|
||||
set_rotation(Vec3d(0., 0., (M_PI / 180.) * wipe_tower_rotation_angle));
|
||||
m_gizmos[0].disable_grabber();
|
||||
m_gizmos[1].disable_grabber();
|
||||
} else {
|
||||
set_rotation(Vec3d::Zero());
|
||||
m_gizmos[0].enable_grabber();
|
||||
m_gizmos[1].enable_grabber();
|
||||
}
|
||||
}
|
||||
|
||||
bool GLGizmoRotate3D::on_init()
|
||||
{
|
||||
for (GLGizmoRotate& g : m_gizmos) {
|
||||
if (!g.init())
|
||||
return false;
|
||||
}
|
||||
for (GLGizmoRotate& g : m_gizmos)
|
||||
if (!g.init()) return false;
|
||||
|
||||
for (unsigned int i = 0; i < 3; ++i) {
|
||||
for (unsigned int i = 0; i < 3; ++i)
|
||||
m_gizmos[i].set_highlight_color(AXES_COLOR[i]);
|
||||
}
|
||||
|
||||
m_shortcut_key = WXK_CONTROL_R;
|
||||
|
||||
|
@ -747,14 +807,21 @@ bool GLGizmoRotate3D::on_is_activable() const
|
|||
|
||||
void GLGizmoRotate3D::on_start_dragging()
|
||||
{
|
||||
if (0 <= m_hover_id && m_hover_id < 3)
|
||||
m_gizmos[m_hover_id].start_dragging();
|
||||
assert(0 <= m_hover_id && m_hover_id < 3);
|
||||
m_gizmos[m_hover_id].start_dragging();
|
||||
}
|
||||
|
||||
void GLGizmoRotate3D::on_stop_dragging()
|
||||
{
|
||||
if (0 <= m_hover_id && m_hover_id < 3)
|
||||
m_gizmos[m_hover_id].stop_dragging();
|
||||
assert(0 <= m_hover_id && m_hover_id < 3);
|
||||
m_parent.do_rotate(L("Gizmo-Rotate"));
|
||||
m_gizmos[m_hover_id].stop_dragging();
|
||||
}
|
||||
|
||||
void GLGizmoRotate3D::on_dragging(const UpdateData &data)
|
||||
{
|
||||
assert(0 <= m_hover_id && m_hover_id < 3);
|
||||
m_gizmos[m_hover_id].dragging(data);
|
||||
}
|
||||
|
||||
void GLGizmoRotate3D::on_render()
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
namespace Slic3r {
|
||||
namespace GUI {
|
||||
|
||||
class Selection;
|
||||
class GLGizmoRotate : public GLGizmoBase
|
||||
{
|
||||
static const float Offset;
|
||||
|
@ -20,9 +20,9 @@ class GLGizmoRotate : public GLGizmoBase
|
|||
public:
|
||||
enum Axis : unsigned char
|
||||
{
|
||||
X,
|
||||
Y,
|
||||
Z
|
||||
X=0,
|
||||
Y=1,
|
||||
Z=2
|
||||
};
|
||||
|
||||
private:
|
||||
|
@ -56,6 +56,8 @@ private:
|
|||
float m_old_hover_radius{ 0.0f };
|
||||
#endif // ENABLE_GLBEGIN_GLEND_REMOVAL
|
||||
|
||||
ColorRGBA m_drag_color;
|
||||
ColorRGBA m_highlight_color;
|
||||
public:
|
||||
GLGizmoRotate(GLCanvas3D& parent, Axis axis);
|
||||
virtual ~GLGizmoRotate() = default;
|
||||
|
@ -65,11 +67,27 @@ public:
|
|||
|
||||
std::string get_tooltip() const override;
|
||||
|
||||
void start_dragging();
|
||||
void stop_dragging();
|
||||
|
||||
void enable_grabber();
|
||||
void disable_grabber();
|
||||
|
||||
void set_highlight_color(const ColorRGBA &color);
|
||||
|
||||
/// <summary>
|
||||
/// Postpone to Grabber for move
|
||||
/// Detect move of object by dragging
|
||||
/// </summary>
|
||||
/// <param name="mouse_event">Keep information about mouse click</param>
|
||||
/// <returns>Return True when use the information otherwise False.</returns>
|
||||
bool on_mouse(const wxMouseEvent &mouse_event) override;
|
||||
void dragging(const UpdateData &data);
|
||||
protected:
|
||||
bool on_init() override;
|
||||
std::string on_get_name() const override { return ""; }
|
||||
void on_start_dragging() override;
|
||||
void on_update(const UpdateData& data) override;
|
||||
void on_dragging(const UpdateData &data) override;
|
||||
void on_render() override;
|
||||
void on_render_for_picking() override;
|
||||
|
||||
|
@ -119,6 +137,14 @@ public:
|
|||
return tooltip;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Postpone to Rotation
|
||||
/// </summary>
|
||||
/// <param name="mouse_event">Keep information about mouse click</param>
|
||||
/// <returns>Return True when use the information otherwise False.</returns>
|
||||
bool on_mouse(const wxMouseEvent &mouse_event) override;
|
||||
|
||||
void data_changed() override;
|
||||
protected:
|
||||
bool on_init() override;
|
||||
std::string on_get_name() const override;
|
||||
|
@ -132,20 +158,17 @@ protected:
|
|||
}
|
||||
void on_enable_grabber(unsigned int id) override {
|
||||
if (id < 3)
|
||||
m_gizmos[id].enable_grabber(0);
|
||||
m_gizmos[id].enable_grabber();
|
||||
}
|
||||
void on_disable_grabber(unsigned int id) override {
|
||||
if (id < 3)
|
||||
m_gizmos[id].disable_grabber(0);
|
||||
m_gizmos[id].disable_grabber();
|
||||
}
|
||||
bool on_is_activable() const override;
|
||||
void on_start_dragging() override;
|
||||
void on_stop_dragging() override;
|
||||
void on_update(const UpdateData& data) override {
|
||||
for (GLGizmoRotate& g : m_gizmos) {
|
||||
g.update(data);
|
||||
}
|
||||
}
|
||||
void on_dragging(const UpdateData &data) override;
|
||||
|
||||
void on_render() override;
|
||||
void on_render_for_picking() override {
|
||||
for (GLGizmoRotate& g : m_gizmos) {
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
|
||||
#include <GL/glew.h>
|
||||
|
||||
#include <wx/utils.h>
|
||||
#include <wx/utils.h>
|
||||
|
||||
namespace Slic3r {
|
||||
namespace GUI {
|
||||
|
@ -18,6 +18,12 @@ const double GLGizmoScale3D::Offset = 5.0;
|
|||
|
||||
GLGizmoScale3D::GLGizmoScale3D(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id)
|
||||
: GLGizmoBase(parent, icon_filename, sprite_id)
|
||||
, m_scale(Vec3d::Ones())
|
||||
, m_offset(Vec3d::Zero())
|
||||
, m_snap_step(0.05)
|
||||
, m_base_color(DEFAULT_BASE_COLOR)
|
||||
, m_drag_color(DEFAULT_DRAG_COLOR)
|
||||
, m_highlight_color(DEFAULT_HIGHLIGHT_COLOR)
|
||||
{
|
||||
#if ENABLE_GLBEGIN_GLEND_REMOVAL
|
||||
m_grabber_connections[0].grabber_indices = { 0, 1 };
|
||||
|
@ -62,6 +68,84 @@ std::string GLGizmoScale3D::get_tooltip() const
|
|||
return "";
|
||||
}
|
||||
|
||||
bool GLGizmoScale3D::on_mouse(const wxMouseEvent &mouse_event)
|
||||
{
|
||||
if (mouse_event.Dragging()) {
|
||||
if (m_dragging) {
|
||||
#if ENABLE_WORLD_COORDINATE_SCALE_REVISITED
|
||||
int res = 1;
|
||||
if (m_scale.x() != m_scale.y() || m_scale.x() != m_scale.z())
|
||||
res = m_parent.get_selection().bake_transform_if_needed();
|
||||
|
||||
if (res != 1) {
|
||||
do_stop_dragging(true);
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
#endif // ENABLE_WORLD_COORDINATE_SCALE_REVISITED
|
||||
// Apply new temporary scale factors
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
TransformationType transformation_type;
|
||||
if (!wxGetApp().obj_manipul()->is_world_coordinates())
|
||||
transformation_type.set_local();
|
||||
#else
|
||||
TransformationType transformation_type(TransformationType::Local_Absolute_Joint);
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
if (mouse_event.AltDown()) transformation_type.set_independent();
|
||||
|
||||
Selection &selection = m_parent.get_selection();
|
||||
selection.scale(m_scale, transformation_type);
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
if (mouse_event.CmdDown()) selection.translate(m_offset, wxGetApp().obj_manipul()->get_coordinates_type());
|
||||
#else
|
||||
if (mouse_event.CmdDown()) selection.translate(m_offset, true);
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
#if ENABLE_WORLD_COORDINATE_SCALE_REVISITED
|
||||
}
|
||||
#endif // ENABLE_WORLD_COORDINATE_SCALE_REVISITED
|
||||
}
|
||||
}
|
||||
return use_grabbers(mouse_event);
|
||||
}
|
||||
|
||||
void GLGizmoScale3D::data_changed()
|
||||
{
|
||||
const Selection &selection = m_parent.get_selection();
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
#if !ENABLE_WORLD_COORDINATE_SCALE_REVISITED
|
||||
bool enable_scale_xyz = !selection.requires_uniform_scale();
|
||||
#endif // !ENABLE_WORLD_COORDINATE_SCALE_REVISITED
|
||||
#else
|
||||
bool enable_scale_xyz = selection.is_single_full_instance() ||
|
||||
selection.is_single_volume() ||
|
||||
selection.is_single_modifier();
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
#if ENABLE_WORLD_COORDINATE_SCALE_REVISITED
|
||||
if (selection.is_single_full_instance() || selection.is_single_volume_or_modifier()) {
|
||||
#else
|
||||
for (unsigned int i = 0; i < 6; ++i)
|
||||
m_grabbers[i].enabled = enable_scale_xyz;
|
||||
|
||||
if (enable_scale_xyz) {
|
||||
#endif // ENABLE_WORLD_COORDINATE_SCALE_REVISITED
|
||||
|
||||
// all volumes in the selection belongs to the same instance, any of
|
||||
// them contains the needed data, so we take the first
|
||||
const GLVolume *volume = selection.get_volume(*selection.get_volume_idxs().begin());
|
||||
if (selection.is_single_full_instance())
|
||||
set_scale(volume->get_instance_scaling_factor());
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
else if (selection.is_single_volume_or_modifier())
|
||||
#else
|
||||
else if (selection.is_single_volume() ||
|
||||
selection.is_single_modifier())
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
set_scale(volume->get_volume_scaling_factor());
|
||||
}
|
||||
else
|
||||
set_scale(Vec3d::Ones());
|
||||
}
|
||||
|
||||
bool GLGizmoScale3D::on_init()
|
||||
{
|
||||
for (int i = 0; i < 10; ++i) {
|
||||
|
@ -98,29 +182,32 @@ bool GLGizmoScale3D::on_is_activable() const
|
|||
|
||||
void GLGizmoScale3D::on_start_dragging()
|
||||
{
|
||||
if (m_hover_id != -1) {
|
||||
m_starting.ctrl_down = wxGetKeyState(WXK_CONTROL);
|
||||
assert(m_hover_id != -1);
|
||||
m_starting.ctrl_down = wxGetKeyState(WXK_CONTROL);
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
m_starting.drag_position = m_grabbers_transform * m_grabbers[m_hover_id].center;
|
||||
m_starting.box = m_bounding_box;
|
||||
m_starting.center = m_center;
|
||||
m_starting.instance_center = m_instance_center;
|
||||
m_starting.drag_position = m_grabbers_transform * m_grabbers[m_hover_id].center;
|
||||
m_starting.box = m_bounding_box;
|
||||
m_starting.center = m_center;
|
||||
m_starting.instance_center = m_instance_center;
|
||||
#else
|
||||
m_starting.drag_position = m_grabbers[m_hover_id].center;
|
||||
m_starting.box = (m_starting.ctrl_down && m_hover_id < 6) ? m_bounding_box : m_parent.get_selection().get_bounding_box();
|
||||
m_starting.drag_position = m_grabbers[m_hover_id].center;
|
||||
m_starting.box = (m_starting.ctrl_down && m_hover_id < 6) ? m_box : m_parent.get_selection().get_bounding_box();
|
||||
|
||||
const Vec3d& center = m_starting.box.center();
|
||||
m_starting.pivots[0] = m_transform * Vec3d(m_starting.box.max.x(), center.y(), center.z());
|
||||
m_starting.pivots[1] = m_transform * Vec3d(m_starting.box.min.x(), center.y(), center.z());
|
||||
m_starting.pivots[2] = m_transform * Vec3d(center.x(), m_starting.box.max.y(), center.z());
|
||||
m_starting.pivots[3] = m_transform * Vec3d(center.x(), m_starting.box.min.y(), center.z());
|
||||
m_starting.pivots[4] = m_transform * Vec3d(center.x(), center.y(), m_starting.box.max.z());
|
||||
m_starting.pivots[5] = m_transform * Vec3d(center.x(), center.y(), m_starting.box.min.z());
|
||||
const Vec3d& center = m_starting.box.center();
|
||||
m_starting.pivots[0] = m_transform * Vec3d(m_starting.box.max.x(), center.y(), center.z());
|
||||
m_starting.pivots[1] = m_transform * Vec3d(m_starting.box.min.x(), center.y(), center.z());
|
||||
m_starting.pivots[2] = m_transform * Vec3d(center.x(), m_starting.box.max.y(), center.z());
|
||||
m_starting.pivots[3] = m_transform * Vec3d(center.x(), m_starting.box.min.y(), center.z());
|
||||
m_starting.pivots[4] = m_transform * Vec3d(center.x(), center.y(), m_starting.box.max.z());
|
||||
m_starting.pivots[5] = m_transform * Vec3d(center.x(), center.y(), m_starting.box.min.z());
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
}
|
||||
}
|
||||
|
||||
void GLGizmoScale3D::on_update(const UpdateData& data)
|
||||
void GLGizmoScale3D::on_stop_dragging() {
|
||||
m_parent.do_scale(L("Gizmo-Scale"));
|
||||
}
|
||||
|
||||
void GLGizmoScale3D::on_dragging(const UpdateData& data)
|
||||
{
|
||||
if (m_hover_id == 0 || m_hover_id == 1)
|
||||
do_scale_along_axis(X, data);
|
||||
|
@ -144,12 +231,7 @@ void GLGizmoScale3D::on_render()
|
|||
m_grabbers_transform = Transform3d::Identity();
|
||||
m_center = Vec3d::Zero();
|
||||
m_instance_center = Vec3d::Zero();
|
||||
#if ENABLE_INSTANCE_COORDINATES_FOR_VOLUMES
|
||||
if (selection.is_single_full_instance() && !wxGetApp().obj_manipul()->is_world_coordinates()) {
|
||||
#else
|
||||
bool world_coordinates = wxGetApp().obj_manipul()->get_world_coordinates();
|
||||
if (selection.is_single_full_instance() && !world_coordinates) {
|
||||
#endif // ENABLE_INSTANCE_COORDINATES_FOR_VOLUMES
|
||||
#else
|
||||
m_transform = Transform3d::Identity();
|
||||
// Transforms grabbers' offsets to world refefence system
|
||||
|
@ -180,6 +262,8 @@ void GLGizmoScale3D::on_render()
|
|||
m_grabbers_transform = v.get_instance_transformation().get_matrix(false, false, true) * Geometry::assemble_transform(m_bounding_box.center());
|
||||
m_center = selection.get_volume(*idxs.begin())->get_instance_transformation().get_matrix(false, false, true, false) * m_bounding_box.center();
|
||||
m_instance_center = v.get_instance_offset();
|
||||
}
|
||||
else if (selection.is_single_volume_or_modifier() && wxGetApp().obj_manipul()->is_instance_coordinates()) {
|
||||
#else
|
||||
m_transform = v.get_instance_transformation().get_matrix();
|
||||
|
||||
|
@ -188,32 +272,18 @@ void GLGizmoScale3D::on_render()
|
|||
// consider rotation+mirror only components of the transform for offsets
|
||||
offsets_transform = Geometry::assemble_transform(Vec3d::Zero(), angles, Vec3d::Ones(), v.get_instance_mirror());
|
||||
m_offsets_transform = offsets_transform;
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
}
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
#if ENABLE_INSTANCE_COORDINATES_FOR_VOLUMES
|
||||
else if (selection.is_single_volume_or_modifier() && wxGetApp().obj_manipul()->is_instance_coordinates()) {
|
||||
#else
|
||||
else if (selection.is_single_volume_or_modifier() && !world_coordinates) {
|
||||
#endif // ENABLE_INSTANCE_COORDINATES_FOR_VOLUMES
|
||||
#else
|
||||
else if (selection.is_single_modifier() || selection.is_single_volume()) {
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
const GLVolume& v = *selection.get_volume(*selection.get_volume_idxs().begin());
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
#if ENABLE_INSTANCE_COORDINATES_FOR_VOLUMES
|
||||
m_bounding_box.merge(v.transformed_convex_hull_bounding_box(v.get_instance_transformation().get_matrix(true, true, false, true) * v.get_volume_transformation().get_matrix(true, false, false, true)));
|
||||
Geometry::Transformation trafo(v.get_instance_transformation().get_matrix(true, false, true, true));
|
||||
#else
|
||||
m_bounding_box.merge(v.transformed_convex_hull_bounding_box(v.get_instance_transformation().get_matrix(true, true, false, true) * v.get_volume_transformation().get_matrix(true, true, false, true)));
|
||||
Geometry::Transformation trafo(v.get_instance_transformation().get_matrix(true, false, true) * v.get_volume_transformation().get_matrix(true, false, true));
|
||||
#endif // ENABLE_INSTANCE_COORDINATES_FOR_VOLUMES
|
||||
trafo.set_offset(v.world_matrix().translation());
|
||||
m_grabbers_transform = trafo.get_matrix();
|
||||
m_center = v.world_matrix() * m_bounding_box.center();
|
||||
m_instance_center = m_center;
|
||||
}
|
||||
#if ENABLE_INSTANCE_COORDINATES_FOR_VOLUMES
|
||||
else if (selection.is_single_volume_or_modifier() && wxGetApp().obj_manipul()->is_local_coordinates()) {
|
||||
const GLVolume& v = *selection.get_volume(*selection.get_volume_idxs().begin());
|
||||
m_bounding_box.merge(v.transformed_convex_hull_bounding_box(v.get_instance_transformation().get_matrix(true, true, false, true) * v.get_volume_transformation().get_matrix(true, true, false, true)));
|
||||
|
@ -223,7 +293,6 @@ void GLGizmoScale3D::on_render()
|
|||
m_center = v.world_matrix() * m_bounding_box.center();
|
||||
m_instance_center = m_center;
|
||||
}
|
||||
#endif // ENABLE_INSTANCE_COORDINATES_FOR_VOLUMES
|
||||
else {
|
||||
m_bounding_box = selection.get_bounding_box();
|
||||
m_grabbers_transform = Geometry::assemble_transform(m_bounding_box.center());
|
||||
|
@ -568,13 +637,8 @@ void GLGizmoScale3D::do_scale_along_axis(Axis axis, const UpdateData& data)
|
|||
Vec3d curr_scale = m_scale;
|
||||
Vec3d starting_scale = m_starting.scale;
|
||||
const Selection& selection = m_parent.get_selection();
|
||||
#if ENABLE_INSTANCE_COORDINATES_FOR_VOLUMES
|
||||
const ECoordinatesType coordinates_type = wxGetApp().obj_manipul()->get_coordinates_type();
|
||||
if (coordinates_type == ECoordinatesType::World) {
|
||||
#else
|
||||
const bool world_coordinates = wxGetApp().obj_manipul()->get_world_coordinates();
|
||||
if (world_coordinates) {
|
||||
#endif // ENABLE_INSTANCE_COORDINATES_FOR_VOLUMES
|
||||
if (selection.is_single_full_instance()) {
|
||||
const Transform3d m = Geometry::assemble_transform(Vec3d::Zero(), selection.get_volume(*selection.get_volume_idxs().begin())->get_instance_rotation());
|
||||
curr_scale = (m * curr_scale).cwiseAbs();
|
||||
|
@ -591,11 +655,7 @@ void GLGizmoScale3D::do_scale_along_axis(Axis axis, const UpdateData& data)
|
|||
|
||||
curr_scale(axis) = starting_scale(axis) * ratio;
|
||||
|
||||
#if ENABLE_INSTANCE_COORDINATES_FOR_VOLUMES
|
||||
if (coordinates_type == ECoordinatesType::World) {
|
||||
#else
|
||||
if (world_coordinates) {
|
||||
#endif // ENABLE_INSTANCE_COORDINATES_FOR_VOLUMES
|
||||
if (selection.is_single_full_instance())
|
||||
m_scale = (Geometry::assemble_transform(Vec3d::Zero(), selection.get_volume(*selection.get_volume_idxs().begin())->get_instance_rotation()).inverse() * curr_scale).cwiseAbs();
|
||||
else if (selection.is_single_volume_or_modifier()) {
|
||||
|
@ -625,11 +685,7 @@ void GLGizmoScale3D::do_scale_along_axis(Axis axis, const UpdateData& data)
|
|||
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
Vec3d center_offset = m_starting.instance_center - m_starting.center;
|
||||
#if ENABLE_INSTANCE_COORDINATES_FOR_VOLUMES
|
||||
if (selection.is_single_full_instance() && coordinates_type != ECoordinatesType::World) {
|
||||
#else
|
||||
if (selection.is_single_full_instance() && !world_coordinates) {
|
||||
#endif // ENABLE_INSTANCE_COORDINATES_FOR_VOLUMES
|
||||
const Transform3d m = Geometry::assemble_transform(Vec3d::Zero(), selection.get_volume(*selection.get_volume_idxs().begin())->get_instance_rotation()).inverse();
|
||||
center_offset = m * center_offset;
|
||||
}
|
||||
|
@ -643,14 +699,6 @@ void GLGizmoScale3D::do_scale_along_axis(Axis axis, const UpdateData& data)
|
|||
case Z: { m_offset = local_offset * Vec3d::UnitZ(); break; }
|
||||
default: { m_offset = Vec3d::Zero(); break; }
|
||||
}
|
||||
|
||||
#if !ENABLE_INSTANCE_COORDINATES_FOR_VOLUMES
|
||||
if (selection.is_single_volume_or_modifier() && !world_coordinates) {
|
||||
const Transform3d mv = Geometry::assemble_transform(Vec3d::Zero(), selection.get_volume(*selection.get_volume_idxs().begin())->get_volume_rotation());
|
||||
const Transform3d mi = Geometry::assemble_transform(Vec3d::Zero(), Vec3d::Zero(), selection.get_volume(*selection.get_volume_idxs().begin())->get_instance_scaling_factor()).inverse();
|
||||
m_offset = mv * mi * m_offset;
|
||||
}
|
||||
#endif // !ENABLE_INSTANCE_COORDINATES_FOR_VOLUMES
|
||||
#else
|
||||
Vec3d local_offset_vec;
|
||||
switch (axis)
|
||||
|
@ -684,29 +732,14 @@ void GLGizmoScale3D::do_scale_uniform(const UpdateData& data)
|
|||
m_offset.y() *= -1.0;
|
||||
|
||||
const Selection& selection = m_parent.get_selection();
|
||||
#if !ENABLE_INSTANCE_COORDINATES_FOR_VOLUMES
|
||||
const bool world_coordinates = wxGetApp().obj_manipul()->get_world_coordinates();
|
||||
#endif // !ENABLE_INSTANCE_COORDINATES_FOR_VOLUMES
|
||||
Vec3d center_offset = m_starting.instance_center - m_starting.center;
|
||||
|
||||
#if ENABLE_INSTANCE_COORDINATES_FOR_VOLUMES
|
||||
if (selection.is_single_full_instance() && !wxGetApp().obj_manipul()->is_world_coordinates()) {
|
||||
#else
|
||||
if (selection.is_single_full_instance() && !world_coordinates) {
|
||||
#endif // ENABLE_INSTANCE_COORDINATES_FOR_VOLUMES
|
||||
const Transform3d m = Geometry::assemble_transform(Vec3d::Zero(), selection.get_volume(*selection.get_volume_idxs().begin())->get_instance_rotation()).inverse();
|
||||
center_offset = m * center_offset;
|
||||
}
|
||||
|
||||
m_offset += (ratio - 1.0) * center_offset;
|
||||
|
||||
#if !ENABLE_INSTANCE_COORDINATES_FOR_VOLUMES
|
||||
if (selection.is_single_volume_or_modifier() && !world_coordinates) {
|
||||
const Transform3d mv = Geometry::assemble_transform(Vec3d::Zero(), selection.get_volume(*selection.get_volume_idxs().begin())->get_volume_rotation());
|
||||
const Transform3d mi = Geometry::assemble_transform(Vec3d::Zero(), Vec3d::Zero(), selection.get_volume(*selection.get_volume_idxs().begin())->get_instance_scaling_factor()).inverse();
|
||||
m_offset = mv * mi * m_offset;
|
||||
}
|
||||
#endif // !ENABLE_INSTANCE_COORDINATES_FOR_VOLUMES
|
||||
}
|
||||
else
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
@ -754,17 +787,9 @@ void GLGizmoScale3D::transform_to_local(const Selection& selection) const
|
|||
{
|
||||
glsafe(::glTranslated(m_center.x(), m_center.y(), m_center.z()));
|
||||
|
||||
#if ENABLE_INSTANCE_COORDINATES_FOR_VOLUMES
|
||||
if (!wxGetApp().obj_manipul()->is_world_coordinates()) {
|
||||
#else
|
||||
if (!wxGetApp().obj_manipul()->get_world_coordinates()) {
|
||||
#endif // ENABLE_INSTANCE_COORDINATES_FOR_VOLUMES
|
||||
Transform3d orient_matrix = selection.get_volume(*selection.get_volume_idxs().begin())->get_instance_transformation().get_matrix(true, false, true, true);
|
||||
#if ENABLE_INSTANCE_COORDINATES_FOR_VOLUMES
|
||||
if (selection.is_single_volume_or_modifier() && wxGetApp().obj_manipul()->is_local_coordinates())
|
||||
#else
|
||||
if (selection.is_single_volume_or_modifier())
|
||||
#endif // ENABLE_INSTANCE_COORDINATES_FOR_VOLUMES
|
||||
orient_matrix = orient_matrix * selection.get_volume(*selection.get_volume_idxs().begin())->get_volume_transformation().get_matrix(true, false, true, true);
|
||||
glsafe(::glMultMatrixd(orient_matrix.data()));
|
||||
}
|
||||
|
|
|
@ -3,11 +3,17 @@
|
|||
|
||||
#include "GLGizmoBase.hpp"
|
||||
|
||||
#if !ENABLE_WORLD_COORDINATE
|
||||
#include "libslic3r/BoundingBox.hpp"
|
||||
#endif // !ENABLE_WORLD_COORDINATE
|
||||
|
||||
namespace Slic3r {
|
||||
namespace GUI {
|
||||
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
class Selection;
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
||||
class GLGizmoScale3D : public GLGizmoBase
|
||||
{
|
||||
static const double Offset;
|
||||
|
@ -53,6 +59,9 @@ class GLGizmoScale3D : public GLGizmoBase
|
|||
std::array<GrabberConnection, 7> m_grabber_connections;
|
||||
#endif // ENABLE_GLBEGIN_GLEND_REMOVAL
|
||||
|
||||
ColorRGBA m_base_color;
|
||||
ColorRGBA m_drag_color;
|
||||
ColorRGBA m_highlight_color;
|
||||
public:
|
||||
GLGizmoScale3D(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id);
|
||||
|
||||
|
@ -62,16 +71,23 @@ public:
|
|||
const Vec3d& get_scale() const { return m_scale; }
|
||||
void set_scale(const Vec3d& scale) { m_starting.scale = scale; m_scale = scale; }
|
||||
|
||||
const Vec3d& get_offset() const { return m_offset; }
|
||||
|
||||
std::string get_tooltip() const override;
|
||||
|
||||
/// <summary>
|
||||
/// Postpone to Grabber for scale
|
||||
/// </summary>
|
||||
/// <param name="mouse_event">Keep information about mouse click</param>
|
||||
/// <returns>Return True when use the information otherwise False.</returns>
|
||||
bool on_mouse(const wxMouseEvent &mouse_event) override;
|
||||
|
||||
void data_changed() override;
|
||||
protected:
|
||||
virtual bool on_init() override;
|
||||
virtual std::string on_get_name() const override;
|
||||
virtual bool on_is_activable() const override;
|
||||
virtual void on_start_dragging() override;
|
||||
virtual void on_update(const UpdateData& data) override;
|
||||
virtual void on_stop_dragging() override;
|
||||
virtual void on_dragging(const UpdateData& data) override;
|
||||
virtual void on_render() override;
|
||||
virtual void on_render_for_picking() override;
|
||||
|
||||
|
|
|
@ -28,9 +28,7 @@ namespace GUI {
|
|||
|
||||
GLGizmoSlaSupports::GLGizmoSlaSupports(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id)
|
||||
: GLGizmoBase(parent, icon_filename, sprite_id)
|
||||
{
|
||||
}
|
||||
|
||||
{}
|
||||
|
||||
bool GLGizmoSlaSupports::on_init()
|
||||
{
|
||||
|
@ -48,11 +46,15 @@ bool GLGizmoSlaSupports::on_init()
|
|||
m_desc["manual_editing"] = _L("Manual editing");
|
||||
m_desc["clipping_of_view"] = _L("Clipping of view")+ ": ";
|
||||
m_desc["reset_direction"] = _L("Reset direction");
|
||||
|
||||
m_cone.init_from(its_make_cone(1., 1., 2 * PI / 24));
|
||||
m_cylinder.init_from(its_make_cylinder(1., 1., 2 * PI / 24.));
|
||||
m_sphere.init_from(its_make_sphere(1., (2 * M_PI) / 24.));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void GLGizmoSlaSupports::set_sla_support_data(ModelObject* model_object, const Selection& selection)
|
||||
void GLGizmoSlaSupports::data_changed()
|
||||
{
|
||||
if (! m_c->selection_info())
|
||||
return;
|
||||
|
@ -553,22 +555,6 @@ void GLGizmoSlaSupports::delete_selected_points(bool force)
|
|||
select_point(NoPoints);
|
||||
}
|
||||
|
||||
void GLGizmoSlaSupports::on_update(const UpdateData& data)
|
||||
{
|
||||
if (! m_editing_mode)
|
||||
return;
|
||||
else {
|
||||
if (m_hover_id != -1 && (! m_editing_cache[m_hover_id].support_point.is_new_island || !m_lock_unique_islands)) {
|
||||
std::pair<Vec3f, Vec3f> pos_and_normal;
|
||||
if (! unproject_on_mesh(data.mouse_pos.cast<double>(), pos_and_normal))
|
||||
return;
|
||||
m_editing_cache[m_hover_id].support_point.pos = pos_and_normal.first;
|
||||
m_editing_cache[m_hover_id].support_point.is_new_island = false;
|
||||
m_editing_cache[m_hover_id].normal = pos_and_normal.second;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<const ConfigOption*> GLGizmoSlaSupports::get_config_options(const std::vector<std::string>& keys) const
|
||||
{
|
||||
std::vector<const ConfigOption*> out;
|
||||
|
@ -985,7 +971,21 @@ void GLGizmoSlaSupports::on_stop_dragging()
|
|||
m_point_before_drag = CacheEntry();
|
||||
}
|
||||
|
||||
void GLGizmoSlaSupports::on_dragging(const UpdateData &data)
|
||||
{
|
||||
assert(m_hover_id != -1);
|
||||
if (!m_editing_mode) return;
|
||||
if (m_editing_cache[m_hover_id].support_point.is_new_island && m_lock_unique_islands)
|
||||
return;
|
||||
|
||||
std::pair<Vec3f, Vec3f> pos_and_normal;
|
||||
if (!unproject_on_mesh(data.mouse_pos.cast<double>(), pos_and_normal))
|
||||
return;
|
||||
|
||||
m_editing_cache[m_hover_id].support_point.pos = pos_and_normal.first;
|
||||
m_editing_cache[m_hover_id].support_point.is_new_island = false;
|
||||
m_editing_cache[m_hover_id].normal = pos_and_normal.second;
|
||||
}
|
||||
|
||||
void GLGizmoSlaSupports::on_load(cereal::BinaryInputArchive& ar)
|
||||
{
|
||||
|
@ -1122,6 +1122,61 @@ void GLGizmoSlaSupports::reslice_SLA_supports(bool postpone_error_messages) cons
|
|||
});
|
||||
}
|
||||
|
||||
bool GLGizmoSlaSupports::on_mouse(const wxMouseEvent &mouse_event){
|
||||
if (mouse_event.Moving()) return false;
|
||||
if (use_grabbers(mouse_event)) return true;
|
||||
|
||||
// wxCoord == int --> wx/types.h
|
||||
Vec2i mouse_coord(mouse_event.GetX(), mouse_event.GetY());
|
||||
Vec2d mouse_pos = mouse_coord.cast<double>();
|
||||
|
||||
static bool pending_right_up = false;
|
||||
if (mouse_event.LeftDown()) {
|
||||
bool grabber_contains_mouse = (get_hover_id() != -1);
|
||||
bool control_down = mouse_event.CmdDown();
|
||||
if ((!control_down || grabber_contains_mouse) &&
|
||||
gizmo_event(SLAGizmoEventType::LeftDown, mouse_pos, mouse_event.ShiftDown(), mouse_event.AltDown(), false))
|
||||
return true;
|
||||
} else if (mouse_event.Dragging()) {
|
||||
bool control_down = mouse_event.CmdDown();
|
||||
if (m_parent.get_move_volume_id() != -1) {
|
||||
// don't allow dragging objects with the Sla gizmo on
|
||||
return true;
|
||||
} else if (!control_down &&
|
||||
gizmo_event(SLAGizmoEventType::Dragging, mouse_pos, mouse_event.ShiftDown(), mouse_event.AltDown(), false)) {
|
||||
// the gizmo got the event and took some action, no need to do
|
||||
// anything more here
|
||||
m_parent.set_as_dirty();
|
||||
return true;
|
||||
} else if (control_down && (mouse_event.LeftIsDown() || mouse_event.RightIsDown())){
|
||||
// CTRL has been pressed while already dragging -> stop current action
|
||||
if (mouse_event.LeftIsDown())
|
||||
gizmo_event(SLAGizmoEventType::LeftUp, mouse_pos, mouse_event.ShiftDown(), mouse_event.AltDown(), true);
|
||||
else if (mouse_event.RightIsDown())
|
||||
pending_right_up = false;
|
||||
}
|
||||
} else if (mouse_event.LeftUp() && !m_parent.is_mouse_dragging()) {
|
||||
// in case SLA/FDM gizmo is selected, we just pass the LeftUp event
|
||||
// and stop processing - neither object moving or selecting is
|
||||
// suppressed in that case
|
||||
gizmo_event(SLAGizmoEventType::LeftUp, mouse_pos, mouse_event.ShiftDown(), mouse_event.AltDown(), mouse_event.CmdDown());
|
||||
return true;
|
||||
}else if (mouse_event.RightDown()){
|
||||
if (m_parent.get_selection().get_object_idx() != -1 &&
|
||||
gizmo_event(SLAGizmoEventType::RightDown, mouse_pos, false, false, false)) {
|
||||
// we need to set the following right up as processed to avoid showing
|
||||
// the context menu if the user release the mouse over the object
|
||||
pending_right_up = true;
|
||||
// event was taken care of by the SlaSupports gizmo
|
||||
return true;
|
||||
}
|
||||
} else if (pending_right_up && mouse_event.RightUp()) {
|
||||
pending_right_up = false;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void GLGizmoSlaSupports::get_data_from_backend()
|
||||
{
|
||||
if (! has_backend_supports())
|
||||
|
|
|
@ -16,7 +16,7 @@ namespace Slic3r {
|
|||
class ConfigOption;
|
||||
|
||||
namespace GUI {
|
||||
|
||||
class Selection;
|
||||
enum class SLAGizmoEventType : unsigned char;
|
||||
|
||||
class GLGizmoSlaSupports : public GLGizmoBase
|
||||
|
@ -57,7 +57,7 @@ private:
|
|||
public:
|
||||
GLGizmoSlaSupports(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id);
|
||||
virtual ~GLGizmoSlaSupports() = default;
|
||||
void set_sla_support_data(ModelObject* model_object, const Selection& selection);
|
||||
void data_changed() override;
|
||||
bool gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_position, bool shift_down, bool alt_down, bool control_down);
|
||||
void delete_selected_points(bool force = false);
|
||||
//ClippingPlane get_sla_clipping_plane() const;
|
||||
|
@ -70,10 +70,15 @@ public:
|
|||
bool wants_enter_leave_snapshots() const override { return true; }
|
||||
std::string get_gizmo_entering_text() const override { return _u8L("Entering SLA support points"); }
|
||||
std::string get_gizmo_leaving_text() const override { return _u8L("Leaving SLA support points"); }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Process mouse event
|
||||
/// </summary>
|
||||
/// <param name="mouse_event">Keep information about mouse click</param>
|
||||
/// <returns>Return True when use the information otherwise False.</returns>
|
||||
bool on_mouse(const wxMouseEvent &mouse_event) override;
|
||||
private:
|
||||
bool on_init() override;
|
||||
void on_update(const UpdateData& data) override;
|
||||
void on_render() override;
|
||||
void on_render_for_picking() override;
|
||||
|
||||
|
@ -107,7 +112,6 @@ private:
|
|||
|
||||
std::vector<const ConfigOption*> get_config_options(const std::vector<std::string>& keys) const;
|
||||
bool is_mesh_point_clipped(const Vec3d& point) const;
|
||||
bool is_point_in_hole(const Vec3f& pt) const;
|
||||
//void find_intersecting_facets(const igl::AABB<Eigen::MatrixXf, 3>* aabb, const Vec3f& normal, double offset, std::vector<unsigned int>& out) const;
|
||||
|
||||
// Methods that do the model_object and editing cache synchronization,
|
||||
|
@ -130,13 +134,13 @@ private:
|
|||
protected:
|
||||
void on_set_state() override;
|
||||
void on_set_hover_id() override
|
||||
|
||||
{
|
||||
if (! m_editing_mode || (int)m_editing_cache.size() <= m_hover_id)
|
||||
m_hover_id = -1;
|
||||
}
|
||||
void on_start_dragging() override;
|
||||
void on_stop_dragging() override;
|
||||
void on_dragging(const UpdateData &data) override;
|
||||
void on_render_input_window(float x, float y, float bottom_limit) override;
|
||||
|
||||
std::string on_get_name() const override;
|
||||
|
|
|
@ -39,6 +39,7 @@ GLGizmosManager::GLGizmosManager(GLCanvas3D& parent)
|
|||
, m_enabled(false)
|
||||
, m_icons_texture_dirty(true)
|
||||
, m_current(Undefined)
|
||||
, m_hover(Undefined)
|
||||
, m_tooltip("")
|
||||
, m_serializing(false)
|
||||
{
|
||||
|
@ -47,33 +48,34 @@ GLGizmosManager::GLGizmosManager(GLCanvas3D& parent)
|
|||
std::vector<size_t> GLGizmosManager::get_selectable_idxs() const
|
||||
{
|
||||
std::vector<size_t> out;
|
||||
out.reserve(m_gizmos.size());
|
||||
for (size_t i=0; i<m_gizmos.size(); ++i)
|
||||
if (m_gizmos[i]->is_selectable())
|
||||
out.push_back(i);
|
||||
return out;
|
||||
}
|
||||
|
||||
size_t GLGizmosManager::get_gizmo_idx_from_mouse(const Vec2d& mouse_pos) const
|
||||
GLGizmosManager::EType GLGizmosManager::get_gizmo_from_mouse(const Vec2d &mouse_pos) const
|
||||
{
|
||||
if (! m_enabled)
|
||||
return Undefined;
|
||||
if (!m_enabled) return Undefined;
|
||||
|
||||
float cnv_h = (float)m_parent.get_canvas_size().get_height();
|
||||
float height = get_scaled_total_height();
|
||||
float cnv_h = (float) m_parent.get_canvas_size().get_height();
|
||||
float height = get_scaled_total_height();
|
||||
float icons_size = m_layout.scaled_icons_size();
|
||||
float border = m_layout.scaled_border();
|
||||
float stride_y = m_layout.scaled_stride_y();
|
||||
float top_y = 0.5f * (cnv_h - height) + border;
|
||||
float border = m_layout.scaled_border();
|
||||
float stride_y = m_layout.scaled_stride_y();
|
||||
float top_y = 0.5f * (cnv_h - height) + border;
|
||||
|
||||
// is mouse horizontally in the area?
|
||||
if ((border <= (float)mouse_pos(0) && ((float)mouse_pos(0) <= border + icons_size))) {
|
||||
if ((border <= (float) mouse_pos(0) &&
|
||||
((float) mouse_pos(0) <= border + icons_size))) {
|
||||
// which icon is it on?
|
||||
size_t from_top = (size_t)((float)mouse_pos(1) - top_y) / stride_y;
|
||||
size_t from_top = (size_t) ((float) mouse_pos(1) - top_y) / stride_y;
|
||||
// is it really on the icon or already past the border?
|
||||
if ((float)mouse_pos(1) <= top_y + from_top * stride_y + icons_size) {
|
||||
if ((float) mouse_pos(1) <= top_y + from_top * stride_y + icons_size) {
|
||||
std::vector<size_t> selectable = get_selectable_idxs();
|
||||
if (from_top < selectable.size())
|
||||
return selectable[from_top];
|
||||
if (from_top < selectable.size())
|
||||
return static_cast<EType>(selectable[from_top]);
|
||||
}
|
||||
}
|
||||
return Undefined;
|
||||
|
@ -163,9 +165,9 @@ void GLGizmosManager::refresh_on_off_state()
|
|||
if (m_serializing || m_current == Undefined || m_gizmos.empty())
|
||||
return;
|
||||
|
||||
if (m_current != Undefined
|
||||
&& ! m_gizmos[m_current]->is_activable() && activate_gizmo(Undefined))
|
||||
update_data();
|
||||
// FS: Why update data after Undefined gizmo activation?
|
||||
if (!m_gizmos[m_current]->is_activable() && activate_gizmo(Undefined))
|
||||
update_data();
|
||||
}
|
||||
|
||||
void GLGizmosManager::reset_all_states()
|
||||
|
@ -179,9 +181,13 @@ void GLGizmosManager::reset_all_states()
|
|||
|
||||
bool GLGizmosManager::open_gizmo(EType type)
|
||||
{
|
||||
int idx = int(type);
|
||||
if (m_gizmos[idx]->is_activable()
|
||||
&& activate_gizmo(m_current == idx ? Undefined : (EType)idx)) {
|
||||
int idx = static_cast<int>(type);
|
||||
|
||||
// re-open same type cause closing
|
||||
if (m_current == type) type = Undefined;
|
||||
|
||||
if (m_gizmos[idx]->is_activable() && activate_gizmo(type)) {
|
||||
// remove update data into gizmo itself
|
||||
update_data();
|
||||
return true;
|
||||
}
|
||||
|
@ -210,90 +216,14 @@ void GLGizmosManager::set_hover_id(int id)
|
|||
m_gizmos[m_current]->set_hover_id(id);
|
||||
}
|
||||
|
||||
void GLGizmosManager::enable_grabber(EType type, unsigned int id, bool enable)
|
||||
{
|
||||
if (!m_enabled || type == Undefined || m_gizmos.empty())
|
||||
return;
|
||||
|
||||
if (enable)
|
||||
m_gizmos[type]->enable_grabber(id);
|
||||
else
|
||||
m_gizmos[type]->disable_grabber(id);
|
||||
}
|
||||
|
||||
void GLGizmosManager::update(const Linef3& mouse_ray, const Point& mouse_pos)
|
||||
{
|
||||
if (!m_enabled)
|
||||
return;
|
||||
|
||||
GLGizmoBase* curr = get_current();
|
||||
if (curr != nullptr)
|
||||
curr->update(GLGizmoBase::UpdateData(mouse_ray, mouse_pos));
|
||||
}
|
||||
|
||||
void GLGizmosManager::update_data()
|
||||
{
|
||||
if (!m_enabled)
|
||||
return;
|
||||
|
||||
const Selection& selection = m_parent.get_selection();
|
||||
|
||||
bool is_wipe_tower = selection.is_wipe_tower();
|
||||
enable_grabber(Move, 2, !is_wipe_tower);
|
||||
enable_grabber(Rotate, 0, !is_wipe_tower);
|
||||
enable_grabber(Rotate, 1, !is_wipe_tower);
|
||||
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
bool enable_scale_xyz = !selection.requires_uniform_scale();
|
||||
#else
|
||||
bool enable_scale_xyz = selection.is_single_full_instance() || selection.is_single_volume() || selection.is_single_modifier();
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
for (unsigned int i = 0; i < 6; ++i) {
|
||||
enable_grabber(Scale, i, enable_scale_xyz);
|
||||
}
|
||||
|
||||
if (!m_enabled) return;
|
||||
if (m_common_gizmos_data)
|
||||
m_common_gizmos_data->update(get_current()
|
||||
? get_current()->get_requirements()
|
||||
: CommonGizmosDataID(0));
|
||||
|
||||
if (selection.is_single_full_instance()) {
|
||||
// all volumes in the selection belongs to the same instance, any of them contains the needed data, so we take the first
|
||||
const GLVolume* volume = selection.get_volume(*selection.get_volume_idxs().begin());
|
||||
set_scale(volume->get_instance_scaling_factor());
|
||||
set_rotation(Vec3d::Zero());
|
||||
ModelObject* model_object = selection.get_model()->objects[selection.get_object_idx()];
|
||||
set_flattening_data(model_object);
|
||||
set_sla_support_data(model_object);
|
||||
set_painter_gizmo_data();
|
||||
}
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
else if (selection.is_single_volume_or_modifier()) {
|
||||
#else
|
||||
else if (selection.is_single_volume() || selection.is_single_modifier()) {
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
const GLVolume* volume = selection.get_volume(*selection.get_volume_idxs().begin());
|
||||
set_scale(volume->get_volume_scaling_factor());
|
||||
set_rotation(Vec3d::Zero());
|
||||
set_flattening_data(nullptr);
|
||||
set_sla_support_data(nullptr);
|
||||
set_painter_gizmo_data();
|
||||
}
|
||||
else if (is_wipe_tower) {
|
||||
DynamicPrintConfig& config = wxGetApp().preset_bundle->prints.get_edited_preset().config;
|
||||
set_scale(Vec3d::Ones());
|
||||
set_rotation(Vec3d(0., 0., (M_PI/180.) * dynamic_cast<const ConfigOptionFloat*>(config.option("wipe_tower_rotation_angle"))->value));
|
||||
set_flattening_data(nullptr);
|
||||
set_sla_support_data(nullptr);
|
||||
set_painter_gizmo_data();
|
||||
}
|
||||
else {
|
||||
set_scale(Vec3d::Ones());
|
||||
set_rotation(Vec3d::Zero());
|
||||
set_flattening_data(selection.is_from_single_object() ? selection.get_model()->objects[selection.get_object_idx()] : nullptr);
|
||||
set_sla_support_data(selection.is_from_single_instance() ? selection.get_model()->objects[selection.get_object_idx()] : nullptr);
|
||||
set_painter_gizmo_data();
|
||||
}
|
||||
if (m_current != Undefined) m_gizmos[m_current]->data_changed();
|
||||
}
|
||||
|
||||
bool GLGizmosManager::is_running() const
|
||||
|
@ -333,107 +263,6 @@ bool GLGizmosManager::is_dragging() const
|
|||
return m_gizmos[m_current]->is_dragging();
|
||||
}
|
||||
|
||||
void GLGizmosManager::start_dragging()
|
||||
{
|
||||
if (! m_enabled || m_current == Undefined)
|
||||
return;
|
||||
m_gizmos[m_current]->start_dragging();
|
||||
}
|
||||
|
||||
void GLGizmosManager::stop_dragging()
|
||||
{
|
||||
if (! m_enabled || m_current == Undefined)
|
||||
return;
|
||||
|
||||
m_gizmos[m_current]->stop_dragging();
|
||||
}
|
||||
|
||||
Vec3d GLGizmosManager::get_displacement() const
|
||||
{
|
||||
if (!m_enabled)
|
||||
return Vec3d::Zero();
|
||||
|
||||
return dynamic_cast<GLGizmoMove3D*>(m_gizmos[Move].get())->get_displacement();
|
||||
}
|
||||
|
||||
Vec3d GLGizmosManager::get_scale() const
|
||||
{
|
||||
if (!m_enabled)
|
||||
return Vec3d::Ones();
|
||||
|
||||
return dynamic_cast<GLGizmoScale3D*>(m_gizmos[Scale].get())->get_scale();
|
||||
}
|
||||
|
||||
void GLGizmosManager::set_scale(const Vec3d& scale)
|
||||
{
|
||||
if (!m_enabled || m_gizmos.empty())
|
||||
return;
|
||||
|
||||
dynamic_cast<GLGizmoScale3D*>(m_gizmos[Scale].get())->set_scale(scale);
|
||||
}
|
||||
|
||||
Vec3d GLGizmosManager::get_scale_offset() const
|
||||
{
|
||||
if (!m_enabled || m_gizmos.empty())
|
||||
return Vec3d::Zero();
|
||||
|
||||
return dynamic_cast<GLGizmoScale3D*>(m_gizmos[Scale].get())->get_offset();
|
||||
}
|
||||
|
||||
Vec3d GLGizmosManager::get_rotation() const
|
||||
{
|
||||
if (!m_enabled || m_gizmos.empty())
|
||||
return Vec3d::Zero();
|
||||
|
||||
return dynamic_cast<GLGizmoRotate3D*>(m_gizmos[Rotate].get())->get_rotation();
|
||||
}
|
||||
|
||||
void GLGizmosManager::set_rotation(const Vec3d& rotation)
|
||||
{
|
||||
if (!m_enabled || m_gizmos.empty())
|
||||
return;
|
||||
dynamic_cast<GLGizmoRotate3D*>(m_gizmos[Rotate].get())->set_rotation(rotation);
|
||||
}
|
||||
|
||||
Vec3d GLGizmosManager::get_flattening_normal() const
|
||||
{
|
||||
if (!m_enabled || m_gizmos.empty())
|
||||
return Vec3d::Zero();
|
||||
|
||||
return dynamic_cast<GLGizmoFlatten*>(m_gizmos[Flatten].get())->get_flattening_normal();
|
||||
}
|
||||
|
||||
void GLGizmosManager::set_flattening_data(const ModelObject* model_object)
|
||||
{
|
||||
if (!m_enabled || m_gizmos.empty())
|
||||
return;
|
||||
|
||||
dynamic_cast<GLGizmoFlatten*>(m_gizmos[Flatten].get())->set_flattening_data(model_object);
|
||||
}
|
||||
|
||||
void GLGizmosManager::set_sla_support_data(ModelObject* model_object)
|
||||
{
|
||||
if (! m_enabled
|
||||
|| m_gizmos.empty()
|
||||
|| wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology() != ptSLA)
|
||||
return;
|
||||
|
||||
auto* gizmo_hollow = dynamic_cast<GLGizmoHollow*>(m_gizmos[Hollow].get());
|
||||
auto* gizmo_supports = dynamic_cast<GLGizmoSlaSupports*>(m_gizmos[SlaSupports].get());
|
||||
gizmo_hollow->set_sla_support_data(model_object, m_parent.get_selection());
|
||||
gizmo_supports->set_sla_support_data(model_object, m_parent.get_selection());
|
||||
}
|
||||
|
||||
void GLGizmosManager::set_painter_gizmo_data()
|
||||
{
|
||||
if (!m_enabled || m_gizmos.empty())
|
||||
return;
|
||||
|
||||
dynamic_cast<GLGizmoFdmSupports*>(m_gizmos[FdmSupports].get())->set_painter_gizmo_data(m_parent.get_selection());
|
||||
dynamic_cast<GLGizmoSeam*>(m_gizmos[Seam].get())->set_painter_gizmo_data(m_parent.get_selection());
|
||||
dynamic_cast<GLGizmoMmuSegmentation*>(m_gizmos[MmuSegmentation].get())->set_painter_gizmo_data(m_parent.get_selection());
|
||||
}
|
||||
|
||||
// Returns true if the gizmo used the event to do something, false otherwise.
|
||||
bool GLGizmosManager::gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_position, bool shift_down, bool alt_down, bool control_down)
|
||||
{
|
||||
|
@ -522,7 +351,7 @@ std::string GLGizmosManager::get_tooltip() const
|
|||
return (curr != nullptr) ? curr->get_tooltip() : "";
|
||||
}
|
||||
|
||||
bool GLGizmosManager::on_mouse_wheel(wxMouseEvent& evt)
|
||||
bool GLGizmosManager::on_mouse_wheel(const wxMouseEvent &evt)
|
||||
{
|
||||
bool processed = false;
|
||||
|
||||
|
@ -535,271 +364,114 @@ bool GLGizmosManager::on_mouse_wheel(wxMouseEvent& evt)
|
|||
return processed;
|
||||
}
|
||||
|
||||
bool GLGizmosManager::on_mouse(wxMouseEvent& evt)
|
||||
{
|
||||
if (m_current != Undefined && m_gizmos[m_current]->on_mouse(evt))
|
||||
return true;
|
||||
|
||||
// used to set a right up event as processed when needed
|
||||
static bool pending_right_up = false;
|
||||
|
||||
Point pos(evt.GetX(), evt.GetY());
|
||||
Vec2d mouse_pos((double)evt.GetX(), (double)evt.GetY());
|
||||
|
||||
Selection& selection = m_parent.get_selection();
|
||||
int selected_object_idx = selection.get_object_idx();
|
||||
bool processed = false;
|
||||
|
||||
// when control is down we allow scene pan and rotation even when clicking over some object
|
||||
bool control_down = evt.CmdDown();
|
||||
|
||||
// mouse anywhere
|
||||
if (evt.Moving()) {
|
||||
m_tooltip = update_hover_state(mouse_pos);
|
||||
if (m_current == MmuSegmentation || m_current == FdmSupports)
|
||||
gizmo_event(SLAGizmoEventType::Moving, mouse_pos, evt.ShiftDown(), evt.AltDown());
|
||||
} else if (evt.LeftUp()) {
|
||||
if (m_mouse_capture.left) {
|
||||
processed = true;
|
||||
m_mouse_capture.left = false;
|
||||
bool GLGizmosManager::gizmos_toolbar_on_mouse(const wxMouseEvent &mouse_event) {
|
||||
assert(m_enabled);
|
||||
// keep information about events to process
|
||||
struct MouseCapture
|
||||
{
|
||||
bool left = false;
|
||||
bool middle = false;
|
||||
bool right = false;
|
||||
bool exist_tooltip = false;
|
||||
MouseCapture() = default;
|
||||
bool any() const { return left || middle || right; }
|
||||
void reset() {
|
||||
left = false;
|
||||
middle = false;
|
||||
right = false;
|
||||
}
|
||||
else if (is_dragging()) {
|
||||
switch (m_current) {
|
||||
case Move: { m_parent.do_move(L("Gizmo-Move")); break; }
|
||||
case Scale: { m_parent.do_scale(L("Gizmo-Scale")); break; }
|
||||
case Rotate: { m_parent.do_rotate(L("Gizmo-Rotate")); break; }
|
||||
default: break;
|
||||
}
|
||||
};
|
||||
static MouseCapture mc;
|
||||
|
||||
stop_dragging();
|
||||
update_data();
|
||||
// wxCoord == int --> wx/types.h
|
||||
Vec2i mouse_coord(mouse_event.GetX(), mouse_event.GetY());
|
||||
Vec2d mouse_pos = mouse_coord.cast<double>();
|
||||
|
||||
wxGetApp().obj_manipul()->set_dirty();
|
||||
// Let the plater know that the dragging finished, so a delayed refresh
|
||||
// of the scene with the background processing data should be performed.
|
||||
m_parent.post_event(SimpleEvent(EVT_GLCANVAS_MOUSE_DRAGGING_FINISHED));
|
||||
// updates camera target constraints
|
||||
m_parent.refresh_camera_scene_box();
|
||||
EType gizmo = get_gizmo_from_mouse(mouse_pos);
|
||||
bool selected_gizmo = gizmo != Undefined;
|
||||
|
||||
processed = true;
|
||||
}
|
||||
// else
|
||||
// return false;
|
||||
}
|
||||
else if (evt.MiddleUp()) {
|
||||
if (m_mouse_capture.middle) {
|
||||
processed = true;
|
||||
m_mouse_capture.middle = false;
|
||||
}
|
||||
else
|
||||
// fast reaction on move mouse
|
||||
if (mouse_event.Moving()) {
|
||||
assert(!mc.any());
|
||||
if (selected_gizmo) {
|
||||
mc.exist_tooltip = true;
|
||||
update_hover_state(gizmo);
|
||||
// at this moment is enebled to process mouse move under gizmo
|
||||
// tools bar e.g. Do not interupt dragging.
|
||||
return false;
|
||||
}
|
||||
else if (mc.exist_tooltip) {
|
||||
// first move out of gizmo tool bar - unselect tooltip
|
||||
mc.exist_tooltip = false;
|
||||
update_hover_state(Undefined);
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
else if (evt.RightUp()) {
|
||||
if (pending_right_up) {
|
||||
pending_right_up = false;
|
||||
|
||||
if (selected_gizmo) {
|
||||
// mouse is above toolbar
|
||||
if (mouse_event.LeftDown() || mouse_event.LeftDClick()) {
|
||||
mc.left = true;
|
||||
open_gizmo(gizmo);
|
||||
return true;
|
||||
}
|
||||
if (m_mouse_capture.right) {
|
||||
processed = true;
|
||||
m_mouse_capture.right = false;
|
||||
else if (mouse_event.RightDown()) {
|
||||
mc.right = true;
|
||||
return true;
|
||||
}
|
||||
else if (mouse_event.MiddleDown()) {
|
||||
mc.middle = true;
|
||||
return true;
|
||||
}
|
||||
// else
|
||||
// return false;
|
||||
}
|
||||
else if (evt.Dragging() && !is_dragging()) {
|
||||
if (m_mouse_capture.any())
|
||||
// if the button down was done on this toolbar, prevent from dragging into the scene
|
||||
processed = true;
|
||||
// else
|
||||
// return false;
|
||||
}
|
||||
else if (evt.Dragging() && is_dragging()) {
|
||||
if (!m_parent.get_wxglcanvas()->HasCapture())
|
||||
m_parent.get_wxglcanvas()->CaptureMouse();
|
||||
|
||||
m_parent.set_mouse_as_dragging();
|
||||
update(m_parent.mouse_ray(pos), pos);
|
||||
|
||||
switch (m_current)
|
||||
{
|
||||
case Move:
|
||||
{
|
||||
// Apply new temporary offset
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
#if ENABLE_INSTANCE_COORDINATES_FOR_VOLUMES
|
||||
selection.translate(get_displacement(), wxGetApp().obj_manipul()->get_coordinates_type());
|
||||
#else
|
||||
selection.translate(get_displacement(), !wxGetApp().obj_manipul()->get_world_coordinates());
|
||||
#endif // ENABLE_INSTANCE_COORDINATES_FOR_VOLUMES
|
||||
#else
|
||||
selection.translate(get_displacement());
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
wxGetApp().obj_manipul()->set_dirty();
|
||||
break;
|
||||
}
|
||||
case Scale:
|
||||
{
|
||||
// Apply new temporary scale factors
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
TransformationType transformation_type;
|
||||
#if ENABLE_INSTANCE_COORDINATES_FOR_VOLUMES
|
||||
if (!wxGetApp().obj_manipul()->is_world_coordinates())
|
||||
#else
|
||||
if (!wxGetApp().obj_manipul()->get_world_coordinates())
|
||||
#endif // ENABLE_INSTANCE_COORDINATES_FOR_VOLUMES
|
||||
transformation_type.set_local();
|
||||
#else
|
||||
TransformationType transformation_type(TransformationType::Local_Absolute_Joint);
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
if (evt.AltDown())
|
||||
transformation_type.set_independent();
|
||||
selection.scale(get_scale(), transformation_type);
|
||||
if (control_down)
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
#if ENABLE_INSTANCE_COORDINATES_FOR_VOLUMES
|
||||
selection.translate(get_scale_offset(), wxGetApp().obj_manipul()->get_coordinates_type());
|
||||
#else
|
||||
selection.translate(get_scale_offset(), !wxGetApp().obj_manipul()->get_world_coordinates());
|
||||
#endif // ENABLE_INSTANCE_COORDINATES_FOR_VOLUMES
|
||||
#else
|
||||
selection.translate(get_scale_offset(), true);
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
wxGetApp().obj_manipul()->set_dirty();
|
||||
break;
|
||||
}
|
||||
case Rotate:
|
||||
{
|
||||
// Apply new temporary rotations
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
#if ENABLE_INSTANCE_COORDINATES_FOR_VOLUMES
|
||||
TransformationType transformation_type;
|
||||
switch (wxGetApp().obj_manipul()->get_coordinates_type())
|
||||
{
|
||||
default:
|
||||
case ECoordinatesType::World: { transformation_type = TransformationType::World_Relative_Joint; break; }
|
||||
case ECoordinatesType::Instance: { transformation_type = TransformationType::Instance_Relative_Joint; break; }
|
||||
case ECoordinatesType::Local: { transformation_type = TransformationType::Local_Relative_Joint; break; }
|
||||
if (mc.any()) {
|
||||
// Check if exist release of event started above toolbar?
|
||||
if (mouse_event.Dragging()) {
|
||||
if (!selected_gizmo && mc.exist_tooltip) {
|
||||
// dragging out of gizmo let tooltip disapear
|
||||
mc.exist_tooltip = false;
|
||||
update_hover_state(Undefined);
|
||||
}
|
||||
#else
|
||||
TransformationType transformation_type(wxGetApp().obj_manipul()->get_world_coordinates() ? TransformationType::World_Relative_Joint : TransformationType::Local_Relative_Joint);
|
||||
#endif // ENABLE_INSTANCE_COORDINATES_FOR_VOLUMES
|
||||
#else
|
||||
TransformationType transformation_type(TransformationType::World_Relative_Joint);
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
if (evt.AltDown())
|
||||
transformation_type.set_independent();
|
||||
selection.rotate(get_rotation(), transformation_type);
|
||||
wxGetApp().obj_manipul()->set_dirty();
|
||||
break;
|
||||
// draging start on toolbar so no propagation into scene
|
||||
return true;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
else if (mc.left && mouse_event.LeftUp()) {
|
||||
mc.left = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
m_parent.set_as_dirty();
|
||||
processed = true;
|
||||
else if (mc.right && mouse_event.RightUp()) {
|
||||
mc.right = false;
|
||||
return true;
|
||||
}
|
||||
else if (mc.middle && mouse_event.MiddleUp()) {
|
||||
mc.middle = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
// event out of window is not porocessed
|
||||
// left down on gizmo -> keep down -> move out of window -> release left
|
||||
if (mouse_event.Leaving()) mc.reset();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if (get_gizmo_idx_from_mouse(mouse_pos) == Undefined) {
|
||||
// mouse is outside the toolbar
|
||||
m_tooltip.clear();
|
||||
bool exist_mouse_grabber = grabber_contains_mouse();
|
||||
if (evt.LeftDown() && (!control_down || exist_mouse_grabber)) {
|
||||
if ((m_current == SlaSupports || m_current == Hollow || m_current == FdmSupports || m_current == Seam || m_current == MmuSegmentation)
|
||||
&& gizmo_event(SLAGizmoEventType::LeftDown, mouse_pos, evt.ShiftDown(), evt.AltDown()))
|
||||
// the gizmo got the event and took some action, there is no need to do anything more
|
||||
processed = true;
|
||||
else if (!selection.is_empty() && exist_mouse_grabber) {
|
||||
update_data();
|
||||
selection.start_dragging();
|
||||
start_dragging();
|
||||
bool GLGizmosManager::on_mouse(const wxMouseEvent &mouse_event)
|
||||
{
|
||||
if (!m_enabled) return false;
|
||||
|
||||
// Let the plater know that the dragging started
|
||||
m_parent.post_event(SimpleEvent(EVT_GLCANVAS_MOUSE_DRAGGING_STARTED));
|
||||
// tool bar wants to use event?
|
||||
if (gizmos_toolbar_on_mouse(mouse_event)) return true;
|
||||
|
||||
if (m_current == Flatten) {
|
||||
// Rotate the object so the normal points downward:
|
||||
m_parent.do_flatten(get_flattening_normal(), L("Gizmo-Place on Face"));
|
||||
wxGetApp().obj_manipul()->set_dirty();
|
||||
}
|
||||
|
||||
m_parent.set_as_dirty();
|
||||
processed = true;
|
||||
}
|
||||
}
|
||||
else if (evt.RightDown() && selected_object_idx != -1 && (m_current == SlaSupports || m_current == Hollow)
|
||||
&& gizmo_event(SLAGizmoEventType::RightDown, mouse_pos)) {
|
||||
// we need to set the following right up as processed to avoid showing the context menu if the user release the mouse over the object
|
||||
pending_right_up = true;
|
||||
// event was taken care of by the SlaSupports gizmo
|
||||
processed = true;
|
||||
}
|
||||
else if (evt.RightDown() && !control_down && selected_object_idx != -1 && (m_current == FdmSupports || m_current == Seam || m_current == MmuSegmentation)
|
||||
&& gizmo_event(SLAGizmoEventType::RightDown, mouse_pos)) {
|
||||
// event was taken care of by the FdmSupports / Seam / MMUPainting gizmo
|
||||
processed = true;
|
||||
}
|
||||
else if (evt.Dragging() && m_parent.get_move_volume_id() != -1
|
||||
&& (m_current == SlaSupports || m_current == Hollow || m_current == FdmSupports || m_current == Seam || m_current == MmuSegmentation))
|
||||
// don't allow dragging objects with the Sla gizmo on
|
||||
processed = true;
|
||||
else if (evt.Dragging() && !control_down && (m_current == SlaSupports || m_current == Hollow || m_current == FdmSupports || m_current == Seam || m_current == MmuSegmentation)
|
||||
&& gizmo_event(SLAGizmoEventType::Dragging, mouse_pos, evt.ShiftDown(), evt.AltDown())) {
|
||||
// the gizmo got the event and took some action, no need to do anything more here
|
||||
m_parent.set_as_dirty();
|
||||
processed = true;
|
||||
}
|
||||
else if (evt.Dragging() && control_down && (evt.LeftIsDown() || evt.RightIsDown())) {
|
||||
// CTRL has been pressed while already dragging -> stop current action
|
||||
if (evt.LeftIsDown())
|
||||
gizmo_event(SLAGizmoEventType::LeftUp, mouse_pos, evt.ShiftDown(), evt.AltDown(), true);
|
||||
else if (evt.RightIsDown())
|
||||
gizmo_event(SLAGizmoEventType::RightUp, mouse_pos, evt.ShiftDown(), evt.AltDown(), true);
|
||||
}
|
||||
else if (evt.LeftUp() && (m_current == SlaSupports || m_current == Hollow || m_current == FdmSupports || m_current == Seam || m_current == MmuSegmentation) && !m_parent.is_mouse_dragging()) {
|
||||
// in case SLA/FDM gizmo is selected, we just pass the LeftUp event and stop processing - neither
|
||||
// object moving or selecting is suppressed in that case
|
||||
gizmo_event(SLAGizmoEventType::LeftUp, mouse_pos, evt.ShiftDown(), evt.AltDown(), control_down);
|
||||
processed = true;
|
||||
}
|
||||
else if (evt.LeftUp() && m_current == Flatten && m_gizmos[m_current]->get_hover_id() != -1) {
|
||||
// to avoid to loose the selection when user clicks an the white faces of a different object while the Flatten gizmo is active
|
||||
selection.stop_dragging();
|
||||
wxGetApp().obj_manipul()->set_dirty();
|
||||
processed = true;
|
||||
}
|
||||
else if (evt.RightUp() && (m_current == FdmSupports || m_current == Seam || m_current == MmuSegmentation) && !m_parent.is_mouse_dragging()) {
|
||||
gizmo_event(SLAGizmoEventType::RightUp, mouse_pos, evt.ShiftDown(), evt.AltDown(), control_down);
|
||||
processed = true;
|
||||
}
|
||||
else if (evt.LeftUp()) {
|
||||
selection.stop_dragging();
|
||||
wxGetApp().obj_manipul()->set_dirty();
|
||||
}
|
||||
}
|
||||
else {
|
||||
// mouse inside toolbar
|
||||
if (evt.LeftDown() || evt.LeftDClick()) {
|
||||
m_mouse_capture.left = true;
|
||||
m_mouse_capture.parent = &m_parent;
|
||||
processed = true;
|
||||
if (!selection.is_empty()) {
|
||||
update_on_off_state(mouse_pos);
|
||||
update_data();
|
||||
m_parent.set_as_dirty();
|
||||
}
|
||||
}
|
||||
else if (evt.MiddleDown()) {
|
||||
m_mouse_capture.middle = true;
|
||||
m_mouse_capture.parent = &m_parent;
|
||||
}
|
||||
else if (evt.RightDown()) {
|
||||
m_mouse_capture.right = true;
|
||||
m_mouse_capture.parent = &m_parent;
|
||||
}
|
||||
}
|
||||
|
||||
return processed;
|
||||
// current gizmo wants to use event?
|
||||
if (m_current != Undefined &&
|
||||
// check if gizmo override method could be slower than simple call virtual function
|
||||
// &m_gizmos[m_current]->on_mouse != &GLGizmoBase::on_mouse &&
|
||||
m_gizmos[m_current]->on_mouse(mouse_event))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool GLGizmosManager::on_char(wxKeyEvent& evt)
|
||||
|
@ -1230,68 +902,64 @@ bool GLGizmosManager::generate_icons_texture() const
|
|||
return res;
|
||||
}
|
||||
|
||||
void GLGizmosManager::update_on_off_state(const Vec2d& mouse_pos)
|
||||
void GLGizmosManager::update_hover_state(const EType &type)
|
||||
{
|
||||
if (!m_enabled)
|
||||
assert(m_enabled);
|
||||
if (type == Undefined) {
|
||||
m_hover = Undefined;
|
||||
m_tooltip.clear();
|
||||
return;
|
||||
|
||||
size_t idx = get_gizmo_idx_from_mouse(mouse_pos);
|
||||
if (idx != Undefined && m_gizmos[idx]->is_activable() && m_hover == idx) {
|
||||
activate_gizmo(m_current == idx ? Undefined : (EType)idx);
|
||||
wxGetApp().obj_list()->select_object_item((EType)idx <= Rotate);
|
||||
}
|
||||
}
|
||||
|
||||
std::string GLGizmosManager::update_hover_state(const Vec2d& mouse_pos)
|
||||
{
|
||||
std::string name = "";
|
||||
|
||||
if (!m_enabled)
|
||||
return name;
|
||||
|
||||
m_hover = Undefined;
|
||||
|
||||
size_t idx = get_gizmo_idx_from_mouse(mouse_pos);
|
||||
if (idx != Undefined) {
|
||||
name = m_gizmos[idx]->get_name();
|
||||
|
||||
if (m_gizmos[idx]->is_activable())
|
||||
m_hover = (EType)idx;
|
||||
}
|
||||
|
||||
return name;
|
||||
const GLGizmoBase &hovered_gizmo = *m_gizmos[type];
|
||||
m_hover = hovered_gizmo.is_activable() ? type : Undefined;
|
||||
m_tooltip = hovered_gizmo.get_name();
|
||||
}
|
||||
|
||||
bool GLGizmosManager::activate_gizmo(EType type)
|
||||
{
|
||||
if (m_gizmos.empty() || m_current == type)
|
||||
return true;
|
||||
assert(!m_gizmos.empty());
|
||||
|
||||
GLGizmoBase* old_gizmo = m_current == Undefined ? nullptr : m_gizmos[m_current].get();
|
||||
GLGizmoBase* new_gizmo = type == Undefined ? nullptr : m_gizmos[type].get();
|
||||
// already activated
|
||||
if (m_current == type) return true;
|
||||
|
||||
if (old_gizmo) {
|
||||
old_gizmo->set_state(GLGizmoBase::Off);
|
||||
if (old_gizmo->get_state() != GLGizmoBase::Off)
|
||||
if (m_current != Undefined) {
|
||||
// clean up previous gizmo
|
||||
GLGizmoBase &old_gizmo = *m_gizmos[m_current];
|
||||
old_gizmo.set_state(GLGizmoBase::Off);
|
||||
if (old_gizmo.get_state() != GLGizmoBase::Off)
|
||||
return false; // gizmo refused to be turned off, do nothing.
|
||||
|
||||
if (! m_parent.get_gizmos_manager().is_serializing()
|
||||
&& old_gizmo->wants_enter_leave_snapshots())
|
||||
Plater::TakeSnapshot snapshot(wxGetApp().plater(),
|
||||
old_gizmo->get_gizmo_leaving_text(),
|
||||
UndoRedo::SnapshotType::LeavingGizmoWithAction);
|
||||
if (!m_serializing && old_gizmo.wants_enter_leave_snapshots())
|
||||
Plater::TakeSnapshot
|
||||
snapshot(wxGetApp().plater(),
|
||||
old_gizmo.get_gizmo_leaving_text(),
|
||||
UndoRedo::SnapshotType::LeavingGizmoWithAction);
|
||||
}
|
||||
|
||||
if (new_gizmo && ! m_parent.get_gizmos_manager().is_serializing()
|
||||
&& new_gizmo->wants_enter_leave_snapshots())
|
||||
if (type == Undefined) {
|
||||
// it is deactivation of gizmo
|
||||
m_current = Undefined;
|
||||
return true;
|
||||
}
|
||||
|
||||
// set up new gizmo
|
||||
GLGizmoBase& new_gizmo = *m_gizmos[type];
|
||||
if (!new_gizmo.is_activable()) return false;
|
||||
|
||||
if (!m_serializing && new_gizmo.wants_enter_leave_snapshots())
|
||||
Plater::TakeSnapshot snapshot(wxGetApp().plater(),
|
||||
new_gizmo->get_gizmo_entering_text(),
|
||||
UndoRedo::SnapshotType::EnteringGizmo);
|
||||
new_gizmo.get_gizmo_entering_text(),
|
||||
UndoRedo::SnapshotType::EnteringGizmo);
|
||||
|
||||
m_current = type;
|
||||
new_gizmo.set_state(GLGizmoBase::On);
|
||||
if (new_gizmo.get_state() != GLGizmoBase::On) {
|
||||
m_current = Undefined;
|
||||
return false; // gizmo refused to be turned on.
|
||||
}
|
||||
|
||||
if (new_gizmo)
|
||||
new_gizmo->set_state(GLGizmoBase::On);
|
||||
// sucessful activation of gizmo
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1329,11 +997,5 @@ bool GLGizmosManager::is_hiding_instances() const
|
|||
&& m_common_gizmos_data->instances_hider()->is_valid());
|
||||
}
|
||||
|
||||
|
||||
int GLGizmosManager::get_shortcut_key(GLGizmosManager::EType type) const
|
||||
{
|
||||
return m_gizmos[type]->get_shortcut_key();
|
||||
}
|
||||
|
||||
} // namespace GUI
|
||||
} // namespace Slic3r
|
||||
|
|
|
@ -113,28 +113,22 @@ private:
|
|||
std::pair<EType, bool> m_highlight; // bool true = higlightedShown, false = highlightedHidden
|
||||
|
||||
std::vector<size_t> get_selectable_idxs() const;
|
||||
size_t get_gizmo_idx_from_mouse(const Vec2d& mouse_pos) const;
|
||||
EType get_gizmo_from_mouse(const Vec2d &mouse_pos) const;
|
||||
|
||||
bool activate_gizmo(EType type);
|
||||
|
||||
struct MouseCapture
|
||||
{
|
||||
bool left;
|
||||
bool middle;
|
||||
bool right;
|
||||
GLCanvas3D* parent;
|
||||
|
||||
MouseCapture() { reset(); }
|
||||
|
||||
bool any() const { return left || middle || right; }
|
||||
void reset() { left = middle = right = false; parent = nullptr; }
|
||||
};
|
||||
|
||||
MouseCapture m_mouse_capture;
|
||||
std::string m_tooltip;
|
||||
bool m_serializing;
|
||||
std::unique_ptr<CommonGizmosDataPool> m_common_gizmos_data;
|
||||
|
||||
/// <summary>
|
||||
/// Process mouse event on gizmo toolbar
|
||||
/// </summary>
|
||||
/// <param name="mouse_event">Event descriptor</param>
|
||||
/// <returns>TRUE when take responsibility for event otherwise FALSE.
|
||||
/// On true, event should not be process by others.
|
||||
/// On false, event should be process by others.</returns>
|
||||
bool gizmos_toolbar_on_mouse(const wxMouseEvent &mouse_event);
|
||||
public:
|
||||
explicit GLGizmosManager(GLCanvas3D& parent);
|
||||
|
||||
|
@ -185,14 +179,15 @@ public:
|
|||
|
||||
void refresh_on_off_state();
|
||||
void reset_all_states();
|
||||
bool is_serializing() const { return m_serializing; }
|
||||
bool open_gizmo(EType type);
|
||||
bool check_gizmos_closed_except(EType) const;
|
||||
|
||||
void set_hover_id(int id);
|
||||
void enable_grabber(EType type, unsigned int id, bool enable);
|
||||
|
||||
void update(const Linef3& mouse_ray, const Point& mouse_pos);
|
||||
/// <summary>
|
||||
/// Distribute information about different data into active gizmo
|
||||
/// Should be called when selection changed
|
||||
/// </summary>
|
||||
void update_data();
|
||||
|
||||
EType get_current_type() const { return m_current; }
|
||||
|
@ -203,28 +198,7 @@ public:
|
|||
bool handle_shortcut(int key);
|
||||
|
||||
bool is_dragging() const;
|
||||
void start_dragging();
|
||||
void stop_dragging();
|
||||
|
||||
Vec3d get_displacement() const;
|
||||
|
||||
Vec3d get_scale() const;
|
||||
void set_scale(const Vec3d& scale);
|
||||
|
||||
Vec3d get_scale_offset() const;
|
||||
|
||||
Vec3d get_rotation() const;
|
||||
void set_rotation(const Vec3d& rotation);
|
||||
|
||||
Vec3d get_flattening_normal() const;
|
||||
|
||||
void set_flattening_data(const ModelObject* model_object);
|
||||
|
||||
void set_sla_support_data(ModelObject* model_object);
|
||||
|
||||
void set_painter_gizmo_data();
|
||||
|
||||
bool gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_position = Vec2d::Zero(), bool shift_down = false, bool alt_down = false, bool control_down = false);
|
||||
ClippingPlane get_clipping_plane() const;
|
||||
bool wants_reslice_supports_on_undo() const;
|
||||
|
||||
|
@ -241,21 +215,26 @@ public:
|
|||
|
||||
std::string get_tooltip() const;
|
||||
|
||||
bool on_mouse(wxMouseEvent& evt);
|
||||
bool on_mouse_wheel(wxMouseEvent& evt);
|
||||
bool on_mouse(const wxMouseEvent &mouse_event);
|
||||
bool on_mouse_wheel(const wxMouseEvent &evt);
|
||||
bool on_char(wxKeyEvent& evt);
|
||||
bool on_key(wxKeyEvent& evt);
|
||||
|
||||
void update_after_undo_redo(const UndoRedo::Snapshot& snapshot);
|
||||
|
||||
int get_selectable_icons_cnt() const { return get_selectable_idxs().size(); }
|
||||
int get_shortcut_key(GLGizmosManager::EType) const;
|
||||
|
||||
// To end highlight set gizmo = undefined
|
||||
void set_highlight(EType gizmo, bool highlight_shown) { m_highlight = std::pair<EType, bool>(gizmo, highlight_shown); }
|
||||
bool get_highlight_state() const { return m_highlight.second; }
|
||||
|
||||
private:
|
||||
bool gizmo_event(SLAGizmoEventType action,
|
||||
const Vec2d & mouse_position = Vec2d::Zero(),
|
||||
bool shift_down = false,
|
||||
bool alt_down = false,
|
||||
bool control_down = false);
|
||||
|
||||
void render_background(float left, float top, float right, float bottom, float border) const;
|
||||
|
||||
void do_render_overlay() const;
|
||||
|
@ -265,8 +244,7 @@ private:
|
|||
|
||||
bool generate_icons_texture() const;
|
||||
|
||||
void update_on_off_state(const Vec2d& mouse_pos);
|
||||
std::string update_hover_state(const Vec2d& mouse_pos);
|
||||
void update_hover_state(const EType &type);
|
||||
bool grabber_contains_mouse() const;
|
||||
};
|
||||
|
||||
|
|
|
@ -1733,8 +1733,8 @@ void ImGuiWrapper::render_draw_data(ImDrawData *draw_data)
|
|||
{
|
||||
// Avoid rendering when minimized, scale coordinates for retina displays (screen coordinates != framebuffer coordinates)
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
int fb_width = (int)(draw_data->DisplaySize.x * io.DisplayFramebufferScale.x);
|
||||
int fb_height = (int)(draw_data->DisplaySize.y * io.DisplayFramebufferScale.y);
|
||||
const int fb_width = (int)(draw_data->DisplaySize.x * io.DisplayFramebufferScale.x);
|
||||
const int fb_height = (int)(draw_data->DisplaySize.y * io.DisplayFramebufferScale.y);
|
||||
if (fb_width == 0 || fb_height == 0)
|
||||
return;
|
||||
draw_data->ScaleClipRects(io.DisplayFramebufferScale);
|
||||
|
@ -1777,8 +1777,7 @@ void ImGuiWrapper::render_draw_data(ImDrawData *draw_data)
|
|||
|
||||
// Render command lists
|
||||
ImVec2 pos = draw_data->DisplayPos;
|
||||
for (int n = 0; n < draw_data->CmdListsCount; n++)
|
||||
{
|
||||
for (int n = 0; n < draw_data->CmdListsCount; ++n) {
|
||||
const ImDrawList* cmd_list = draw_data->CmdLists[n];
|
||||
const ImDrawVert* vtx_buffer = cmd_list->VtxBuffer.Data;
|
||||
const ImDrawIdx* idx_buffer = cmd_list->IdxBuffer.Data;
|
||||
|
@ -1786,19 +1785,14 @@ void ImGuiWrapper::render_draw_data(ImDrawData *draw_data)
|
|||
glsafe(::glTexCoordPointer(2, GL_FLOAT, sizeof(ImDrawVert), (const GLvoid*)((const char*)vtx_buffer + IM_OFFSETOF(ImDrawVert, uv))));
|
||||
glsafe(::glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(ImDrawVert), (const GLvoid*)((const char*)vtx_buffer + IM_OFFSETOF(ImDrawVert, col))));
|
||||
|
||||
for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++)
|
||||
{
|
||||
for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; ++cmd_i) {
|
||||
const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i];
|
||||
if (pcmd->UserCallback)
|
||||
{
|
||||
// User callback (registered via ImDrawList::AddCallback)
|
||||
pcmd->UserCallback(cmd_list, pcmd);
|
||||
}
|
||||
else
|
||||
{
|
||||
else {
|
||||
ImVec4 clip_rect = ImVec4(pcmd->ClipRect.x - pos.x, pcmd->ClipRect.y - pos.y, pcmd->ClipRect.z - pos.x, pcmd->ClipRect.w - pos.y);
|
||||
if (clip_rect.x < fb_width && clip_rect.y < fb_height && clip_rect.z >= 0.0f && clip_rect.w >= 0.0f)
|
||||
{
|
||||
if (clip_rect.x < fb_width && clip_rect.y < fb_height && clip_rect.z >= 0.0f && clip_rect.w >= 0.0f) {
|
||||
// Apply scissor/clipping rectangle
|
||||
glsafe(::glScissor((int)clip_rect.x, (int)(fb_height - clip_rect.w), (int)(clip_rect.z - clip_rect.x), (int)(clip_rect.w - clip_rect.y)));
|
||||
|
||||
|
|
|
@ -859,7 +859,10 @@ bool MainFrame::save_project_as(const wxString& filename)
|
|||
{
|
||||
bool ret = (m_plater != nullptr) ? m_plater->export_3mf(into_path(filename)) : false;
|
||||
if (ret) {
|
||||
// wxGetApp().update_saved_preset_from_current_preset();
|
||||
// Make a copy of the active presets for detecting changes in preset values.
|
||||
wxGetApp().update_saved_preset_from_current_preset();
|
||||
// Save the names of active presets and project specific config into ProjectDirtyStateManager.
|
||||
// Reset ProjectDirtyStateManager's state as saved, mark active UndoRedo step as saved with project.
|
||||
m_plater->reset_project_dirty_after_save();
|
||||
}
|
||||
return ret;
|
||||
|
|
|
@ -311,7 +311,11 @@ wxString get_wraped_wxString(const wxString& in, size_t line_len /*=80*/)
|
|||
overwrite = true;
|
||||
if (newline)
|
||||
break;
|
||||
} else if (in[j] == '/') {
|
||||
} else if (in[j] == '/'
|
||||
#ifdef _WIN32
|
||||
|| in[j] == '\\'
|
||||
#endif // _WIN32
|
||||
) {
|
||||
// Insert after the slash.
|
||||
ibreak = ++ j;
|
||||
overwrite = false;
|
||||
|
|
|
@ -245,7 +245,7 @@ public:
|
|||
GetBtnsListCtrl()->Rescale();
|
||||
}
|
||||
|
||||
void Notebook::OnNavigationKey(wxNavigationKeyEvent& event)
|
||||
void OnNavigationKey(wxNavigationKeyEvent& event)
|
||||
{
|
||||
if (event.IsWindowChange()) {
|
||||
// change pages
|
||||
|
|
|
@ -57,9 +57,9 @@
|
|||
#include "GUI_ObjectManipulation.hpp"
|
||||
#include "GUI_ObjectLayers.hpp"
|
||||
#include "GUI_Utils.hpp"
|
||||
#if ENABLE_INSTANCE_COORDINATES_FOR_VOLUMES
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
#include "GUI_Geometry.hpp"
|
||||
#endif // ENABLE_INSTANCE_COORDINATES_FOR_VOLUMES
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
#include "GUI_Factories.hpp"
|
||||
#include "wxExtensions.hpp"
|
||||
#include "MainFrame.hpp"
|
||||
|
@ -502,6 +502,7 @@ FreqChangedParams::FreqChangedParams(wxWindow* parent) :
|
|||
std::vector<float> extruders = dlg.get_extruders();
|
||||
(project_config.option<ConfigOptionFloats>("wiping_volumes_matrix"))->values = std::vector<double>(matrix.begin(), matrix.end());
|
||||
(project_config.option<ConfigOptionFloats>("wiping_volumes_extruders"))->values = std::vector<double>(extruders.begin(), extruders.end());
|
||||
// Update Project dirty state, update application title bar.
|
||||
wxGetApp().plater()->update_project_dirty_from_presets();
|
||||
wxPostEvent(parent, SimpleEvent(EVT_SCHEDULE_BACKGROUND_PROCESS, parent));
|
||||
}
|
||||
|
@ -1521,10 +1522,10 @@ void Sidebar::update_mode()
|
|||
|
||||
wxWindowUpdateLocker noUpdates(this);
|
||||
|
||||
#if ENABLE_INSTANCE_COORDINATES_FOR_VOLUMES
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
if (m_mode == comSimple)
|
||||
p->object_manipulation->set_coordinates_type(ECoordinatesType::World);
|
||||
#endif // ENABLE_INSTANCE_COORDINATES_FOR_VOLUMES
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
||||
p->object_list->get_sizer()->Show(m_mode > comSimple);
|
||||
|
||||
|
@ -2359,7 +2360,7 @@ std::vector<size_t> Plater::priv::load_files(const std::vector<fs::path>& input_
|
|||
}
|
||||
|
||||
const auto loading = _L("Loading") + dots;
|
||||
wxProgressDialog dlg(loading, "", 100, find_toplevel_parent(q), wxPD_AUTO_HIDE);
|
||||
wxProgressDialog progress_dlg(loading, "", 100, find_toplevel_parent(q), wxPD_AUTO_HIDE);
|
||||
wxBusyCursor busy;
|
||||
|
||||
auto *new_model = (!load_model || one_by_one) ? nullptr : new Slic3r::Model();
|
||||
|
@ -2368,7 +2369,8 @@ std::vector<size_t> Plater::priv::load_files(const std::vector<fs::path>& input_
|
|||
int answer_convert_from_meters = wxOK_DEFAULT;
|
||||
int answer_convert_from_imperial_units = wxOK_DEFAULT;
|
||||
|
||||
for (size_t i = 0; i < input_files.size(); ++i) {
|
||||
size_t input_files_size = input_files.size();
|
||||
for (size_t i = 0; i < input_files_size; ++i) {
|
||||
#ifdef _WIN32
|
||||
auto path = input_files[i];
|
||||
// On Windows, we swap slashes to back slashes, see GH #6803 as read_from_file() does not understand slashes on Windows thus it assignes full path to names of loaded objects.
|
||||
|
@ -2378,8 +2380,8 @@ std::vector<size_t> Plater::priv::load_files(const std::vector<fs::path>& input_
|
|||
const auto &path = input_files[i];
|
||||
#endif // _WIN32
|
||||
const auto filename = path.filename();
|
||||
dlg.Update(static_cast<int>(100.0f * static_cast<float>(i) / static_cast<float>(input_files.size())), _L("Loading file") + ": " + from_path(filename));
|
||||
dlg.Fit();
|
||||
progress_dlg.Update(static_cast<int>(100.0f * static_cast<float>(i) / static_cast<float>(input_files.size())), _L("Loading file") + ": " + from_path(filename));
|
||||
progress_dlg.Fit();
|
||||
|
||||
const bool type_3mf = std::regex_match(path.string(), pattern_3mf);
|
||||
const bool type_zip_amf = !type_3mf && std::regex_match(path.string(), pattern_zip_amf);
|
||||
|
@ -2390,17 +2392,28 @@ std::vector<size_t> Plater::priv::load_files(const std::vector<fs::path>& input_
|
|||
bool is_project_file = type_prusa;
|
||||
try {
|
||||
if (type_3mf || type_zip_amf) {
|
||||
#ifdef __linux__
|
||||
// On Linux Constructor of the ProgressDialog calls DisableOtherWindows() function which causes a disabling of all children of the find_toplevel_parent(q)
|
||||
// And a destructor of the ProgressDialog calls ReenableOtherWindows() function which revert previously disabled children.
|
||||
// But if printer technology will be changes during project loading,
|
||||
// then related SLA Print and Materials Settings or FFF Print and Filaments Settings will be unparent from the wxNoteBook
|
||||
// and that is why they will never be enabled after destruction of the ProgressDialog.
|
||||
// So, distroy progress_gialog if we are loading project file
|
||||
if (input_files_size == 1)
|
||||
progress_dlg.Destroy();
|
||||
#endif
|
||||
DynamicPrintConfig config;
|
||||
PrinterTechnology loaded_printer_technology {ptFFF};
|
||||
{
|
||||
DynamicPrintConfig config_loaded;
|
||||
ConfigSubstitutionContext config_substitutions{ ForwardCompatibilitySubstitutionRule::Enable };
|
||||
model = Slic3r::Model::read_from_archive(path.string(), &config_loaded, &config_substitutions, only_if(load_config, Model::LoadAttribute::CheckVersion));
|
||||
if (load_config && !config_loaded.empty()) {
|
||||
// Based on the printer technology field found in the loaded config, select the base for the config,
|
||||
PrinterTechnology printer_technology = Preset::printer_technology(config_loaded);
|
||||
loaded_printer_technology = Preset::printer_technology(config_loaded);
|
||||
|
||||
// We can't to load SLA project if there is at least one multi-part object on the bed
|
||||
if (printer_technology == ptSLA) {
|
||||
if (loaded_printer_technology == ptSLA) {
|
||||
const ModelObjectPtrs& objects = q->model().objects;
|
||||
for (auto object : objects)
|
||||
if (object->volumes.size() > 1) {
|
||||
|
@ -2412,7 +2425,7 @@ std::vector<size_t> Plater::priv::load_files(const std::vector<fs::path>& input_
|
|||
}
|
||||
}
|
||||
|
||||
config.apply(printer_technology == ptFFF ?
|
||||
config.apply(loaded_printer_technology == ptFFF ?
|
||||
static_cast<const ConfigBase&>(FullPrintConfig::defaults()) :
|
||||
static_cast<const ConfigBase&>(SLAFullPrintConfig::defaults()));
|
||||
// and place the loaded config over the base.
|
||||
|
@ -2443,7 +2456,7 @@ std::vector<size_t> Plater::priv::load_files(const std::vector<fs::path>& input_
|
|||
};
|
||||
|
||||
std::vector<std::string> names;
|
||||
if (printer_technology == ptFFF) {
|
||||
if (loaded_printer_technology == ptFFF) {
|
||||
update_selected_preset_visibility(preset_bundle->prints, names);
|
||||
for (const std::string& filament : preset_bundle->filament_presets) {
|
||||
Preset* preset = preset_bundle->filaments.find_preset(filament);
|
||||
|
@ -2474,7 +2487,7 @@ std::vector<size_t> Plater::priv::load_files(const std::vector<fs::path>& input_
|
|||
}
|
||||
}
|
||||
|
||||
if (printer_technology == ptFFF)
|
||||
if (loaded_printer_technology == ptFFF)
|
||||
CustomGCode::update_custom_gcode_per_print_z_from_config(model.custom_gcode_per_print_z, &preset_bundle->project_config);
|
||||
|
||||
// For exporting from the amf/3mf we shouldn't check printer_presets for the containing information about "Print Host upload"
|
||||
|
@ -5275,8 +5288,11 @@ void Plater::new_project()
|
|||
take_snapshot(_L("New Project"), UndoRedo::SnapshotType::ProjectSeparator);
|
||||
Plater::SuppressSnapshots suppress(this);
|
||||
reset();
|
||||
// Save the names of active presets and project specific config into ProjectDirtyStateManager.
|
||||
reset_project_dirty_initial_presets();
|
||||
// Make a copy of the active presets for detecting changes in preset values.
|
||||
wxGetApp().update_saved_preset_from_current_preset();
|
||||
// Update Project dirty state, update application title bar.
|
||||
update_project_dirty_from_presets();
|
||||
}
|
||||
|
||||
|
@ -5305,7 +5321,11 @@ void Plater::load_project(const wxString& filename)
|
|||
if (! load_files({ into_path(filename) }).empty()) {
|
||||
// At least one file was loaded.
|
||||
p->set_project_filename(filename);
|
||||
// Save the names of active presets and project specific config into ProjectDirtyStateManager.
|
||||
reset_project_dirty_initial_presets();
|
||||
// Make a copy of the active presets for detecting changes in preset values.
|
||||
wxGetApp().update_saved_preset_from_current_preset();
|
||||
// Update Project dirty state, update application title bar.
|
||||
update_project_dirty_from_presets();
|
||||
}
|
||||
}
|
||||
|
@ -5990,7 +6010,6 @@ void Plater::export_stl_obj(bool extended, bool selection_only)
|
|||
}
|
||||
else if (0 <= instance_id && instance_id < int(mo.instances.size()))
|
||||
mesh.transform(mo.instances[instance_id]->get_matrix(), true);
|
||||
|
||||
return mesh;
|
||||
};
|
||||
|
||||
|
|
|
@ -17,9 +17,11 @@ namespace GUI {
|
|||
|
||||
void ProjectDirtyStateManager::update_from_undo_redo_stack(bool dirty)
|
||||
{
|
||||
m_plater_dirty = dirty;
|
||||
if (const Plater *plater = wxGetApp().plater(); plater && wxGetApp().initialized())
|
||||
wxGetApp().mainframe->update_title();
|
||||
if (m_plater_dirty != dirty) {
|
||||
m_plater_dirty = dirty;
|
||||
if (const Plater *plater = wxGetApp().plater(); plater && wxGetApp().initialized())
|
||||
wxGetApp().mainframe->update_title();
|
||||
}
|
||||
}
|
||||
|
||||
void ProjectDirtyStateManager::update_from_presets()
|
||||
|
@ -27,11 +29,11 @@ void ProjectDirtyStateManager::update_from_presets()
|
|||
m_presets_dirty = false;
|
||||
// check switching of the presets only for exist/loaded project, but not for new
|
||||
GUI_App &app = wxGetApp();
|
||||
if (!app.plater()->get_project_filename().IsEmpty()) {
|
||||
for (const auto& [type, name] : app.get_selected_presets())
|
||||
m_presets_dirty |= !m_initial_presets[type].empty() && m_initial_presets[type] != name;
|
||||
bool has_project = ! app.plater()->get_project_filename().IsEmpty();
|
||||
for (const PresetCollection *preset_collection : app.get_active_preset_collections()) {
|
||||
auto type = preset_collection->type();
|
||||
m_presets_dirty |= (has_project && !m_initial_presets[type].empty() && m_initial_presets[type] != preset_collection->get_selected_preset_name()) || preset_collection->saved_is_dirty();
|
||||
}
|
||||
m_presets_dirty |= app.has_unsaved_preset_changes();
|
||||
m_project_config_dirty = m_initial_project_config != app.preset_bundle->project_config;
|
||||
app.mainframe->update_title();
|
||||
}
|
||||
|
@ -49,8 +51,8 @@ void ProjectDirtyStateManager::reset_initial_presets()
|
|||
{
|
||||
m_initial_presets.fill(std::string{});
|
||||
GUI_App &app = wxGetApp();
|
||||
for (const auto& [type, name] : app.get_selected_presets())
|
||||
m_initial_presets[type] = name;
|
||||
for (const PresetCollection *preset_collection : app.get_active_preset_collections())
|
||||
m_initial_presets[preset_collection->type()] = preset_collection->get_selected_preset_name();
|
||||
m_initial_project_config = app.preset_bundle->project_config;
|
||||
}
|
||||
|
||||
|
|
|
@ -7,9 +7,14 @@
|
|||
#include "GUI.hpp"
|
||||
#include "GUI_ObjectManipulation.hpp"
|
||||
#include "GUI_ObjectList.hpp"
|
||||
#include "Gizmos/GLGizmoBase.hpp"
|
||||
#include "Camera.hpp"
|
||||
#include "Plater.hpp"
|
||||
#if ENABLE_WORLD_COORDINATE_SCALE_REVISITED
|
||||
#include "MsgDialog.hpp"
|
||||
#endif // ENABLE_WORLD_COORDINATE_SCALE_REVISITED
|
||||
|
||||
#include "Gizmos/GLGizmoBase.hpp"
|
||||
|
||||
#include "slic3r/Utils/UndoRedo.hpp"
|
||||
|
||||
#include "libslic3r/LocalesUtils.hpp"
|
||||
|
@ -115,9 +120,14 @@ Selection::Selection()
|
|||
, m_type(Empty)
|
||||
, m_valid(false)
|
||||
, m_scale_factor(1.0f)
|
||||
, m_dragging(false)
|
||||
{
|
||||
this->set_bounding_boxes_dirty();
|
||||
#if ENABLE_WORLD_COORDINATE_SHOW_AXES
|
||||
m_axes.set_stem_radius(0.15f);
|
||||
m_axes.set_stem_length(3.0f);
|
||||
m_axes.set_tip_radius(0.45f);
|
||||
m_axes.set_tip_length(1.5f);
|
||||
#endif // ENABLE_WORLD_COORDINATE_SHOW_AXES
|
||||
}
|
||||
|
||||
|
||||
|
@ -592,19 +602,18 @@ bool Selection::matches(const std::vector<unsigned int>& volume_idxs) const
|
|||
return count == (unsigned int)m_list.size();
|
||||
}
|
||||
|
||||
#if ENABLE_INSTANCE_COORDINATES_FOR_VOLUMES
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
bool Selection::requires_uniform_scale(EUniformScaleRequiredReason* reason) const
|
||||
#else
|
||||
bool Selection::requires_uniform_scale() const
|
||||
#endif // ENABLE_INSTANCE_COORDINATES_FOR_VOLUMES
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
{
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
#if ENABLE_INSTANCE_COORDINATES_FOR_VOLUMES
|
||||
if (is_empty())
|
||||
return false;
|
||||
|
||||
ECoordinatesType coord_type = wxGetApp().obj_manipul()->get_coordinates_type();
|
||||
#endif // ENABLE_INSTANCE_COORDINATES_FOR_VOLUMES
|
||||
if (is_single_volume_or_modifier())
|
||||
#if ENABLE_INSTANCE_COORDINATES_FOR_VOLUMES
|
||||
{
|
||||
if (is_single_volume_or_modifier()) {
|
||||
if (coord_type == ECoordinatesType::World) {
|
||||
if (!Geometry::is_rotation_ninety_degrees(Geometry::Transformation(get_volume(*m_list.begin())->world_matrix()).get_rotation())) {
|
||||
if (reason != nullptr)
|
||||
|
@ -621,11 +630,7 @@ bool Selection::requires_uniform_scale() const
|
|||
}
|
||||
return false;
|
||||
}
|
||||
#else
|
||||
return !Geometry::is_rotation_ninety_degrees(Geometry::Transformation(get_volume(*m_list.begin())->world_matrix()).get_rotation());
|
||||
#endif // ENABLE_INSTANCE_COORDINATES_FOR_VOLUMES
|
||||
else if (is_single_full_instance()) {
|
||||
#if ENABLE_INSTANCE_COORDINATES_FOR_VOLUMES
|
||||
if (coord_type == ECoordinatesType::World) {
|
||||
if (!Geometry::is_rotation_ninety_degrees(get_volume(*m_list.begin())->get_instance_rotation())) {
|
||||
if (reason != nullptr)
|
||||
|
@ -641,7 +646,6 @@ bool Selection::requires_uniform_scale() const
|
|||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
for (unsigned int i : m_list) {
|
||||
|
@ -651,17 +655,12 @@ bool Selection::requires_uniform_scale() const
|
|||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if (reason != nullptr)
|
||||
*reason = EUniformScaleRequiredReason::MultipleSelection;
|
||||
#else
|
||||
return wxGetApp().obj_manipul()->get_world_coordinates() ?
|
||||
!Geometry::is_rotation_ninety_degrees(get_volume(*m_list.begin())->get_instance_rotation()) : false;
|
||||
}
|
||||
#endif // ENABLE_INSTANCE_COORDINATES_FOR_VOLUMES
|
||||
|
||||
return true;
|
||||
#else
|
||||
|
@ -751,20 +750,19 @@ const BoundingBoxf3& Selection::get_scaled_instance_bounding_box() const
|
|||
return *m_scaled_instance_bounding_box;
|
||||
}
|
||||
|
||||
void Selection::start_dragging()
|
||||
void Selection::setup_cache()
|
||||
{
|
||||
if (!m_valid)
|
||||
return;
|
||||
|
||||
m_dragging = true;
|
||||
set_caches();
|
||||
}
|
||||
|
||||
#if ENABLE_INSTANCE_COORDINATES_FOR_VOLUMES
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
void Selection::translate(const Vec3d& displacement, ECoordinatesType type)
|
||||
#else
|
||||
void Selection::translate(const Vec3d& displacement, bool local)
|
||||
#endif // ENABLE_INSTANCE_COORDINATES_FOR_VOLUMES
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
{
|
||||
if (!m_valid)
|
||||
return;
|
||||
|
@ -774,19 +772,19 @@ void Selection::translate(const Vec3d& displacement, bool local)
|
|||
for (unsigned int i : m_list) {
|
||||
GLVolume& v = *(*m_volumes)[i];
|
||||
if (m_mode == Volume || v.is_wipe_tower) {
|
||||
#if ENABLE_INSTANCE_COORDINATES_FOR_VOLUMES
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
if (type == ECoordinatesType::Instance)
|
||||
#else
|
||||
if (local)
|
||||
#endif // ENABLE_INSTANCE_COORDINATES_FOR_VOLUMES
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
v.set_volume_offset(m_cache.volumes_data[i].get_volume_position() + displacement);
|
||||
#if ENABLE_INSTANCE_COORDINATES_FOR_VOLUMES
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
else if (type == ECoordinatesType::Local) {
|
||||
const VolumeCache& volume_data = m_cache.volumes_data[i];
|
||||
const Vec3d local_displacement = volume_data.get_volume_rotation_matrix() * displacement;
|
||||
v.set_volume_offset(volume_data.get_volume_position() + local_displacement);
|
||||
}
|
||||
#endif // ENABLE_INSTANCE_COORDINATES_FOR_VOLUMES
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
else {
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
const VolumeCache& volume_data = m_cache.volumes_data[i];
|
||||
|
@ -801,15 +799,9 @@ void Selection::translate(const Vec3d& displacement, bool local)
|
|||
else if (m_mode == Instance) {
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
if (is_from_fully_selected_instance(i)) {
|
||||
#if ENABLE_INSTANCE_COORDINATES_FOR_VOLUMES
|
||||
if (type == ECoordinatesType::Local) {
|
||||
const VolumeCache& volume_data = m_cache.volumes_data[i];
|
||||
const Vec3d world_displacement = volume_data.get_instance_rotation_matrix() * displacement;
|
||||
#else
|
||||
if (local) {
|
||||
const VolumeCache& volume_data = m_cache.volumes_data[i];
|
||||
const Vec3d world_displacement = (volume_data.get_instance_rotation_matrix() * volume_data.get_instance_mirror_matrix()) * displacement;
|
||||
#endif // ENABLE_INSTANCE_COORDINATES_FOR_VOLUMES
|
||||
v.set_instance_offset(volume_data.get_instance_position() + world_displacement);
|
||||
}
|
||||
else
|
||||
|
@ -918,19 +910,15 @@ void Selection::rotate(const Vec3d& rotation, TransformationType transformation_
|
|||
rotate_instance(v, i);
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
else if (is_single_volume_or_modifier()) {
|
||||
#if ENABLE_INSTANCE_COORDINATES_FOR_VOLUMES
|
||||
if (transformation_type.local()) {
|
||||
const Transform3d m = Geometry::assemble_transform(Vec3d::Zero(), rotation);
|
||||
v.set_volume_rotation(Geometry::extract_euler_angles(m_cache.volumes_data[i].get_volume_rotation_matrix() * m));
|
||||
const Vec3d new_rotation = transformation_type.absolute() ? rotation : Geometry::extract_euler_angles(m_cache.volumes_data[i].get_volume_rotation_matrix() * m);
|
||||
v.set_volume_rotation(new_rotation);
|
||||
}
|
||||
else if (transformation_type.instance()) {
|
||||
const Transform3d m = Geometry::assemble_transform(Vec3d::Zero(), rotation);
|
||||
v.set_volume_rotation(Geometry::extract_euler_angles(m * m_cache.volumes_data[i].get_volume_rotation_matrix()));
|
||||
}
|
||||
#else
|
||||
if (transformation_type.local())
|
||||
v.set_volume_rotation(m_cache.volumes_data[i].get_volume_rotation() + rotation);
|
||||
#endif // ENABLE_INSTANCE_COORDINATES_FOR_VOLUMES
|
||||
else {
|
||||
Transform3d m = Geometry::assemble_transform(Vec3d::Zero(), rotation);
|
||||
m = m * m_cache.volumes_data[i].get_instance_rotation_matrix();
|
||||
|
@ -1123,12 +1111,12 @@ void Selection::scale_to_fit_print_volume(const BuildVolume& volume)
|
|||
type.set_joint();
|
||||
|
||||
// apply scale
|
||||
start_dragging();
|
||||
setup_cache();
|
||||
scale(s * Vec3d::Ones(), type);
|
||||
wxGetApp().plater()->canvas3D()->do_scale(""); // avoid storing another snapshot
|
||||
|
||||
// center selection on print bed
|
||||
start_dragging();
|
||||
setup_cache();
|
||||
offset.z() = -get_bounding_box().min.z();
|
||||
translate(offset);
|
||||
wxGetApp().plater()->canvas3D()->do_move(""); // avoid storing another snapshot
|
||||
|
@ -1318,6 +1306,59 @@ void Selection::translate(unsigned int object_idx, unsigned int instance_idx, co
|
|||
this->set_bounding_boxes_dirty();
|
||||
}
|
||||
|
||||
#if ENABLE_WORLD_COORDINATE_SCALE_REVISITED
|
||||
int Selection::bake_transform_if_needed() const
|
||||
{
|
||||
if ((is_single_full_instance() && wxGetApp().obj_manipul()->is_world_coordinates()) ||
|
||||
(is_single_volume_or_modifier() && !wxGetApp().obj_manipul()->is_local_coordinates())) {
|
||||
// Verify whether the instance rotation is multiples of 90 degrees, so that the scaling in world coordinates is possible.
|
||||
// all volumes in the selection belongs to the same instance, any of them contains the needed instance data, so we take the first one
|
||||
const GLVolume& volume = *get_volume(*get_volume_idxs().begin());
|
||||
bool needs_baking = false;
|
||||
if (is_single_full_instance()) {
|
||||
// Is the instance angle close to a multiple of 90 degrees?
|
||||
needs_baking |= !Geometry::is_rotation_ninety_degrees(volume.get_instance_rotation());
|
||||
// Are all volumes angles close to a multiple of 90 degrees?
|
||||
for (unsigned int id : get_volume_idxs()) {
|
||||
if (needs_baking)
|
||||
break;
|
||||
needs_baking |= !Geometry::is_rotation_ninety_degrees(get_volume(id)->get_volume_rotation());
|
||||
}
|
||||
}
|
||||
else if (is_single_volume_or_modifier()) {
|
||||
// is the volume angle close to a multiple of 90 degrees?
|
||||
needs_baking |= !Geometry::is_rotation_ninety_degrees(volume.get_volume_rotation());
|
||||
if (wxGetApp().obj_manipul()->is_world_coordinates())
|
||||
// Is the instance angle close to a multiple of 90 degrees?
|
||||
needs_baking |= !Geometry::is_rotation_ninety_degrees(volume.get_instance_rotation());
|
||||
}
|
||||
|
||||
if (needs_baking) {
|
||||
MessageDialog dlg((wxWindow*)wxGetApp().mainframe,
|
||||
_L("The currently manipulated object is tilted or contains tilted parts (rotation angles are not multiples of 90°). "
|
||||
"Non-uniform scaling of tilted objects is only possible in non-local coordinate systems, "
|
||||
"once the rotation is embedded into the object coordinates.") + "\n" +
|
||||
_L("This operation is irreversible.") + "\n" +
|
||||
_L("Do you want to proceed?"),
|
||||
SLIC3R_APP_NAME,
|
||||
wxYES_NO | wxNO_DEFAULT | wxICON_QUESTION);
|
||||
if (dlg.ShowModal() != wxID_YES)
|
||||
return -1;
|
||||
|
||||
wxGetApp().plater()->take_snapshot(_("Bake transform"));
|
||||
|
||||
// Bake the rotation into the meshes of the object.
|
||||
wxGetApp().model().objects[volume.composite_id.object_id]->bake_xy_rotation_into_meshes(volume.composite_id.instance_id);
|
||||
// Update the 3D scene, selections etc.
|
||||
wxGetApp().plater()->update();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
#endif // ENABLE_WORLD_COORDINATE_SCALE_REVISITED
|
||||
|
||||
void Selection::erase()
|
||||
{
|
||||
if (!m_valid)
|
||||
|
@ -1431,7 +1472,33 @@ void Selection::render(float scale_factor)
|
|||
m_scale_factor = scale_factor;
|
||||
// render cumulative bounding box of selected volumes
|
||||
#if ENABLE_GLBEGIN_GLEND_REMOVAL
|
||||
#if ENABLE_COORDINATE_DEPENDENT_SELECTION_BOX
|
||||
BoundingBoxf3 box;
|
||||
Transform3d trafo;
|
||||
const ECoordinatesType coordinates_type = wxGetApp().obj_manipul()->get_coordinates_type();
|
||||
if (coordinates_type == ECoordinatesType::World) {
|
||||
box = get_bounding_box();
|
||||
trafo = Transform3d::Identity();
|
||||
}
|
||||
else if (coordinates_type == ECoordinatesType::Local && is_single_volume_or_modifier()) {
|
||||
const GLVolume& v = *get_volume(*get_volume_idxs().begin());
|
||||
box = v.transformed_convex_hull_bounding_box(v.get_instance_transformation().get_matrix(true, true, false, true) * v.get_volume_transformation().get_matrix(true, true, false, true));
|
||||
trafo = v.get_instance_transformation().get_matrix(false, false, true, false) * v.get_volume_transformation().get_matrix(false, false, true, false);
|
||||
}
|
||||
else {
|
||||
const Selection::IndicesList& ids = get_volume_idxs();
|
||||
for (unsigned int id : ids) {
|
||||
const GLVolume& v = *get_volume(id);
|
||||
box.merge(v.transformed_convex_hull_bounding_box(v.get_volume_transformation().get_matrix()));
|
||||
}
|
||||
box = box.transformed(get_volume(*ids.begin())->get_instance_transformation().get_matrix(true, true, false, true));
|
||||
trafo = get_volume(*ids.begin())->get_instance_transformation().get_matrix(false, false, true, false);
|
||||
}
|
||||
|
||||
render_bounding_box(box, trafo, ColorRGB::WHITE());
|
||||
#else
|
||||
render_bounding_box(get_bounding_box(), ColorRGB::WHITE());
|
||||
#endif // ENABLE_COORDINATE_DEPENDENT_SELECTION_BOX
|
||||
#else
|
||||
render_selected_volumes();
|
||||
#endif // ENABLE_GLBEGIN_GLEND_REMOVAL
|
||||
|
@ -1500,38 +1567,36 @@ void Selection::render_sidebar_hints(const std::string& sidebar_field)
|
|||
|
||||
glsafe(::glEnable(GL_DEPTH_TEST));
|
||||
|
||||
#if ENABLE_WORLD_COORDINATE_SHOW_AXES
|
||||
const Vec3d center = get_bounding_box().center();
|
||||
Vec3d axes_center = center;
|
||||
Transform3d orient_matrix = Transform3d::Identity();
|
||||
#else
|
||||
glsafe(::glPushMatrix());
|
||||
#endif // ENABLE_WORLD_COORDINATE_SHOW_AXES
|
||||
|
||||
if (!boost::starts_with(sidebar_field, "layer")) {
|
||||
#if !ENABLE_WORLD_COORDINATE_SHOW_AXES
|
||||
const Vec3d center = get_bounding_box().center();
|
||||
|
||||
#if ENABLE_INSTANCE_COORDINATES_FOR_VOLUMES
|
||||
#endif // !ENABLE_WORLD_COORDINATE_SHOW_AXES
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
if (is_single_full_instance() && !wxGetApp().obj_manipul()->is_world_coordinates()) {
|
||||
#else
|
||||
if (is_single_full_instance() && !wxGetApp().obj_manipul()->get_world_coordinates()) {
|
||||
#endif // ENABLE_INSTANCE_COORDINATES_FOR_VOLUMES
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
#if !ENABLE_WORLD_COORDINATE_SHOW_AXES
|
||||
glsafe(::glTranslated(center.x(), center.y(), center.z()));
|
||||
#endif // !ENABLE_WORLD_COORDINATE_SHOW_AXES
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
#if !ENABLE_WORLD_COORDINATE_SHOW_AXES
|
||||
Transform3d orient_matrix = Transform3d::Identity();
|
||||
#if ENABLE_INSTANCE_COORDINATES_FOR_VOLUMES
|
||||
#endif // !ENABLE_WORLD_COORDINATE_SHOW_AXES
|
||||
orient_matrix = (*m_volumes)[*m_list.begin()]->get_instance_transformation().get_matrix(true, false, true, true);
|
||||
#if ENABLE_WORLD_COORDINATE_SHOW_AXES
|
||||
axes_center = (*m_volumes)[*m_list.begin()]->get_instance_offset();
|
||||
#else
|
||||
if (boost::starts_with(sidebar_field, "position") || boost::starts_with(sidebar_field, "scale"))
|
||||
orient_matrix = (*m_volumes)[*m_list.begin()]->get_instance_transformation().get_matrix(true, false, true, true);
|
||||
else if (boost::starts_with(sidebar_field, "rotation")) {
|
||||
if (boost::ends_with(sidebar_field, "x"))
|
||||
orient_matrix = (*m_volumes)[*m_list.begin()]->get_instance_transformation().get_matrix(true, false, true, true);
|
||||
else if (boost::ends_with(sidebar_field, "y")) {
|
||||
const Vec3d& rotation = (*m_volumes)[*m_list.begin()]->get_instance_transformation().get_rotation();
|
||||
if (rotation.x() == 0.0)
|
||||
orient_matrix = (*m_volumes)[*m_list.begin()]->get_instance_transformation().get_matrix(true, false, true, true);
|
||||
else
|
||||
orient_matrix.rotate(Eigen::AngleAxisd(rotation.z(), Vec3d::UnitZ()));
|
||||
}
|
||||
}
|
||||
#endif // ENABLE_INSTANCE_COORDINATES_FOR_VOLUMES
|
||||
|
||||
glsafe(::glMultMatrixd(orient_matrix.data()));
|
||||
#endif // ENABLE_WORLD_COORDINATE_SHOW_AXES
|
||||
#else
|
||||
if (!boost::starts_with(sidebar_field, "position")) {
|
||||
Transform3d orient_matrix = Transform3d::Identity();
|
||||
|
@ -1558,23 +1623,30 @@ void Selection::render_sidebar_hints(const std::string& sidebar_field)
|
|||
#else
|
||||
else if (is_single_volume() || is_single_modifier()) {
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
#if !ENABLE_WORLD_COORDINATE_SHOW_AXES
|
||||
glsafe(::glTranslated(center.x(), center.y(), center.z()));
|
||||
#endif // !ENABLE_WORLD_COORDINATE_SHOW_AXES
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
#if ENABLE_INSTANCE_COORDINATES_FOR_VOLUMES
|
||||
if (!wxGetApp().obj_manipul()->is_world_coordinates()) {
|
||||
#if !ENABLE_WORLD_COORDINATE_SHOW_AXES
|
||||
Transform3d orient_matrix = Transform3d::Identity();
|
||||
#endif // !ENABLE_WORLD_COORDINATE_SHOW_AXES
|
||||
if (wxGetApp().obj_manipul()->is_local_coordinates()) {
|
||||
#else
|
||||
if (!wxGetApp().obj_manipul()->get_world_coordinates()) {
|
||||
Transform3d orient_matrix = Transform3d::Identity();
|
||||
if (boost::starts_with(sidebar_field, "scale")) {
|
||||
#endif // ENABLE_INSTANCE_COORDINATES_FOR_VOLUMES
|
||||
const GLVolume* v = (*m_volumes)[*m_list.begin()];
|
||||
orient_matrix = v->get_instance_transformation().get_matrix(true, false, true, true) * v->get_volume_transformation().get_matrix(true, false, true, true);
|
||||
#if ENABLE_WORLD_COORDINATE_SHOW_AXES
|
||||
axes_center = (*m_volumes)[*m_list.begin()]->world_matrix().translation();
|
||||
#endif // ENABLE_WORLD_COORDINATE_SHOW_AXES
|
||||
}
|
||||
else
|
||||
else {
|
||||
orient_matrix = (*m_volumes)[*m_list.begin()]->get_instance_transformation().get_matrix(true, false, true, true);
|
||||
#if ENABLE_WORLD_COORDINATE_SHOW_AXES
|
||||
axes_center = (*m_volumes)[*m_list.begin()]->get_instance_offset();
|
||||
}
|
||||
#else
|
||||
}
|
||||
glsafe(::glMultMatrixd(orient_matrix.data()));
|
||||
#endif // ENABLE_WORLD_COORDINATE_SHOW_AXES
|
||||
}
|
||||
#else
|
||||
Transform3d orient_matrix = (*m_volumes)[*m_list.begin()]->get_instance_transformation().get_matrix(true, false, true, true);
|
||||
|
@ -1584,11 +1656,16 @@ void Selection::render_sidebar_hints(const std::string& sidebar_field)
|
|||
#endif // ENABLE_WORLD_COORDINATE
|
||||
}
|
||||
else {
|
||||
#if ENABLE_WORLD_COORDINATE_SHOW_AXES
|
||||
if (requires_local_axes())
|
||||
orient_matrix = (*m_volumes)[*m_list.begin()]->get_instance_transformation().get_matrix(true, false, true, true);
|
||||
#else
|
||||
glsafe(::glTranslated(center.x(), center.y(), center.z()));
|
||||
if (requires_local_axes()) {
|
||||
const Transform3d orient_matrix = (*m_volumes)[*m_list.begin()]->get_instance_transformation().get_matrix(true, false, true, true);
|
||||
glsafe(::glMultMatrixd(orient_matrix.data()));
|
||||
}
|
||||
#endif // ENABLE_WORLD_COORDINATE_SHOW_AXES
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1597,6 +1674,15 @@ void Selection::render_sidebar_hints(const std::string& sidebar_field)
|
|||
glsafe(::glClear(GL_DEPTH_BUFFER_BIT));
|
||||
#endif // ENABLE_GLBEGIN_GLEND_REMOVAL
|
||||
|
||||
#if ENABLE_WORLD_COORDINATE_SHOW_AXES
|
||||
if (!boost::starts_with(sidebar_field, "layer")) {
|
||||
shader->set_uniform("emission_factor", 0.1f);
|
||||
glsafe(::glPushMatrix());
|
||||
glsafe(::glTranslated(center.x(), center.y(), center.z()));
|
||||
glsafe(::glMultMatrixd(orient_matrix.data()));
|
||||
}
|
||||
#endif // ENABLE_WORLD_COORDINATE_SHOW_AXES
|
||||
|
||||
if (boost::starts_with(sidebar_field, "position"))
|
||||
render_sidebar_position_hints(sidebar_field);
|
||||
else if (boost::starts_with(sidebar_field, "rotation"))
|
||||
|
@ -1606,7 +1692,19 @@ void Selection::render_sidebar_hints(const std::string& sidebar_field)
|
|||
else if (boost::starts_with(sidebar_field, "layer"))
|
||||
render_sidebar_layers_hints(sidebar_field);
|
||||
|
||||
#if ENABLE_WORLD_COORDINATE_SHOW_AXES
|
||||
if (!boost::starts_with(sidebar_field, "layer")) {
|
||||
glsafe(::glPopMatrix());
|
||||
glsafe(::glPushMatrix());
|
||||
glsafe(::glTranslated(axes_center.x(), axes_center.y(), axes_center.z()));
|
||||
glsafe(::glMultMatrixd(orient_matrix.data()));
|
||||
if (!wxGetApp().obj_manipul()->is_world_coordinates())
|
||||
m_axes.render(0.25f);
|
||||
glsafe(::glPopMatrix());
|
||||
}
|
||||
#else
|
||||
glsafe(::glPopMatrix());
|
||||
#endif // ENABLE_WORLD_COORDINATE_SHOW_AXES
|
||||
|
||||
#if !ENABLE_GLBEGIN_GLEND_REMOVAL
|
||||
if (!boost::starts_with(sidebar_field, "layer"))
|
||||
|
@ -2042,6 +2140,12 @@ void Selection::render_synchronized_volumes()
|
|||
float color[3] = { 1.0f, 1.0f, 0.0f };
|
||||
#endif // !ENABLE_GLBEGIN_GLEND_REMOVAL
|
||||
|
||||
#if ENABLE_COORDINATE_DEPENDENT_SELECTION_BOX
|
||||
const ECoordinatesType coordinates_type = wxGetApp().obj_manipul()->get_coordinates_type();
|
||||
BoundingBoxf3 box;
|
||||
Transform3d trafo;
|
||||
#endif // ENABLE_COORDINATE_DEPENDENT_SELECTION_BOX
|
||||
|
||||
for (unsigned int i : m_list) {
|
||||
const GLVolume& volume = *(*m_volumes)[i];
|
||||
int object_idx = volume.object_idx();
|
||||
|
@ -2055,7 +2159,23 @@ void Selection::render_synchronized_volumes()
|
|||
continue;
|
||||
|
||||
#if ENABLE_GLBEGIN_GLEND_REMOVAL
|
||||
#if ENABLE_COORDINATE_DEPENDENT_SELECTION_BOX
|
||||
if (coordinates_type == ECoordinatesType::World) {
|
||||
box = v.transformed_convex_hull_bounding_box();
|
||||
trafo = Transform3d::Identity();
|
||||
}
|
||||
else if (coordinates_type == ECoordinatesType::Local) {
|
||||
box = v.bounding_box();
|
||||
trafo = v.world_matrix();
|
||||
}
|
||||
else {
|
||||
box = v.transformed_convex_hull_bounding_box(v.get_volume_transformation().get_matrix());
|
||||
trafo = v.get_instance_transformation().get_matrix();
|
||||
}
|
||||
render_bounding_box(box, trafo, ColorRGB::YELLOW());
|
||||
#else
|
||||
render_bounding_box(v.transformed_convex_hull_bounding_box(), ColorRGB::YELLOW());
|
||||
#endif // ENABLE_COORDINATE_DEPENDENT_SELECTION_BOX
|
||||
#else
|
||||
render_bounding_box(v.transformed_convex_hull_bounding_box(), color);
|
||||
#endif // ENABLE_GLBEGIN_GLEND_REMOVAL
|
||||
|
@ -2064,7 +2184,11 @@ void Selection::render_synchronized_volumes()
|
|||
}
|
||||
|
||||
#if ENABLE_GLBEGIN_GLEND_REMOVAL
|
||||
#if ENABLE_COORDINATE_DEPENDENT_SELECTION_BOX
|
||||
void Selection::render_bounding_box(const BoundingBoxf3& box, const Transform3d& trafo, const ColorRGB& color)
|
||||
#else
|
||||
void Selection::render_bounding_box(const BoundingBoxf3& box, const ColorRGB& color)
|
||||
#endif // ENABLE_COORDINATE_DEPENDENT_SELECTION_BOX
|
||||
{
|
||||
#else
|
||||
void Selection::render_bounding_box(const BoundingBoxf3 & box, float* color) const
|
||||
|
@ -2083,6 +2207,7 @@ void Selection::render_bounding_box(const BoundingBoxf3 & box, float* color) con
|
|||
|
||||
#if ENABLE_GLBEGIN_GLEND_REMOVAL
|
||||
const BoundingBoxf3& curr_box = m_box.get_bounding_box();
|
||||
|
||||
if (!m_box.is_initialized() || !is_approx(box.min, curr_box.min) || !is_approx(box.max, curr_box.max)) {
|
||||
m_box.reset();
|
||||
|
||||
|
@ -2168,10 +2293,19 @@ void Selection::render_bounding_box(const BoundingBoxf3 & box, float* color) con
|
|||
if (shader == nullptr)
|
||||
return;
|
||||
|
||||
#if ENABLE_COORDINATE_DEPENDENT_SELECTION_BOX
|
||||
glsafe(::glPushMatrix());
|
||||
glsafe(::glMultMatrixd(trafo.data()));
|
||||
#endif // ENABLE_COORDINATE_DEPENDENT_SELECTION_BOX
|
||||
|
||||
shader->start_using();
|
||||
m_box.set_color(to_rgba(color));
|
||||
m_box.render();
|
||||
shader->stop_using();
|
||||
|
||||
#if ENABLE_COORDINATE_DEPENDENT_SELECTION_BOX
|
||||
glsafe(::glPopMatrix());
|
||||
#endif // ENABLE_COORDINATE_DEPENDENT_SELECTION_BOX
|
||||
#else
|
||||
::glBegin(GL_LINES);
|
||||
|
||||
|
@ -2308,9 +2442,11 @@ void Selection::render_sidebar_scale_hints(const std::string& sidebar_field)
|
|||
#else
|
||||
m_arrow.set_color(-1, uniform_scale ? UNIFORM_SCALE_COLOR : get_color(axis));
|
||||
#endif // ENABLE_GLBEGIN_GLEND_REMOVAL
|
||||
#if !ENABLE_WORLD_COORDINATE_SHOW_AXES
|
||||
GLShaderProgram* shader = wxGetApp().get_current_shader();
|
||||
if (shader != nullptr)
|
||||
shader->set_uniform("emission_factor", 0.0f);
|
||||
#endif // !ENABLE_WORLD_COORDINATE_SHOW_AXES
|
||||
|
||||
glsafe(::glTranslated(0.0, 5.0, 0.0));
|
||||
m_arrow.render();
|
||||
|
|
|
@ -2,10 +2,16 @@
|
|||
#define slic3r_GUI_Selection_hpp_
|
||||
|
||||
#include "libslic3r/Geometry.hpp"
|
||||
#if ENABLE_INSTANCE_COORDINATES_FOR_VOLUMES
|
||||
#include "slic3r/GUI/GUI_Geometry.hpp"
|
||||
#endif // ENABLE_INSTANCE_COORDINATES_FOR_VOLUMES
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
#include "GUI_Geometry.hpp"
|
||||
#if ENABLE_WORLD_COORDINATE_SHOW_AXES
|
||||
#include "CoordAxes.hpp"
|
||||
#else
|
||||
#include "GLModel.hpp"
|
||||
#endif // ENABLE_WORLD_COORDINATE_SHOW_AXES
|
||||
#else
|
||||
#include "GLModel.hpp"
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
||||
#include <set>
|
||||
#include <optional>
|
||||
|
@ -27,7 +33,7 @@ using ModelObjectPtrs = std::vector<ModelObject*>;
|
|||
|
||||
|
||||
namespace GUI {
|
||||
#if !ENABLE_INSTANCE_COORDINATES_FOR_VOLUMES
|
||||
#if !ENABLE_WORLD_COORDINATE
|
||||
class TransformationType
|
||||
{
|
||||
public:
|
||||
|
@ -80,7 +86,7 @@ private:
|
|||
|
||||
Enum m_value;
|
||||
};
|
||||
#endif // !ENABLE_INSTANCE_COORDINATES_FOR_VOLUMES
|
||||
#endif // !ENABLE_WORLD_COORDINATE
|
||||
|
||||
class Selection
|
||||
{
|
||||
|
@ -221,6 +227,9 @@ private:
|
|||
GLModel m_vbo_sphere;
|
||||
#endif // ENABLE_RENDER_SELECTION_CENTER
|
||||
|
||||
#if ENABLE_WORLD_COORDINATE_SHOW_AXES
|
||||
CoordAxes m_axes;
|
||||
#endif // ENABLE_WORLD_COORDINATE_SHOW_AXES
|
||||
GLModel m_arrow;
|
||||
GLModel m_curved_arrow;
|
||||
#if ENABLE_GLBEGIN_GLEND_REMOVAL
|
||||
|
@ -234,7 +243,6 @@ private:
|
|||
#endif // ENABLE_GLBEGIN_GLEND_REMOVAL
|
||||
|
||||
float m_scale_factor;
|
||||
bool m_dragging;
|
||||
|
||||
public:
|
||||
Selection();
|
||||
|
@ -308,7 +316,7 @@ public:
|
|||
// returns true if the selection contains all and only the given indices
|
||||
bool matches(const std::vector<unsigned int>& volume_idxs) const;
|
||||
|
||||
#if ENABLE_INSTANCE_COORDINATES_FOR_VOLUMES
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
enum class EUniformScaleRequiredReason : unsigned char
|
||||
{
|
||||
NotRequired,
|
||||
|
@ -320,7 +328,7 @@ public:
|
|||
bool requires_uniform_scale(EUniformScaleRequiredReason* reason = nullptr) const;
|
||||
#else
|
||||
bool requires_uniform_scale() const;
|
||||
#endif // ENABLE_INSTANCE_COORDINATES_FOR_VOLUMES
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
||||
// Returns the the object id if the selection is from a single object, otherwise is -1
|
||||
int get_object_idx() const;
|
||||
|
@ -342,15 +350,13 @@ public:
|
|||
const BoundingBoxf3& get_unscaled_instance_bounding_box() const;
|
||||
const BoundingBoxf3& get_scaled_instance_bounding_box() const;
|
||||
|
||||
void start_dragging();
|
||||
void stop_dragging() { m_dragging = false; }
|
||||
bool is_dragging() const { return m_dragging; }
|
||||
void setup_cache();
|
||||
|
||||
#if ENABLE_INSTANCE_COORDINATES_FOR_VOLUMES
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
void translate(const Vec3d& displacement, ECoordinatesType type = ECoordinatesType::World);
|
||||
#else
|
||||
void translate(const Vec3d& displacement, bool local = false);
|
||||
#endif // ENABLE_INSTANCE_COORDINATES_FOR_VOLUMES
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
void rotate(const Vec3d& rotation, TransformationType transformation_type);
|
||||
void flattening_rotate(const Vec3d& normal);
|
||||
void scale(const Vec3d& scale, TransformationType transformation_type);
|
||||
|
@ -360,6 +366,14 @@ public:
|
|||
void translate(unsigned int object_idx, const Vec3d& displacement);
|
||||
void translate(unsigned int object_idx, unsigned int instance_idx, const Vec3d& displacement);
|
||||
|
||||
#if ENABLE_WORLD_COORDINATE_SCALE_REVISITED
|
||||
// returns:
|
||||
// -1 if the user refused to proceed with baking when asked
|
||||
// 0 if the baking was performed
|
||||
// 1 if no baking was needed
|
||||
int bake_transform_if_needed() const;
|
||||
#endif // ENABLE_WORLD_COORDINATE_SCALE_REVISITED
|
||||
|
||||
void erase();
|
||||
|
||||
void render(float scale_factor = 1.0);
|
||||
|
@ -398,7 +412,11 @@ private:
|
|||
void set_bounding_boxes_dirty() { m_bounding_box.reset(); m_unscaled_instance_bounding_box.reset(); m_scaled_instance_bounding_box.reset(); }
|
||||
void render_synchronized_volumes();
|
||||
#if ENABLE_GLBEGIN_GLEND_REMOVAL
|
||||
#if ENABLE_COORDINATE_DEPENDENT_SELECTION_BOX
|
||||
void render_bounding_box(const BoundingBoxf3& box, const Transform3d& trafo, const ColorRGB& color);
|
||||
#else
|
||||
void render_bounding_box(const BoundingBoxf3& box, const ColorRGB& color);
|
||||
#endif // ENABLE_COORDINATE_DEPENDENT_SELECTION_BOX
|
||||
#else
|
||||
void render_selected_volumes() const;
|
||||
void render_bounding_box(const BoundingBoxf3& box, float* color) const;
|
||||
|
|
|
@ -1247,6 +1247,7 @@ void Tab::on_presets_changed()
|
|||
// to avoid needless preset loading from update() function
|
||||
m_dependent_tabs.clear();
|
||||
|
||||
// Update Project dirty state, update application title bar.
|
||||
wxGetApp().plater()->update_project_dirty_from_presets();
|
||||
}
|
||||
|
||||
|
@ -4113,7 +4114,7 @@ wxSizer* TabPrint::create_manage_substitution_widget(wxWindow* parent)
|
|||
|
||||
create_btn(&m_del_all_substitutions_btn, _L("Delete all"), "cross");
|
||||
m_del_all_substitutions_btn->Bind(wxEVT_BUTTON, [this, parent](wxCommandEvent e) {
|
||||
if (MessageDialog(parent, _L("Are you sure you want to delete all substitutions?"), SLIC3R_APP_NAME, wxYES_NO | wxICON_QUESTION).
|
||||
if (MessageDialog(parent, _L("Are you sure you want to delete all substitutions?"), SLIC3R_APP_NAME, wxYES_NO | wxCANCEL | wxICON_QUESTION).
|
||||
ShowModal() != wxID_YES)
|
||||
return;
|
||||
m_subst_manager.delete_all();
|
||||
|
|
|
@ -371,6 +371,7 @@ public:
|
|||
|
||||
DynamicPrintConfig* get_config() { return m_config; }
|
||||
PresetCollection* get_presets() { return m_presets; }
|
||||
const PresetCollection* get_presets() const { return m_presets; }
|
||||
|
||||
void on_value_change(const std::string& opt_key, const boost::any& value);
|
||||
|
||||
|
|
|
@ -581,8 +581,12 @@ void LockButton::OnButton(wxCommandEvent& event)
|
|||
if (m_disabled)
|
||||
return;
|
||||
|
||||
#if ENABLE_WORLD_COORDINATE_SCALE_REVISITED
|
||||
SetLock(!m_is_pushed);
|
||||
#else
|
||||
m_is_pushed = !m_is_pushed;
|
||||
update_button_bitmaps();
|
||||
#endif // ENABLE_WORLD_COORDINATE_SCALE_REVISITED
|
||||
|
||||
event.Skip();
|
||||
}
|
||||
|
|
|
@ -1,3 +1,18 @@
|
|||
#include <catch_main.hpp>
|
||||
|
||||
#include "libslic3r/libslic3r.h"
|
||||
|
||||
// __has_feature() is used later for Clang, this is for compatibility with other compilers (such as GCC and MSVC)
|
||||
#ifndef __has_feature
|
||||
# define __has_feature(x) 0
|
||||
#endif
|
||||
|
||||
// Print reports about memory leaks but exit with zero exit code when any memory leaks is found to make unit tests pass.
|
||||
// After merging the stable branch (2.4.1) with the master branch, this should be deleted.
|
||||
#if __has_feature(address_sanitizer) || defined(__SANITIZE_ADDRESS__)
|
||||
extern "C" {
|
||||
const char *__lsan_default_options() {
|
||||
return "exitcode=0";
|
||||
}
|
||||
}
|
||||
#endif
|
Loading…
Add table
Reference in a new issue