Merge remote-tracking branch 'origin/master' into ys_cut
This commit is contained in:
commit
ba7b0839f2
103 changed files with 21521 additions and 19209 deletions
|
@ -506,6 +506,12 @@ endif ()
|
|||
|
||||
# Find the Cereal serialization library
|
||||
find_package(cereal REQUIRED)
|
||||
add_library(libcereal INTERFACE)
|
||||
if (NOT TARGET cereal::cereal)
|
||||
target_link_libraries(libcereal INTERFACE cereal)
|
||||
else()
|
||||
target_link_libraries(libcereal INTERFACE cereal::cereal)
|
||||
endif()
|
||||
|
||||
# l10n
|
||||
set(L10N_DIR "${SLIC3R_RESOURCES_DIR}/localization")
|
||||
|
@ -517,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
|
||||
|
@ -539,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
|
@ -126,7 +126,7 @@ if (NOT WIN32 AND NOT APPLE)
|
|||
set_target_properties(PrusaSlicer PROPERTIES OUTPUT_NAME "prusa-slicer")
|
||||
endif ()
|
||||
|
||||
target_link_libraries(PrusaSlicer libslic3r cereal)
|
||||
target_link_libraries(PrusaSlicer libslic3r libcereal)
|
||||
if (APPLE)
|
||||
# add_compile_options(-stdlib=libc++)
|
||||
# add_definitions(-DBOOST_THREAD_DONT_USE_CHRONO -DBOOST_NO_CXX11_RVALUE_REFERENCES -DBOOST_THREAD_USES_MOVE)
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -94,6 +94,8 @@ set(SLIC3R_SOURCES
|
|||
Format/objparser.hpp
|
||||
Format/STL.cpp
|
||||
Format/STL.hpp
|
||||
Format/SLAArchive.hpp
|
||||
Format/SLAArchive.cpp
|
||||
Format/SL1.hpp
|
||||
Format/SL1.cpp
|
||||
Format/SL1_SVG.hpp
|
||||
|
@ -356,7 +358,7 @@ find_package(JPEG REQUIRED)
|
|||
target_link_libraries(libslic3r
|
||||
libnest2d
|
||||
admesh
|
||||
cereal
|
||||
libcereal
|
||||
libigl
|
||||
miniz
|
||||
boost_libs
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#include <utility>
|
||||
#include <cstddef>
|
||||
#include <iterator>
|
||||
#include <algorithm>
|
||||
|
||||
#include "libslic3r/libslic3r.h"
|
||||
|
||||
|
@ -44,7 +45,8 @@ size_t max_concurrency(const EP &ep)
|
|||
template<class EP, class It, class Fn, class = ExecutionPolicyOnly<EP>>
|
||||
void for_each(const EP &ep, It from, It to, Fn &&fn, size_t granularity = 1)
|
||||
{
|
||||
AsTraits<EP>::for_each(ep, from, to, std::forward<Fn>(fn), granularity);
|
||||
AsTraits<EP>::for_each(ep, from, to, std::forward<Fn>(fn),
|
||||
std::max(granularity, size_t(1)));
|
||||
}
|
||||
|
||||
// A reduce operation with the execution policy passed as argument.
|
||||
|
@ -68,7 +70,7 @@ T reduce(const EP & ep,
|
|||
return AsTraits<EP>::reduce(ep, from, to, init,
|
||||
std::forward<MergeFn>(mergefn),
|
||||
std::forward<AccessFn>(accessfn),
|
||||
granularity);
|
||||
std::max(granularity, size_t(1)));
|
||||
}
|
||||
|
||||
// An overload of reduce method to be used with iterators as 'from' and 'to'
|
||||
|
@ -87,7 +89,7 @@ T reduce(const EP &ep,
|
|||
{
|
||||
return reduce(
|
||||
ep, from, to, init, std::forward<MergeFn>(mergefn),
|
||||
[](const auto &i) { return i; }, granularity);
|
||||
[](const auto &i) { return i; }, std::max(granularity, size_t(1)));
|
||||
}
|
||||
|
||||
template<class EP,
|
||||
|
@ -103,7 +105,8 @@ T accumulate(const EP & ep,
|
|||
size_t granularity = 1)
|
||||
{
|
||||
return reduce(ep, from, to, init, std::plus<T>{},
|
||||
std::forward<AccessFn>(accessfn), granularity);
|
||||
std::forward<AccessFn>(accessfn),
|
||||
std::max(granularity, size_t(1)));
|
||||
}
|
||||
|
||||
|
||||
|
@ -119,7 +122,7 @@ T accumulate(const EP &ep,
|
|||
{
|
||||
return reduce(
|
||||
ep, from, to, init, std::plus<T>{}, [](const auto &i) { return i; },
|
||||
granularity);
|
||||
std::max(granularity, size_t(1)));
|
||||
}
|
||||
|
||||
} // namespace execution_policy
|
||||
|
|
|
@ -3,8 +3,12 @@
|
|||
|
||||
#include <string>
|
||||
|
||||
#include "SLAArchive.hpp"
|
||||
|
||||
#include "libslic3r/Zipper.hpp"
|
||||
#include "libslic3r/SLAPrint.hpp"
|
||||
#include "libslic3r/PrintConfig.hpp"
|
||||
|
||||
struct indexed_triangle_set;
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#include "SLA/RasterBase.hpp"
|
||||
#include "libslic3r/LocalesUtils.hpp"
|
||||
#include "libslic3r/ClipperUtils.hpp"
|
||||
#include "libslic3r/BoundingBox.hpp"
|
||||
|
||||
#include <limits>
|
||||
#include <cstdint>
|
||||
|
|
74
src/libslic3r/Format/SLAArchive.cpp
Normal file
74
src/libslic3r/Format/SLAArchive.cpp
Normal file
|
@ -0,0 +1,74 @@
|
|||
#include "SLAArchive.hpp"
|
||||
|
||||
#include "SL1.hpp"
|
||||
#include "SL1_SVG.hpp"
|
||||
#include "pwmx.hpp"
|
||||
|
||||
#include "libslic3r/libslic3r.h"
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <tuple>
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
using ArchiveFactory = std::function<std::unique_ptr<SLAArchive>(const SLAPrinterConfig&)>;
|
||||
|
||||
struct ArchiveEntry {
|
||||
const char *ext;
|
||||
ArchiveFactory factoryfn;
|
||||
};
|
||||
|
||||
static const std::map<std::string, ArchiveEntry> REGISTERED_ARCHIVES {
|
||||
{
|
||||
"SL1",
|
||||
{ "sl1", [] (const auto &cfg) { return std::make_unique<SL1Archive>(cfg); } }
|
||||
},
|
||||
{
|
||||
"SL2",
|
||||
{ "sl2", [] (const auto &cfg) { return std::make_unique<SL1_SVGArchive>(cfg); } }
|
||||
},
|
||||
{
|
||||
"pwmx",
|
||||
{ "pwmx", [] (const auto &cfg) { return std::make_unique<PwmxArchive>(cfg); } }
|
||||
}
|
||||
};
|
||||
|
||||
std::unique_ptr<SLAArchive>
|
||||
SLAArchive::create(const std::string &archtype, const SLAPrinterConfig &cfg)
|
||||
{
|
||||
auto entry = REGISTERED_ARCHIVES.find(archtype);
|
||||
|
||||
if (entry != REGISTERED_ARCHIVES.end())
|
||||
return entry->second.factoryfn(cfg);
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const std::vector<const char*>& SLAArchive::registered_archives()
|
||||
{
|
||||
static std::vector<const char*> archnames;
|
||||
|
||||
if (archnames.empty()) {
|
||||
archnames.reserve(REGISTERED_ARCHIVES.size());
|
||||
|
||||
for (auto &[name, _] : REGISTERED_ARCHIVES)
|
||||
archnames.emplace_back(name.c_str());
|
||||
}
|
||||
|
||||
return archnames;
|
||||
}
|
||||
|
||||
const char *SLAArchive::get_extension(const char *archtype)
|
||||
{
|
||||
static const char* DEFAULT_EXT = "zip";
|
||||
|
||||
auto entry = REGISTERED_ARCHIVES.find(archtype);
|
||||
if (entry != REGISTERED_ARCHIVES.end())
|
||||
return entry->second.ext;
|
||||
|
||||
return DEFAULT_EXT;
|
||||
}
|
||||
|
||||
} // namespace Slic3r
|
64
src/libslic3r/Format/SLAArchive.hpp
Normal file
64
src/libslic3r/Format/SLAArchive.hpp
Normal file
|
@ -0,0 +1,64 @@
|
|||
#ifndef SLAARCHIVE_HPP
|
||||
#define SLAARCHIVE_HPP
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "libslic3r/SLA/RasterBase.hpp"
|
||||
#include "libslic3r/Execution/ExecutionTBB.hpp"
|
||||
#include "libslic3r/GCode/ThumbnailData.hpp"
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
class SLAPrint;
|
||||
class SLAPrinterConfig;
|
||||
|
||||
class SLAArchive {
|
||||
protected:
|
||||
std::vector<sla::EncodedRaster> m_layers;
|
||||
|
||||
virtual std::unique_ptr<sla::RasterBase> create_raster() const = 0;
|
||||
virtual sla::RasterEncoder get_encoder() const = 0;
|
||||
|
||||
public:
|
||||
virtual ~SLAArchive() = default;
|
||||
|
||||
// Fn have to be thread safe: void(sla::RasterBase& raster, size_t lyrid);
|
||||
template<class Fn, class CancelFn, class EP = ExecutionTBB>
|
||||
void draw_layers(
|
||||
size_t layer_num,
|
||||
Fn && drawfn,
|
||||
CancelFn cancelfn = []() { return false; },
|
||||
const EP & ep = {})
|
||||
{
|
||||
m_layers.resize(layer_num);
|
||||
execution::for_each(
|
||||
ep, size_t(0), m_layers.size(),
|
||||
[this, &drawfn, &cancelfn](size_t idx) {
|
||||
if (cancelfn()) return;
|
||||
|
||||
sla::EncodedRaster &enc = m_layers[idx];
|
||||
auto rst = create_raster();
|
||||
drawfn(*rst, idx);
|
||||
enc = rst->encode(get_encoder());
|
||||
},
|
||||
execution::max_concurrency(ep));
|
||||
}
|
||||
|
||||
// Export the print into an archive using the provided filename.
|
||||
virtual void export_print(const std::string fname,
|
||||
const SLAPrint &print,
|
||||
const ThumbnailsList &thumbnails,
|
||||
const std::string &projectname = "") = 0;
|
||||
|
||||
// Factory method to create an archiver instance
|
||||
static std::unique_ptr<SLAArchive> create(const std::string &archtype, const SLAPrinterConfig&);
|
||||
|
||||
// Get the names of currently known archiver implementations
|
||||
static const std::vector<const char *> & registered_archives();
|
||||
|
||||
// Get the default file extension belonging to an archive format
|
||||
static const char *get_extension(const char *archtype);
|
||||
};
|
||||
|
||||
} // namespace Slic3r
|
||||
#endif // SLAARCHIVE_HPP
|
|
@ -1,6 +1,7 @@
|
|||
#include "pwmx.hpp"
|
||||
#include "GCode/ThumbnailData.hpp"
|
||||
#include "SLA/RasterBase.hpp"
|
||||
#include "libslic3r/SLAPrint.hpp"
|
||||
|
||||
#include <sstream>
|
||||
#include <iostream>
|
||||
|
@ -277,8 +278,9 @@ void fill_header(pwmx_format_header &h,
|
|||
std::float_t bottle_volume_ml;
|
||||
std::float_t bottle_cost;
|
||||
std::float_t material_density;
|
||||
auto & cfg = print.full_print_config();
|
||||
std::string mnotes = cfg.option("material_notes")->serialize();
|
||||
auto &cfg = print.full_print_config();
|
||||
auto mat_opt = cfg.option("material_notes");
|
||||
std::string mnotes = mat_opt? cfg.option("material_notes")->serialize() : "";
|
||||
// create a config parser from the material notes
|
||||
Slic3r::PwmxFormatDynamicConfig mat_cfg;
|
||||
SLAPrintStatistics stats = print.print_statistics();
|
||||
|
|
|
@ -3,7 +3,9 @@
|
|||
|
||||
#include <string>
|
||||
|
||||
#include "libslic3r/SLAPrint.hpp"
|
||||
#include "SLAArchive.hpp"
|
||||
|
||||
#include "libslic3r/PrintConfig.hpp"
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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.");
|
||||
|
|
|
@ -982,7 +982,7 @@ bool SupportTreeBuildsteps::connect_to_model_body(Head &head)
|
|||
double w = dist - 2 * head.r_pin_mm - head.r_back_mm;
|
||||
|
||||
if (w < 0.) {
|
||||
BOOST_LOG_TRIVIAL(error) << "Pinhead width is negative!";
|
||||
BOOST_LOG_TRIVIAL(warning) << "Pinhead width is negative!";
|
||||
w = 0.;
|
||||
}
|
||||
|
||||
|
|
|
@ -245,15 +245,8 @@ SLAPrint::ApplyStatus SLAPrint::apply(const Model &model, DynamicPrintConfig con
|
|||
// Handle changes to object config defaults
|
||||
m_default_object_config.apply_only(config, object_diff, true);
|
||||
|
||||
if (!m_archiver || !printer_diff.empty()) {
|
||||
if (m_printer_config.sla_archive_format.value == "SL1")
|
||||
m_archiver = std::make_unique<SL1Archive>(m_printer_config);
|
||||
else if (m_printer_config.sla_archive_format.value == "SL2")
|
||||
m_archiver = std::make_unique<SL1_SVGArchive>(m_printer_config);
|
||||
else if (m_printer_config.sla_archive_format.value == "pwmx") {
|
||||
m_archiver = std::make_unique<PwmxArchive>(m_printer_config);
|
||||
}
|
||||
}
|
||||
if (!m_archiver || !printer_diff.empty())
|
||||
m_archiver = SLAArchive::create(m_printer_config.sla_archive_format.value.c_str(), m_printer_config);
|
||||
|
||||
struct ModelObjectStatus {
|
||||
enum Status {
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#include "Point.hpp"
|
||||
#include "MTUtils.hpp"
|
||||
#include "Zipper.hpp"
|
||||
#include "Format/SLAArchive.hpp"
|
||||
#include "GCode/ThumbnailData.hpp"
|
||||
|
||||
#include "libslic3r/Execution/ExecutionTBB.hpp"
|
||||
|
@ -390,45 +391,6 @@ struct SLAPrintStatistics
|
|||
}
|
||||
};
|
||||
|
||||
class SLAArchive {
|
||||
protected:
|
||||
std::vector<sla::EncodedRaster> m_layers;
|
||||
|
||||
virtual std::unique_ptr<sla::RasterBase> create_raster() const = 0;
|
||||
virtual sla::RasterEncoder get_encoder() const = 0;
|
||||
|
||||
public:
|
||||
virtual ~SLAArchive() = default;
|
||||
|
||||
// Fn have to be thread safe: void(sla::RasterBase& raster, size_t lyrid);
|
||||
template<class Fn, class CancelFn, class EP = ExecutionTBB>
|
||||
void draw_layers(
|
||||
size_t layer_num,
|
||||
Fn && drawfn,
|
||||
CancelFn cancelfn = []() { return false; },
|
||||
const EP & ep = {})
|
||||
{
|
||||
m_layers.resize(layer_num);
|
||||
execution::for_each(
|
||||
ep, size_t(0), m_layers.size(),
|
||||
[this, &drawfn, &cancelfn](size_t idx) {
|
||||
if (cancelfn()) return;
|
||||
|
||||
sla::EncodedRaster &enc = m_layers[idx];
|
||||
auto rst = create_raster();
|
||||
drawfn(*rst, idx);
|
||||
enc = rst->encode(get_encoder());
|
||||
},
|
||||
execution::max_concurrency(ep));
|
||||
}
|
||||
|
||||
// Export the print into an archive using the provided filename.
|
||||
virtual void export_print(const std::string fname,
|
||||
const SLAPrint &print,
|
||||
const ThumbnailsList &thumbnails,
|
||||
const std::string &projectname = "") = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief This class is the high level FSM for the SLA printing process.
|
||||
*
|
||||
|
|
|
@ -270,7 +270,7 @@ endforeach()
|
|||
|
||||
encoding_check(libslic3r_gui)
|
||||
|
||||
target_link_libraries(libslic3r_gui libslic3r avrdude cereal imgui GLEW::GLEW OpenGL::GL hidapi libcurl ${wxWidgets_LIBRARIES})
|
||||
target_link_libraries(libslic3r_gui libslic3r avrdude libcereal imgui GLEW::GLEW OpenGL::GL hidapi libcurl ${wxWidgets_LIBRARIES})
|
||||
|
||||
if (MSVC)
|
||||
target_link_libraries(libslic3r_gui Setupapi.lib)
|
||||
|
|
|
@ -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
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
@ -4356,7 +4392,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;
|
||||
|
@ -5562,6 +5602,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));
|
||||
|
||||
|
@ -5577,9 +5623,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));
|
||||
|
@ -6165,23 +6219,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)
|
||||
|
@ -6353,7 +6432,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);
|
||||
|
@ -6365,31 +6449,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();
|
||||
|
@ -6404,17 +6514,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 ||
|
||||
|
@ -6422,19 +6542,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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -6442,28 +6574,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();
|
||||
|
@ -6478,8 +6632,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();
|
||||
|
@ -6499,10 +6659,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(); }
|
||||
|
||||
|
@ -6544,6 +6704,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);
|
||||
|
@ -6557,23 +6722,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) {
|
||||
|
@ -6615,21 +6803,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.
|
||||
|
@ -6643,8 +6852,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();
|
||||
|
@ -6668,11 +6883,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));
|
||||
|
|
|
@ -793,7 +793,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, 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
|
||||
|
|
|
@ -98,7 +98,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));
|
||||
|
||||
|
|
|
@ -754,7 +754,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())
|
||||
|
@ -1285,8 +1285,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();
|
||||
}
|
||||
|
||||
|
@ -2447,16 +2452,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;
|
||||
}
|
||||
|
||||
|
|
|
@ -252,7 +252,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);
|
||||
|
|
|
@ -657,9 +657,9 @@ void ObjectManipulation::update_if_dirty()
|
|||
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;
|
||||
|
@ -814,9 +814,8 @@ 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();
|
||||
selection.translate(position - m_cache.position, selection.requires_local_axes());
|
||||
selection.stop_dragging();
|
||||
canvas->do_move(L("Set Position"));
|
||||
|
||||
m_cache.position = position;
|
||||
|
@ -844,11 +843,10 @@ void ObjectManipulation::change_rotation_value(int axis, double value)
|
|||
transformation_type.set_local();
|
||||
}
|
||||
|
||||
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;
|
||||
|
@ -925,9 +923,8 @@ void ObjectManipulation::do_scale(int axis, const Vec3d &scale) const
|
|||
if (m_uniform_scale || selection.requires_uniform_scale())
|
||||
scaling_factor = scale(axis) * Vec3d::Ones();
|
||||
|
||||
selection.start_dragging();
|
||||
selection.setup_cache();
|
||||
selection.scale(scaling_factor, transformation_type);
|
||||
selection.stop_dragging();
|
||||
wxGetApp().plater()->canvas3D()->do_scale(L("Set Scale"));
|
||||
}
|
||||
|
||||
|
|
|
@ -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,64 +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()
|
||||
|
@ -139,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
|
||||
{
|
||||
|
@ -190,6 +147,80 @@ 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) {
|
||||
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();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
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
|
||||
{
|
||||
|
@ -85,28 +85,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(); }
|
||||
|
||||
|
@ -115,9 +109,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(); }
|
||||
|
||||
|
@ -139,27 +130,33 @@ 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);
|
||||
|
||||
/// <summary>
|
||||
/// 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 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:
|
||||
virtual bool on_init() = 0;
|
||||
virtual void on_load(cereal::BinaryInputArchive& ar) {}
|
||||
|
@ -172,9 +169,12 @@ protected:
|
|||
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) {}
|
||||
|
@ -191,6 +191,15 @@ protected:
|
|||
|
||||
// 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);
|
||||
private:
|
||||
// Flag for dirty visible state of Gizmo
|
||||
// When True then need new rendering
|
||||
|
|
|
@ -65,6 +65,11 @@ std::string GLGizmoCut3D::get_tooltip() const
|
|||
return tooltip;
|
||||
}
|
||||
|
||||
bool GLGizmoCut::on_mouse(const wxMouseEvent &mouse_event)
|
||||
{
|
||||
return use_grabbers(mouse_event);
|
||||
}
|
||||
|
||||
void GLGizmoCut3D::shift_cut_z(double delta)
|
||||
{
|
||||
Vec3d new_cut_center = m_plane_center;
|
||||
|
@ -283,6 +288,13 @@ void GLGizmoCut3D::render_cut_plane()
|
|||
if (shader == nullptr)
|
||||
return;
|
||||
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 Vec3d& angles = m_rotation_gizmo.get_rotation();
|
||||
|
||||
|
@ -594,7 +606,7 @@ void GLGizmoCut3D::on_render_input_window(float x, float y, float bottom_limit)
|
|||
revert_rotation = render_revert_button("rotation");
|
||||
for (Axis axis : {X, Y, Z})
|
||||
render_rotation_input(axis);
|
||||
m_imgui->text(_L("°"));
|
||||
m_imgui->text(_L("°"));
|
||||
}
|
||||
else {
|
||||
ImGui::AlignTextToFramePadding();
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
|
||||
namespace Slic3r {
|
||||
namespace GUI {
|
||||
class Selection;
|
||||
|
||||
enum class SLAGizmoEventType : unsigned char;
|
||||
|
||||
|
@ -29,7 +30,7 @@ class GLGizmoCut3D : 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
|
||||
|
||||
bool m_keep_upper{ true };
|
||||
|
@ -104,6 +105,13 @@ public:
|
|||
std::string get_tooltip() const override;
|
||||
bool gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_position, bool shift_down, bool alt_down, bool control_down);
|
||||
|
||||
/// <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;
|
||||
|
||||
void shift_cut_z(double delta);
|
||||
void rotate_vec3d_around_center(Vec3d& vec, const Vec3d& angles, const Vec3d& center);
|
||||
void update_clipper();
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -32,6 +32,16 @@ std::string GLGizmoMove3D::get_tooltip() const
|
|||
return "";
|
||||
}
|
||||
|
||||
bool GLGizmoMove3D::on_mouse(const wxMouseEvent &mouse_event) {
|
||||
return use_grabbers(mouse_event);
|
||||
}
|
||||
|
||||
void GLGizmoMove3D::data_changed() {
|
||||
const Selection &selection = m_parent.get_selection();
|
||||
bool is_wipe_tower = selection.is_wipe_tower();
|
||||
m_grabbers[2].enabled = !is_wipe_tower;
|
||||
}
|
||||
|
||||
bool GLGizmoMove3D::on_init()
|
||||
{
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
|
@ -55,22 +65,23 @@ bool GLGizmoMove3D::on_is_activable() const
|
|||
|
||||
void GLGizmoMove3D::on_start_dragging()
|
||||
{
|
||||
if (m_hover_id != -1) {
|
||||
m_displacement = Vec3d::Zero();
|
||||
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(2) = box.min(2);
|
||||
}
|
||||
assert(m_hover_id != -1);
|
||||
|
||||
m_displacement = Vec3d::Zero();
|
||||
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(2) = box.min(2);
|
||||
}
|
||||
|
||||
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);
|
||||
|
@ -78,6 +89,9 @@ 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();
|
||||
selection.translate(m_displacement);
|
||||
}
|
||||
|
||||
void GLGizmoMove3D::on_render()
|
||||
|
|
|
@ -34,19 +34,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;
|
||||
|
|
|
@ -28,7 +28,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)
|
||||
{
|
||||
|
@ -56,6 +72,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());
|
||||
|
@ -73,7 +111,7 @@ void GLGizmoRotate::on_start_dragging()
|
|||
m_snap_fine_out_radius = m_snap_fine_in_radius + m_radius * ScaleLongTooth;
|
||||
}
|
||||
|
||||
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()));
|
||||
|
||||
|
@ -429,22 +467,26 @@ void GLGizmoRotate::render_angle() const
|
|||
const float ex_radius = m_radius * (1.0f + GrabberOffset);
|
||||
|
||||
#if ENABLE_GLBEGIN_GLEND_REMOVAL
|
||||
if (!m_angle_arc.is_initialized() || radius_changed) {
|
||||
const bool angle_changed = std::abs(m_old_angle - m_angle) > EPSILON;
|
||||
m_old_angle = m_angle;
|
||||
|
||||
if (!m_angle_arc.is_initialized() || radius_changed || angle_changed) {
|
||||
m_angle_arc.reset();
|
||||
if (m_angle > 0.0f) {
|
||||
GLModel::Geometry init_data;
|
||||
init_data.format = { GLModel::Geometry::EPrimitiveType::LineStrip, GLModel::Geometry::EVertexLayout::P3, GLModel::Geometry::EIndexType::USHORT };
|
||||
init_data.reserve_vertices(1 + AngleResolution);
|
||||
init_data.reserve_indices(1 + AngleResolution);
|
||||
|
||||
GLModel::Geometry init_data;
|
||||
init_data.format = { GLModel::Geometry::EPrimitiveType::LineStrip, GLModel::Geometry::EVertexLayout::P3, GLModel::Geometry::EIndexType::USHORT };
|
||||
init_data.reserve_vertices(1 + AngleResolution);
|
||||
init_data.reserve_indices(1 + AngleResolution);
|
||||
// vertices + indices
|
||||
for (unsigned short i = 0; i <= AngleResolution; ++i) {
|
||||
const float angle = float(i) * step_angle;
|
||||
init_data.add_vertex(Vec3f(::cos(angle) * ex_radius, ::sin(angle) * ex_radius, 0.0f));
|
||||
init_data.add_ushort_index(i);
|
||||
}
|
||||
|
||||
// vertices + indices
|
||||
for (unsigned short i = 0; i <= AngleResolution; ++i) {
|
||||
const float angle = float(i) * step_angle;
|
||||
init_data.add_vertex(Vec3f(::cos(angle) * ex_radius, ::sin(angle) * ex_radius, 0.0f));
|
||||
init_data.add_ushort_index(i);
|
||||
m_angle_arc.init_from(std::move(init_data));
|
||||
}
|
||||
|
||||
m_angle_arc.init_from(std::move(init_data));
|
||||
}
|
||||
|
||||
m_angle_arc.set_color(color);
|
||||
|
@ -629,25 +671,50 @@ 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
|
||||
TransformationType transformation_type(
|
||||
TransformationType::World_Relative_Joint);
|
||||
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;
|
||||
|
||||
|
@ -666,14 +733,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:
|
||||
|
@ -52,8 +52,11 @@ private:
|
|||
GrabberConnection m_grabber_connection;
|
||||
float m_old_radius{ 0.0f };
|
||||
float m_old_hover_radius{ 0.0f };
|
||||
float m_old_angle{ 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 +68,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;
|
||||
|
||||
|
@ -116,6 +135,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;
|
||||
|
@ -129,20 +156,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) {
|
||||
|
|
|
@ -14,7 +14,13 @@ namespace GUI {
|
|||
const float GLGizmoScale3D::Offset = 5.0f;
|
||||
|
||||
GLGizmoScale3D::GLGizmoScale3D(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id)
|
||||
: GLGizmoBase(parent, icon_filename, 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 };
|
||||
|
@ -58,6 +64,46 @@ std::string GLGizmoScale3D::get_tooltip() const
|
|||
return "";
|
||||
}
|
||||
|
||||
bool GLGizmoScale3D::on_mouse(const wxMouseEvent &mouse_event)
|
||||
{
|
||||
if (mouse_event.Dragging()) {
|
||||
if (m_dragging) {
|
||||
// Apply new temporary scale factors
|
||||
TransformationType transformation_type(TransformationType::Local_Absolute_Joint);
|
||||
if (mouse_event.AltDown()) transformation_type.set_independent();
|
||||
|
||||
Selection &selection = m_parent.get_selection();
|
||||
selection.scale(get_scale(), transformation_type);
|
||||
if (mouse_event.CmdDown()) selection.translate(m_offset, true);
|
||||
}
|
||||
}
|
||||
return use_grabbers(mouse_event);
|
||||
}
|
||||
|
||||
void GLGizmoScale3D::data_changed()
|
||||
{
|
||||
const Selection &selection = m_parent.get_selection();
|
||||
bool enable_scale_xyz = selection.is_single_full_instance() ||
|
||||
selection.is_single_volume() ||
|
||||
selection.is_single_modifier();
|
||||
for (unsigned int i = 0; i < 6; ++i)
|
||||
m_grabbers[i].enabled = enable_scale_xyz;
|
||||
|
||||
if (enable_scale_xyz) {
|
||||
// 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());
|
||||
} else if (selection.is_single_volume() ||
|
||||
selection.is_single_modifier()) {
|
||||
set_scale(volume->get_volume_scaling_factor());
|
||||
}
|
||||
} else {
|
||||
set_scale(Vec3d::Ones());
|
||||
}
|
||||
}
|
||||
|
||||
bool GLGizmoScale3D::on_init()
|
||||
{
|
||||
for (int i = 0; i < 10; ++i) {
|
||||
|
@ -92,22 +138,25 @@ bool GLGizmoScale3D::on_is_activable() const
|
|||
|
||||
void GLGizmoScale3D::on_start_dragging()
|
||||
{
|
||||
if (m_hover_id != -1) {
|
||||
m_starting.drag_position = m_grabbers[m_hover_id].center;
|
||||
m_starting.ctrl_down = wxGetKeyState(WXK_CONTROL);
|
||||
m_starting.box = (m_starting.ctrl_down && (m_hover_id < 6)) ? m_box : m_parent.get_selection().get_bounding_box();
|
||||
assert(m_hover_id != -1);
|
||||
m_starting.drag_position = m_grabbers[m_hover_id].center;
|
||||
m_starting.ctrl_down = wxGetKeyState(WXK_CONTROL);
|
||||
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());
|
||||
}
|
||||
|
||||
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);
|
||||
|
|
|
@ -44,6 +44,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);
|
||||
|
||||
|
@ -53,16 +56,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;
|
||||
|
|
|
@ -38,6 +38,7 @@ GLGizmosManager::GLGizmosManager(GLCanvas3D& parent)
|
|||
, m_enabled(false)
|
||||
, m_icons_texture_dirty(true)
|
||||
, m_current(Undefined)
|
||||
, m_hover(Undefined)
|
||||
, m_tooltip("")
|
||||
, m_serializing(false)
|
||||
{
|
||||
|
@ -46,33 +47,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;
|
||||
|
@ -161,9 +163,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()
|
||||
|
@ -177,9 +179,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;
|
||||
}
|
||||
|
@ -208,87 +214,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);
|
||||
|
||||
bool enable_scale_xyz = selection.is_single_full_instance() || selection.is_single_volume() || selection.is_single_modifier();
|
||||
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();
|
||||
}
|
||||
else if (selection.is_single_volume() || selection.is_single_modifier())
|
||||
{
|
||||
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
|
||||
|
@ -328,107 +261,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)
|
||||
{
|
||||
|
@ -519,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;
|
||||
|
||||
|
@ -532,227 +364,108 @@ bool GLGizmosManager::on_mouse_wheel(wxMouseEvent& evt)
|
|||
return processed;
|
||||
}
|
||||
|
||||
bool GLGizmosManager::on_mouse(wxMouseEvent& evt)
|
||||
{
|
||||
// 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;
|
||||
} else if (mouse_event.RightDown()) {
|
||||
mc.right = true;
|
||||
return true;
|
||||
} else if (mouse_event.MiddleDown()) {
|
||||
mc.middle = true;
|
||||
return true;
|
||||
}
|
||||
if (m_mouse_capture.right) {
|
||||
processed = true;
|
||||
m_mouse_capture.right = false;
|
||||
}
|
||||
// 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
|
||||
selection.translate(get_displacement());
|
||||
wxGetApp().obj_manipul()->set_dirty();
|
||||
break;
|
||||
}
|
||||
case Scale:
|
||||
{
|
||||
// Apply new temporary scale factors
|
||||
TransformationType transformation_type(TransformationType::Local_Absolute_Joint);
|
||||
if (evt.AltDown())
|
||||
transformation_type.set_independent();
|
||||
selection.scale(get_scale(), transformation_type);
|
||||
if (control_down)
|
||||
selection.translate(get_scale_offset(), true);
|
||||
wxGetApp().obj_manipul()->set_dirty();
|
||||
break;
|
||||
}
|
||||
case Rotate:
|
||||
{
|
||||
// Apply new temporary rotations
|
||||
TransformationType transformation_type(TransformationType::World_Relative_Joint);
|
||||
if (evt.AltDown())
|
||||
transformation_type.set_independent();
|
||||
selection.rotate(get_rotation(), transformation_type);
|
||||
wxGetApp().obj_manipul()->set_dirty();
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
m_parent.set_as_dirty();
|
||||
processed = true;
|
||||
}
|
||||
|
||||
if (get_gizmo_idx_from_mouse(mouse_pos) == Undefined) {
|
||||
// mouse is outside the toolbar
|
||||
m_tooltip.clear();
|
||||
|
||||
if (evt.LeftDown() && (!control_down || grabber_contains_mouse())) {
|
||||
if ((m_current == SlaSupports || m_current == Hollow || m_current == FdmSupports || m_current == Seam || m_current == MmuSegmentation || m_current == Cut)
|
||||
&& 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() && grabber_contains_mouse()) {
|
||||
update_data();
|
||||
selection.start_dragging();
|
||||
start_dragging();
|
||||
|
||||
// Let the plater know that the dragging started
|
||||
m_parent.post_event(SimpleEvent(EVT_GLCANVAS_MOUSE_DRAGGING_STARTED));
|
||||
|
||||
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;
|
||||
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);
|
||||
}
|
||||
// draging start on toolbar so no propagation into scene
|
||||
return true;
|
||||
} else if (mc.left && mouse_event.LeftUp()) {
|
||||
mc.left = false;
|
||||
return 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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
return processed;
|
||||
bool GLGizmosManager::on_mouse(const wxMouseEvent &mouse_event)
|
||||
{
|
||||
if (!m_enabled) return false;
|
||||
|
||||
// tool bar wants to use event?
|
||||
if (gizmos_toolbar_on_mouse(mouse_event)) return true;
|
||||
|
||||
// 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)
|
||||
|
@ -1182,68 +895,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;
|
||||
}
|
||||
|
||||
|
@ -1281,11 +990,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
|
||||
|
|
|
@ -112,28 +112,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);
|
||||
|
||||
|
@ -184,14 +178,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; }
|
||||
|
@ -202,28 +197,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;
|
||||
|
||||
|
@ -240,21 +214,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;
|
||||
|
@ -264,8 +243,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;
|
||||
};
|
||||
|
||||
|
|
|
@ -1445,8 +1445,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);
|
||||
|
@ -1489,8 +1489,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;
|
||||
|
@ -1498,19 +1497,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)));
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#include "SLAImportJob.hpp"
|
||||
|
||||
#include "libslic3r/SLAPrint.hpp"
|
||||
#include "libslic3r/Format/SL1.hpp"
|
||||
|
||||
#include "slic3r/GUI/GUI.hpp"
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -233,8 +233,9 @@ OpenGLManager::~OpenGLManager()
|
|||
bool OpenGLManager::init_gl()
|
||||
{
|
||||
if (!m_gl_initialized) {
|
||||
if (glewInit() != GLEW_OK) {
|
||||
BOOST_LOG_TRIVIAL(error) << "Unable to init glew library";
|
||||
GLenum err = glewInit();
|
||||
if (err != GLEW_OK) {
|
||||
BOOST_LOG_TRIVIAL(error) << "Unable to init glew library: " << glewGetErrorString(err);
|
||||
return false;
|
||||
}
|
||||
m_gl_initialized = true;
|
||||
|
|
|
@ -499,6 +499,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));
|
||||
}
|
||||
|
@ -2351,7 +2352,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();
|
||||
|
@ -2360,7 +2361,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.
|
||||
|
@ -2370,8 +2372,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);
|
||||
|
@ -2382,17 +2384,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) {
|
||||
|
@ -2404,7 +2417,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.
|
||||
|
@ -2435,7 +2448,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);
|
||||
|
@ -2466,7 +2479,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"
|
||||
|
@ -5257,8 +5270,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();
|
||||
}
|
||||
|
||||
|
@ -5287,7 +5303,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();
|
||||
}
|
||||
}
|
||||
|
@ -5996,7 +6016,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;
|
||||
}
|
||||
|
||||
|
|
|
@ -115,7 +115,6 @@ Selection::Selection()
|
|||
, m_type(Empty)
|
||||
, m_valid(false)
|
||||
, m_scale_factor(1.0f)
|
||||
, m_dragging(false)
|
||||
{
|
||||
this->set_bounding_boxes_dirty();
|
||||
}
|
||||
|
@ -679,12 +678,11 @@ 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();
|
||||
}
|
||||
|
||||
|
@ -955,12 +953,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
|
||||
|
|
|
@ -229,7 +229,6 @@ private:
|
|||
#endif // ENABLE_GLBEGIN_GLEND_REMOVAL
|
||||
|
||||
float m_scale_factor;
|
||||
bool m_dragging;
|
||||
|
||||
public:
|
||||
Selection();
|
||||
|
@ -322,9 +321,7 @@ 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();
|
||||
|
||||
void translate(const Vec3d& displacement, bool local = false);
|
||||
void rotate(const Vec3d& rotation, TransformationType transformation_type);
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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
|
|
@ -4,4 +4,6 @@ target_link_libraries(${_TEST_NAME}_tests test_common libnest2d )
|
|||
set_property(TARGET ${_TEST_NAME}_tests PROPERTY FOLDER "tests")
|
||||
|
||||
# catch_discover_tests(${_TEST_NAME}_tests TEST_PREFIX "${_TEST_NAME}: ")
|
||||
add_test(${_TEST_NAME}_tests ${_TEST_NAME}_tests "${CATCH_EXTRA_ARGS} exclude:[NotWorking]")
|
||||
set(_catch_args "exclude:[NotWorking]")
|
||||
list(APPEND _catch_args "${CATCH_EXTRA_ARGS}")
|
||||
add_test(${_TEST_NAME}_tests ${_TEST_NAME}_tests ${_catch_args})
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue