Merge remote-tracking branch 'remotes/origin/master' into vb_print_regions

This commit is contained in:
Vojtech Bubnik 2021-05-31 14:05:53 +02:00
commit 033d9f3a5e
38 changed files with 1502 additions and 587 deletions

View File

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

View File

@ -542,7 +542,7 @@ std::vector<GCode::LayerToPrint> GCode::collect_layers_to_print(const PrintObjec
if (has_extrusions && layer_to_print.print_z() > maximal_print_z + 2. * EPSILON) { if (has_extrusions && layer_to_print.print_z() > maximal_print_z + 2. * EPSILON) {
const_cast<Print*>(object.print())->active_step_add_warning(PrintStateBase::WarningLevel::CRITICAL, const_cast<Print*>(object.print())->active_step_add_warning(PrintStateBase::WarningLevel::CRITICAL,
_(L("Empty layers detected, the output would not be printable.")) + "\n\n" + _(L("Empty layers detected. Make sure the object is printable.")) + "\n\n" +
_(L("Object name")) + ": " + object.model_object()->name + "\n" + _(L("Print z")) + ": " + _(L("Object name")) + ": " + object.model_object()->name + "\n" + _(L("Print z")) + ": " +
std::to_string(layers_to_print.back().print_z()) + "\n\n" + _(L("This is " std::to_string(layers_to_print.back().print_z()) + "\n\n" + _(L("This is "
"usually caused by negligibly small extrusions or by a faulty model. Try to repair " "usually caused by negligibly small extrusions or by a faulty model. Try to repair "

View File

@ -27,6 +27,7 @@ using Vec2crd = Eigen::Matrix<coord_t, 2, 1, Eigen::DontAlign>;
using Vec3crd = Eigen::Matrix<coord_t, 3, 1, Eigen::DontAlign>; using Vec3crd = Eigen::Matrix<coord_t, 3, 1, Eigen::DontAlign>;
using Vec2i = Eigen::Matrix<int, 2, 1, Eigen::DontAlign>; using Vec2i = Eigen::Matrix<int, 2, 1, Eigen::DontAlign>;
using Vec3i = Eigen::Matrix<int, 3, 1, Eigen::DontAlign>; using Vec3i = Eigen::Matrix<int, 3, 1, Eigen::DontAlign>;
using Vec4i = Eigen::Matrix<int, 4, 1, Eigen::DontAlign>;
using Vec2i32 = Eigen::Matrix<int32_t, 2, 1, Eigen::DontAlign>; using Vec2i32 = Eigen::Matrix<int32_t, 2, 1, Eigen::DontAlign>;
using Vec2i64 = Eigen::Matrix<int64_t, 2, 1, Eigen::DontAlign>; using Vec2i64 = Eigen::Matrix<int64_t, 2, 1, Eigen::DontAlign>;
using Vec3i32 = Eigen::Matrix<int32_t, 3, 1, Eigen::DontAlign>; using Vec3i32 = Eigen::Matrix<int32_t, 3, 1, Eigen::DontAlign>;
@ -50,6 +51,8 @@ using Matrix2f = Eigen::Matrix<float, 2, 2, Eigen::DontAlign>;
using Matrix2d = Eigen::Matrix<double, 2, 2, Eigen::DontAlign>; using Matrix2d = Eigen::Matrix<double, 2, 2, Eigen::DontAlign>;
using Matrix3f = Eigen::Matrix<float, 3, 3, Eigen::DontAlign>; using Matrix3f = Eigen::Matrix<float, 3, 3, Eigen::DontAlign>;
using Matrix3d = Eigen::Matrix<double, 3, 3, Eigen::DontAlign>; using Matrix3d = Eigen::Matrix<double, 3, 3, Eigen::DontAlign>;
using Matrix4f = Eigen::Matrix<float, 4, 4, Eigen::DontAlign>;
using Matrix4d = Eigen::Matrix<double, 4, 4, Eigen::DontAlign>;
using Transform2f = Eigen::Transform<float, 2, Eigen::Affine, Eigen::DontAlign>; using Transform2f = Eigen::Transform<float, 2, Eigen::Affine, Eigen::DontAlign>;
using Transform2d = Eigen::Transform<double, 2, Eigen::Affine, Eigen::DontAlign>; using Transform2d = Eigen::Transform<double, 2, Eigen::Affine, Eigen::DontAlign>;

View File

@ -354,9 +354,19 @@ bool Print::has_brim() const
return std::any_of(m_objects.begin(), m_objects.end(), [](PrintObject *object) { return object->has_brim(); }); return std::any_of(m_objects.begin(), m_objects.end(), [](PrintObject *object) { return object->has_brim(); });
} }
#if ENABLE_SEQUENTIAL_LIMITS
bool Print::sequential_print_horizontal_clearance_valid(const Print& print, Polygons* polygons)
#else
static inline bool sequential_print_horizontal_clearance_valid(const Print &print) static inline bool sequential_print_horizontal_clearance_valid(const Print &print)
#endif // ENABLE_SEQUENTIAL_LIMITS
{ {
Polygons convex_hulls_other; Polygons convex_hulls_other;
#if ENABLE_SEQUENTIAL_LIMITS
if (polygons != nullptr)
polygons->clear();
std::vector<size_t> intersecting_idxs;
#endif // ENABLE_SEQUENTIAL_LIMITS
std::map<ObjectID, Polygon> map_model_object_to_convex_hull; std::map<ObjectID, Polygon> map_model_object_to_convex_hull;
for (const PrintObject *print_object : print.objects()) { for (const PrintObject *print_object : print.objects()) {
assert(! print_object->model_object()->instances.empty()); assert(! print_object->model_object()->instances.empty());
@ -378,7 +388,7 @@ static inline bool sequential_print_horizontal_clearance_valid(const Print &prin
// Shrink the extruder_clearance_radius a tiny bit, so that if the object arrangement algorithm placed the objects // Shrink the extruder_clearance_radius a tiny bit, so that if the object arrangement algorithm placed the objects
// exactly by satisfying the extruder_clearance_radius, this test will not trigger collision. // exactly by satisfying the extruder_clearance_radius, this test will not trigger collision.
float(scale_(0.5 * print.config().extruder_clearance_radius.value - EPSILON)), float(scale_(0.5 * print.config().extruder_clearance_radius.value - EPSILON)),
jtRound, float(scale_(0.1))).front()); jtRound, scale_(0.1)).front());
#else #else
it_convex_hull = map_model_object_to_convex_hull.emplace_hint(it_convex_hull, model_object_id, it_convex_hull = map_model_object_to_convex_hull.emplace_hint(it_convex_hull, model_object_id,
offset(print_object->model_object()->convex_hull_2d( offset(print_object->model_object()->convex_hull_2d(
@ -391,21 +401,47 @@ static inline bool sequential_print_horizontal_clearance_valid(const Print &prin
} }
// Make a copy, so it may be rotated for instances. // Make a copy, so it may be rotated for instances.
Polygon convex_hull0 = it_convex_hull->second; Polygon convex_hull0 = it_convex_hull->second;
double z_diff = Geometry::rotation_diff_z(model_instance0->get_rotation(), print_object->instances().front().model_instance->get_rotation()); const double z_diff = Geometry::rotation_diff_z(model_instance0->get_rotation(), print_object->instances().front().model_instance->get_rotation());
if (std::abs(z_diff) > EPSILON) if (std::abs(z_diff) > EPSILON)
convex_hull0.rotate(z_diff); convex_hull0.rotate(z_diff);
// Now we check that no instance of convex_hull intersects any of the previously checked object instances. // Now we check that no instance of convex_hull intersects any of the previously checked object instances.
for (const PrintInstance &instance : print_object->instances()) { for (const PrintInstance &instance : print_object->instances()) {
Polygon convex_hull = convex_hull0; Polygon convex_hull = convex_hull0;
// instance.shift is a position of a centered object, while model object may not be centered. // instance.shift is a position of a centered object, while model object may not be centered.
// Conver the shift from the PrintObject's coordinates into ModelObject's coordinates by removing the centering offset. // Convert the shift from the PrintObject's coordinates into ModelObject's coordinates by removing the centering offset.
convex_hull.translate(instance.shift - print_object->center_offset()); convex_hull.translate(instance.shift - print_object->center_offset());
if (! intersection(convex_hulls_other, (Polygons)convex_hull).empty()) #if ENABLE_SEQUENTIAL_LIMITS
return false; // if output needed, collect indices (inside convex_hulls_other) of intersecting hulls
convex_hulls_other.emplace_back(std::move(convex_hull)); for (size_t i = 0; i < convex_hulls_other.size(); ++i) {
if (!intersection((Polygons)convex_hulls_other[i], (Polygons)convex_hull).empty()) {
if (polygons == nullptr)
return false;
else {
intersecting_idxs.emplace_back(i);
intersecting_idxs.emplace_back(convex_hulls_other.size());
}
}
}
#else
if (!intersection(convex_hulls_other, (Polygons)convex_hull).empty())
return false;
#endif // ENABLE_SEQUENTIAL_LIMITS
convex_hulls_other.emplace_back(std::move(convex_hull));
} }
} }
return true;
#if ENABLE_SEQUENTIAL_LIMITS
if (!intersecting_idxs.empty()) {
// use collected indices (inside convex_hulls_other) to update output
std::sort(intersecting_idxs.begin(), intersecting_idxs.end());
intersecting_idxs.erase(std::unique(intersecting_idxs.begin(), intersecting_idxs.end()), intersecting_idxs.end());
for (size_t i : intersecting_idxs) {
polygons->emplace_back(std::move(convex_hulls_other[i]));
}
return false;
}
#endif // ENABLE_SEQUENTIAL_LIMITS
return true;
} }
static inline bool sequential_print_vertical_clearance_valid(const Print &print) static inline bool sequential_print_vertical_clearance_valid(const Print &print)

View File

@ -584,6 +584,10 @@ public:
const PrintRegion& get_print_region(size_t idx) const { return *m_print_regions[idx]; } const PrintRegion& get_print_region(size_t idx) const { return *m_print_regions[idx]; }
const ToolOrdering& get_tool_ordering() const { return m_wipe_tower_data.tool_ordering; } const ToolOrdering& get_tool_ordering() const { return m_wipe_tower_data.tool_ordering; }
#if ENABLE_SEQUENTIAL_LIMITS
static bool sequential_print_horizontal_clearance_valid(const Print& print, Polygons* polygons = nullptr);
#endif // ENABLE_SEQUENTIAL_LIMITS
protected: protected:
// Invalidates the step, and its depending steps in Print. // Invalidates the step, and its depending steps in Print.
bool invalidate_step(PrintStep step); bool invalidate_step(PrintStep step);

View File

@ -1,4 +1,5 @@
#include <functional> #include <functional>
#include <optional>
#include <libslic3r/OpenVDBUtils.hpp> #include <libslic3r/OpenVDBUtils.hpp>
#include <libslic3r/TriangleMesh.hpp> #include <libslic3r/TriangleMesh.hpp>

View File

@ -2,6 +2,7 @@
#define SLASUPPORTTREEALGORITHM_H #define SLASUPPORTTREEALGORITHM_H
#include <cstdint> #include <cstdint>
#include <optional>
#include <libslic3r/SLA/SupportTreeBuilder.hpp> #include <libslic3r/SLA/SupportTreeBuilder.hpp>
#include <libslic3r/SLA/Clustering.hpp> #include <libslic3r/SLA/Clustering.hpp>

View File

@ -66,6 +66,8 @@
// Enable to push object instances under the bed // Enable to push object instances under the bed
#define ENABLE_ALLOW_NEGATIVE_Z (1 && ENABLE_2_4_0_ALPHA0) #define ENABLE_ALLOW_NEGATIVE_Z (1 && ENABLE_2_4_0_ALPHA0)
#define DISABLE_ALLOW_NEGATIVE_Z_FOR_SLA (1 && ENABLE_ALLOW_NEGATIVE_Z) #define DISABLE_ALLOW_NEGATIVE_Z_FOR_SLA (1 && ENABLE_ALLOW_NEGATIVE_Z)
// Enable visualization of objects clearance for sequential prints
#define ENABLE_SEQUENTIAL_LIMITS (1 && ENABLE_2_4_0_ALPHA0)
#endif // _prusaslicer_technologies_h_ #endif // _prusaslicer_technologies_h_

View File

@ -1020,6 +1020,33 @@ TriangleMesh make_cylinder(double r, double h, double fa)
return mesh; return mesh;
} }
TriangleMesh make_cone(double r, double h, double fa)
{
Pointf3s vertices;
std::vector<Vec3i> facets;
vertices.reserve(3+size_t(2*PI/fa));
vertices.reserve(3+2*size_t(2*PI/fa));
vertices = { Vec3d::Zero(), Vec3d(0., 0., h) }; // base center and top vertex
size_t i = 0;
for (double angle=0; angle<2*PI; angle+=fa) {
vertices.emplace_back(r*std::cos(angle), r*std::sin(angle), 0.);
if (angle > 0.) {
facets.emplace_back(0, i+2, i+1);
facets.emplace_back(1, i+1, i+2);
}
++i;
}
facets.emplace_back(0, 2, i+1); // close the shape
facets.emplace_back(1, i+1, 2);
TriangleMesh mesh(std::move(vertices), std::move(facets));
mesh.repair();
return mesh;
}
// Generates mesh for a sphere centered about the origin, using the generated angle // Generates mesh for a sphere centered about the origin, using the generated angle
// to determine the granularity. // to determine the granularity.
// Default angle is 1 degree. // Default angle is 1 degree.

View File

@ -125,10 +125,8 @@ Polygon its_convex_hull_2d_above(const indexed_triangle_set &its, const Matrix3f
Polygon its_convex_hull_2d_above(const indexed_triangle_set &its, const Transform3f &t, const float z); Polygon its_convex_hull_2d_above(const indexed_triangle_set &its, const Transform3f &t, const float z);
TriangleMesh make_cube(double x, double y, double z); TriangleMesh make_cube(double x, double y, double z);
// Generate a TriangleMesh of a cylinder
TriangleMesh make_cylinder(double r, double h, double fa=(2*PI/360)); TriangleMesh make_cylinder(double r, double h, double fa=(2*PI/360));
TriangleMesh make_cone(double r, double h, double fa=(2*PI/360));
TriangleMesh make_sphere(double rho, double fa=(2*PI/360)); TriangleMesh make_sphere(double rho, double fa=(2*PI/360));
} }

View File

@ -5953,16 +5953,18 @@ static mz_uint32 mz_zip_writer_create_zip64_extra_data(mz_uint8 *pBuf, mz_uint64
static mz_bool mz_zip_writer_create_local_dir_header(mz_zip_archive *pZip, mz_uint8 *pDst, mz_uint16 filename_size, mz_uint16 extra_size, mz_uint64 uncomp_size, mz_uint64 comp_size, mz_uint32 uncomp_crc32, mz_uint16 method, mz_uint16 bit_flags, mz_uint16 dos_time, mz_uint16 dos_date) static mz_bool mz_zip_writer_create_local_dir_header(mz_zip_archive *pZip, mz_uint8 *pDst, mz_uint16 filename_size, mz_uint16 extra_size, mz_uint64 uncomp_size, mz_uint64 comp_size, mz_uint32 uncomp_crc32, mz_uint16 method, mz_uint16 bit_flags, mz_uint16 dos_time, mz_uint16 dos_date)
{ {
(void)pZip;
mz_bool is_zip64_needed = uncomp_size >= MZ_UINT32_MAX || comp_size >= MZ_UINT32_MAX;
memset(pDst, 0, MZ_ZIP_LOCAL_DIR_HEADER_SIZE); memset(pDst, 0, MZ_ZIP_LOCAL_DIR_HEADER_SIZE);
MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_SIG_OFS, MZ_ZIP_LOCAL_DIR_HEADER_SIG); MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_SIG_OFS, MZ_ZIP_LOCAL_DIR_HEADER_SIG);
MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_VERSION_NEEDED_OFS, (pZip->m_pState->m_zip64) ? 0x002D : (method ? 0x0014 : 0x0000)); MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_VERSION_NEEDED_OFS, is_zip64_needed ? 0x002D : (method ? 0x0014 : 0x0000));
MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_BIT_FLAG_OFS, bit_flags); MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_BIT_FLAG_OFS, bit_flags);
MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_METHOD_OFS, method); MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_METHOD_OFS, method);
MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_FILE_TIME_OFS, dos_time); MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_FILE_TIME_OFS, dos_time);
MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_FILE_DATE_OFS, dos_date); MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_FILE_DATE_OFS, dos_date);
MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_CRC32_OFS, uncomp_crc32); MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_CRC32_OFS, uncomp_crc32);
MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_COMPRESSED_SIZE_OFS, (pZip->m_pState->m_zip64 || comp_size > MZ_UINT32_MAX) ? MZ_UINT32_MAX : comp_size); MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_COMPRESSED_SIZE_OFS, is_zip64_needed ? MZ_UINT32_MAX : comp_size);
MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_DECOMPRESSED_SIZE_OFS, (pZip->m_pState->m_zip64 || uncomp_size > MZ_UINT32_MAX) ? MZ_UINT32_MAX : uncomp_size); MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_DECOMPRESSED_SIZE_OFS, is_zip64_needed ? MZ_UINT32_MAX : uncomp_size);
MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_FILENAME_LEN_OFS, filename_size); MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_FILENAME_LEN_OFS, filename_size);
MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_EXTRA_LEN_OFS, extra_size); MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_EXTRA_LEN_OFS, extra_size);
return MZ_TRUE; return MZ_TRUE;
@ -5974,7 +5976,7 @@ static mz_bool mz_zip_writer_create_central_dir_header(mz_zip_archive *pZip, mz_
mz_uint16 method, mz_uint16 bit_flags, mz_uint16 dos_time, mz_uint16 dos_date, mz_uint16 method, mz_uint16 bit_flags, mz_uint16 dos_time, mz_uint16 dos_date,
mz_uint64 local_header_ofs, mz_uint32 ext_attributes) mz_uint64 local_header_ofs, mz_uint32 ext_attributes)
{ {
mz_zip_internal_state *pState = pZip->m_pState; (void)pZip;
mz_bool is_zip64_needed = uncomp_size >= MZ_UINT32_MAX || comp_size >= MZ_UINT32_MAX; mz_bool is_zip64_needed = uncomp_size >= MZ_UINT32_MAX || comp_size >= MZ_UINT32_MAX;
memset(pDst, 0, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE); memset(pDst, 0, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE);
MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_SIG_OFS, MZ_ZIP_CENTRAL_DIR_HEADER_SIG); MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_SIG_OFS, MZ_ZIP_CENTRAL_DIR_HEADER_SIG);
@ -6793,13 +6795,7 @@ mz_bool mz_zip_writer_add_staged_open(mz_zip_archive* pZip, mz_zip_writer_staged
} }
MZ_CLEAR_OBJ(local_dir_header); MZ_CLEAR_OBJ(local_dir_header);
if (pState->m_zip64) if (max_size > MZ_UINT32_MAX)
{
pContext->pExtra_data = pContext->extra_data;
pContext->extra_size = mz_zip_writer_create_zip64_extra_data(pContext->extra_data, &pContext->uncomp_size, &pContext->comp_size,
(pContext->local_dir_header_ofs >= MZ_UINT32_MAX) ? &pContext->local_dir_header_ofs : NULL);
}
else if (!pState->m_zip64 && max_size > MZ_UINT32_MAX)
{ {
pContext->pExtra_data = pContext->extra_data; pContext->pExtra_data = pContext->extra_data;
pContext->extra_size = mz_zip_writer_preallocate_extra_data(pContext->extra_data, 2 * sizeof(mz_uint64)); pContext->extra_size = mz_zip_writer_preallocate_extra_data(pContext->extra_data, 2 * sizeof(mz_uint64));

View File

@ -242,7 +242,7 @@ add_library(libslic3r_gui STATIC ${SLIC3R_GUI_SOURCES})
encoding_check(libslic3r_gui) encoding_check(libslic3r_gui)
target_link_libraries(libslic3r_gui libslic3r avrdude cereal imgui GLEW::GLEW OpenGL::GL OpenGL::GLU hidapi libcurl ${wxWidgets_LIBRARIES}) target_link_libraries(libslic3r_gui libslic3r avrdude cereal imgui GLEW::GLEW OpenGL::GL hidapi libcurl ${wxWidgets_LIBRARIES})
if (CMAKE_SYSTEM_NAME STREQUAL "Linux") if (CMAKE_SYSTEM_NAME STREQUAL "Linux")
target_link_libraries(libslic3r_gui ${DBUS_LIBRARIES}) target_link_libraries(libslic3r_gui ${DBUS_LIBRARIES})

View File

@ -98,12 +98,6 @@ const float Bed3D::Axes::DefaultStemLength = 25.0f;
const float Bed3D::Axes::DefaultTipRadius = 2.5f * Bed3D::Axes::DefaultStemRadius; const float Bed3D::Axes::DefaultTipRadius = 2.5f * Bed3D::Axes::DefaultStemRadius;
const float Bed3D::Axes::DefaultTipLength = 5.0f; const float Bed3D::Axes::DefaultTipLength = 5.0f;
void Bed3D::Axes::set_stem_length(float length)
{
m_stem_length = length;
m_arrow.reset();
}
void Bed3D::Axes::render() const void Bed3D::Axes::render() const
{ {
auto render_axis = [this](const Transform3f& transform) { auto render_axis = [this](const Transform3f& transform) {
@ -113,7 +107,10 @@ void Bed3D::Axes::render() const
glsafe(::glPopMatrix()); glsafe(::glPopMatrix());
}; };
const_cast<GLModel*>(&m_arrow)->init_from(stilized_arrow(16, DefaultTipRadius, DefaultTipLength, DefaultStemRadius, m_stem_length)); #if ENABLE_SEQUENTIAL_LIMITS
if (!m_arrow.is_initialized())
#endif // ENABLE_SEQUENTIAL_LIMITS
const_cast<GLModel*>(&m_arrow)->init_from(stilized_arrow(16, DefaultTipRadius, DefaultTipLength, DefaultStemRadius, m_stem_length));
GLShaderProgram* shader = wxGetApp().get_shader("gouraud_light"); GLShaderProgram* shader = wxGetApp().get_shader("gouraud_light");
if (shader == nullptr) if (shader == nullptr)
@ -122,20 +119,33 @@ void Bed3D::Axes::render() const
glsafe(::glEnable(GL_DEPTH_TEST)); glsafe(::glEnable(GL_DEPTH_TEST));
shader->start_using(); shader->start_using();
shader->set_uniform("emission_factor", 0.0);
// x axis // x axis
#if ENABLE_SEQUENTIAL_LIMITS
const_cast<GLModel*>(&m_arrow)->set_color(-1, { 0.75f, 0.0f, 0.0f, 1.0f });
#else
std::array<float, 4> color = { 0.75f, 0.0f, 0.0f, 1.0f }; std::array<float, 4> color = { 0.75f, 0.0f, 0.0f, 1.0f };
shader->set_uniform("uniform_color", color); shader->set_uniform("uniform_color", color);
render_axis(Geometry::assemble_transform(m_origin, { 0.0, 0.5 * M_PI, 0.0f }).cast<float>()); #endif // ENABLE_SEQUENTIAL_LIMITS
render_axis(Geometry::assemble_transform(m_origin, { 0.0, 0.5 * M_PI, 0.0 }).cast<float>());
// y axis // y axis
#if ENABLE_SEQUENTIAL_LIMITS
const_cast<GLModel*>(&m_arrow)->set_color(-1, { 0.0f, 0.75f, 0.0f, 1.0f });
#else
color = { 0.0f, 0.75f, 0.0f, 1.0f }; color = { 0.0f, 0.75f, 0.0f, 1.0f };
shader->set_uniform("uniform_color", color); shader->set_uniform("uniform_color", color);
render_axis(Geometry::assemble_transform(m_origin, { -0.5 * M_PI, 0.0, 0.0f }).cast<float>()); #endif // ENABLE_SEQUENTIAL_LIMITS
render_axis(Geometry::assemble_transform(m_origin, { -0.5 * M_PI, 0.0, 0.0 }).cast<float>());
// z axis // z axis
#if ENABLE_SEQUENTIAL_LIMITS
const_cast<GLModel*>(&m_arrow)->set_color(-1, { 0.0f, 0.0f, 0.75f, 1.0f });
#else
color = { 0.0f, 0.0f, 0.75f, 1.0f }; color = { 0.0f, 0.0f, 0.75f, 1.0f };
shader->set_uniform("uniform_color", color); shader->set_uniform("uniform_color", color);
#endif // ENABLE_SEQUENTIAL_LIMITS
render_axis(Geometry::assemble_transform(m_origin).cast<float>()); render_axis(Geometry::assemble_transform(m_origin).cast<float>());
shader->stop_using(); shader->stop_using();
@ -415,7 +425,10 @@ void Bed3D::render_texture(bool bottom, GLCanvas3D& canvas) const
} }
glsafe(::glEnable(GL_DEPTH_TEST)); glsafe(::glEnable(GL_DEPTH_TEST));
glsafe(::glDepthMask(GL_FALSE)); #if ENABLE_SEQUENTIAL_LIMITS
if (bottom)
#endif // ENABLE_SEQUENTIAL_LIMITS
glsafe(::glDepthMask(GL_FALSE));
glsafe(::glEnable(GL_BLEND)); glsafe(::glEnable(GL_BLEND));
glsafe(::glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)); glsafe(::glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA));
@ -460,7 +473,10 @@ void Bed3D::render_texture(bool bottom, GLCanvas3D& canvas) const
glsafe(::glFrontFace(GL_CCW)); glsafe(::glFrontFace(GL_CCW));
glsafe(::glDisable(GL_BLEND)); glsafe(::glDisable(GL_BLEND));
glsafe(::glDepthMask(GL_TRUE)); #if ENABLE_SEQUENTIAL_LIMITS
if (bottom)
#endif // ENABLE_SEQUENTIAL_LIMITS
glsafe(::glDepthMask(GL_TRUE));
shader->stop_using(); shader->stop_using();
} }
@ -475,6 +491,10 @@ void Bed3D::render_model() const
GLModel* model = const_cast<GLModel*>(&m_model); GLModel* model = const_cast<GLModel*>(&m_model);
if (model->get_filename() != m_model_filename && model->init_from_file(m_model_filename)) { if (model->get_filename() != m_model_filename && model->init_from_file(m_model_filename)) {
#if ENABLE_SEQUENTIAL_LIMITS
model->set_color(-1, m_model_color);
#endif // ENABLE_SEQUENTIAL_LIMITS
// move the model so that its origin (0.0, 0.0, 0.0) goes into the bed shape center and a bit down to avoid z-fighting with the texture quad // move the model so that its origin (0.0, 0.0, 0.0) goes into the bed shape center and a bit down to avoid z-fighting with the texture quad
Vec3d shift = m_bounding_box.center(); Vec3d shift = m_bounding_box.center();
shift(2) = -0.03; shift(2) = -0.03;
@ -488,9 +508,12 @@ void Bed3D::render_model() const
GLShaderProgram* shader = wxGetApp().get_shader("gouraud_light"); GLShaderProgram* shader = wxGetApp().get_shader("gouraud_light");
if (shader != nullptr) { if (shader != nullptr) {
shader->start_using(); shader->start_using();
#if !ENABLE_SEQUENTIAL_LIMITS
shader->set_uniform("uniform_color", m_model_color); shader->set_uniform("uniform_color", m_model_color);
#endif // !ENABLE_SEQUENTIAL_LIMITS
shader->set_uniform("emission_factor", 0.0);
::glPushMatrix(); ::glPushMatrix();
::glTranslated(m_model_offset(0), m_model_offset(1), m_model_offset(2)); ::glTranslated(m_model_offset.x(), m_model_offset.y(), m_model_offset.z());
model->render(); model->render();
::glPopMatrix(); ::glPopMatrix();
shader->stop_using(); shader->stop_using();

View File

@ -17,8 +17,8 @@ class GeometryBuffer
{ {
struct Vertex struct Vertex
{ {
Vec3f position = Vec3f::Zero(); Vec3f position{ Vec3f::Zero() };
Vec2f tex_coords = Vec2f::Zero(); Vec2f tex_coords{ Vec2f::Zero() };
}; };
std::vector<Vertex> m_vertices; std::vector<Vertex> m_vertices;
@ -53,7 +53,10 @@ class Bed3D
public: public:
const Vec3d& get_origin() const { return m_origin; } const Vec3d& get_origin() const { return m_origin; }
void set_origin(const Vec3d& origin) { m_origin = origin; } void set_origin(const Vec3d& origin) { m_origin = origin; }
void set_stem_length(float length); void set_stem_length(float length) {
m_stem_length = length;
m_arrow.reset();
}
float get_total_length() const { return m_stem_length + DefaultTipLength; } float get_total_length() const { return m_stem_length + DefaultTipLength; }
void render() const; void render() const;
}; };

View File

@ -205,6 +205,9 @@ void GCodeViewer::SequentialRangeCap::reset() {
void GCodeViewer::SequentialView::Marker::init() void GCodeViewer::SequentialView::Marker::init()
{ {
m_model.init_from(stilized_arrow(16, 2.0f, 4.0f, 1.0f, 8.0f)); m_model.init_from(stilized_arrow(16, 2.0f, 4.0f, 1.0f, 8.0f));
#if ENABLE_SEQUENTIAL_LIMITS
m_model.set_color(-1, { 1.0f, 1.0f, 1.0f, 0.5f });
#endif // ENABLE_SEQUENTIAL_LIMITS
} }
void GCodeViewer::SequentialView::Marker::set_world_position(const Vec3f& position) void GCodeViewer::SequentialView::Marker::set_world_position(const Vec3f& position)
@ -226,7 +229,10 @@ void GCodeViewer::SequentialView::Marker::render() const
glsafe(::glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)); glsafe(::glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA));
shader->start_using(); shader->start_using();
#if !ENABLE_SEQUENTIAL_LIMITS
shader->set_uniform("uniform_color", m_color); shader->set_uniform("uniform_color", m_color);
#endif // !ENABLE_SEQUENTIAL_LIMITS
shader->set_uniform("emission_factor", 0.0);
glsafe(::glPushMatrix()); glsafe(::glPushMatrix());
glsafe(::glMultMatrixf(m_world_transform.data())); glsafe(::glMultMatrixf(m_world_transform.data()));

View File

@ -505,7 +505,9 @@ public:
Vec3f m_world_position; Vec3f m_world_position;
Transform3f m_world_transform; Transform3f m_world_transform;
float m_z_offset{ 0.5f }; float m_z_offset{ 0.5f };
#if !ENABLE_SEQUENTIAL_LIMITS
std::array<float, 4> m_color{ 1.0f, 1.0f, 1.0f, 0.5f }; std::array<float, 4> m_color{ 1.0f, 1.0f, 1.0f, 0.5f };
#endif // !ENABLE_SEQUENTIAL_LIMITS
bool m_visible{ true }; bool m_visible{ true };
public: public:
@ -514,7 +516,9 @@ public:
const BoundingBoxf3& get_bounding_box() const { return m_model.get_bounding_box(); } const BoundingBoxf3& get_bounding_box() const { return m_model.get_bounding_box(); }
void set_world_position(const Vec3f& position); void set_world_position(const Vec3f& position);
#if !ENABLE_SEQUENTIAL_LIMITS
void set_color(const std::array<float, 4>& color) { m_color = color; } void set_color(const std::array<float, 4>& color) { m_color = color; }
#endif // !ENABLE_SEQUENTIAL_LIMITS
bool is_visible() const { return m_visible; } bool is_visible() const { return m_visible; }
void set_visible(bool visible) { m_visible = visible; } void set_visible(bool visible) { m_visible = visible; }

View File

@ -1,6 +1,8 @@
#include "libslic3r/libslic3r.h" #include "libslic3r/libslic3r.h"
#include "GLCanvas3D.hpp" #include "GLCanvas3D.hpp"
#include <igl/unproject.h>
#include "libslic3r/ClipperUtils.hpp" #include "libslic3r/ClipperUtils.hpp"
#include "libslic3r/PrintConfig.hpp" #include "libslic3r/PrintConfig.hpp"
#include "libslic3r/GCode/ThumbnailData.hpp" #include "libslic3r/GCode/ThumbnailData.hpp"
@ -787,6 +789,97 @@ void GLCanvas3D::Tooltip::render(const Vec2d& mouse_position, GLCanvas3D& canvas
ImGui::PopStyleVar(2); ImGui::PopStyleVar(2);
} }
#if ENABLE_SEQUENTIAL_LIMITS
void GLCanvas3D::SequentialPrintClearance::set(const Polygons& polygons, bool fill)
{
m_render_fill = fill;
m_perimeter.reset();
m_fill.reset();
if (polygons.empty())
return;
size_t triangles_count = 0;
for (const Polygon& poly : polygons) {
triangles_count += poly.points.size() - 2;
}
size_t vertices_count = 3 * triangles_count;
if (fill) {
GLModel::InitializationData fill_data;
GLModel::InitializationData::Entity entity;
entity.type = GLModel::PrimitiveType::Triangles;
entity.color = { 0.3333f, 0.0f, 0.0f, 0.5f };
entity.positions.reserve(vertices_count);
entity.normals.reserve(vertices_count);
entity.indices.reserve(vertices_count);
ExPolygons polygons_union = union_ex(polygons);
for (const ExPolygon& poly : polygons_union) {
std::vector<Vec3d> triangulation = triangulate_expolygon_3d(poly, false);
for (const Vec3d& v : triangulation) {
entity.positions.emplace_back(v.cast<float>() + Vec3f(0.0f, 0.0f, 0.0125f)); // add a small positive z to avoid z-fighting
entity.normals.emplace_back(Vec3f::UnitZ());
size_t positions_count = entity.positions.size();
if (positions_count % 3 == 0) {
entity.indices.emplace_back(positions_count - 3);
entity.indices.emplace_back(positions_count - 2);
entity.indices.emplace_back(positions_count - 1);
}
}
}
fill_data.entities.emplace_back(entity);
m_fill.init_from(fill_data);
}
GLModel::InitializationData perimeter_data;
for (const Polygon& poly : polygons) {
GLModel::InitializationData::Entity ent;
ent.type = GLModel::PrimitiveType::LineLoop;
ent.positions.reserve(poly.points.size());
ent.indices.reserve(poly.points.size());
unsigned int id_count = 0;
for (const Point& p : poly.points) {
ent.positions.emplace_back(unscale<float>(p.x()), unscale<float>(p.y()), 0.025f); // add a small positive z to avoid z-fighting
ent.normals.emplace_back(Vec3f::UnitZ());
ent.indices.emplace_back(id_count++);
}
perimeter_data.entities.emplace_back(ent);
}
m_perimeter.init_from(perimeter_data);
}
void GLCanvas3D::SequentialPrintClearance::render() const
{
std::array<float, 4> FILL_COLOR = { 1.0f, 0.0f, 0.0f, 0.5f };
std::array<float, 4> NO_FILL_COLOR = { 1.0f, 1.0f, 1.0f, 0.75f };
GLShaderProgram* shader = wxGetApp().get_shader("gouraud_light");
if (shader == nullptr)
return;
shader->start_using();
glsafe(::glEnable(GL_DEPTH_TEST));
glsafe(::glDisable(GL_CULL_FACE));
glsafe(::glEnable(GL_BLEND));
glsafe(::glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA));
const_cast<GLModel*>(&m_perimeter)->set_color(-1, m_render_fill ? FILL_COLOR : NO_FILL_COLOR);
m_perimeter.render();
m_fill.render();
glsafe(::glDisable(GL_BLEND));
glsafe(::glEnable(GL_CULL_FACE));
glsafe(::glDisable(GL_DEPTH_TEST));
shader->stop_using();
}
#endif // ENABLE_SEQUENTIAL_LIMITS
wxDEFINE_EVENT(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS, SimpleEvent); wxDEFINE_EVENT(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS, SimpleEvent);
wxDEFINE_EVENT(EVT_GLCANVAS_OBJECT_SELECT, SimpleEvent); wxDEFINE_EVENT(EVT_GLCANVAS_OBJECT_SELECT, SimpleEvent);
wxDEFINE_EVENT(EVT_GLCANVAS_RIGHT_CLICK, RBtnEvent); wxDEFINE_EVENT(EVT_GLCANVAS_RIGHT_CLICK, RBtnEvent);
@ -1375,7 +1468,11 @@ void GLCanvas3D::render()
_render_sla_slices(); _render_sla_slices();
_render_selection(); _render_selection();
_render_bed(!camera.is_looking_downward(), true); _render_bed(!camera.is_looking_downward(), true);
#if ENABLE_SEQUENTIAL_LIMITS
if (m_gizmos.get_current_type() == GLGizmosManager::EType::Undefined &&
!m_layers_editing.is_enabled())
_render_sequential_clearance();
#endif // ENABLE_SEQUENTIAL_LIMITS
#if ENABLE_RENDER_SELECTION_CENTER #if ENABLE_RENDER_SELECTION_CENTER
_render_selection_center(); _render_selection_center();
#endif // ENABLE_RENDER_SELECTION_CENTER #endif // ENABLE_RENDER_SELECTION_CENTER
@ -1616,6 +1713,8 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re
_set_current(); _set_current();
m_hover_volume_idxs.clear();
struct ModelVolumeState { struct ModelVolumeState {
ModelVolumeState(const GLVolume* volume) : ModelVolumeState(const GLVolume* volume) :
model_volume(nullptr), geometry_id(volume->geometry_id), volume_idx(-1) {} model_volume(nullptr), geometry_id(volume->geometry_id), volume_idx(-1) {}
@ -1914,7 +2013,7 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re
bool wt = dynamic_cast<const ConfigOptionBool*>(m_config->option("wipe_tower"))->value; bool wt = dynamic_cast<const ConfigOptionBool*>(m_config->option("wipe_tower"))->value;
bool co = dynamic_cast<const ConfigOptionBool*>(m_config->option("complete_objects"))->value; bool co = dynamic_cast<const ConfigOptionBool*>(m_config->option("complete_objects"))->value;
if ((extruders_count > 1) && wt && !co) { if (extruders_count > 1 && wt && !co) {
// Height of a print (Show at least a slab) // Height of a print (Show at least a slab)
double height = std::max(m_model->bounding_box().max(2), 10.0); double height = std::max(m_model->bounding_box().max(2), 10.0);
@ -2861,6 +2960,23 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
m_mouse.set_start_position_3D_as_invalid(); m_mouse.set_start_position_3D_as_invalid();
m_mouse.position = pos.cast<double>(); m_mouse.position = pos.cast<double>();
#if ENABLE_SEQUENTIAL_LIMITS
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; }
}
}
#endif // ENABLE_SEQUENTIAL_LIMITS
return; return;
} }
@ -2983,6 +3099,9 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
m_mouse.drag.move_volume_idx = volume_idx; m_mouse.drag.move_volume_idx = volume_idx;
m_selection.start_dragging(); m_selection.start_dragging();
m_mouse.drag.start_position_3D = m_mouse.scene_position; m_mouse.drag.start_position_3D = m_mouse.scene_position;
#if ENABLE_SEQUENTIAL_LIMITS
m_sequential_print_clearance_first_displacement = true;
#endif // ENABLE_SEQUENTIAL_LIMITS
m_moving = true; m_moving = true;
} }
} }
@ -3028,6 +3147,10 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
} }
m_selection.translate(cur_pos - m_mouse.drag.start_position_3D); m_selection.translate(cur_pos - m_mouse.drag.start_position_3D);
#if ENABLE_SEQUENTIAL_LIMITS
if (current_printer_technology() == ptFFF && fff_print()->config().complete_objects)
update_sequential_clearance();
#endif // ENABLE_SEQUENTIAL_LIMITS
wxGetApp().obj_manipul()->set_dirty(); wxGetApp().obj_manipul()->set_dirty();
m_dirty = true; m_dirty = true;
} }
@ -3060,7 +3183,7 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
// See GH issue #3816. // See GH issue #3816.
Camera& camera = wxGetApp().plater()->get_camera(); Camera& camera = wxGetApp().plater()->get_camera();
camera.recover_from_free_camera(); camera.recover_from_free_camera();
camera.rotate_on_sphere(rot.x(), rot.y(), wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology() != ptSLA); camera.rotate_on_sphere(rot.x(), rot.y(), current_printer_technology() != ptSLA);
} }
m_dirty = true; m_dirty = true;
@ -3277,15 +3400,15 @@ void GLCanvas3D::do_move(const std::string& snapshot_type)
for (const std::pair<int, int>& i : done) { for (const std::pair<int, int>& i : done) {
ModelObject* m = m_model->objects[i.first]; ModelObject* m = m_model->objects[i.first];
#if ENABLE_ALLOW_NEGATIVE_Z #if ENABLE_ALLOW_NEGATIVE_Z
double shift_z = m->get_instance_min_z(i.second); const double shift_z = m->get_instance_min_z(i.second);
#if DISABLE_ALLOW_NEGATIVE_Z_FOR_SLA #if DISABLE_ALLOW_NEGATIVE_Z_FOR_SLA
if (current_printer_technology() == ptSLA || shift_z > 0.0) { if (current_printer_technology() == ptSLA || shift_z > 0.0) {
#else #else
if (shift_z > 0.0) { if (shift_z > 0.0) {
#endif // DISABLE_ALLOW_NEGATIVE_Z_FOR_SLA #endif // DISABLE_ALLOW_NEGATIVE_Z_FOR_SLA
Vec3d shift(0.0, 0.0, -shift_z); const Vec3d shift(0.0, 0.0, -shift_z);
#else #else
Vec3d shift(0.0, 0.0, -m->get_instance_min_z(i.second)); const Vec3d shift(0.0, 0.0, -m->get_instance_min_z(i.second));
#endif // ENABLE_ALLOW_NEGATIVE_Z #endif // ENABLE_ALLOW_NEGATIVE_Z
m_selection.translate(i.first, i.second, shift); m_selection.translate(i.first, i.second, shift);
m->translate_instance(i.second, shift); m->translate_instance(i.second, shift);
@ -3307,6 +3430,10 @@ void GLCanvas3D::do_move(const std::string& snapshot_type)
if (wipe_tower_origin != Vec3d::Zero()) if (wipe_tower_origin != Vec3d::Zero())
post_event(Vec3dEvent(EVT_GLCANVAS_WIPETOWER_MOVED, std::move(wipe_tower_origin))); post_event(Vec3dEvent(EVT_GLCANVAS_WIPETOWER_MOVED, std::move(wipe_tower_origin)));
#if ENABLE_SEQUENTIAL_LIMITS
set_sequential_print_clearance(Polygons(), false);
#endif // ENABLE_SEQUENTIAL_LIMITS
m_dirty = true; m_dirty = true;
} }
@ -3653,6 +3780,93 @@ void GLCanvas3D::mouse_up_cleanup()
m_canvas->ReleaseMouse(); m_canvas->ReleaseMouse();
} }
#if ENABLE_SEQUENTIAL_LIMITS
void GLCanvas3D::update_sequential_clearance()
{
if (current_printer_technology() != ptFFF || !fff_print()->config().complete_objects)
return;
// collects instance transformations from volumes
// first define temporary cache
unsigned int instances_count = 0;
std::vector<std::vector<std::optional<Geometry::Transformation>>> instance_transforms;
for (size_t obj = 0; obj < m_model->objects.size(); ++obj) {
instance_transforms.emplace_back(std::vector<std::optional<Geometry::Transformation>>());
const ModelObject* model_object = m_model->objects[obj];
for (size_t i = 0; i < model_object->instances.size(); ++i) {
instance_transforms[obj].emplace_back(std::optional<Geometry::Transformation>());
++instances_count;
}
}
if (instances_count == 1)
return;
// second fill temporary cache with data from volumes
for (const GLVolume* v : m_volumes.volumes) {
if (v->is_modifier || v->is_wipe_tower)
continue;
auto& transform = instance_transforms[v->object_idx()][v->instance_idx()];
if (!transform.has_value())
transform = v->get_instance_transformation();
}
// calculates objects 2d hulls (see also: Print::sequential_print_horizontal_clearance_valid())
// this is done only the first time this method is called while moving the mouse,
// the results are then cached for following displacements
if (m_sequential_print_clearance_first_displacement) {
m_sequential_print_clearance.m_hull_2d_cache.clear();
float shrink_factor = static_cast<float>(scale_(0.5 * fff_print()->config().extruder_clearance_radius.value - EPSILON));
double mitter_limit = scale_(0.1);
m_sequential_print_clearance.m_hull_2d_cache.reserve(m_model->objects.size());
for (size_t i = 0; i < m_model->objects.size(); ++i) {
ModelObject* model_object = m_model->objects[i];
ModelInstance* model_instance0 = model_object->instances.front();
Polygon hull_2d = offset(model_object->convex_hull_2d(Geometry::assemble_transform({ 0.0, 0.0, model_instance0->get_offset().z() }, model_instance0->get_rotation(),
model_instance0->get_scaling_factor(), model_instance0->get_mirror())),
// Shrink the extruder_clearance_radius a tiny bit, so that if the object arrangement algorithm placed the objects
// exactly by satisfying the extruder_clearance_radius, this test will not trigger collision.
shrink_factor,
jtRound, mitter_limit).front();
Pointf3s& cache_hull_2d = m_sequential_print_clearance.m_hull_2d_cache.emplace_back(Pointf3s());
cache_hull_2d.reserve(hull_2d.points.size());
for (const Point& p : hull_2d.points) {
cache_hull_2d.emplace_back(unscale<double>(p.x()), unscale<double>(p.y()), 0.0);
}
}
m_sequential_print_clearance_first_displacement = false;
}
// calculates instances 2d hulls (see also: Print::sequential_print_horizontal_clearance_valid())
Polygons polygons;
polygons.reserve(instances_count);
for (size_t i = 0; i < instance_transforms.size(); ++i) {
const auto& instances = instance_transforms[i];
double rotation_z0 = instances.front()->get_rotation().z();
for (const auto& instance : instances) {
Geometry::Transformation transformation;
const Vec3d& offset = instance->get_offset();
transformation.set_offset({ offset.x(), offset.y(), 0.0 });
transformation.set_rotation(Z, instance->get_rotation().z() - rotation_z0);
const Transform3d& trafo = transformation.get_matrix();
const Pointf3s& hull_2d = m_sequential_print_clearance.m_hull_2d_cache[i];
Points inst_pts;
inst_pts.reserve(hull_2d.size());
for (size_t j = 0; j < hull_2d.size(); ++j) {
const Vec3d p = trafo * hull_2d[j];
inst_pts.emplace_back(scaled<double>(p.x()), scaled<double>(p.y()));
}
polygons.emplace_back(Geometry::convex_hull(std::move(inst_pts)));
}
}
// sends instances 2d hulls to be rendered
set_sequential_print_clearance(polygons, false);
}
#endif // ENABLE_SEQUENTIAL_LIMITS
bool GLCanvas3D::_is_shown_on_screen() const bool GLCanvas3D::_is_shown_on_screen() const
{ {
return (m_canvas != nullptr) ? m_canvas->IsShownOnScreen() : false; return (m_canvas != nullptr) ? m_canvas->IsShownOnScreen() : false;
@ -3916,7 +4130,7 @@ void GLCanvas3D::_render_thumbnail_internal(ThumbnailData& thumbnail_data, bool
glsafe(::glEnable(GL_DEPTH_TEST)); glsafe(::glEnable(GL_DEPTH_TEST));
shader->start_using(); shader->start_using();
shader->set_uniform("print_box.volume_detection", 0); shader->set_uniform("emission_factor", 0.0);
for (GLVolume* vol : visible_volumes) { for (GLVolume* vol : visible_volumes) {
shader->set_uniform("uniform_color", (vol->printable && !vol->is_outside) ? orange : gray); shader->set_uniform("uniform_color", (vol->printable && !vol->is_outside) ? orange : gray);
@ -4754,7 +4968,7 @@ void GLCanvas3D::_render_background() const
bool use_error_color = false; bool use_error_color = false;
if (wxGetApp().is_editor()) { if (wxGetApp().is_editor()) {
use_error_color = m_dynamic_background_enabled && use_error_color = m_dynamic_background_enabled &&
(wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology() != ptSLA || !m_volumes.empty()); (current_printer_technology() != ptSLA || !m_volumes.empty());
if (!m_volumes.empty()) if (!m_volumes.empty())
use_error_color &= _is_any_volume_outside(); use_error_color &= _is_any_volume_outside();
@ -4902,6 +5116,13 @@ void GLCanvas3D::_render_selection() const
m_selection.render(scale_factor); m_selection.render(scale_factor);
} }
#if ENABLE_SEQUENTIAL_LIMITS
void GLCanvas3D::_render_sequential_clearance() const
{
m_sequential_print_clearance.render();
}
#endif // ENABLE_SEQUENTIAL_LIMITS
#if ENABLE_RENDER_SELECTION_CENTER #if ENABLE_RENDER_SELECTION_CENTER
void GLCanvas3D::_render_selection_center() const void GLCanvas3D::_render_selection_center() const
{ {
@ -5167,7 +5388,7 @@ void GLCanvas3D::_render_camera_target() const
void GLCanvas3D::_render_sla_slices() const void GLCanvas3D::_render_sla_slices() const
{ {
if (!m_use_clipping_planes || wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology() != ptSLA) if (!m_use_clipping_planes || current_printer_technology() != ptSLA)
return; return;
const SLAPrint* print = this->sla_print(); const SLAPrint* print = this->sla_print();
@ -5393,9 +5614,9 @@ Vec3d GLCanvas3D::_mouse_to_3d(const Point& mouse_pos, float* z)
return Vec3d(DBL_MAX, DBL_MAX, DBL_MAX); return Vec3d(DBL_MAX, DBL_MAX, DBL_MAX);
const Camera& camera = wxGetApp().plater()->get_camera(); const Camera& camera = wxGetApp().plater()->get_camera();
const std::array<int, 4>& viewport = camera.get_viewport(); Matrix4d modelview = camera.get_view_matrix().matrix();
const Transform3d& modelview_matrix = camera.get_view_matrix(); Matrix4d projection= camera.get_projection_matrix().matrix();
const Transform3d& projection_matrix = camera.get_projection_matrix(); Vec4i viewport(camera.get_viewport().data());
GLint y = viewport[3] - (GLint)mouse_pos(1); GLint y = viewport[3] - (GLint)mouse_pos(1);
GLfloat mouse_z; GLfloat mouse_z;
@ -5404,9 +5625,9 @@ Vec3d GLCanvas3D::_mouse_to_3d(const Point& mouse_pos, float* z)
else else
mouse_z = *z; mouse_z = *z;
GLdouble out_x, out_y, out_z; Vec3d out;
::gluUnProject((GLdouble)mouse_pos(0), (GLdouble)y, (GLdouble)mouse_z, (GLdouble*)modelview_matrix.data(), (GLdouble*)projection_matrix.data(), (GLint*)viewport.data(), &out_x, &out_y, &out_z); igl::unproject(Vec3d(mouse_pos(0), y, mouse_z), modelview, projection, viewport, out);
return Vec3d((double)out_x, (double)out_y, (double)out_z); return out;
} }
Vec3d GLCanvas3D::_mouse_to_bed_3d(const Point& mouse_pos) Vec3d GLCanvas3D::_mouse_to_bed_3d(const Point& mouse_pos)

View File

@ -496,6 +496,26 @@ private:
void load_arrange_settings(); void load_arrange_settings();
#if ENABLE_SEQUENTIAL_LIMITS
class SequentialPrintClearance
{
GLModel m_fill;
GLModel m_perimeter;
bool m_render_fill{ true };
std::vector<Pointf3s> m_hull_2d_cache;
public:
void set(const Polygons& polygons, bool fill);
void render() const;
friend class GLCanvas3D;
};
SequentialPrintClearance m_sequential_print_clearance;
bool m_sequential_print_clearance_first_displacement{ true };
#endif // ENABLE_SEQUENTIAL_LIMITS
public: public:
explicit GLCanvas3D(wxGLCanvas* canvas); explicit GLCanvas3D(wxGLCanvas* canvas);
~GLCanvas3D(); ~GLCanvas3D();
@ -737,6 +757,14 @@ public:
#endif #endif
} }
#if ENABLE_SEQUENTIAL_LIMITS
void set_sequential_print_clearance(const Polygons& polygons, bool fill) { m_sequential_print_clearance.set(polygons, fill); }
void update_sequential_clearance();
#endif // ENABLE_SEQUENTIAL_LIMITS
const Print* fff_print() const;
const SLAPrint* sla_print() const;
#if ENABLE_SCROLLABLE_LEGEND #if ENABLE_SCROLLABLE_LEGEND
void reset_old_size() { m_old_size = { 0, 0 }; } void reset_old_size() { m_old_size = { 0, 0 }; }
#endif // ENABLE_SCROLLABLE_LEGEND #endif // ENABLE_SCROLLABLE_LEGEND
@ -767,6 +795,9 @@ private:
void _render_objects() const; void _render_objects() const;
void _render_gcode() const; void _render_gcode() const;
void _render_selection() const; void _render_selection() const;
#if ENABLE_SEQUENTIAL_LIMITS
void _render_sequential_clearance() const;
#endif // ENABLE_SEQUENTIAL_LIMITS
#if ENABLE_RENDER_SELECTION_CENTER #if ENABLE_RENDER_SELECTION_CENTER
void _render_selection_center() const; void _render_selection_center() const;
#endif // ENABLE_RENDER_SELECTION_CENTER #endif // ENABLE_RENDER_SELECTION_CENTER
@ -843,10 +874,6 @@ private:
float get_overlay_window_width() { return LayersEditing::get_overlay_window_width(); } float get_overlay_window_width() { return LayersEditing::get_overlay_window_width(); }
static std::vector<float> _parse_colors(const std::vector<std::string>& colors); static std::vector<float> _parse_colors(const std::vector<std::string>& colors);
public:
const Print* fff_print() const;
const SLAPrint* sla_print() const;
}; };
} // namespace GUI } // namespace GUI

View File

@ -2,6 +2,11 @@
#include "GLModel.hpp" #include "GLModel.hpp"
#include "3DScene.hpp" #include "3DScene.hpp"
#if ENABLE_SEQUENTIAL_LIMITS
#include "GUI_App.hpp"
#include "GLShader.hpp"
#endif // ENABLE_SEQUENTIAL_LIMITS
#include "libslic3r/TriangleMesh.hpp" #include "libslic3r/TriangleMesh.hpp"
#include "libslic3r/Model.hpp" #include "libslic3r/Model.hpp"
@ -13,6 +18,45 @@
namespace Slic3r { namespace Slic3r {
namespace GUI { namespace GUI {
#if ENABLE_SEQUENTIAL_LIMITS
void GLModel::init_from(const InitializationData& data)
{
if (!m_render_data.empty()) // call reset() if you want to reuse this model
return;
for (const InitializationData::Entity& entity : data.entities) {
if (entity.positions.empty() || entity.indices.empty())
continue;
assert(entity.normals.empty() || entity.normals.size() == entity.positions.size());
RenderData rdata;
rdata.type = entity.type;
rdata.color = entity.color;
// vertices/normals data
std::vector<float> vertices(6 * entity.positions.size());
for (size_t i = 0; i < entity.positions.size(); ++i) {
const size_t offset = i * 6;
::memcpy(static_cast<void*>(&vertices[offset]), static_cast<const void*>(entity.positions[i].data()), 3 * sizeof(float));
if (!entity.normals.empty())
::memcpy(static_cast<void*>(&vertices[3 + offset]), static_cast<const void*>(entity.normals[i].data()), 3 * sizeof(float));
}
// indices data
std::vector<unsigned int> indices = entity.indices;
rdata.indices_count = static_cast<unsigned int>(indices.size());
// update bounding box
for (size_t i = 0; i < entity.positions.size(); ++i) {
m_bounding_box.merge(entity.positions[i].cast<double>());
}
send_to_gpu(rdata, vertices, indices);
m_render_data.emplace_back(rdata);
}
#else
void GLModel::init_from(const GLModelInitializationData& data) void GLModel::init_from(const GLModelInitializationData& data)
{ {
assert(!data.positions.empty() && !data.triangles.empty()); assert(!data.positions.empty() && !data.triangles.empty());
@ -44,10 +88,41 @@ void GLModel::init_from(const GLModelInitializationData& data)
} }
send_to_gpu(vertices, indices); send_to_gpu(vertices, indices);
#endif // ENABLE_SEQUENTIAL_LIMITS
} }
void GLModel::init_from(const TriangleMesh& mesh) void GLModel::init_from(const TriangleMesh& mesh)
{ {
#if ENABLE_SEQUENTIAL_LIMITS
if (!m_render_data.empty()) // call reset() if you want to reuse this model
return;
RenderData data;
data.type = PrimitiveType::Triangles;
std::vector<float> vertices = std::vector<float>(18 * mesh.stl.stats.number_of_facets);
std::vector<unsigned int> indices = std::vector<unsigned int>(3 * mesh.stl.stats.number_of_facets);
unsigned int vertices_count = 0;
for (uint32_t i = 0; i < mesh.stl.stats.number_of_facets; ++i) {
const stl_facet& facet = mesh.stl.facet_start[i];
for (size_t j = 0; j < 3; ++j) {
size_t offset = i * 18 + j * 6;
::memcpy(static_cast<void*>(&vertices[offset]), static_cast<const void*>(facet.vertex[j].data()), 3 * sizeof(float));
::memcpy(static_cast<void*>(&vertices[3 + offset]), static_cast<const void*>(facet.normal.data()), 3 * sizeof(float));
}
for (size_t j = 0; j < 3; ++j) {
indices[i * 3 + j] = vertices_count + j;
}
vertices_count += 3;
}
data.indices_count = static_cast<unsigned int>(indices.size());
m_bounding_box = mesh.bounding_box();
send_to_gpu(data, vertices, indices);
m_render_data.emplace_back(data);
#else
if (m_vbo_id > 0) // call reset() if you want to reuse this model if (m_vbo_id > 0) // call reset() if you want to reuse this model
return; return;
@ -72,6 +147,7 @@ void GLModel::init_from(const TriangleMesh& mesh)
m_bounding_box = mesh.bounding_box(); m_bounding_box = mesh.bounding_box();
send_to_gpu(vertices, indices); send_to_gpu(vertices, indices);
#endif // ENABLE_SEQUENTIAL_LIMITS
} }
bool GLModel::init_from_file(const std::string& filename) bool GLModel::init_from_file(const std::string& filename)
@ -99,8 +175,29 @@ bool GLModel::init_from_file(const std::string& filename)
return true; return true;
} }
#if ENABLE_SEQUENTIAL_LIMITS
void GLModel::set_color(int entity_id, const std::array<float, 4>& color)
{
for (size_t i = 0; i < m_render_data.size(); ++i) {
if (entity_id == -1 || static_cast<int>(i) == entity_id)
m_render_data[i].color = color;
}
}
#endif // ENABLE_SEQUENTIAL_LIMITS
void GLModel::reset() void GLModel::reset()
{ {
#if ENABLE_SEQUENTIAL_LIMITS
for (RenderData& data : m_render_data) {
// release gpu memory
if (data.ibo_id > 0)
glsafe(::glDeleteBuffers(1, &data.ibo_id));
if (data.vbo_id > 0)
glsafe(::glDeleteBuffers(1, &data.vbo_id));
}
m_render_data.clear();
#else
// release gpu memory // release gpu memory
if (m_ibo_id > 0) { if (m_ibo_id > 0) {
glsafe(::glDeleteBuffers(1, &m_ibo_id)); glsafe(::glDeleteBuffers(1, &m_ibo_id));
@ -113,12 +210,49 @@ void GLModel::reset()
} }
m_indices_count = 0; m_indices_count = 0;
#endif // ENABLE_SEQUENTIAL_LIMITS
m_bounding_box = BoundingBoxf3(); m_bounding_box = BoundingBoxf3();
m_filename = std::string(); m_filename = std::string();
} }
void GLModel::render() const void GLModel::render() const
{ {
#if ENABLE_SEQUENTIAL_LIMITS
for (const RenderData& data : m_render_data) {
if (data.vbo_id == 0 || data.ibo_id == 0)
continue;
GLenum mode;
switch (data.type)
{
default:
case PrimitiveType::Triangles: { mode = GL_TRIANGLES; break; }
case PrimitiveType::Lines: { mode = GL_LINES; break; }
case PrimitiveType::LineStrip: { mode = GL_LINE_STRIP; break; }
case PrimitiveType::LineLoop: { mode = GL_LINE_LOOP; break; }
}
glsafe(::glBindBuffer(GL_ARRAY_BUFFER, data.vbo_id));
glsafe(::glVertexPointer(3, GL_FLOAT, 6 * sizeof(float), (const void*)0));
glsafe(::glNormalPointer(GL_FLOAT, 6 * sizeof(float), (const void*)(3 * sizeof(float))));
glsafe(::glEnableClientState(GL_VERTEX_ARRAY));
glsafe(::glEnableClientState(GL_NORMAL_ARRAY));
GLShaderProgram* shader = wxGetApp().get_current_shader();
if (shader != nullptr)
shader->set_uniform("uniform_color", data.color);
glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, data.ibo_id));
glsafe(::glDrawElements(mode, static_cast<GLsizei>(data.indices_count), GL_UNSIGNED_INT, (const void*)0));
glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0));
glsafe(::glDisableClientState(GL_NORMAL_ARRAY));
glsafe(::glDisableClientState(GL_VERTEX_ARRAY));
glsafe(::glBindBuffer(GL_ARRAY_BUFFER, 0));
}
#else
if (m_vbo_id == 0 || m_ibo_id == 0) if (m_vbo_id == 0 || m_ibo_id == 0)
return; return;
@ -137,8 +271,28 @@ void GLModel::render() const
glsafe(::glDisableClientState(GL_VERTEX_ARRAY)); glsafe(::glDisableClientState(GL_VERTEX_ARRAY));
glsafe(::glBindBuffer(GL_ARRAY_BUFFER, 0)); glsafe(::glBindBuffer(GL_ARRAY_BUFFER, 0));
#endif // ENABLE_SEQUENTIAL_LIMITS
} }
#if ENABLE_SEQUENTIAL_LIMITS
void GLModel::send_to_gpu(RenderData& data, const std::vector<float>& vertices, const std::vector<unsigned int>& indices)
{
assert(data.vbo_id == 0);
assert(data.ibo_id == 0);
// vertex data -> send to gpu
glsafe(::glGenBuffers(1, &data.vbo_id));
glsafe(::glBindBuffer(GL_ARRAY_BUFFER, data.vbo_id));
glsafe(::glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(float), vertices.data(), GL_STATIC_DRAW));
glsafe(::glBindBuffer(GL_ARRAY_BUFFER, 0));
// indices data -> send to gpu
glsafe(::glGenBuffers(1, &data.ibo_id));
glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, data.ibo_id));
glsafe(::glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size() * sizeof(unsigned int), indices.data(), GL_STATIC_DRAW));
glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0));
}
#else
void GLModel::send_to_gpu(const std::vector<float>& vertices, const std::vector<unsigned int>& indices) void GLModel::send_to_gpu(const std::vector<float>& vertices, const std::vector<unsigned int>& indices)
{ {
// vertex data -> send to gpu // vertex data -> send to gpu
@ -153,60 +307,138 @@ void GLModel::send_to_gpu(const std::vector<float>& vertices, const std::vector<
glsafe(::glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size() * sizeof(unsigned int), indices.data(), GL_STATIC_DRAW)); glsafe(::glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size() * sizeof(unsigned int), indices.data(), GL_STATIC_DRAW));
glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0)); glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0));
} }
#endif // ENABLE_SEQUENTIAL_LIMITS
#if ENABLE_SEQUENTIAL_LIMITS
GLModel::InitializationData stilized_arrow(int resolution, float tip_radius, float tip_height, float stem_radius, float stem_height)
{
auto append_vertex = [](GLModel::InitializationData::Entity& entity, const Vec3f& position, const Vec3f& normal) {
entity.positions.emplace_back(position);
entity.normals.emplace_back(normal);
};
auto append_indices = [](GLModel::InitializationData::Entity& entity, unsigned int v1, unsigned int v2, unsigned int v3) {
entity.indices.emplace_back(v1);
entity.indices.emplace_back(v2);
entity.indices.emplace_back(v3);
};
#else
GLModelInitializationData stilized_arrow(int resolution, float tip_radius, float tip_height, float stem_radius, float stem_height) GLModelInitializationData stilized_arrow(int resolution, float tip_radius, float tip_height, float stem_radius, float stem_height)
{ {
auto append_vertex = [](GLModelInitializationData& data, const Vec3f& position, const Vec3f& normal) { auto append_vertex = [](GLModelInitializationData& data, const Vec3f& position, const Vec3f& normal) {
data.positions.emplace_back(position); data.positions.emplace_back(position);
data.normals.emplace_back(normal); data.normals.emplace_back(normal);
}; };
#endif // ENABLE_SEQUENTIAL_LIMITS
resolution = std::max(4, resolution); resolution = std::max(4, resolution);
#if ENABLE_SEQUENTIAL_LIMITS
GLModel::InitializationData data;
GLModel::InitializationData::Entity entity;
entity.type = GLModel::PrimitiveType::Triangles;
#else
GLModelInitializationData data; GLModelInitializationData data;
#endif // ENABLE_SEQUENTIAL_LIMITS
const float angle_step = 2.0f * M_PI / static_cast<float>(resolution); const float angle_step = 2.0f * M_PI / static_cast<float>(resolution);
std::vector<float> cosines(resolution); std::vector<float> cosines(resolution);
std::vector<float> sines(resolution); std::vector<float> sines(resolution);
for (int i = 0; i < resolution; ++i) for (int i = 0; i < resolution; ++i) {
{ const float angle = angle_step * static_cast<float>(i);
float angle = angle_step * static_cast<float>(i);
cosines[i] = ::cos(angle); cosines[i] = ::cos(angle);
sines[i] = -::sin(angle); sines[i] = -::sin(angle);
} }
const float total_height = tip_height + stem_height; const float total_height = tip_height + stem_height;
#if ENABLE_SEQUENTIAL_LIMITS
// tip vertices/normals
append_vertex(entity, { 0.0f, 0.0f, total_height }, Vec3f::UnitZ());
for (int i = 0; i < resolution; ++i) {
append_vertex(entity, { tip_radius * sines[i], tip_radius * cosines[i], stem_height }, { sines[i], cosines[i], 0.0f });
}
// tip triangles
for (int i = 0; i < resolution; ++i) {
const int v3 = (i < resolution - 1) ? i + 2 : 1;
append_indices(entity, 0, i + 1, v3);
}
// tip cap outer perimeter vertices
for (int i = 0; i < resolution; ++i) {
append_vertex(entity, { tip_radius * sines[i], tip_radius * cosines[i], stem_height }, -Vec3f::UnitZ());
}
// tip cap inner perimeter vertices
for (int i = 0; i < resolution; ++i) {
append_vertex(entity, { stem_radius * sines[i], stem_radius * cosines[i], stem_height }, -Vec3f::UnitZ());
}
// tip cap triangles
for (int i = 0; i < resolution; ++i) {
const int v2 = (i < resolution - 1) ? i + resolution + 2 : resolution + 1;
const int v3 = (i < resolution - 1) ? i + 2 * resolution + 2 : 2 * resolution + 1;
append_indices(entity, i + resolution + 1, v3, v2);
append_indices(entity, i + resolution + 1, i + 2 * resolution + 1, v3);
}
// stem bottom vertices
for (int i = 0; i < resolution; ++i) {
append_vertex(entity, { stem_radius * sines[i], stem_radius * cosines[i], stem_height }, { sines[i], cosines[i], 0.0f });
}
// stem top vertices
for (int i = 0; i < resolution; ++i) {
append_vertex(entity, { stem_radius * sines[i], stem_radius * cosines[i], 0.0f }, { sines[i], cosines[i], 0.0f });
}
// stem triangles
for (int i = 0; i < resolution; ++i) {
const int v2 = (i < resolution - 1) ? i + 3 * resolution + 2 : 3 * resolution + 1;
const int v3 = (i < resolution - 1) ? i + 4 * resolution + 2 : 4 * resolution + 1;
append_indices(entity, i + 3 * resolution + 1, v3, v2);
append_indices(entity, i + 3 * resolution + 1, i + 4 * resolution + 1, v3);
}
// stem cap vertices
append_vertex(entity, Vec3f::Zero(), -Vec3f::UnitZ());
for (int i = 0; i < resolution; ++i) {
append_vertex(entity, { stem_radius * sines[i], stem_radius * cosines[i], 0.0f }, -Vec3f::UnitZ());
}
// stem cap triangles
for (int i = 0; i < resolution; ++i) {
const int v3 = (i < resolution - 1) ? i + 5 * resolution + 3 : 5 * resolution + 2;
append_indices(entity, 5 * resolution + 1, v3, i + 5 * resolution + 2);
}
data.entities.emplace_back(entity);
#else
// tip vertices/normals // tip vertices/normals
append_vertex(data, { 0.0f, 0.0f, total_height }, Vec3f::UnitZ()); append_vertex(data, { 0.0f, 0.0f, total_height }, Vec3f::UnitZ());
for (int i = 0; i < resolution; ++i) for (int i = 0; i < resolution; ++i) {
{
append_vertex(data, { tip_radius * sines[i], tip_radius * cosines[i], stem_height }, { sines[i], cosines[i], 0.0f }); append_vertex(data, { tip_radius * sines[i], tip_radius * cosines[i], stem_height }, { sines[i], cosines[i], 0.0f });
} }
// tip triangles // tip triangles
for (int i = 0; i < resolution; ++i) for (int i = 0; i < resolution; ++i) {
{
int v3 = (i < resolution - 1) ? i + 2 : 1; int v3 = (i < resolution - 1) ? i + 2 : 1;
data.triangles.emplace_back(0, i + 1, v3); data.triangles.emplace_back(0, i + 1, v3);
} }
// tip cap outer perimeter vertices // tip cap outer perimeter vertices
for (int i = 0; i < resolution; ++i) for (int i = 0; i < resolution; ++i) {
{
append_vertex(data, { tip_radius * sines[i], tip_radius * cosines[i], stem_height }, -Vec3f::UnitZ()); append_vertex(data, { tip_radius * sines[i], tip_radius * cosines[i], stem_height }, -Vec3f::UnitZ());
} }
// tip cap inner perimeter vertices // tip cap inner perimeter vertices
for (int i = 0; i < resolution; ++i) for (int i = 0; i < resolution; ++i) {
{
append_vertex(data, { stem_radius * sines[i], stem_radius * cosines[i], stem_height }, -Vec3f::UnitZ()); append_vertex(data, { stem_radius * sines[i], stem_radius * cosines[i], stem_height }, -Vec3f::UnitZ());
} }
// tip cap triangles // tip cap triangles
for (int i = 0; i < resolution; ++i) for (int i = 0; i < resolution; ++i) {
{
int v2 = (i < resolution - 1) ? i + resolution + 2 : resolution + 1; int v2 = (i < resolution - 1) ? i + resolution + 2 : resolution + 1;
int v3 = (i < resolution - 1) ? i + 2 * resolution + 2 : 2 * resolution + 1; int v3 = (i < resolution - 1) ? i + 2 * resolution + 2 : 2 * resolution + 1;
data.triangles.emplace_back(i + resolution + 1, v3, v2); data.triangles.emplace_back(i + resolution + 1, v3, v2);
@ -214,20 +446,17 @@ GLModelInitializationData stilized_arrow(int resolution, float tip_radius, float
} }
// stem bottom vertices // stem bottom vertices
for (int i = 0; i < resolution; ++i) for (int i = 0; i < resolution; ++i) {
{
append_vertex(data, { stem_radius * sines[i], stem_radius * cosines[i], stem_height }, { sines[i], cosines[i], 0.0f }); append_vertex(data, { stem_radius * sines[i], stem_radius * cosines[i], stem_height }, { sines[i], cosines[i], 0.0f });
} }
// stem top vertices // stem top vertices
for (int i = 0; i < resolution; ++i) for (int i = 0; i < resolution; ++i) {
{
append_vertex(data, { stem_radius * sines[i], stem_radius * cosines[i], 0.0f }, { sines[i], cosines[i], 0.0f }); append_vertex(data, { stem_radius * sines[i], stem_radius * cosines[i], 0.0f }, { sines[i], cosines[i], 0.0f });
} }
// stem triangles // stem triangles
for (int i = 0; i < resolution; ++i) for (int i = 0; i < resolution; ++i) {
{
int v2 = (i < resolution - 1) ? i + 3 * resolution + 2 : 3 * resolution + 1; int v2 = (i < resolution - 1) ? i + 3 * resolution + 2 : 3 * resolution + 1;
int v3 = (i < resolution - 1) ? i + 4 * resolution + 2 : 4 * resolution + 1; int v3 = (i < resolution - 1) ? i + 4 * resolution + 2 : 4 * resolution + 1;
data.triangles.emplace_back(i + 3 * resolution + 1, v3, v2); data.triangles.emplace_back(i + 3 * resolution + 1, v3, v2);
@ -236,31 +465,50 @@ GLModelInitializationData stilized_arrow(int resolution, float tip_radius, float
// stem cap vertices // stem cap vertices
append_vertex(data, Vec3f::Zero(), -Vec3f::UnitZ()); append_vertex(data, Vec3f::Zero(), -Vec3f::UnitZ());
for (int i = 0; i < resolution; ++i) for (int i = 0; i < resolution; ++i) {
{
append_vertex(data, { stem_radius * sines[i], stem_radius * cosines[i], 0.0f }, -Vec3f::UnitZ()); append_vertex(data, { stem_radius * sines[i], stem_radius * cosines[i], 0.0f }, -Vec3f::UnitZ());
} }
// stem cap triangles // stem cap triangles
for (int i = 0; i < resolution; ++i) for (int i = 0; i < resolution; ++i) {
{
int v3 = (i < resolution - 1) ? i + 5 * resolution + 3 : 5 * resolution + 2; int v3 = (i < resolution - 1) ? i + 5 * resolution + 3 : 5 * resolution + 2;
data.triangles.emplace_back(5 * resolution + 1, v3, i + 5 * resolution + 2); data.triangles.emplace_back(5 * resolution + 1, v3, i + 5 * resolution + 2);
} }
#endif // ENABLE_SEQUENTIAL_LIMITS
return data; return data;
} }
#if ENABLE_SEQUENTIAL_LIMITS
GLModel::InitializationData circular_arrow(int resolution, float radius, float tip_height, float tip_width, float stem_width, float thickness)
{
auto append_vertex = [](GLModel::InitializationData::Entity& entity, const Vec3f& position, const Vec3f& normal) {
entity.positions.emplace_back(position);
entity.normals.emplace_back(normal);
};
auto append_indices = [](GLModel::InitializationData::Entity& entity, unsigned int v1, unsigned int v2, unsigned int v3) {
entity.indices.emplace_back(v1);
entity.indices.emplace_back(v2);
entity.indices.emplace_back(v3);
};
#else
GLModelInitializationData circular_arrow(int resolution, float radius, float tip_height, float tip_width, float stem_width, float thickness) GLModelInitializationData circular_arrow(int resolution, float radius, float tip_height, float tip_width, float stem_width, float thickness)
{ {
auto append_vertex = [](GLModelInitializationData& data, const Vec3f& position, const Vec3f& normal) { auto append_vertex = [](GLModelInitializationData& data, const Vec3f& position, const Vec3f& normal) {
data.positions.emplace_back(position); data.positions.emplace_back(position);
data.normals.emplace_back(normal); data.normals.emplace_back(normal);
}; };
#endif // ENABLE_SEQUENTIAL_LIMITS
resolution = std::max(2, resolution); resolution = std::max(2, resolution);
#if ENABLE_SEQUENTIAL_LIMITS
GLModel::InitializationData data;
GLModel::InitializationData::Entity entity;
entity.type = GLModel::PrimitiveType::Triangles;
#else
GLModelInitializationData data; GLModelInitializationData data;
#endif // ENABLE_SEQUENTIAL_LIMITS
const float half_thickness = 0.5f * thickness; const float half_thickness = 0.5f * thickness;
const float half_stem_width = 0.5f * stem_width; const float half_stem_width = 0.5f * stem_width;
@ -270,6 +518,153 @@ GLModelInitializationData circular_arrow(int resolution, float radius, float tip
const float inner_radius = radius - half_stem_width; const float inner_radius = radius - half_stem_width;
const float step_angle = 0.5f * PI / static_cast<float>(resolution); const float step_angle = 0.5f * PI / static_cast<float>(resolution);
#if ENABLE_SEQUENTIAL_LIMITS
// tip
// top face vertices
append_vertex(entity, { 0.0f, outer_radius, half_thickness }, Vec3f::UnitZ());
append_vertex(entity, { 0.0f, radius + half_tip_width, half_thickness }, Vec3f::UnitZ());
append_vertex(entity, { -tip_height, radius, half_thickness }, Vec3f::UnitZ());
append_vertex(entity, { 0.0f, radius - half_tip_width, half_thickness }, Vec3f::UnitZ());
append_vertex(entity, { 0.0f, inner_radius, half_thickness }, Vec3f::UnitZ());
// top face triangles
append_indices(entity, 0, 1, 2);
append_indices(entity, 0, 2, 4);
append_indices(entity, 4, 2, 3);
// bottom face vertices
append_vertex(entity, { 0.0f, outer_radius, -half_thickness }, -Vec3f::UnitZ());
append_vertex(entity, { 0.0f, radius + half_tip_width, -half_thickness }, -Vec3f::UnitZ());
append_vertex(entity, { -tip_height, radius, -half_thickness }, -Vec3f::UnitZ());
append_vertex(entity, { 0.0f, radius - half_tip_width, -half_thickness }, -Vec3f::UnitZ());
append_vertex(entity, { 0.0f, inner_radius, -half_thickness }, -Vec3f::UnitZ());
// bottom face triangles
append_indices(entity, 5, 7, 6);
append_indices(entity, 5, 9, 7);
append_indices(entity, 9, 8, 7);
// side faces vertices
append_vertex(entity, { 0.0f, outer_radius, -half_thickness }, Vec3f::UnitX());
append_vertex(entity, { 0.0f, radius + half_tip_width, -half_thickness }, Vec3f::UnitX());
append_vertex(entity, { 0.0f, outer_radius, half_thickness }, Vec3f::UnitX());
append_vertex(entity, { 0.0f, radius + half_tip_width, half_thickness }, Vec3f::UnitX());
Vec3f normal(-half_tip_width, tip_height, 0.0f);
normal.normalize();
append_vertex(entity, { 0.0f, radius + half_tip_width, -half_thickness }, normal);
append_vertex(entity, { -tip_height, radius, -half_thickness }, normal);
append_vertex(entity, { 0.0f, radius + half_tip_width, half_thickness }, normal);
append_vertex(entity, { -tip_height, radius, half_thickness }, normal);
normal = Vec3f(-half_tip_width, -tip_height, 0.0f);
normal.normalize();
append_vertex(entity, { -tip_height, radius, -half_thickness }, normal);
append_vertex(entity, { 0.0f, radius - half_tip_width, -half_thickness }, normal);
append_vertex(entity, { -tip_height, radius, half_thickness }, normal);
append_vertex(entity, { 0.0f, radius - half_tip_width, half_thickness }, normal);
append_vertex(entity, { 0.0f, radius - half_tip_width, -half_thickness }, Vec3f::UnitX());
append_vertex(entity, { 0.0f, inner_radius, -half_thickness }, Vec3f::UnitX());
append_vertex(entity, { 0.0f, radius - half_tip_width, half_thickness }, Vec3f::UnitX());
append_vertex(entity, { 0.0f, inner_radius, half_thickness }, Vec3f::UnitX());
// side face triangles
for (int i = 0; i < 4; ++i) {
const int ii = i * 4;
append_indices(entity, 10 + ii, 11 + ii, 13 + ii);
append_indices(entity, 10 + ii, 13 + ii, 12 + ii);
}
// stem
// top face vertices
for (int i = 0; i <= resolution; ++i) {
const float angle = static_cast<float>(i) * step_angle;
append_vertex(entity, { inner_radius * ::sin(angle), inner_radius * ::cos(angle), half_thickness }, Vec3f::UnitZ());
}
for (int i = 0; i <= resolution; ++i) {
const float angle = static_cast<float>(i) * step_angle;
append_vertex(entity, { outer_radius * ::sin(angle), outer_radius * ::cos(angle), half_thickness }, Vec3f::UnitZ());
}
// top face triangles
for (int i = 0; i < resolution; ++i) {
append_indices(entity, 26 + i, 27 + i, 27 + resolution + i);
append_indices(entity, 27 + i, 28 + resolution + i, 27 + resolution + i);
}
// bottom face vertices
for (int i = 0; i <= resolution; ++i) {
const float angle = static_cast<float>(i) * step_angle;
append_vertex(entity, { inner_radius * ::sin(angle), inner_radius * ::cos(angle), -half_thickness }, -Vec3f::UnitZ());
}
for (int i = 0; i <= resolution; ++i) {
const float angle = static_cast<float>(i) * step_angle;
append_vertex(entity, { outer_radius * ::sin(angle), outer_radius * ::cos(angle), -half_thickness }, -Vec3f::UnitZ());
}
// bottom face triangles
for (int i = 0; i < resolution; ++i) {
append_indices(entity, 28 + 2 * resolution + i, 29 + 3 * resolution + i, 29 + 2 * resolution + i);
append_indices(entity, 29 + 2 * resolution + i, 29 + 3 * resolution + i, 30 + 3 * resolution + i);
}
// side faces vertices and triangles
for (int i = 0; i <= resolution; ++i) {
const float angle = static_cast<float>(i) * step_angle;
const float c = ::cos(angle);
const float s = ::sin(angle);
append_vertex(entity, { inner_radius * s, inner_radius * c, -half_thickness }, { -s, -c, 0.0f });
}
for (int i = 0; i <= resolution; ++i) {
const float angle = static_cast<float>(i) * step_angle;
const float c = ::cos(angle);
const float s = ::sin(angle);
append_vertex(entity, { inner_radius * s, inner_radius * c, half_thickness }, { -s, -c, 0.0f });
}
int first_id = 26 + 4 * (resolution + 1);
for (int i = 0; i < resolution; ++i) {
const int ii = first_id + i;
append_indices(entity, ii, ii + 1, ii + resolution + 2);
append_indices(entity, ii, ii + resolution + 2, ii + resolution + 1);
}
append_vertex(entity, { inner_radius, 0.0f, -half_thickness }, -Vec3f::UnitY());
append_vertex(entity, { outer_radius, 0.0f, -half_thickness }, -Vec3f::UnitY());
append_vertex(entity, { inner_radius, 0.0f, half_thickness }, -Vec3f::UnitY());
append_vertex(entity, { outer_radius, 0.0f, half_thickness }, -Vec3f::UnitY());
first_id = 26 + 6 * (resolution + 1);
append_indices(entity, first_id, first_id + 1, first_id + 3);
append_indices(entity, first_id, first_id + 3, first_id + 2);
for (int i = resolution; i >= 0; --i) {
const float angle = static_cast<float>(i) * step_angle;
const float c = ::cos(angle);
const float s = ::sin(angle);
append_vertex(entity, { outer_radius * s, outer_radius * c, -half_thickness }, { s, c, 0.0f });
}
for (int i = resolution; i >= 0; --i) {
const float angle = static_cast<float>(i) * step_angle;
const float c = ::cos(angle);
const float s = ::sin(angle);
append_vertex(entity, { outer_radius * s, outer_radius * c, +half_thickness }, { s, c, 0.0f });
}
first_id = 30 + 6 * (resolution + 1);
for (int i = 0; i < resolution; ++i) {
const int ii = first_id + i;
append_indices(entity, ii, ii + 1, ii + resolution + 2);
append_indices(entity, ii, ii + resolution + 2, ii + resolution + 1);
}
data.entities.emplace_back(entity);
#else
// tip // tip
// top face vertices // top face vertices
append_vertex(data, { 0.0f, outer_radius, half_thickness }, Vec3f::UnitZ()); append_vertex(data, { 0.0f, outer_radius, half_thickness }, Vec3f::UnitZ());
@ -321,8 +716,7 @@ GLModelInitializationData circular_arrow(int resolution, float radius, float tip
append_vertex(data, { 0.0f, inner_radius, half_thickness }, Vec3f::UnitX()); append_vertex(data, { 0.0f, inner_radius, half_thickness }, Vec3f::UnitX());
// side face triangles // side face triangles
for (int i = 0; i < 4; ++i) for (int i = 0; i < 4; ++i) {
{
int ii = i * 4; int ii = i * 4;
data.triangles.emplace_back(10 + ii, 11 + ii, 13 + ii); data.triangles.emplace_back(10 + ii, 11 + ii, 13 + ii);
data.triangles.emplace_back(10 + ii, 13 + ii, 12 + ii); data.triangles.emplace_back(10 + ii, 13 + ii, 12 + ii);
@ -330,56 +724,48 @@ GLModelInitializationData circular_arrow(int resolution, float radius, float tip
// stem // stem
// top face vertices // top face vertices
for (int i = 0; i <= resolution; ++i) for (int i = 0; i <= resolution; ++i) {
{
float angle = static_cast<float>(i) * step_angle; float angle = static_cast<float>(i) * step_angle;
append_vertex(data, { inner_radius * ::sin(angle), inner_radius * ::cos(angle), half_thickness }, Vec3f::UnitZ()); append_vertex(data, { inner_radius * ::sin(angle), inner_radius * ::cos(angle), half_thickness }, Vec3f::UnitZ());
} }
for (int i = 0; i <= resolution; ++i) for (int i = 0; i <= resolution; ++i) {
{
float angle = static_cast<float>(i) * step_angle; float angle = static_cast<float>(i) * step_angle;
append_vertex(data, { outer_radius * ::sin(angle), outer_radius * ::cos(angle), half_thickness }, Vec3f::UnitZ()); append_vertex(data, { outer_radius * ::sin(angle), outer_radius * ::cos(angle), half_thickness }, Vec3f::UnitZ());
} }
// top face triangles // top face triangles
for (int i = 0; i < resolution; ++i) for (int i = 0; i < resolution; ++i) {
{
data.triangles.emplace_back(26 + i, 27 + i, 27 + resolution + i); data.triangles.emplace_back(26 + i, 27 + i, 27 + resolution + i);
data.triangles.emplace_back(27 + i, 28 + resolution + i, 27 + resolution + i); data.triangles.emplace_back(27 + i, 28 + resolution + i, 27 + resolution + i);
} }
// bottom face vertices // bottom face vertices
for (int i = 0; i <= resolution; ++i) for (int i = 0; i <= resolution; ++i) {
{
float angle = static_cast<float>(i) * step_angle; float angle = static_cast<float>(i) * step_angle;
append_vertex(data, { inner_radius * ::sin(angle), inner_radius * ::cos(angle), -half_thickness }, -Vec3f::UnitZ()); append_vertex(data, { inner_radius * ::sin(angle), inner_radius * ::cos(angle), -half_thickness }, -Vec3f::UnitZ());
} }
for (int i = 0; i <= resolution; ++i) for (int i = 0; i <= resolution; ++i) {
{
float angle = static_cast<float>(i) * step_angle; float angle = static_cast<float>(i) * step_angle;
append_vertex(data, { outer_radius * ::sin(angle), outer_radius * ::cos(angle), -half_thickness }, -Vec3f::UnitZ()); append_vertex(data, { outer_radius * ::sin(angle), outer_radius * ::cos(angle), -half_thickness }, -Vec3f::UnitZ());
} }
// bottom face triangles // bottom face triangles
for (int i = 0; i < resolution; ++i) for (int i = 0; i < resolution; ++i) {
{
data.triangles.emplace_back(28 + 2 * resolution + i, 29 + 3 * resolution + i, 29 + 2 * resolution + i); data.triangles.emplace_back(28 + 2 * resolution + i, 29 + 3 * resolution + i, 29 + 2 * resolution + i);
data.triangles.emplace_back(29 + 2 * resolution + i, 29 + 3 * resolution + i, 30 + 3 * resolution + i); data.triangles.emplace_back(29 + 2 * resolution + i, 29 + 3 * resolution + i, 30 + 3 * resolution + i);
} }
// side faces vertices and triangles // side faces vertices and triangles
for (int i = 0; i <= resolution; ++i) for (int i = 0; i <= resolution; ++i) {
{
float angle = static_cast<float>(i) * step_angle; float angle = static_cast<float>(i) * step_angle;
float c = ::cos(angle); float c = ::cos(angle);
float s = ::sin(angle); float s = ::sin(angle);
append_vertex(data, { inner_radius * s, inner_radius * c, -half_thickness }, { -s, -c, 0.0f }); append_vertex(data, { inner_radius * s, inner_radius * c, -half_thickness }, { -s, -c, 0.0f });
} }
for (int i = 0; i <= resolution; ++i) for (int i = 0; i <= resolution; ++i) {
{
float angle = static_cast<float>(i) * step_angle; float angle = static_cast<float>(i) * step_angle;
float c = ::cos(angle); float c = ::cos(angle);
float s = ::sin(angle); float s = ::sin(angle);
@ -387,8 +773,7 @@ GLModelInitializationData circular_arrow(int resolution, float radius, float tip
} }
int first_id = 26 + 4 * (resolution + 1); int first_id = 26 + 4 * (resolution + 1);
for (int i = 0; i < resolution; ++i) for (int i = 0; i < resolution; ++i) {
{
int ii = first_id + i; int ii = first_id + i;
data.triangles.emplace_back(ii, ii + 1, ii + resolution + 2); data.triangles.emplace_back(ii, ii + 1, ii + resolution + 2);
data.triangles.emplace_back(ii, ii + resolution + 2, ii + resolution + 1); data.triangles.emplace_back(ii, ii + resolution + 2, ii + resolution + 1);
@ -403,16 +788,14 @@ GLModelInitializationData circular_arrow(int resolution, float radius, float tip
data.triangles.emplace_back(first_id, first_id + 1, first_id + 3); data.triangles.emplace_back(first_id, first_id + 1, first_id + 3);
data.triangles.emplace_back(first_id, first_id + 3, first_id + 2); data.triangles.emplace_back(first_id, first_id + 3, first_id + 2);
for (int i = resolution; i >= 0; --i) for (int i = resolution; i >= 0; --i) {
{
float angle = static_cast<float>(i) * step_angle; float angle = static_cast<float>(i) * step_angle;
float c = ::cos(angle); float c = ::cos(angle);
float s = ::sin(angle); float s = ::sin(angle);
append_vertex(data, { outer_radius * s, outer_radius * c, -half_thickness }, { s, c, 0.0f }); append_vertex(data, { outer_radius * s, outer_radius * c, -half_thickness }, { s, c, 0.0f });
} }
for (int i = resolution; i >= 0; --i) for (int i = resolution; i >= 0; --i) {
{
float angle = static_cast<float>(i) * step_angle; float angle = static_cast<float>(i) * step_angle;
float c = ::cos(angle); float c = ::cos(angle);
float s = ::sin(angle); float s = ::sin(angle);
@ -420,16 +803,33 @@ GLModelInitializationData circular_arrow(int resolution, float radius, float tip
} }
first_id = 30 + 6 * (resolution + 1); first_id = 30 + 6 * (resolution + 1);
for (int i = 0; i < resolution; ++i) for (int i = 0; i < resolution; ++i) {
{
int ii = first_id + i; int ii = first_id + i;
data.triangles.emplace_back(ii, ii + 1, ii + resolution + 2); data.triangles.emplace_back(ii, ii + 1, ii + resolution + 2);
data.triangles.emplace_back(ii, ii + resolution + 2, ii + resolution + 1); data.triangles.emplace_back(ii, ii + resolution + 2, ii + resolution + 1);
} }
#endif // ENABLE_SEQUENTIAL_LIMITS
return data; return data;
} }
#if ENABLE_SEQUENTIAL_LIMITS
GLModel::InitializationData straight_arrow(float tip_width, float tip_height, float stem_width, float stem_height, float thickness)
{
auto append_vertex = [](GLModel::InitializationData::Entity& entity, const Vec3f& position, const Vec3f& normal) {
entity.positions.emplace_back(position);
entity.normals.emplace_back(normal);
};
auto append_indices = [](GLModel::InitializationData::Entity& entity, unsigned int v1, unsigned int v2, unsigned int v3) {
entity.indices.emplace_back(v1);
entity.indices.emplace_back(v2);
entity.indices.emplace_back(v3);
};
GLModel::InitializationData data;
GLModel::InitializationData::Entity entity;
entity.type = GLModel::PrimitiveType::Triangles;
#else
GLModelInitializationData straight_arrow(float tip_width, float tip_height, float stem_width, float stem_height, float thickness) GLModelInitializationData straight_arrow(float tip_width, float tip_height, float stem_width, float stem_height, float thickness)
{ {
auto append_vertex = [](GLModelInitializationData& data, const Vec3f& position, const Vec3f& normal) { auto append_vertex = [](GLModelInitializationData& data, const Vec3f& position, const Vec3f& normal) {
@ -438,6 +838,7 @@ GLModelInitializationData straight_arrow(float tip_width, float tip_height, floa
}; };
GLModelInitializationData data; GLModelInitializationData data;
#endif // ENABLE_SEQUENTIAL_LIMITS
const float half_thickness = 0.5f * thickness; const float half_thickness = 0.5f * thickness;
const float half_stem_width = 0.5f * stem_width; const float half_stem_width = 0.5f * stem_width;
@ -445,6 +846,87 @@ GLModelInitializationData straight_arrow(float tip_width, float tip_height, floa
const float total_height = tip_height + stem_height; const float total_height = tip_height + stem_height;
// top face vertices // top face vertices
#if ENABLE_SEQUENTIAL_LIMITS
append_vertex(entity, { half_stem_width, 0.0, half_thickness }, Vec3f::UnitZ());
append_vertex(entity, { half_stem_width, stem_height, half_thickness }, Vec3f::UnitZ());
append_vertex(entity, { half_tip_width, stem_height, half_thickness }, Vec3f::UnitZ());
append_vertex(entity, { 0.0, total_height, half_thickness }, Vec3f::UnitZ());
append_vertex(entity, { -half_tip_width, stem_height, half_thickness }, Vec3f::UnitZ());
append_vertex(entity, { -half_stem_width, stem_height, half_thickness }, Vec3f::UnitZ());
append_vertex(entity, { -half_stem_width, 0.0, half_thickness }, Vec3f::UnitZ());
// top face triangles
append_indices(entity, 0, 1, 6);
append_indices(entity, 6, 1, 5);
append_indices(entity, 4, 5, 3);
append_indices(entity, 5, 1, 3);
append_indices(entity, 1, 2, 3);
// bottom face vertices
append_vertex(entity, { half_stem_width, 0.0, -half_thickness }, -Vec3f::UnitZ());
append_vertex(entity, { half_stem_width, stem_height, -half_thickness }, -Vec3f::UnitZ());
append_vertex(entity, { half_tip_width, stem_height, -half_thickness }, -Vec3f::UnitZ());
append_vertex(entity, { 0.0, total_height, -half_thickness }, -Vec3f::UnitZ());
append_vertex(entity, { -half_tip_width, stem_height, -half_thickness }, -Vec3f::UnitZ());
append_vertex(entity, { -half_stem_width, stem_height, -half_thickness }, -Vec3f::UnitZ());
append_vertex(entity, { -half_stem_width, 0.0, -half_thickness }, -Vec3f::UnitZ());
// bottom face triangles
append_indices(entity, 7, 13, 8);
append_indices(entity, 13, 12, 8);
append_indices(entity, 12, 11, 10);
append_indices(entity, 8, 12, 10);
append_indices(entity, 9, 8, 10);
// side faces vertices
append_vertex(entity, { half_stem_width, 0.0, -half_thickness }, Vec3f::UnitX());
append_vertex(entity, { half_stem_width, stem_height, -half_thickness }, Vec3f::UnitX());
append_vertex(entity, { half_stem_width, 0.0, half_thickness }, Vec3f::UnitX());
append_vertex(entity, { half_stem_width, stem_height, half_thickness }, Vec3f::UnitX());
append_vertex(entity, { half_stem_width, stem_height, -half_thickness }, -Vec3f::UnitY());
append_vertex(entity, { half_tip_width, stem_height, -half_thickness }, -Vec3f::UnitY());
append_vertex(entity, { half_stem_width, stem_height, half_thickness }, -Vec3f::UnitY());
append_vertex(entity, { half_tip_width, stem_height, half_thickness }, -Vec3f::UnitY());
Vec3f normal(tip_height, half_tip_width, 0.0f);
normal.normalize();
append_vertex(entity, { half_tip_width, stem_height, -half_thickness }, normal);
append_vertex(entity, { 0.0, total_height, -half_thickness }, normal);
append_vertex(entity, { half_tip_width, stem_height, half_thickness }, normal);
append_vertex(entity, { 0.0, total_height, half_thickness }, normal);
normal = Vec3f(-tip_height, half_tip_width, 0.0f);
normal.normalize();
append_vertex(entity, { 0.0, total_height, -half_thickness }, normal);
append_vertex(entity, { -half_tip_width, stem_height, -half_thickness }, normal);
append_vertex(entity, { 0.0, total_height, half_thickness }, normal);
append_vertex(entity, { -half_tip_width, stem_height, half_thickness }, normal);
append_vertex(entity, { -half_tip_width, stem_height, -half_thickness }, -Vec3f::UnitY());
append_vertex(entity, { -half_stem_width, stem_height, -half_thickness }, -Vec3f::UnitY());
append_vertex(entity, { -half_tip_width, stem_height, half_thickness }, -Vec3f::UnitY());
append_vertex(entity, { -half_stem_width, stem_height, half_thickness }, -Vec3f::UnitY());
append_vertex(entity, { -half_stem_width, stem_height, -half_thickness }, -Vec3f::UnitX());
append_vertex(entity, { -half_stem_width, 0.0, -half_thickness }, -Vec3f::UnitX());
append_vertex(entity, { -half_stem_width, stem_height, half_thickness }, -Vec3f::UnitX());
append_vertex(entity, { -half_stem_width, 0.0, half_thickness }, -Vec3f::UnitX());
append_vertex(entity, { -half_stem_width, 0.0, -half_thickness }, -Vec3f::UnitY());
append_vertex(entity, { half_stem_width, 0.0, -half_thickness }, -Vec3f::UnitY());
append_vertex(entity, { -half_stem_width, 0.0, half_thickness }, -Vec3f::UnitY());
append_vertex(entity, { half_stem_width, 0.0, half_thickness }, -Vec3f::UnitY());
// side face triangles
for (int i = 0; i < 7; ++i) {
const int ii = i * 4;
append_indices(entity, 14 + ii, 15 + ii, 17 + ii);
append_indices(entity, 14 + ii, 17 + ii, 16 + ii);
}
data.entities.emplace_back(entity);
#else
append_vertex(data, { half_stem_width, 0.0, half_thickness }, Vec3f::UnitZ()); append_vertex(data, { half_stem_width, 0.0, half_thickness }, Vec3f::UnitZ());
append_vertex(data, { half_stem_width, stem_height, half_thickness }, Vec3f::UnitZ()); append_vertex(data, { half_stem_width, stem_height, half_thickness }, Vec3f::UnitZ());
append_vertex(data, { half_tip_width, stem_height, half_thickness }, Vec3f::UnitZ()); append_vertex(data, { half_tip_width, stem_height, half_thickness }, Vec3f::UnitZ());
@ -517,12 +999,12 @@ GLModelInitializationData straight_arrow(float tip_width, float tip_height, floa
append_vertex(data, { half_stem_width, 0.0, half_thickness }, -Vec3f::UnitY()); append_vertex(data, { half_stem_width, 0.0, half_thickness }, -Vec3f::UnitY());
// side face triangles // side face triangles
for (int i = 0; i < 7; ++i) for (int i = 0; i < 7; ++i) {
{
int ii = i * 4; int ii = i * 4;
data.triangles.emplace_back(14 + ii, 15 + ii, 17 + ii); data.triangles.emplace_back(14 + ii, 15 + ii, 17 + ii);
data.triangles.emplace_back(14 + ii, 17 + ii, 16 + ii); data.triangles.emplace_back(14 + ii, 17 + ii, 16 + ii);
} }
#endif // ENABLE_SEQUENTIAL_LIMITS
return data; return data;
} }

View File

@ -12,40 +12,115 @@ class TriangleMesh;
namespace GUI { namespace GUI {
#if !ENABLE_SEQUENTIAL_LIMITS
struct GLModelInitializationData struct GLModelInitializationData
{ {
std::vector<Vec3f> positions; std::vector<Vec3f> positions;
std::vector<Vec3f> normals; std::vector<Vec3f> normals;
std::vector<Vec3i> triangles; std::vector<Vec3i> triangles;
}; };
#endif // !ENABLE_SEQUENTIAL_LIMITS
class GLModel class GLModel
{ {
#if ENABLE_SEQUENTIAL_LIMITS
public:
enum class PrimitiveType : unsigned char
{
Triangles,
Lines,
LineStrip,
LineLoop
};
struct RenderData
{
PrimitiveType type;
unsigned int vbo_id{ 0 };
unsigned int ibo_id{ 0 };
size_t indices_count{ 0 };
std::array<float, 4> color{ 1.0f, 1.0f, 1.0f, 1.0f };
};
struct InitializationData
{
struct Entity
{
PrimitiveType type;
std::vector<Vec3f> positions;
std::vector<Vec3f> normals;
std::vector<unsigned int> indices;
std::array<float, 4> color{ 1.0f, 1.0f, 1.0f, 1.0f };
};
std::vector<Entity> entities;
};
private:
std::vector<RenderData> m_render_data;
#else
unsigned int m_vbo_id{ 0 }; unsigned int m_vbo_id{ 0 };
unsigned int m_ibo_id{ 0 }; unsigned int m_ibo_id{ 0 };
size_t m_indices_count{ 0 }; size_t m_indices_count{ 0 };
#endif // ENABLE_SEQUENTIAL_LIMITS
BoundingBoxf3 m_bounding_box; BoundingBoxf3 m_bounding_box;
std::string m_filename; std::string m_filename;
public: public:
GLModel() = default;
virtual ~GLModel() { reset(); } virtual ~GLModel() { reset(); }
#if ENABLE_SEQUENTIAL_LIMITS
void init_from(const InitializationData& data);
#else
void init_from(const GLModelInitializationData& data); void init_from(const GLModelInitializationData& data);
#endif // ENABLE_SEQUENTIAL_LIMITS
void init_from(const TriangleMesh& mesh); void init_from(const TriangleMesh& mesh);
bool init_from_file(const std::string& filename); bool init_from_file(const std::string& filename);
#if ENABLE_SEQUENTIAL_LIMITS
// if entity_id == -1 set the color of all entities
void set_color(int entity_id, const std::array<float, 4>& color);
#endif // ENABLE_SEQUENTIAL_LIMITS
void reset(); void reset();
void render() const; void render() const;
const BoundingBoxf3& get_bounding_box() const { return m_bounding_box; } #if ENABLE_SEQUENTIAL_LIMITS
bool is_initialized() const { return !m_render_data.empty(); }
#endif // ENABLE_SEQUENTIAL_LIMITS
const BoundingBoxf3& get_bounding_box() const { return m_bounding_box; }
const std::string& get_filename() const { return m_filename; } const std::string& get_filename() const { return m_filename; }
private: private:
#if ENABLE_SEQUENTIAL_LIMITS
void send_to_gpu(RenderData& data, const std::vector<float>& vertices, const std::vector<unsigned int>& indices);
#else
void send_to_gpu(const std::vector<float>& vertices, const std::vector<unsigned int>& indices); void send_to_gpu(const std::vector<float>& vertices, const std::vector<unsigned int>& indices);
#endif // ENABLE_SEQUENTIAL_LIMITS
}; };
#if ENABLE_SEQUENTIAL_LIMITS
// 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
// used to render bed axes and sequential marker
GLModel::InitializationData stilized_arrow(int resolution, float tip_radius, float tip_height, float stem_radius, float stem_height);
// create an arrow whose stem is a quarter of circle, with the given dimensions and resolution
// the origin of the arrow is in the center of the circle
// the arrow is contained in the 1st quadrant of the XY plane and is pointing counterclockwise
// used to render sidebar hints for rotations
GLModel::InitializationData circular_arrow(int resolution, float radius, float tip_height, float tip_width, float stem_width, float thickness);
// create an arrow with the given dimensions
// the origin of the arrow is in the center of the stem cap
// the arrow is contained in XY plane and has its main axis along the Y axis
// used to render sidebar hints for position and scale
GLModel::InitializationData straight_arrow(float tip_width, float tip_height, float stem_width, float stem_height, float thickness);
#else
// create an arrow with cylindrical stem and conical tip, with the given dimensions and resolution // 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 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 // the arrow has its axis of symmetry along the Z axis and is pointing upward
@ -60,6 +135,7 @@ namespace GUI {
// the origin of the arrow is in the center of the stem cap // the origin of the arrow is in the center of the stem cap
// the arrow is contained in XY plane and has its main axis along the Y axis // the arrow is contained in XY plane and has its main axis along the Y axis
GLModelInitializationData straight_arrow(float tip_width, float tip_height, float stem_width, float stem_height, float thickness); GLModelInitializationData straight_arrow(float tip_width, float tip_height, float stem_width, float stem_height, float thickness);
#endif // ENABLE_SEQUENTIAL_LIMITS
} // namespace GUI } // namespace GUI
} // namespace Slic3r } // namespace Slic3r

View File

@ -4,6 +4,7 @@
#include "GLCanvas3D.hpp" #include "GLCanvas3D.hpp"
#include "GUI_App.hpp" #include "GUI_App.hpp"
#include "Plater.hpp" #include "Plater.hpp"
#include <igl/project.h>
#include <GL/glew.h> #include <GL/glew.h>
@ -38,23 +39,26 @@ namespace GUI {
m_state = Off; m_state = Off;
const Camera& camera = wxGetApp().plater()->get_camera(); const Camera& camera = wxGetApp().plater()->get_camera();
const std::array<int, 4>& viewport = camera.get_viewport(); Matrix4d modelview = camera.get_view_matrix().matrix();
const Transform3d& modelview_matrix = camera.get_view_matrix(); Matrix4d projection= camera.get_projection_matrix().matrix();
const Transform3d& projection_matrix = camera.get_projection_matrix(); Vec4i viewport(camera.get_viewport().data());
// Convert our std::vector to Eigen dynamic matrix.
Eigen::Matrix<double, Eigen::Dynamic, 3, Eigen::DontAlign> pts(points.size(), 3);
for (size_t i=0; i<points.size(); ++i)
pts.block<1, 3>(i, 0) = points[i];
// Get the projections.
Eigen::Matrix<double, Eigen::Dynamic, 3, Eigen::DontAlign> projections;
igl::project(pts, modelview, projection, viewport, projections);
// bounding box created from the rectangle corners - will take care of order of the corners // bounding box created from the rectangle corners - will take care of order of the corners
BoundingBox rectangle(Points{ Point(m_start_corner.cast<coord_t>()), Point(m_end_corner.cast<coord_t>()) }); BoundingBox rectangle(Points{ Point(m_start_corner.cast<coord_t>()), Point(m_end_corner.cast<coord_t>()) });
// Iterate over all points and determine whether they're in the rectangle. // Iterate over all points and determine whether they're in the rectangle.
for (unsigned int i = 0; i<points.size(); ++i) { for (int i = 0; i<projections.rows(); ++i)
const Vec3d& point = points[i]; if (rectangle.contains(Point(projections(i, 0), canvas.get_canvas_size().get_height() - projections(i, 1))))
GLdouble out_x, out_y, out_z;
::gluProject((GLdouble)point(0), (GLdouble)point(1), (GLdouble)point(2), (GLdouble*)modelview_matrix.data(), (GLdouble*)projection_matrix.data(), (GLint*)viewport.data(), &out_x, &out_y, &out_z);
out_y = canvas.get_canvas_size().get_height() - out_y;
if (rectangle.contains(Point(out_x, out_y)))
out.push_back(i); out.push_back(i);
}
return out; return out;
} }

View File

@ -20,26 +20,22 @@ GLGizmoBase::Grabber::Grabber()
, dragging(false) , dragging(false)
, enabled(true) , enabled(true)
{ {
color[0] = 1.0f; color = { 1.0f, 1.0f, 1.0f, 1.0f };
color[1] = 1.0f;
color[2] = 1.0f;
color[3] = 1.0f;
} }
void GLGizmoBase::Grabber::render(bool hover, float size) const void GLGizmoBase::Grabber::render(bool hover, float size) const
{ {
float render_color[4]; std::array<float, 4> render_color;
if (hover) if (hover) {
{ render_color[0] = (1.0f - color[0]);
render_color[0] = 1.0f - color[0]; render_color[1] = (1.0f - color[1]);
render_color[1] = 1.0f - color[1]; render_color[2] = (1.0f - color[2]);
render_color[2] = 1.0f - color[2];
render_color[3] = color[3]; render_color[3] = color[3];
} }
else else
::memcpy((void*)render_color, (const void*)color, 4 * sizeof(float)); render_color = color;
render(size, render_color, true); render(size, render_color, false);
} }
float GLGizmoBase::Grabber::get_half_size(float size) const float GLGizmoBase::Grabber::get_half_size(float size) const
@ -52,80 +48,37 @@ float GLGizmoBase::Grabber::get_dragging_half_size(float size) const
return get_half_size(size) * DraggingScaleFactor; return get_half_size(size) * DraggingScaleFactor;
} }
void GLGizmoBase::Grabber::render(float size, const float* render_color, bool use_lighting) const void GLGizmoBase::Grabber::render(float size, const std::array<float, 4>& render_color, bool picking) const
{ {
float half_size = dragging ? get_dragging_half_size(size) : get_half_size(size); if (! cube_initialized) {
// This cannot be done in constructor, OpenGL is not yet
// initialized at that point (on Linux at least).
TriangleMesh mesh = make_cube(1., 1., 1.);
mesh.translate(Vec3f(-0.5, -0.5, -0.5));
const_cast<GLModel&>(cube).init_from(mesh);
const_cast<bool&>(cube_initialized) = true;
}
if (use_lighting) float fullsize = 2 * (dragging ? get_dragging_half_size(size) : get_half_size(size));
glsafe(::glEnable(GL_LIGHTING));
glsafe(::glColor4fv(render_color)); GLShaderProgram* shader = picking ? nullptr : wxGetApp().get_current_shader();
if (shader != nullptr)
#if ENABLE_SEQUENTIAL_LIMITS
const_cast<GLModel*>(&cube)->set_color(-1, render_color);
#else
shader->set_uniform("uniform_color", render_color);
#endif // ENABLE_SEQUENTIAL_LIMITS
else
glsafe(::glColor4fv(render_color.data())); // picking
glsafe(::glPushMatrix()); glsafe(::glPushMatrix());
glsafe(::glTranslated(center(0), center(1), center(2))); glsafe(::glTranslated(center.x(), center.y(), center.z()));
glsafe(::glRotated(Geometry::rad2deg(angles.z()), 0.0, 0.0, 1.0));
glsafe(::glRotated(Geometry::rad2deg(angles(2)), 0.0, 0.0, 1.0)); glsafe(::glRotated(Geometry::rad2deg(angles.y()), 0.0, 1.0, 0.0));
glsafe(::glRotated(Geometry::rad2deg(angles(1)), 0.0, 1.0, 0.0)); glsafe(::glRotated(Geometry::rad2deg(angles.x()), 1.0, 0.0, 0.0));
glsafe(::glRotated(Geometry::rad2deg(angles(0)), 1.0, 0.0, 0.0)); glsafe(::glScaled(fullsize, fullsize, fullsize));
cube.render();
// face min x
glsafe(::glPushMatrix());
glsafe(::glTranslatef(-(GLfloat)half_size, 0.0f, 0.0f));
glsafe(::glRotatef(-90.0f, 0.0f, 1.0f, 0.0f));
render_face(half_size);
glsafe(::glPopMatrix()); glsafe(::glPopMatrix());
// face max x
glsafe(::glPushMatrix());
glsafe(::glTranslatef((GLfloat)half_size, 0.0f, 0.0f));
glsafe(::glRotatef(90.0f, 0.0f, 1.0f, 0.0f));
render_face(half_size);
glsafe(::glPopMatrix());
// face min y
glsafe(::glPushMatrix());
glsafe(::glTranslatef(0.0f, -(GLfloat)half_size, 0.0f));
glsafe(::glRotatef(90.0f, 1.0f, 0.0f, 0.0f));
render_face(half_size);
glsafe(::glPopMatrix());
// face max y
glsafe(::glPushMatrix());
glsafe(::glTranslatef(0.0f, (GLfloat)half_size, 0.0f));
glsafe(::glRotatef(-90.0f, 1.0f, 0.0f, 0.0f));
render_face(half_size);
glsafe(::glPopMatrix());
// face min z
glsafe(::glPushMatrix());
glsafe(::glTranslatef(0.0f, 0.0f, -(GLfloat)half_size));
glsafe(::glRotatef(180.0f, 1.0f, 0.0f, 0.0f));
render_face(half_size);
glsafe(::glPopMatrix());
// face max z
glsafe(::glPushMatrix());
glsafe(::glTranslatef(0.0f, 0.0f, (GLfloat)half_size));
render_face(half_size);
glsafe(::glPopMatrix());
glsafe(::glPopMatrix());
if (use_lighting)
glsafe(::glDisable(GL_LIGHTING));
}
void GLGizmoBase::Grabber::render_face(float half_size) const
{
::glBegin(GL_TRIANGLES);
::glNormal3f(0.0f, 0.0f, 1.0f);
::glVertex3f(-(GLfloat)half_size, -(GLfloat)half_size, 0.0f);
::glVertex3f((GLfloat)half_size, -(GLfloat)half_size, 0.0f);
::glVertex3f((GLfloat)half_size, (GLfloat)half_size, 0.0f);
::glVertex3f((GLfloat)half_size, (GLfloat)half_size, 0.0f);
::glVertex3f(-(GLfloat)half_size, (GLfloat)half_size, 0.0f);
::glVertex3f(-(GLfloat)half_size, -(GLfloat)half_size, 0.0f);
glsafe(::glEnd());
} }
@ -141,9 +94,12 @@ GLGizmoBase::GLGizmoBase(GLCanvas3D& parent, const std::string& icon_filename, u
, m_imgui(wxGetApp().imgui()) , m_imgui(wxGetApp().imgui())
, m_first_input_window_render(true) , m_first_input_window_render(true)
{ {
::memcpy((void*)m_base_color, (const void*)DEFAULT_BASE_COLOR, 4 * sizeof(float)); m_base_color = DEFAULT_BASE_COLOR;
::memcpy((void*)m_drag_color, (const void*)DEFAULT_DRAG_COLOR, 4 * sizeof(float)); m_drag_color = DEFAULT_DRAG_COLOR;
::memcpy((void*)m_highlight_color, (const void*)DEFAULT_HIGHLIGHT_COLOR, 4 * sizeof(float)); m_highlight_color = DEFAULT_HIGHLIGHT_COLOR;
m_cone.init_from(make_cone(1., 1., 2 * PI / 24));
m_sphere.init_from(make_sphere(1., (2 * M_PI) / 24.));
m_cylinder.init_from(make_cylinder(1., 1., 2 * PI / 24.));
} }
void GLGizmoBase::set_hover_id(int id) void GLGizmoBase::set_hover_id(int id)
@ -155,10 +111,9 @@ void GLGizmoBase::set_hover_id(int id)
} }
} }
void GLGizmoBase::set_highlight_color(const float* color) void GLGizmoBase::set_highlight_color(const std::array<float, 4>& color)
{ {
if (color != nullptr) m_highlight_color = color;
::memcpy((void*)m_highlight_color, (const void*)color, 4 * sizeof(float));
} }
void GLGizmoBase::enable_grabber(unsigned int id) void GLGizmoBase::enable_grabber(unsigned int id)
@ -227,31 +182,31 @@ std::array<float, 4> GLGizmoBase::picking_color_component(unsigned int id) const
void GLGizmoBase::render_grabbers(const BoundingBoxf3& box) const void GLGizmoBase::render_grabbers(const BoundingBoxf3& box) const
{ {
render_grabbers((float)((box.size()(0) + box.size()(1) + box.size()(2)) / 3.0)); render_grabbers((float)((box.size().x() + box.size().y() + box.size().z()) / 3.0));
} }
void GLGizmoBase::render_grabbers(float size) const void GLGizmoBase::render_grabbers(float size) const
{ {
for (int i = 0; i < (int)m_grabbers.size(); ++i) GLShaderProgram* shader = wxGetApp().get_shader("gouraud_light");
{ if (shader == nullptr)
return;
shader->start_using();
shader->set_uniform("emission_factor", 0.1);
for (int i = 0; i < (int)m_grabbers.size(); ++i) {
if (m_grabbers[i].enabled) if (m_grabbers[i].enabled)
m_grabbers[i].render((m_hover_id == i), size); m_grabbers[i].render(m_hover_id == i, size);
} }
shader->stop_using();
} }
void GLGizmoBase::render_grabbers_for_picking(const BoundingBoxf3& box) const void GLGizmoBase::render_grabbers_for_picking(const BoundingBoxf3& box) const
{ {
float mean_size = (float)((box.size()(0) + box.size()(1) + box.size()(2)) / 3.0); float mean_size = (float)((box.size().x() + box.size().y() + box.size().z()) / 3.0);
for (unsigned int i = 0; i < (unsigned int)m_grabbers.size(); ++i) for (unsigned int i = 0; i < (unsigned int)m_grabbers.size(); ++i) {
{ if (m_grabbers[i].enabled) {
if (m_grabbers[i].enabled)
{
std::array<float, 4> color = picking_color_component(i); std::array<float, 4> color = picking_color_component(i);
m_grabbers[i].color[0] = color[0]; m_grabbers[i].color = color;
m_grabbers[i].color[1] = color[1];
m_grabbers[i].color[2] = color[2];
m_grabbers[i].color[3] = color[3];
m_grabbers[i].render_for_picking(mean_size); m_grabbers[i].render_for_picking(mean_size);
} }
} }
@ -265,8 +220,7 @@ std::string GLGizmoBase::format(float value, unsigned int decimals) const
void GLGizmoBase::render_input_window(float x, float y, float bottom_limit) void GLGizmoBase::render_input_window(float x, float y, float bottom_limit)
{ {
on_render_input_window(x, y, bottom_limit); on_render_input_window(x, y, bottom_limit);
if (m_first_input_window_render) if (m_first_input_window_render) {
{
// for some reason, the imgui dialogs are not shown on screen in the 1st frame where they are rendered, but show up only with the 2nd rendered frame // for some reason, the imgui dialogs are not shown on screen in the 1st frame where they are rendered, but show up only with the 2nd rendered frame
// so, we forces another frame rendering the first time the imgui window is shown // so, we forces another frame rendering the first time the imgui window is shown
m_parent.set_as_dirty(); m_parent.set_as_dirty();

View File

@ -4,13 +4,11 @@
#include "libslic3r/Point.hpp" #include "libslic3r/Point.hpp"
#include "slic3r/GUI/I18N.hpp" #include "slic3r/GUI/I18N.hpp"
#include "slic3r/GUI/GLModel.hpp"
#include <cereal/archives/binary.hpp> #include <cereal/archives/binary.hpp>
class wxWindow; class wxWindow;
class GLUquadric;
typedef class GLUquadric GLUquadricObj;
namespace Slic3r { namespace Slic3r {
@ -20,13 +18,15 @@ class ModelObject;
namespace GUI { namespace GUI {
static const float DEFAULT_BASE_COLOR[4] = { 0.625f, 0.625f, 0.625f, 1.0f }; static const std::array<float, 4> DEFAULT_BASE_COLOR = { 0.625f, 0.625f, 0.625f, 1.0f };
static const float DEFAULT_DRAG_COLOR[4] = { 1.0f, 1.0f, 1.0f, 1.0f }; static const std::array<float, 4> DEFAULT_DRAG_COLOR = { 1.0f, 1.0f, 1.0f, 1.0f };
static const float DEFAULT_HIGHLIGHT_COLOR[4] = { 1.0f, 0.38f, 0.0f, 1.0f }; static const std::array<float, 4> DEFAULT_HIGHLIGHT_COLOR = { 1.0f, 0.38f, 0.0f, 1.0f };
static const float AXES_COLOR[][4] = { { 0.75f, 0.0f, 0.0f, 1.0f }, { 0.0f, 0.75f, 0.0f, 1.0f }, { 0.0f, 0.0f, 0.75f, 1.0f } }; static const std::array<std::array<float, 4>, 3> AXES_COLOR = {{
static const float CONSTRAINED_COLOR[4] = { 0.5f, 0.5f, 0.5f, 1.0f }; { 0.75f, 0.0f, 0.0f, 1.0f },
{ 0.0f, 0.75f, 0.0f, 1.0f },
{ 0.0f, 0.0f, 0.75f, 1.0f }
}};
static const std::array<float, 4> CONSTRAINED_COLOR = { 0.5f, 0.5f, 0.5f, 1.0f };
class ImGuiWrapper; class ImGuiWrapper;
class GLCanvas3D; class GLCanvas3D;
@ -50,21 +50,23 @@ protected:
Vec3d center; Vec3d center;
Vec3d angles; Vec3d angles;
float color[4]; std::array<float, 4> color;
bool enabled; bool enabled;
bool dragging; bool dragging;
Grabber(); Grabber();
void render(bool hover, float size) const; void render(bool hover, float size) const;
void render_for_picking(float size) const { render(size, color, false); } void render_for_picking(float size) const { render(size, color, true); }
float get_half_size(float size) const; float get_half_size(float size) const;
float get_dragging_half_size(float size) const; float get_dragging_half_size(float size) const;
private: private:
void render(float size, const float* render_color, bool use_lighting) const; void render(float size, const std::array<float, 4>& render_color, bool picking) const;
void render_face(float half_size) const;
GLModel cube;
bool cube_initialized = false;
}; };
public: public:
@ -95,14 +97,17 @@ protected:
unsigned int m_sprite_id; unsigned int m_sprite_id;
int m_hover_id; int m_hover_id;
bool m_dragging; bool m_dragging;
float m_base_color[4]; std::array<float, 4> m_base_color;
float m_drag_color[4]; std::array<float, 4> m_drag_color;
float m_highlight_color[4]; std::array<float, 4> m_highlight_color;
mutable std::vector<Grabber> m_grabbers; mutable std::vector<Grabber> m_grabbers;
ImGuiWrapper* m_imgui; ImGuiWrapper* m_imgui;
bool m_first_input_window_render; bool m_first_input_window_render;
mutable std::string m_tooltip; mutable std::string m_tooltip;
CommonGizmosDataPool* m_c; CommonGizmosDataPool* m_c;
GLModel m_cone;
GLModel m_cylinder;
GLModel m_sphere;
public: public:
GLGizmoBase(GLCanvas3D& parent, GLGizmoBase(GLCanvas3D& parent,
@ -137,7 +142,7 @@ public:
int get_hover_id() const { return m_hover_id; } int get_hover_id() const { return m_hover_id; }
void set_hover_id(int id); void set_hover_id(int id);
void set_highlight_color(const float* color); void set_highlight_color(const std::array<float, 4>& color);
void enable_grabber(unsigned int id); void enable_grabber(unsigned int id);
void disable_grabber(unsigned int id); void disable_grabber(unsigned int id);

View File

@ -51,7 +51,7 @@ bool GLGizmoCut::on_init()
std::string GLGizmoCut::on_get_name() const std::string GLGizmoCut::on_get_name() const
{ {
return (_(L("Cut")) + " [C]").ToUTF8().data(); return (_L("Cut") + " [C]").ToUTF8().data();
} }
void GLGizmoCut::on_set_state() void GLGizmoCut::on_set_state()
@ -96,12 +96,12 @@ void GLGizmoCut::on_render() const
const BoundingBoxf3& box = selection.get_bounding_box(); const BoundingBoxf3& box = selection.get_bounding_box();
Vec3d plane_center = box.center(); Vec3d plane_center = box.center();
plane_center(2) = m_cut_z; plane_center.z() = m_cut_z;
const float min_x = box.min(0) - Margin; const float min_x = box.min.x() - Margin;
const float max_x = box.max(0) + Margin; const float max_x = box.max.x() + Margin;
const float min_y = box.min(1) - Margin; const float min_y = box.min.y() - Margin;
const float max_y = box.max(1) + Margin; const float max_y = box.max.y() + Margin;
glsafe(::glEnable(GL_DEPTH_TEST)); glsafe(::glEnable(GL_DEPTH_TEST));
glsafe(::glDisable(GL_CULL_FACE)); glsafe(::glDisable(GL_CULL_FACE));
glsafe(::glEnable(GL_BLEND)); glsafe(::glEnable(GL_BLEND));
@ -110,10 +110,10 @@ void GLGizmoCut::on_render() const
// Draw the cutting plane // Draw the cutting plane
::glBegin(GL_QUADS); ::glBegin(GL_QUADS);
::glColor4f(0.8f, 0.8f, 0.8f, 0.5f); ::glColor4f(0.8f, 0.8f, 0.8f, 0.5f);
::glVertex3f(min_x, min_y, plane_center(2)); ::glVertex3f(min_x, min_y, plane_center.z());
::glVertex3f(max_x, min_y, plane_center(2)); ::glVertex3f(max_x, min_y, plane_center.z());
::glVertex3f(max_x, max_y, plane_center(2)); ::glVertex3f(max_x, max_y, plane_center.z());
::glVertex3f(min_x, max_y, plane_center(2)); ::glVertex3f(min_x, max_y, plane_center.z());
glsafe(::glEnd()); glsafe(::glEnd());
glsafe(::glEnable(GL_CULL_FACE)); glsafe(::glEnable(GL_CULL_FACE));
@ -123,9 +123,10 @@ void GLGizmoCut::on_render() const
// Draw the grabber and the connecting line // Draw the grabber and the connecting line
m_grabbers[0].center = plane_center; m_grabbers[0].center = plane_center;
m_grabbers[0].center(2) = plane_center(2) + Offset; m_grabbers[0].center.z() = plane_center.z() + Offset;
glsafe(::glClear(GL_DEPTH_BUFFER_BIT));
glsafe(::glDisable(GL_DEPTH_TEST));
glsafe(::glLineWidth(m_hover_id != -1 ? 2.0f : 1.5f)); glsafe(::glLineWidth(m_hover_id != -1 ? 2.0f : 1.5f));
glsafe(::glColor3f(1.0, 1.0, 0.0)); glsafe(::glColor3f(1.0, 1.0, 0.0));
::glBegin(GL_LINES); ::glBegin(GL_LINES);
@ -133,8 +134,16 @@ void GLGizmoCut::on_render() const
::glVertex3dv(m_grabbers[0].center.data()); ::glVertex3dv(m_grabbers[0].center.data());
glsafe(::glEnd()); glsafe(::glEnd());
std::copy(std::begin(GrabberColor), std::end(GrabberColor), m_grabbers[0].color); GLShaderProgram* shader = wxGetApp().get_shader("gouraud_light");
m_grabbers[0].render(m_hover_id == 0, (float)((box.size()(0) + box.size()(1) + box.size()(2)) / 3.0)); if (shader == nullptr)
return;
shader->start_using();
shader->set_uniform("emission_factor", 0.1);
m_grabbers[0].color = GrabberColor;
m_grabbers[0].render(m_hover_id == 0, (float)((box.size().x() + box.size().y() + box.size().z()) / 3.0));
shader->stop_using();
} }
void GLGizmoCut::on_render_for_picking() const void GLGizmoCut::on_render_for_picking() const

View File

@ -19,20 +19,10 @@ namespace GUI {
GLGizmoHollow::GLGizmoHollow(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id) GLGizmoHollow::GLGizmoHollow(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id)
: GLGizmoBase(parent, icon_filename, sprite_id) : GLGizmoBase(parent, icon_filename, sprite_id)
, m_quadric(nullptr)
{ {
m_quadric = ::gluNewQuadric(); m_vbo_cylinder.init_from(make_cylinder(1., 1.));
if (m_quadric != nullptr)
// using GLU_FILL does not work when the instance's transformation
// contains mirroring (normals are reverted)
::gluQuadricDrawStyle(m_quadric, GLU_FILL);
} }
GLGizmoHollow::~GLGizmoHollow()
{
if (m_quadric != nullptr)
::gluDeleteQuadric(m_quadric);
}
bool GLGizmoHollow::on_init() bool GLGizmoHollow::on_init()
{ {
@ -87,7 +77,7 @@ void GLGizmoHollow::on_render() const
glsafe(::glEnable(GL_BLEND)); glsafe(::glEnable(GL_BLEND));
glsafe(::glEnable(GL_DEPTH_TEST)); glsafe(::glEnable(GL_DEPTH_TEST));
if (m_quadric != nullptr && selection.is_from_single_instance()) if (selection.is_from_single_instance())
render_points(selection, false); render_points(selection, false);
m_selection_rectangle.render(m_parent); m_selection_rectangle.render(m_parent);
@ -111,8 +101,10 @@ void GLGizmoHollow::on_render_for_picking() const
void GLGizmoHollow::render_points(const Selection& selection, bool picking) const void GLGizmoHollow::render_points(const Selection& selection, bool picking) const
{ {
if (!picking) GLShaderProgram* shader = picking ? nullptr : wxGetApp().get_shader("gouraud_light");
glsafe(::glEnable(GL_LIGHTING)); if (shader)
shader->start_using();
ScopeGuard guard([shader]() { if (shader) shader->stop_using(); });
const GLVolume* vol = selection.get_volume(*selection.get_volume_idxs().begin()); const GLVolume* vol = selection.get_volume(*selection.get_volume_idxs().begin());
const Transform3d& instance_scaling_matrix_inverse = vol->get_instance_transformation().get_matrix(true, true, false, true).inverse(); const Transform3d& instance_scaling_matrix_inverse = vol->get_instance_transformation().get_matrix(true, true, false, true).inverse();
@ -150,16 +142,21 @@ void GLGizmoHollow::render_points(const Selection& selection, bool picking) cons
} }
else { // neigher hover nor picking else { // neigher hover nor picking
render_color[0] = point_selected ? 1.0f : 0.7f; render_color[0] = point_selected ? 1.0f : 1.f;
render_color[1] = point_selected ? 0.3f : 0.7f; render_color[1] = point_selected ? 0.3f : 1.f;
render_color[2] = point_selected ? 0.3f : 0.7f; render_color[2] = point_selected ? 0.3f : 1.f;
render_color[3] = 0.5f; render_color[3] = 0.5f;
} }
} }
glsafe(::glColor4fv(render_color.data())); if (shader && ! picking)
float render_color_emissive[4] = { 0.5f * render_color[0], 0.5f * render_color[1], 0.5f * render_color[2], 1.f}; #if ENABLE_SEQUENTIAL_LIMITS
glsafe(::glMaterialfv(GL_FRONT, GL_EMISSION, render_color_emissive)); const_cast<GLModel*>(&m_vbo_cylinder)->set_color(-1 , render_color);
#else
shader->set_uniform("uniform_color", render_color);
#endif // ENABLE_SEQUENTIAL_LIMITS
else // picking
glsafe(::glColor4fv(render_color.data()));
// Inverse matrix of the instance scaling is applied so that the mark does not scale with the object. // Inverse matrix of the instance scaling is applied so that the mark does not scale with the object.
glsafe(::glPushMatrix()); glsafe(::glPushMatrix());
@ -176,12 +173,8 @@ void GLGizmoHollow::render_points(const Selection& selection, bool picking) cons
glsafe(::glRotated(aa.angle() * (180. / M_PI), aa.axis()(0), aa.axis()(1), aa.axis()(2))); glsafe(::glRotated(aa.angle() * (180. / M_PI), aa.axis()(0), aa.axis()(1), aa.axis()(2)));
glsafe(::glPushMatrix()); glsafe(::glPushMatrix());
glsafe(::glTranslated(0., 0., -drain_hole.height)); glsafe(::glTranslated(0., 0., -drain_hole.height));
::gluCylinder(m_quadric, drain_hole.radius, drain_hole.radius, drain_hole.height + sla::HoleStickOutLength, 24, 1); glsafe(::glScaled(drain_hole.radius, drain_hole.radius, drain_hole.height + sla::HoleStickOutLength));
glsafe(::glTranslated(0., 0., drain_hole.height + sla::HoleStickOutLength)); m_vbo_cylinder.render();
::gluDisk(m_quadric, 0.0, drain_hole.radius, 24, 1);
glsafe(::glTranslated(0., 0., -drain_hole.height - sla::HoleStickOutLength));
glsafe(::glRotatef(180.f, 1.f, 0.f, 0.f));
::gluDisk(m_quadric, 0.0, drain_hole.radius, 24, 1);
glsafe(::glPopMatrix()); glsafe(::glPopMatrix());
if (vol->is_left_handed()) if (vol->is_left_handed())
@ -189,15 +182,6 @@ void GLGizmoHollow::render_points(const Selection& selection, bool picking) cons
glsafe(::glPopMatrix()); glsafe(::glPopMatrix());
} }
{
// Reset emissive component to zero (the default value)
float render_color_emissive[4] = { 0.f, 0.f, 0.f, 1.f };
glsafe(::glMaterialfv(GL_FRONT, GL_EMISSION, render_color_emissive));
}
if (!picking)
glsafe(::glDisable(GL_LIGHTING));
glsafe(::glPopMatrix()); glsafe(::glPopMatrix());
} }

View File

@ -25,12 +25,10 @@ class GLGizmoHollow : public GLGizmoBase
private: private:
bool unproject_on_mesh(const Vec2d& mouse_pos, std::pair<Vec3f, Vec3f>& pos_and_normal); bool unproject_on_mesh(const Vec2d& mouse_pos, std::pair<Vec3f, Vec3f>& pos_and_normal);
GLUquadricObj* m_quadric;
public: public:
GLGizmoHollow(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id); GLGizmoHollow(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id);
~GLGizmoHollow() override; virtual ~GLGizmoHollow() = default;
void set_sla_support_data(ModelObject* model_object, const Selection& selection); void set_sla_support_data(ModelObject* model_object, const Selection& selection);
bool gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_position, bool shift_down, bool alt_down, bool control_down); bool gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_position, bool shift_down, bool alt_down, bool control_down);
void delete_selected_points(); void delete_selected_points();
@ -50,7 +48,7 @@ private:
ObjectID m_old_mo_id = -1; ObjectID m_old_mo_id = -1;
// bool m_show_supports = true; GLModel m_vbo_cylinder;
float m_new_hole_radius = 2.f; // Size of a new hole. float m_new_hole_radius = 2.f; // Size of a new hole.
float m_new_hole_height = 6.f; float m_new_hole_height = 6.f;
mutable std::vector<bool> m_selected; // which holes are currently selected mutable std::vector<bool> m_selected; // which holes are currently selected

View File

@ -1,6 +1,7 @@
// Include GLGizmoBase.hpp before I18N.hpp as it includes some libigl code, which overrides our localization "L" macro. // Include GLGizmoBase.hpp before I18N.hpp as it includes some libigl code, which overrides our localization "L" macro.
#include "GLGizmoMove.hpp" #include "GLGizmoMove.hpp"
#include "slic3r/GUI/GLCanvas3D.hpp" #include "slic3r/GUI/GLCanvas3D.hpp"
#include "slic3r/GUI/GUI_App.hpp"
#include <GL/glew.h> #include <GL/glew.h>
@ -18,17 +19,8 @@ GLGizmoMove3D::GLGizmoMove3D(GLCanvas3D& parent, const std::string& icon_filenam
, m_starting_drag_position(Vec3d::Zero()) , m_starting_drag_position(Vec3d::Zero())
, m_starting_box_center(Vec3d::Zero()) , m_starting_box_center(Vec3d::Zero())
, m_starting_box_bottom_center(Vec3d::Zero()) , m_starting_box_bottom_center(Vec3d::Zero())
, m_quadric(nullptr)
{ {
m_quadric = ::gluNewQuadric(); m_vbo_cone.init_from(make_cone(1., 1., 2*PI/36));
if (m_quadric != nullptr)
::gluQuadricDrawStyle(m_quadric, GLU_FILL);
}
GLGizmoMove3D::~GLGizmoMove3D()
{
if (m_quadric != nullptr)
::gluDeleteQuadric(m_quadric);
} }
std::string GLGizmoMove3D::get_tooltip() const std::string GLGizmoMove3D::get_tooltip() const
@ -49,8 +41,7 @@ std::string GLGizmoMove3D::get_tooltip() const
bool GLGizmoMove3D::on_init() bool GLGizmoMove3D::on_init()
{ {
for (int i = 0; i < 3; ++i) for (int i = 0; i < 3; ++i) {
{
m_grabbers.push_back(Grabber()); m_grabbers.push_back(Grabber());
} }
@ -61,7 +52,7 @@ bool GLGizmoMove3D::on_init()
std::string GLGizmoMove3D::on_get_name() const std::string GLGizmoMove3D::on_get_name() const
{ {
return (_(L("Move")) + " [M]").ToUTF8().data(); return (_L("Move") + " [M]").ToUTF8().data();
} }
bool GLGizmoMove3D::on_is_activable() const bool GLGizmoMove3D::on_is_activable() const
@ -71,8 +62,7 @@ bool GLGizmoMove3D::on_is_activable() const
void GLGizmoMove3D::on_start_dragging() void GLGizmoMove3D::on_start_dragging()
{ {
if (m_hover_id != -1) if (m_hover_id != -1) {
{
m_displacement = Vec3d::Zero(); m_displacement = Vec3d::Zero();
const BoundingBoxf3& box = m_parent.get_selection().get_bounding_box(); const BoundingBoxf3& box = m_parent.get_selection().get_bounding_box();
m_starting_drag_position = m_grabbers[m_hover_id].center; m_starting_drag_position = m_grabbers[m_hover_id].center;
@ -90,11 +80,11 @@ void GLGizmoMove3D::on_stop_dragging()
void GLGizmoMove3D::on_update(const UpdateData& data) void GLGizmoMove3D::on_update(const UpdateData& data)
{ {
if (m_hover_id == 0) if (m_hover_id == 0)
m_displacement(0) = calc_projection(data); m_displacement.x() = calc_projection(data);
else if (m_hover_id == 1) else if (m_hover_id == 1)
m_displacement(1) = calc_projection(data); m_displacement.y() = calc_projection(data);
else if (m_hover_id == 2) else if (m_hover_id == 2)
m_displacement(2) = calc_projection(data); m_displacement.z() = calc_projection(data);
} }
void GLGizmoMove3D::on_render() const void GLGizmoMove3D::on_render() const
@ -108,27 +98,24 @@ void GLGizmoMove3D::on_render() const
const Vec3d& center = box.center(); const Vec3d& center = box.center();
// x axis // x axis
m_grabbers[0].center = Vec3d(box.max(0) + Offset, center(1), center(2)); m_grabbers[0].center = { box.max.x() + Offset, center.y(), center.z() };
::memcpy((void*)m_grabbers[0].color, (const void*)&AXES_COLOR[0], 4 * sizeof(float)); m_grabbers[0].color = AXES_COLOR[0];
// y axis // y axis
m_grabbers[1].center = Vec3d(center(0), box.max(1) + Offset, center(2)); m_grabbers[1].center = { center.x(), box.max.y() + Offset, center.z() };
::memcpy((void*)m_grabbers[1].color, (const void*)&AXES_COLOR[1], 4 * sizeof(float)); m_grabbers[1].color = AXES_COLOR[1];
// z axis // z axis
m_grabbers[2].center = Vec3d(center(0), center(1), box.max(2) + Offset); m_grabbers[2].center = { center.x(), center.y(), box.max.z() + Offset };
::memcpy((void*)m_grabbers[2].color, (const void*)&AXES_COLOR[2], 4 * sizeof(float)); m_grabbers[2].color = AXES_COLOR[2];
glsafe(::glLineWidth((m_hover_id != -1) ? 2.0f : 1.5f)); glsafe(::glLineWidth((m_hover_id != -1) ? 2.0f : 1.5f));
if (m_hover_id == -1) if (m_hover_id == -1) {
{
// draw axes // draw axes
for (unsigned int i = 0; i < 3; ++i) for (unsigned int i = 0; i < 3; ++i) {
{ if (m_grabbers[i].enabled) {
if (m_grabbers[i].enabled) glsafe(::glColor4fv(AXES_COLOR[i].data()));
{
glsafe(::glColor4fv(AXES_COLOR[i]));
::glBegin(GL_LINES); ::glBegin(GL_LINES);
::glVertex3dv(center.data()); ::glVertex3dv(center.data());
::glVertex3dv(m_grabbers[i].center.data()); ::glVertex3dv(m_grabbers[i].center.data());
@ -138,24 +125,28 @@ void GLGizmoMove3D::on_render() const
// draw grabbers // draw grabbers
render_grabbers(box); render_grabbers(box);
for (unsigned int i = 0; i < 3; ++i) for (unsigned int i = 0; i < 3; ++i) {
{
if (m_grabbers[i].enabled) if (m_grabbers[i].enabled)
render_grabber_extension((Axis)i, box, false); render_grabber_extension((Axis)i, box, false);
} }
} }
else else {
{
// draw axis // draw axis
glsafe(::glColor4fv(AXES_COLOR[m_hover_id])); glsafe(::glColor4fv(AXES_COLOR[m_hover_id].data()));
::glBegin(GL_LINES); ::glBegin(GL_LINES);
::glVertex3dv(center.data()); ::glVertex3dv(center.data());
::glVertex3dv(m_grabbers[m_hover_id].center.data()); ::glVertex3dv(m_grabbers[m_hover_id].center.data());
glsafe(::glEnd()); glsafe(::glEnd());
// draw grabber GLShaderProgram* shader = wxGetApp().get_shader("gouraud_light");
float mean_size = (float)((box.size()(0) + box.size()(1) + box.size()(2)) / 3.0); if (shader != nullptr) {
m_grabbers[m_hover_id].render(true, mean_size); shader->start_using();
shader->set_uniform("emission_factor", 0.1);
// draw grabber
float mean_size = (float)((box.size().x() + box.size().y() + box.size().z()) / 3.0);
m_grabbers[m_hover_id].render(true, mean_size);
shader->stop_using();
}
render_grabber_extension((Axis)m_hover_id, box, false); render_grabber_extension((Axis)m_hover_id, box, false);
} }
} }
@ -177,8 +168,7 @@ double GLGizmoMove3D::calc_projection(const UpdateData& data) const
Vec3d starting_vec = m_starting_drag_position - m_starting_box_center; Vec3d starting_vec = m_starting_drag_position - m_starting_box_center;
double len_starting_vec = starting_vec.norm(); double len_starting_vec = starting_vec.norm();
if (len_starting_vec != 0.0) if (len_starting_vec != 0.0) {
{
Vec3d mouse_dir = data.mouse_ray.unit_vector(); Vec3d mouse_dir = data.mouse_ray.unit_vector();
// finds the intersection of the mouse ray with the plane parallel to the camera viewport and passing throught the starting position // finds the intersection of the mouse ray with the plane parallel to the camera viewport and passing throught the starting position
// use ray-plane intersection see i.e. https://en.wikipedia.org/wiki/Line%E2%80%93plane_intersection algebric form // use ray-plane intersection see i.e. https://en.wikipedia.org/wiki/Line%E2%80%93plane_intersection algebric form
@ -200,42 +190,46 @@ double GLGizmoMove3D::calc_projection(const UpdateData& data) const
void GLGizmoMove3D::render_grabber_extension(Axis axis, const BoundingBoxf3& box, bool picking) const void GLGizmoMove3D::render_grabber_extension(Axis axis, const BoundingBoxf3& box, bool picking) const
{ {
if (m_quadric == nullptr) float mean_size = (float)((box.size().x() + box.size().y() + box.size().z()) / 3.0);
return;
float mean_size = (float)((box.size()(0) + box.size()(1) + box.size()(2)) / 3.0);
double size = m_dragging ? (double)m_grabbers[axis].get_dragging_half_size(mean_size) : (double)m_grabbers[axis].get_half_size(mean_size); double size = m_dragging ? (double)m_grabbers[axis].get_dragging_half_size(mean_size) : (double)m_grabbers[axis].get_half_size(mean_size);
float color[4]; std::array<float, 4> color = m_grabbers[axis].color;
::memcpy((void*)color, (const void*)m_grabbers[axis].color, 4 * sizeof(float)); if (!picking && m_hover_id != -1) {
if (!picking && (m_hover_id != -1))
{
color[0] = 1.0f - color[0]; color[0] = 1.0f - color[0];
color[1] = 1.0f - color[1]; color[1] = 1.0f - color[1];
color[2] = 1.0f - color[2]; color[2] = 1.0f - color[2];
color[3] = color[3]; color[3] = color[3];
} }
if (!picking) GLShaderProgram* shader = wxGetApp().get_shader("gouraud_light");
glsafe(::glEnable(GL_LIGHTING)); if (shader == nullptr)
return;
if (! picking) {
shader->start_using();
shader->set_uniform("emission_factor", 0.1);
#if ENABLE_SEQUENTIAL_LIMITS
const_cast<GLModel*>(&m_vbo_cone)->set_color(-1, color);
#else
shader->set_uniform("uniform_color", color);
#endif // ENABLE_SEQUENTIAL_LIMITS
} else
glsafe(::glColor4fv(color.data()));
glsafe(::glColor4fv(color));
glsafe(::glPushMatrix()); glsafe(::glPushMatrix());
glsafe(::glTranslated(m_grabbers[axis].center(0), m_grabbers[axis].center(1), m_grabbers[axis].center(2))); glsafe(::glTranslated(m_grabbers[axis].center.x(), m_grabbers[axis].center.y(), m_grabbers[axis].center.z()));
if (axis == X) if (axis == X)
glsafe(::glRotated(90.0, 0.0, 1.0, 0.0)); glsafe(::glRotated(90.0, 0.0, 1.0, 0.0));
else if (axis == Y) else if (axis == Y)
glsafe(::glRotated(-90.0, 1.0, 0.0, 0.0)); glsafe(::glRotated(-90.0, 1.0, 0.0, 0.0));
glsafe(::glTranslated(0.0, 0.0, 2.0 * size)); glsafe(::glTranslated(0.0, 0.0, 2.0 * size));
::gluQuadricOrientation(m_quadric, GLU_OUTSIDE); glsafe(::glScaled(0.75 * size, 0.75 * size, 3.0 * size));
::gluCylinder(m_quadric, 0.75 * size, 0.0, 3.0 * size, 36, 1); m_vbo_cone.render();
::gluQuadricOrientation(m_quadric, GLU_INSIDE);
::gluDisk(m_quadric, 0.0, 0.75 * size, 36, 1);
glsafe(::glPopMatrix()); glsafe(::glPopMatrix());
if (!picking) if (! picking)
glsafe(::glDisable(GL_LIGHTING)); shader->stop_using();
} }

View File

@ -19,11 +19,11 @@ class GLGizmoMove3D : public GLGizmoBase
Vec3d m_starting_box_center; Vec3d m_starting_box_center;
Vec3d m_starting_box_bottom_center; Vec3d m_starting_box_bottom_center;
GLUquadricObj* m_quadric; GLModel m_vbo_cone;
public: public:
GLGizmoMove3D(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id); GLGizmoMove3D(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id);
virtual ~GLGizmoMove3D(); virtual ~GLGizmoMove3D() = default;
double get_snap_step(double step) const { return m_snap_step; } double get_snap_step(double step) const { return m_snap_step; }
void set_snap_step(double step) { m_snap_step = step; } void set_snap_step(double step) { m_snap_step = step; }

View File

@ -30,7 +30,6 @@ GLGizmoRotate::GLGizmoRotate(GLCanvas3D& parent, GLGizmoRotate::Axis axis)
: GLGizmoBase(parent, "", -1) : GLGizmoBase(parent, "", -1)
, m_axis(axis) , m_axis(axis)
, m_angle(0.0) , m_angle(0.0)
, m_quadric(nullptr)
, m_center(0.0, 0.0, 0.0) , m_center(0.0, 0.0, 0.0)
, m_radius(0.0f) , m_radius(0.0f)
, m_snap_coarse_in_radius(0.0f) , m_snap_coarse_in_radius(0.0f)
@ -38,16 +37,12 @@ GLGizmoRotate::GLGizmoRotate(GLCanvas3D& parent, GLGizmoRotate::Axis axis)
, m_snap_fine_in_radius(0.0f) , m_snap_fine_in_radius(0.0f)
, m_snap_fine_out_radius(0.0f) , m_snap_fine_out_radius(0.0f)
{ {
m_quadric = ::gluNewQuadric();
if (m_quadric != nullptr)
::gluQuadricDrawStyle(m_quadric, GLU_FILL);
} }
GLGizmoRotate::GLGizmoRotate(const GLGizmoRotate& other) GLGizmoRotate::GLGizmoRotate(const GLGizmoRotate& other)
: GLGizmoBase(other.m_parent, other.m_icon_filename, other.m_sprite_id) : GLGizmoBase(other.m_parent, other.m_icon_filename, other.m_sprite_id)
, m_axis(other.m_axis) , m_axis(other.m_axis)
, m_angle(other.m_angle) , m_angle(other.m_angle)
, m_quadric(nullptr)
, m_center(other.m_center) , m_center(other.m_center)
, m_radius(other.m_radius) , m_radius(other.m_radius)
, m_snap_coarse_in_radius(other.m_snap_coarse_in_radius) , m_snap_coarse_in_radius(other.m_snap_coarse_in_radius)
@ -55,16 +50,8 @@ GLGizmoRotate::GLGizmoRotate(const GLGizmoRotate& other)
, m_snap_fine_in_radius(other.m_snap_fine_in_radius) , m_snap_fine_in_radius(other.m_snap_fine_in_radius)
, m_snap_fine_out_radius(other.m_snap_fine_out_radius) , m_snap_fine_out_radius(other.m_snap_fine_out_radius)
{ {
m_quadric = ::gluNewQuadric();
if (m_quadric != nullptr)
::gluQuadricDrawStyle(m_quadric, GLU_FILL);
} }
GLGizmoRotate::~GLGizmoRotate()
{
if (m_quadric != nullptr)
::gluDeleteQuadric(m_quadric);
}
void GLGizmoRotate::set_angle(double angle) void GLGizmoRotate::set_angle(double angle)
{ {
@ -146,8 +133,7 @@ void GLGizmoRotate::on_render() const
const Selection& selection = m_parent.get_selection(); const Selection& selection = m_parent.get_selection();
const BoundingBoxf3& box = selection.get_bounding_box(); const BoundingBoxf3& box = selection.get_bounding_box();
if (m_hover_id != 0 && !m_grabbers[0].dragging) if (m_hover_id != 0 && !m_grabbers[0].dragging) {
{
m_center = box.center(); m_center = box.center();
m_radius = Offset + box.radius(); m_radius = Offset + box.radius();
m_snap_coarse_in_radius = m_radius / 3.0f; m_snap_coarse_in_radius = m_radius / 3.0f;
@ -162,18 +148,17 @@ void GLGizmoRotate::on_render() const
transform_to_local(selection); transform_to_local(selection);
glsafe(::glLineWidth((m_hover_id != -1) ? 2.0f : 1.5f)); glsafe(::glLineWidth((m_hover_id != -1) ? 2.0f : 1.5f));
glsafe(::glColor4fv((m_hover_id != -1) ? m_drag_color : m_highlight_color)); glsafe(::glColor4fv((m_hover_id != -1) ? m_drag_color.data() : m_highlight_color.data()));
render_circle(); render_circle();
if (m_hover_id != -1) if (m_hover_id != -1) {
{
render_scale(); render_scale();
render_snap_radii(); render_snap_radii();
render_reference_radius(); render_reference_radius();
} }
glsafe(::glColor4fv(m_highlight_color)); glsafe(::glColor4fv(m_highlight_color.data()));
if (m_hover_id != -1) if (m_hover_id != -1)
render_angle(); render_angle();
@ -324,69 +309,70 @@ void GLGizmoRotate::render_grabber(const BoundingBoxf3& box) const
m_grabbers[0].center = Vec3d(::cos(m_angle) * grabber_radius, ::sin(m_angle) * grabber_radius, 0.0); m_grabbers[0].center = Vec3d(::cos(m_angle) * grabber_radius, ::sin(m_angle) * grabber_radius, 0.0);
m_grabbers[0].angles(2) = m_angle; m_grabbers[0].angles(2) = m_angle;
glsafe(::glColor4fv((m_hover_id != -1) ? m_drag_color : m_highlight_color)); glsafe(::glColor4fv((m_hover_id != -1) ? m_drag_color.data() : m_highlight_color.data()));
::glBegin(GL_LINES); ::glBegin(GL_LINES);
::glVertex3f(0.0f, 0.0f, 0.0f); ::glVertex3f(0.0f, 0.0f, 0.0f);
::glVertex3dv(m_grabbers[0].center.data()); ::glVertex3dv(m_grabbers[0].center.data());
glsafe(::glEnd()); glsafe(::glEnd());
::memcpy((void*)m_grabbers[0].color, (const void*)m_highlight_color, 4 * sizeof(float)); m_grabbers[0].color = m_highlight_color;
render_grabbers(box); render_grabbers(box);
} }
void GLGizmoRotate::render_grabber_extension(const BoundingBoxf3& box, bool picking) const void GLGizmoRotate::render_grabber_extension(const BoundingBoxf3& box, bool picking) const
{ {
if (m_quadric == nullptr)
return;
float mean_size = (float)((box.size()(0) + box.size()(1) + box.size()(2)) / 3.0); float mean_size = (float)((box.size()(0) + box.size()(1) + box.size()(2)) / 3.0);
double size = m_dragging ? (double)m_grabbers[0].get_dragging_half_size(mean_size) : (double)m_grabbers[0].get_half_size(mean_size); double size = m_dragging ? (double)m_grabbers[0].get_dragging_half_size(mean_size) : (double)m_grabbers[0].get_half_size(mean_size);
float color[4]; std::array<float, 4> color = m_grabbers[0].color;
::memcpy((void*)color, (const void*)m_grabbers[0].color, 4 * sizeof(float)); if (!picking && m_hover_id != -1) {
if (!picking && (m_hover_id != -1))
{
color[0] = 1.0f - color[0]; color[0] = 1.0f - color[0];
color[1] = 1.0f - color[1]; color[1] = 1.0f - color[1];
color[2] = 1.0f - color[2]; color[2] = 1.0f - color[2];
} }
if (!picking) GLShaderProgram* shader = wxGetApp().get_shader("gouraud_light");
glsafe(::glEnable(GL_LIGHTING)); if (shader == nullptr)
return;
if (! picking) {
shader->start_using();
shader->set_uniform("emission_factor", 0.1);
#if ENABLE_SEQUENTIAL_LIMITS
const_cast<GLModel*>(&m_cone)->set_color(-1, color);
#else
shader->set_uniform("uniform_color", color);
#endif // ENABLE_SEQUENTIAL_LIMITS
} else
glsafe(::glColor4fv(color.data()));
glsafe(::glColor4fv(color));
glsafe(::glPushMatrix()); glsafe(::glPushMatrix());
glsafe(::glTranslated(m_grabbers[0].center(0), m_grabbers[0].center(1), m_grabbers[0].center(2))); glsafe(::glTranslated(m_grabbers[0].center.x(), m_grabbers[0].center.y(), m_grabbers[0].center.z()));
glsafe(::glRotated(Geometry::rad2deg(m_angle), 0.0, 0.0, 1.0)); glsafe(::glRotated(Geometry::rad2deg(m_angle), 0.0, 0.0, 1.0));
glsafe(::glRotated(90.0, 1.0, 0.0, 0.0)); glsafe(::glRotated(90.0, 1.0, 0.0, 0.0));
glsafe(::glTranslated(0.0, 0.0, 2.0 * size)); glsafe(::glTranslated(0.0, 0.0, 2.0 * size));
::gluQuadricOrientation(m_quadric, GLU_OUTSIDE); glsafe(::glScaled(0.75 * size, 0.75 * size, 3.0 * size));
::gluCylinder(m_quadric, 0.75 * size, 0.0, 3.0 * size, 36, 1); m_cone.render();
::gluQuadricOrientation(m_quadric, GLU_INSIDE);
::gluDisk(m_quadric, 0.0, 0.75 * size, 36, 1);
glsafe(::glPopMatrix()); glsafe(::glPopMatrix());
glsafe(::glPushMatrix()); glsafe(::glPushMatrix());
glsafe(::glTranslated(m_grabbers[0].center(0), m_grabbers[0].center(1), m_grabbers[0].center(2))); glsafe(::glTranslated(m_grabbers[0].center.x(), m_grabbers[0].center.y(), m_grabbers[0].center.z()));
glsafe(::glRotated(Geometry::rad2deg(m_angle), 0.0, 0.0, 1.0)); glsafe(::glRotated(Geometry::rad2deg(m_angle), 0.0, 0.0, 1.0));
glsafe(::glRotated(-90.0, 1.0, 0.0, 0.0)); glsafe(::glRotated(-90.0, 1.0, 0.0, 0.0));
glsafe(::glTranslated(0.0, 0.0, 2.0 * size)); glsafe(::glTranslated(0.0, 0.0, 2.0 * size));
::gluQuadricOrientation(m_quadric, GLU_OUTSIDE); glsafe(::glScaled(0.75 * size, 0.75 * size, 3.0 * size));
::gluCylinder(m_quadric, 0.75 * size, 0.0, 3.0 * size, 36, 1); m_cone.render();
::gluQuadricOrientation(m_quadric, GLU_INSIDE);
::gluDisk(m_quadric, 0.0, 0.75 * size, 36, 1);
glsafe(::glPopMatrix()); glsafe(::glPopMatrix());
if (!picking) if (! picking)
glsafe(::glDisable(GL_LIGHTING)); shader->stop_using();
} }
void GLGizmoRotate::transform_to_local(const Selection& selection) const void GLGizmoRotate::transform_to_local(const Selection& selection) const
{ {
glsafe(::glTranslated(m_center(0), m_center(1), m_center(2))); glsafe(::glTranslated(m_center(0), m_center(1), m_center(2)));
if (selection.is_single_volume() || selection.is_single_modifier() || selection.requires_local_axes()) if (selection.is_single_volume() || selection.is_single_modifier() || selection.requires_local_axes()) {
{
Transform3d orient_matrix = selection.get_volume(*selection.get_volume_idxs().begin())->get_instance_transformation().get_matrix(true, false, true, true); Transform3d orient_matrix = selection.get_volume(*selection.get_volume_idxs().begin())->get_instance_transformation().get_matrix(true, false, true, true);
glsafe(::glMultMatrixd(orient_matrix.data())); glsafe(::glMultMatrixd(orient_matrix.data()));
} }
@ -457,8 +443,7 @@ GLGizmoRotate3D::GLGizmoRotate3D(GLCanvas3D& parent, const std::string& icon_fil
m_gizmos.emplace_back(parent, GLGizmoRotate::Y); m_gizmos.emplace_back(parent, GLGizmoRotate::Y);
m_gizmos.emplace_back(parent, GLGizmoRotate::Z); m_gizmos.emplace_back(parent, GLGizmoRotate::Z);
for (unsigned int i = 0; i < 3; ++i) for (unsigned int i = 0; i < 3; ++i) {
{
m_gizmos[i].set_group_id(i); m_gizmos[i].set_group_id(i);
} }
@ -467,14 +452,12 @@ GLGizmoRotate3D::GLGizmoRotate3D(GLCanvas3D& parent, const std::string& icon_fil
bool GLGizmoRotate3D::on_init() bool GLGizmoRotate3D::on_init()
{ {
for (GLGizmoRotate& g : m_gizmos) for (GLGizmoRotate& g : m_gizmos) {
{
if (!g.init()) if (!g.init())
return false; 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_gizmos[i].set_highlight_color(AXES_COLOR[i]);
} }
@ -485,7 +468,7 @@ bool GLGizmoRotate3D::on_init()
std::string GLGizmoRotate3D::on_get_name() const std::string GLGizmoRotate3D::on_get_name() const
{ {
return (_(L("Rotate")) + " [R]").ToUTF8().data(); return (_L("Rotate") + " [R]").ToUTF8().data();
} }
bool GLGizmoRotate3D::on_is_activable() const bool GLGizmoRotate3D::on_is_activable() const

View File

@ -32,8 +32,6 @@ private:
Axis m_axis; Axis m_axis;
double m_angle; double m_angle;
GLUquadricObj* m_quadric;
mutable Vec3d m_center; mutable Vec3d m_center;
mutable float m_radius; mutable float m_radius;
@ -45,7 +43,7 @@ private:
public: public:
GLGizmoRotate(GLCanvas3D& parent, Axis axis); GLGizmoRotate(GLCanvas3D& parent, Axis axis);
GLGizmoRotate(const GLGizmoRotate& other); GLGizmoRotate(const GLGizmoRotate& other);
virtual ~GLGizmoRotate(); virtual ~GLGizmoRotate() = default;
double get_angle() const { return m_angle; } double get_angle() const { return m_angle; }
void set_angle(double angle); void set_angle(double angle);
@ -122,16 +120,14 @@ protected:
void on_stop_dragging() override; void on_stop_dragging() override;
void on_update(const UpdateData& data) override void on_update(const UpdateData& data) override
{ {
for (GLGizmoRotate& g : m_gizmos) for (GLGizmoRotate& g : m_gizmos) {
{
g.update(data); g.update(data);
} }
} }
void on_render() const override; void on_render() const override;
void on_render_for_picking() const override void on_render_for_picking() const override
{ {
for (const GLGizmoRotate& g : m_gizmos) for (const GLGizmoRotate& g : m_gizmos) {
{
g.render_for_picking(); g.render_for_picking();
} }
} }

View File

@ -1,6 +1,7 @@
// Include GLGizmoBase.hpp before I18N.hpp as it includes some libigl code, which overrides our localization "L" macro. // Include GLGizmoBase.hpp before I18N.hpp as it includes some libigl code, which overrides our localization "L" macro.
#include "GLGizmoScale.hpp" #include "GLGizmoScale.hpp"
#include "slic3r/GUI/GLCanvas3D.hpp" #include "slic3r/GUI/GLCanvas3D.hpp"
#include "slic3r/GUI/GUI_App.hpp"
#include <GL/glew.h> #include <GL/glew.h>
@ -75,7 +76,7 @@ bool GLGizmoScale3D::on_init()
std::string GLGizmoScale3D::on_get_name() const std::string GLGizmoScale3D::on_get_name() const
{ {
return (_(L("Scale")) + " [S]").ToUTF8().data(); return (_L("Scale") + " [S]").ToUTF8().data();
} }
bool GLGizmoScale3D::on_is_activable() const bool GLGizmoScale3D::on_is_activable() const
@ -131,12 +132,10 @@ void GLGizmoScale3D::on_render() const
m_offsets_transform = Transform3d::Identity(); m_offsets_transform = Transform3d::Identity();
Vec3d angles = Vec3d::Zero(); Vec3d angles = Vec3d::Zero();
if (single_instance) if (single_instance) {
{
// calculate bounding box in instance local reference system // calculate bounding box in instance local reference system
const Selection::IndicesList& idxs = selection.get_volume_idxs(); const Selection::IndicesList& idxs = selection.get_volume_idxs();
for (unsigned int idx : idxs) for (unsigned int idx : idxs) {
{
const GLVolume* vol = selection.get_volume(idx); const GLVolume* vol = selection.get_volume(idx);
m_box.merge(vol->bounding_box().transformed(vol->get_volume_transformation().get_matrix())); m_box.merge(vol->bounding_box().transformed(vol->get_volume_transformation().get_matrix()));
} }
@ -150,8 +149,7 @@ void GLGizmoScale3D::on_render() const
offsets_transform = Geometry::assemble_transform(Vec3d::Zero(), angles, Vec3d::Ones(), v->get_instance_mirror()); offsets_transform = Geometry::assemble_transform(Vec3d::Zero(), angles, Vec3d::Ones(), v->get_instance_mirror());
m_offsets_transform = offsets_transform; m_offsets_transform = offsets_transform;
} }
else if (single_volume) else if (single_volume) {
{
const GLVolume* v = selection.get_volume(*selection.get_volume_idxs().begin()); const GLVolume* v = selection.get_volume(*selection.get_volume_idxs().begin());
m_box = v->bounding_box(); m_box = v->bounding_box();
m_transform = v->world_matrix(); m_transform = v->world_matrix();
@ -172,35 +170,33 @@ void GLGizmoScale3D::on_render() const
// x axis // x axis
m_grabbers[0].center = m_transform * Vec3d(m_box.min(0), center(1), center(2)) - offset_x; m_grabbers[0].center = m_transform * Vec3d(m_box.min(0), center(1), center(2)) - offset_x;
m_grabbers[0].color = (ctrl_down && (m_hover_id == 1)) ? CONSTRAINED_COLOR : AXES_COLOR[0];
m_grabbers[1].center = m_transform * Vec3d(m_box.max(0), center(1), center(2)) + offset_x; m_grabbers[1].center = m_transform * Vec3d(m_box.max(0), center(1), center(2)) + offset_x;
::memcpy((void*)m_grabbers[0].color, (ctrl_down && (m_hover_id == 1)) ? (const void*)CONSTRAINED_COLOR : (const void*)&AXES_COLOR[0], 4 * sizeof(float)); m_grabbers[1].color = (ctrl_down && (m_hover_id == 0)) ? CONSTRAINED_COLOR : AXES_COLOR[0];
::memcpy((void*)m_grabbers[1].color, (ctrl_down && (m_hover_id == 0)) ? (const void*)CONSTRAINED_COLOR : (const void*)&AXES_COLOR[0], 4 * sizeof(float));
// y axis // y axis
m_grabbers[2].center = m_transform * Vec3d(center(0), m_box.min(1), center(2)) - offset_y; m_grabbers[2].center = m_transform * Vec3d(center(0), m_box.min(1), center(2)) - offset_y;
m_grabbers[2].color = (ctrl_down && (m_hover_id == 3)) ? CONSTRAINED_COLOR : AXES_COLOR[1];
m_grabbers[3].center = m_transform * Vec3d(center(0), m_box.max(1), center(2)) + offset_y; m_grabbers[3].center = m_transform * Vec3d(center(0), m_box.max(1), center(2)) + offset_y;
::memcpy((void*)m_grabbers[2].color, (ctrl_down && (m_hover_id == 3)) ? (const void*)CONSTRAINED_COLOR : (const void*)&AXES_COLOR[1], 4 * sizeof(float)); m_grabbers[3].color = (ctrl_down && (m_hover_id == 2)) ? CONSTRAINED_COLOR : AXES_COLOR[1];
::memcpy((void*)m_grabbers[3].color, (ctrl_down && (m_hover_id == 2)) ? (const void*)CONSTRAINED_COLOR : (const void*)&AXES_COLOR[1], 4 * sizeof(float));
// z axis // z axis
m_grabbers[4].center = m_transform * Vec3d(center(0), center(1), m_box.min(2)) - offset_z; m_grabbers[4].center = m_transform * Vec3d(center(0), center(1), m_box.min(2)) - offset_z;
m_grabbers[4].color = (ctrl_down && (m_hover_id == 5)) ? CONSTRAINED_COLOR : AXES_COLOR[2];
m_grabbers[5].center = m_transform * Vec3d(center(0), center(1), m_box.max(2)) + offset_z; m_grabbers[5].center = m_transform * Vec3d(center(0), center(1), m_box.max(2)) + offset_z;
::memcpy((void*)m_grabbers[4].color, (ctrl_down && (m_hover_id == 5)) ? (const void*)CONSTRAINED_COLOR : (const void*)&AXES_COLOR[2], 4 * sizeof(float)); m_grabbers[5].color = (ctrl_down && (m_hover_id == 4)) ? CONSTRAINED_COLOR : AXES_COLOR[2];
::memcpy((void*)m_grabbers[5].color, (ctrl_down && (m_hover_id == 4)) ? (const void*)CONSTRAINED_COLOR : (const void*)&AXES_COLOR[2], 4 * sizeof(float));
// uniform // uniform
m_grabbers[6].center = m_transform * Vec3d(m_box.min(0), m_box.min(1), center(2)) - offset_x - offset_y; m_grabbers[6].center = m_transform * Vec3d(m_box.min(0), m_box.min(1), center(2)) - offset_x - offset_y;
m_grabbers[7].center = m_transform * Vec3d(m_box.max(0), m_box.min(1), center(2)) + offset_x - offset_y; m_grabbers[7].center = m_transform * Vec3d(m_box.max(0), m_box.min(1), center(2)) + offset_x - offset_y;
m_grabbers[8].center = m_transform * Vec3d(m_box.max(0), m_box.max(1), center(2)) + offset_x + offset_y; m_grabbers[8].center = m_transform * Vec3d(m_box.max(0), m_box.max(1), center(2)) + offset_x + offset_y;
m_grabbers[9].center = m_transform * Vec3d(m_box.min(0), m_box.max(1), center(2)) - offset_x + offset_y; m_grabbers[9].center = m_transform * Vec3d(m_box.min(0), m_box.max(1), center(2)) - offset_x + offset_y;
for (int i = 6; i < 10; ++i) for (int i = 6; i < 10; ++i) {
{ m_grabbers[i].color = m_highlight_color;
::memcpy((void*)m_grabbers[i].color, (const void*)m_highlight_color, 4 * sizeof(float));
} }
// sets grabbers orientation // sets grabbers orientation
for (int i = 0; i < 10; ++i) for (int i = 0; i < 10; ++i) {
{
m_grabbers[i].angles = angles; m_grabbers[i].angles = angles;
} }
@ -210,25 +206,21 @@ void GLGizmoScale3D::on_render() const
float grabber_mean_size = (float)((selection_box.size()(0) + selection_box.size()(1) + selection_box.size()(2)) / 3.0); float grabber_mean_size = (float)((selection_box.size()(0) + selection_box.size()(1) + selection_box.size()(2)) / 3.0);
if (m_hover_id == -1) if (m_hover_id == -1) {
{
// draw connections // draw connections
if (m_grabbers[0].enabled && m_grabbers[1].enabled) if (m_grabbers[0].enabled && m_grabbers[1].enabled) {
{ glsafe(::glColor4fv(m_grabbers[0].color.data()));
glsafe(::glColor4fv(m_grabbers[0].color));
render_grabbers_connection(0, 1); render_grabbers_connection(0, 1);
} }
if (m_grabbers[2].enabled && m_grabbers[3].enabled) if (m_grabbers[2].enabled && m_grabbers[3].enabled) {
{ glsafe(::glColor4fv(m_grabbers[2].color.data()));
glsafe(::glColor4fv(m_grabbers[2].color));
render_grabbers_connection(2, 3); render_grabbers_connection(2, 3);
} }
if (m_grabbers[4].enabled && m_grabbers[5].enabled) if (m_grabbers[4].enabled && m_grabbers[5].enabled) {
{ glsafe(::glColor4fv(m_grabbers[4].color.data()));
glsafe(::glColor4fv(m_grabbers[4].color));
render_grabbers_connection(4, 5); render_grabbers_connection(4, 5);
} }
glsafe(::glColor4fv(m_base_color)); glsafe(::glColor4fv(m_base_color.data()));
render_grabbers_connection(6, 7); render_grabbers_connection(6, 7);
render_grabbers_connection(7, 8); render_grabbers_connection(7, 8);
render_grabbers_connection(8, 9); render_grabbers_connection(8, 9);
@ -236,45 +228,68 @@ void GLGizmoScale3D::on_render() const
// draw grabbers // draw grabbers
render_grabbers(grabber_mean_size); render_grabbers(grabber_mean_size);
} }
else if ((m_hover_id == 0) || (m_hover_id == 1)) else if (m_hover_id == 0 || m_hover_id == 1) {
{
// draw connection // draw connection
glsafe(::glColor4fv(m_grabbers[0].color)); glsafe(::glColor4fv(m_grabbers[0].color.data()));
render_grabbers_connection(0, 1); render_grabbers_connection(0, 1);
// draw grabbers
m_grabbers[0].render(true, grabber_mean_size); GLShaderProgram* shader = wxGetApp().get_shader("gouraud_light");
m_grabbers[1].render(true, grabber_mean_size); if (shader != nullptr) {
shader->start_using();
shader->set_uniform("emission_factor", 0.1);
// draw grabbers
m_grabbers[0].render(true, grabber_mean_size);
m_grabbers[1].render(true, grabber_mean_size);
shader->stop_using();
}
} }
else if ((m_hover_id == 2) || (m_hover_id == 3)) else if (m_hover_id == 2 || m_hover_id == 3) {
{
// draw connection // draw connection
glsafe(::glColor4fv(m_grabbers[2].color)); glsafe(::glColor4fv(m_grabbers[2].color.data()));
render_grabbers_connection(2, 3); render_grabbers_connection(2, 3);
// draw grabbers
m_grabbers[2].render(true, grabber_mean_size); GLShaderProgram* shader = wxGetApp().get_shader("gouraud_light");
m_grabbers[3].render(true, grabber_mean_size); if (shader != nullptr) {
shader->start_using();
shader->set_uniform("emission_factor", 0.1);
// draw grabbers
m_grabbers[2].render(true, grabber_mean_size);
m_grabbers[3].render(true, grabber_mean_size);
shader->stop_using();
}
} }
else if ((m_hover_id == 4) || (m_hover_id == 5)) else if (m_hover_id == 4 || m_hover_id == 5) {
{
// draw connection // draw connection
glsafe(::glColor4fv(m_grabbers[4].color)); glsafe(::glColor4fv(m_grabbers[4].color.data()));
render_grabbers_connection(4, 5); render_grabbers_connection(4, 5);
// draw grabbers
m_grabbers[4].render(true, grabber_mean_size); GLShaderProgram* shader = wxGetApp().get_shader("gouraud_light");
m_grabbers[5].render(true, grabber_mean_size); if (shader != nullptr) {
shader->start_using();
shader->set_uniform("emission_factor", 0.1);
// draw grabbers
m_grabbers[4].render(true, grabber_mean_size);
m_grabbers[5].render(true, grabber_mean_size);
shader->stop_using();
}
} }
else if (m_hover_id >= 6) else if (m_hover_id >= 6) {
{
// draw connection // draw connection
glsafe(::glColor4fv(m_drag_color)); glsafe(::glColor4fv(m_drag_color.data()));
render_grabbers_connection(6, 7); render_grabbers_connection(6, 7);
render_grabbers_connection(7, 8); render_grabbers_connection(7, 8);
render_grabbers_connection(8, 9); render_grabbers_connection(8, 9);
render_grabbers_connection(9, 6); render_grabbers_connection(9, 6);
// draw grabbers
for (int i = 6; i < 10; ++i) GLShaderProgram* shader = wxGetApp().get_shader("gouraud_light");
{ if (shader != nullptr) {
m_grabbers[i].render(true, grabber_mean_size); shader->start_using();
shader->set_uniform("emission_factor", 0.1);
// draw grabbers
for (int i = 6; i < 10; ++i) {
m_grabbers[i].render(true, grabber_mean_size);
}
shader->stop_using();
} }
} }
} }

View File

@ -26,20 +26,9 @@ namespace GUI {
GLGizmoSlaSupports::GLGizmoSlaSupports(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id) GLGizmoSlaSupports::GLGizmoSlaSupports(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id)
: GLGizmoBase(parent, icon_filename, sprite_id) : GLGizmoBase(parent, icon_filename, sprite_id)
, m_quadric(nullptr) {
{
m_quadric = ::gluNewQuadric();
if (m_quadric != nullptr)
// using GLU_FILL does not work when the instance's transformation
// contains mirroring (normals are reverted)
::gluQuadricDrawStyle(m_quadric, GLU_FILL);
} }
GLGizmoSlaSupports::~GLGizmoSlaSupports()
{
if (m_quadric != nullptr)
::gluDeleteQuadric(m_quadric);
}
bool GLGizmoSlaSupports::on_init() bool GLGizmoSlaSupports::on_init()
{ {
@ -100,7 +89,7 @@ void GLGizmoSlaSupports::on_render() const
glsafe(::glEnable(GL_BLEND)); glsafe(::glEnable(GL_BLEND));
glsafe(::glEnable(GL_DEPTH_TEST)); glsafe(::glEnable(GL_DEPTH_TEST));
if (m_quadric != nullptr && selection.is_from_single_instance()) if (selection.is_from_single_instance())
render_points(selection, false); render_points(selection, false);
m_selection_rectangle.render(m_parent); m_selection_rectangle.render(m_parent);
@ -114,14 +103,28 @@ void GLGizmoSlaSupports::on_render() const
void GLGizmoSlaSupports::on_render_for_picking() const void GLGizmoSlaSupports::on_render_for_picking() const
{ {
const Selection& selection = m_parent.get_selection(); const Selection& selection = m_parent.get_selection();
glsafe(::glEnable(GL_DEPTH_TEST)); //glsafe(::glEnable(GL_DEPTH_TEST));
render_points(selection, true); render_points(selection, true);
} }
void GLGizmoSlaSupports::render_points(const Selection& selection, bool picking) const void GLGizmoSlaSupports::render_points(const Selection& selection, bool picking) const
{ {
if (!picking) size_t cache_size = m_editing_mode ? m_editing_cache.size() : m_normal_cache.size();
glsafe(::glEnable(GL_LIGHTING));
bool has_points = (cache_size != 0);
bool has_holes = (! m_c->hollowed_mesh()->get_hollowed_mesh()
&& ! m_c->selection_info()->model_object()->sla_drain_holes.empty());
if (! has_points && ! has_holes)
return;
GLShaderProgram* shader = picking ? nullptr : wxGetApp().get_shader("gouraud_light");
if (shader != nullptr)
shader->start_using();
ScopeGuard guard([shader]() {
if (shader != nullptr)
shader->stop_using();
});
const GLVolume* vol = selection.get_volume(*selection.get_volume_idxs().begin()); const GLVolume* vol = selection.get_volume(*selection.get_volume_idxs().begin());
const Transform3d& instance_scaling_matrix_inverse = vol->get_instance_transformation().get_matrix(true, true, false, true).inverse(); const Transform3d& instance_scaling_matrix_inverse = vol->get_instance_transformation().get_matrix(true, true, false, true).inverse();
@ -132,8 +135,7 @@ void GLGizmoSlaSupports::render_points(const Selection& selection, bool picking)
glsafe(::glTranslated(0.0, 0.0, z_shift)); glsafe(::glTranslated(0.0, 0.0, z_shift));
glsafe(::glMultMatrixd(instance_matrix.data())); glsafe(::glMultMatrixd(instance_matrix.data()));
float render_color[4]; std::array<float, 4> render_color;
size_t cache_size = m_editing_mode ? m_editing_cache.size() : m_normal_cache.size();
for (size_t i = 0; i < cache_size; ++i) for (size_t i = 0; i < cache_size; ++i)
{ {
const sla::SupportPoint& support_point = m_editing_mode ? m_editing_cache[i].support_point : m_normal_cache[i]; const sla::SupportPoint& support_point = m_editing_mode ? m_editing_cache[i].support_point : m_normal_cache[i];
@ -143,34 +145,38 @@ void GLGizmoSlaSupports::render_points(const Selection& selection, bool picking)
continue; continue;
// First decide about the color of the point. // First decide about the color of the point.
if (picking) { if (picking)
std::array<float, 4> color = picking_color_component(i); render_color = picking_color_component(i);
render_color[0] = color[0];
render_color[1] = color[1];
render_color[2] = color[2];
render_color[3] = color[3];
}
else { else {
render_color[3] = 1.f; if ((size_t(m_hover_id) == i && m_editing_mode)) // ignore hover state unless editing mode is active
if ((size_t(m_hover_id) == i && m_editing_mode)) { // ignore hover state unless editing mode is active render_color = { 0.f, 1.f, 1.f, 1.f };
render_color[0] = 0.f;
render_color[1] = 1.0f;
render_color[2] = 1.0f;
}
else { // neigher hover nor picking else { // neigher hover nor picking
bool supports_new_island = m_lock_unique_islands && support_point.is_new_island; bool supports_new_island = m_lock_unique_islands && support_point.is_new_island;
if (m_editing_mode) { if (m_editing_mode) {
render_color[0] = point_selected ? 1.0f : (supports_new_island ? 0.3f : 0.7f); if (point_selected)
render_color[1] = point_selected ? 0.3f : (supports_new_island ? 0.3f : 0.7f); render_color = { 1.f, 0.3f, 0.3f, 1.f};
render_color[2] = point_selected ? 0.3f : (supports_new_island ? 1.0f : 0.7f); else
if (supports_new_island)
render_color = { 0.3f, 0.3f, 1.f, 1.f };
else
render_color = { 0.7f, 0.7f, 0.7f, 1.f };
} }
else else
for (unsigned char i=0; i<3; ++i) render_color[i] = 0.5f; render_color = { 0.5f, 0.5f, 0.5f, 1.f };
} }
} }
glsafe(::glColor4fv(render_color)); if (shader && ! picking) {
float render_color_emissive[4] = { 0.5f * render_color[0], 0.5f * render_color[1], 0.5f * render_color[2], 1.f}; #if ENABLE_SEQUENTIAL_LIMITS
glsafe(::glMaterialfv(GL_FRONT, GL_EMISSION, render_color_emissive)); const_cast<GLModel*>(&m_cone)->set_color(-1, render_color);
const_cast<GLModel*>(&m_sphere)->set_color(-1, render_color);
#else
shader->set_uniform("uniform_color", render_color);
#endif // ENABLE_SEQUENTIAL_LIMITS
shader->set_uniform("emission_factor", 0.5);
}
else // picking
glsafe(::glColor4fv(render_color.data()));
// Inverse matrix of the instance scaling is applied so that the mark does not scale with the object. // Inverse matrix of the instance scaling is applied so that the mark does not scale with the object.
glsafe(::glPushMatrix()); glsafe(::glPushMatrix());
@ -195,33 +201,42 @@ void GLGizmoSlaSupports::render_points(const Selection& selection, bool picking)
const double cone_radius = 0.25; // mm const double cone_radius = 0.25; // mm
const double cone_height = 0.75; const double cone_height = 0.75;
glsafe(::glPushMatrix()); glsafe(::glPushMatrix());
glsafe(::glTranslatef(0.f, 0.f, support_point.head_front_radius * RenderPointScale)); glsafe(::glTranslatef(0.f, 0.f, cone_height + support_point.head_front_radius * RenderPointScale));
::gluCylinder(m_quadric, 0., cone_radius, cone_height, 24, 1); glsafe(::glPushMatrix());
glsafe(::glRotated(180., 1., 0., 0.));
glsafe(::glScaled(cone_radius, cone_radius, cone_height));
m_cone.render();
glsafe(::glPopMatrix());
glsafe(::glTranslatef(0.f, 0.f, cone_height)); glsafe(::glTranslatef(0.f, 0.f, cone_height));
::gluDisk(m_quadric, 0.0, cone_radius, 24, 1);
glsafe(::glPopMatrix()); glsafe(::glPopMatrix());
} }
::gluSphere(m_quadric, (double)support_point.head_front_radius * RenderPointScale, 24, 12);
glsafe(::glPushMatrix());
double radius = (double)support_point.head_front_radius * RenderPointScale;
glsafe(::glScaled(radius, radius, radius));
m_sphere.render();
glsafe(::glPopMatrix());
if (vol->is_left_handed()) if (vol->is_left_handed())
glFrontFace(GL_CCW); glFrontFace(GL_CCW);
glsafe(::glPopMatrix()); glsafe(::glPopMatrix());
} }
{
// Reset emissive component to zero (the default value)
float render_color_emissive[4] = { 0.f, 0.f, 0.f, 1.f };
glsafe(::glMaterialfv(GL_FRONT, GL_EMISSION, render_color_emissive));
}
// Now render the drain holes: // Now render the drain holes:
//if (! m_c->has_drilled_mesh()) { if (has_holes && ! picking) {
if (! m_c->hollowed_mesh()->get_hollowed_mesh()) {
render_color[0] = 0.7f; render_color[0] = 0.7f;
render_color[1] = 0.7f; render_color[1] = 0.7f;
render_color[2] = 0.7f; render_color[2] = 0.7f;
render_color[3] = 0.7f; render_color[3] = 0.7f;
glsafe(::glColor4fv(render_color)); if (shader) {
#if ENABLE_SEQUENTIAL_LIMITS
const_cast<GLModel*>(&m_cylinder)->set_color(-1, render_color);
#else
shader->set_uniform("uniform_color", render_color);
#endif // ENABLE_SEQUENTIAL_LIMITS
shader->set_uniform("emission_factor", 0.5);
}
for (const sla::DrainHole& drain_hole : m_c->selection_info()->model_object()->sla_drain_holes) { for (const sla::DrainHole& drain_hole : m_c->selection_info()->model_object()->sla_drain_holes) {
if (is_mesh_point_clipped(drain_hole.pos.cast<double>())) if (is_mesh_point_clipped(drain_hole.pos.cast<double>()))
continue; continue;
@ -242,12 +257,8 @@ void GLGizmoSlaSupports::render_points(const Selection& selection, bool picking)
glsafe(::glRotated(aa.angle() * (180. / M_PI), aa.axis()(0), aa.axis()(1), aa.axis()(2))); glsafe(::glRotated(aa.angle() * (180. / M_PI), aa.axis()(0), aa.axis()(1), aa.axis()(2)));
glsafe(::glPushMatrix()); glsafe(::glPushMatrix());
glsafe(::glTranslated(0., 0., -drain_hole.height)); glsafe(::glTranslated(0., 0., -drain_hole.height));
::gluCylinder(m_quadric, drain_hole.radius, drain_hole.radius, drain_hole.height + sla::HoleStickOutLength, 24, 1); glsafe(::glScaled(drain_hole.radius, drain_hole.radius, drain_hole.height + sla::HoleStickOutLength));
glsafe(::glTranslated(0., 0., drain_hole.height + sla::HoleStickOutLength)); m_cylinder.render();
::gluDisk(m_quadric, 0.0, drain_hole.radius, 24, 1);
glsafe(::glTranslated(0., 0., -drain_hole.height - sla::HoleStickOutLength));
glsafe(::glRotatef(180.f, 1.f, 0.f, 0.f));
::gluDisk(m_quadric, 0.0, drain_hole.radius, 24, 1);
glsafe(::glPopMatrix()); glsafe(::glPopMatrix());
if (vol->is_left_handed()) if (vol->is_left_handed())
@ -256,9 +267,6 @@ void GLGizmoSlaSupports::render_points(const Selection& selection, bool picking)
} }
} }
if (!picking)
glsafe(::glDisable(GL_LIGHTING));
glsafe(::glPopMatrix()); glsafe(::glPopMatrix());
} }

View File

@ -27,8 +27,6 @@ private:
const float RenderPointScale = 1.f; const float RenderPointScale = 1.f;
GLUquadricObj* m_quadric;
class CacheEntry { class CacheEntry {
public: public:
CacheEntry() : CacheEntry() :
@ -58,7 +56,7 @@ private:
public: public:
GLGizmoSlaSupports(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id); GLGizmoSlaSupports(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id);
~GLGizmoSlaSupports() override; virtual ~GLGizmoSlaSupports() = default;
void set_sla_support_data(ModelObject* model_object, const Selection& selection); void set_sla_support_data(ModelObject* model_object, const Selection& selection);
bool gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_position, bool shift_down, bool alt_down, bool control_down); 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); void delete_selected_points(bool force = false);

View File

@ -781,11 +781,9 @@ bool GLGizmosManager::on_char(wxKeyEvent& evt)
break; break;
} }
#ifdef __APPLE__
case WXK_BACK: // the low cost Apple solutions are not equipped with a Delete key, use Backspace instead. case WXK_BACK:
#else /* __APPLE__ */
case WXK_DELETE: case WXK_DELETE:
#endif /* __APPLE__ */
{ {
if ((m_current == SlaSupports || m_current == Hollow) && gizmo_event(SLAGizmoEventType::Delete)) if ((m_current == SlaSupports || m_current == Hollow) && gizmo_event(SLAGizmoEventType::Delete))
processed = true; processed = true;

View File

@ -9,6 +9,8 @@
#include <GL/glew.h> #include <GL/glew.h>
#include <igl/unproject.h>
namespace Slic3r { namespace Slic3r {
namespace GUI { namespace GUI {
@ -122,14 +124,16 @@ Vec3f MeshRaycaster::get_triangle_normal(size_t facet_idx) const
void MeshRaycaster::line_from_mouse_pos(const Vec2d& mouse_pos, const Transform3d& trafo, const Camera& camera, void MeshRaycaster::line_from_mouse_pos(const Vec2d& mouse_pos, const Transform3d& trafo, const Camera& camera,
Vec3d& point, Vec3d& direction) const Vec3d& point, Vec3d& direction) const
{ {
const std::array<int, 4>& viewport = camera.get_viewport(); Matrix4d modelview = camera.get_view_matrix().matrix();
const Transform3d& model_mat = camera.get_view_matrix(); Matrix4d projection= camera.get_projection_matrix().matrix();
const Transform3d& proj_mat = camera.get_projection_matrix(); Vec4i viewport(camera.get_viewport().data());
Vec3d pt1; Vec3d pt1;
Vec3d pt2; Vec3d pt2;
::gluUnProject(mouse_pos(0), viewport[3] - mouse_pos(1), 0., model_mat.data(), proj_mat.data(), viewport.data(), &pt1(0), &pt1(1), &pt1(2)); igl::unproject(Vec3d(mouse_pos(0), viewport[3] - mouse_pos(1), 0.),
::gluUnProject(mouse_pos(0), viewport[3] - mouse_pos(1), 1., model_mat.data(), proj_mat.data(), viewport.data(), &pt2(0), &pt2(1), &pt2(2)); modelview, projection, viewport, pt1);
igl::unproject(Vec3d(mouse_pos(0), viewport[3] - mouse_pos(1), 1.),
modelview, projection, viewport, pt2);
Transform3d inv = trafo.inverse(); Transform3d inv = trafo.inverse();
pt1 = inv * pt1; pt1 = inv * pt1;

View File

@ -2730,6 +2730,10 @@ void Plater::priv::reset()
reset_gcode_toolpaths(); reset_gcode_toolpaths();
gcode_result.reset(); gcode_result.reset();
#if ENABLE_SEQUENTIAL_LIMITS
view3D->get_canvas3d()->set_sequential_print_clearance(Polygons(), false);
#endif // ENABLE_SEQUENTIAL_LIMITS
// Stop and reset the Print content. // Stop and reset the Print content.
this->background_process.reset(); this->background_process.reset();
model.clear_objects(); model.clear_objects();
@ -2894,12 +2898,12 @@ unsigned int Plater::priv::update_background_process(bool force_validation, bool
// If the update_background_process() was not called by the timer, kill the timer, // If the update_background_process() was not called by the timer, kill the timer,
// so the update_restart_background_process() will not be called again in vain. // so the update_restart_background_process() will not be called again in vain.
this->background_process_timer.Stop(); background_process_timer.Stop();
// Update the "out of print bed" state of ModelInstances. // Update the "out of print bed" state of ModelInstances.
this->update_print_volume_state(); update_print_volume_state();
// Apply new config to the possibly running background task. // Apply new config to the possibly running background task.
bool was_running = this->background_process.running(); bool was_running = background_process.running();
Print::ApplyStatus invalidated = this->background_process.apply(this->q->model(), wxGetApp().preset_bundle->full_config()); Print::ApplyStatus invalidated = background_process.apply(q->model(), wxGetApp().preset_bundle->full_config());
// Just redraw the 3D canvas without reloading the scene to consume the update of the layer height profile. // Just redraw the 3D canvas without reloading the scene to consume the update of the layer height profile.
if (view3D->is_layers_editing_enabled()) if (view3D->is_layers_editing_enabled())
@ -2908,40 +2912,56 @@ unsigned int Plater::priv::update_background_process(bool force_validation, bool
if (invalidated == Print::APPLY_STATUS_INVALIDATED) { if (invalidated == Print::APPLY_STATUS_INVALIDATED) {
// Some previously calculated data on the Print was invalidated. // Some previously calculated data on the Print was invalidated.
// Hide the slicing results, as the current slicing status is no more valid. // Hide the slicing results, as the current slicing status is no more valid.
this->sidebar->show_sliced_info_sizer(false); sidebar->show_sliced_info_sizer(false);
// Reset preview canvases. If the print has been invalidated, the preview canvases will be cleared. // Reset preview canvases. If the print has been invalidated, the preview canvases will be cleared.
// Otherwise they will be just refreshed. // Otherwise they will be just refreshed.
if (this->preview != nullptr) { if (preview != nullptr) {
// If the preview is not visible, the following line just invalidates the preview, // If the preview is not visible, the following line just invalidates the preview,
// but the G-code paths or SLA preview are calculated first once the preview is made visible. // but the G-code paths or SLA preview are calculated first once the preview is made visible.
reset_gcode_toolpaths(); reset_gcode_toolpaths();
this->preview->reload_print(); preview->reload_print();
} }
// In FDM mode, we need to reload the 3D scene because of the wipe tower preview box. // In FDM mode, we need to reload the 3D scene because of the wipe tower preview box.
// In SLA mode, we need to reload the 3D scene every time to show the support structures. // In SLA mode, we need to reload the 3D scene every time to show the support structures.
if (this->printer_technology == ptSLA || (this->printer_technology == ptFFF && this->config->opt_bool("wipe_tower"))) if (printer_technology == ptSLA || (printer_technology == ptFFF && config->opt_bool("wipe_tower")))
return_state |= UPDATE_BACKGROUND_PROCESS_REFRESH_SCENE; return_state |= UPDATE_BACKGROUND_PROCESS_REFRESH_SCENE;
} }
if ((invalidated != Print::APPLY_STATUS_UNCHANGED || force_validation) && ! this->background_process.empty()) { if ((invalidated != Print::APPLY_STATUS_UNCHANGED || force_validation) && ! background_process.empty()) {
// The delayed error message is no more valid. // The delayed error message is no more valid.
this->delayed_error_message.clear(); delayed_error_message.clear();
// The state of the Print changed, and it is non-zero. Let's validate it and give the user feedback on errors. // The state of the Print changed, and it is non-zero. Let's validate it and give the user feedback on errors.
std::string warning; std::string warning;
std::string err = this->background_process.validate(&warning); std::string err = background_process.validate(&warning);
if (err.empty()) { if (err.empty()) {
notification_manager->set_all_slicing_errors_gray(true); notification_manager->set_all_slicing_errors_gray(true);
if (invalidated != Print::APPLY_STATUS_UNCHANGED && this->background_processing_enabled()) if (invalidated != Print::APPLY_STATUS_UNCHANGED && background_processing_enabled())
return_state |= UPDATE_BACKGROUND_PROCESS_RESTART; return_state |= UPDATE_BACKGROUND_PROCESS_RESTART;
// Pass a warning from validation and either show a notification, // Pass a warning from validation and either show a notification,
// or hide the old one. // or hide the old one.
process_validation_warning(warning); process_validation_warning(warning);
#if ENABLE_SEQUENTIAL_LIMITS
if (printer_technology == ptFFF) {
view3D->get_canvas3d()->set_sequential_print_clearance(Polygons(), false);
view3D->get_canvas3d()->set_as_dirty();
view3D->get_canvas3d()->request_extra_frame();
}
#endif // ENABLE_SEQUENTIAL_LIMITS
} else { } else {
// The print is not valid. // The print is not valid.
// Show error as notification. // Show error as notification.
notification_manager->push_slicing_error_notification(err); notification_manager->push_slicing_error_notification(err);
return_state |= UPDATE_BACKGROUND_PROCESS_INVALID; return_state |= UPDATE_BACKGROUND_PROCESS_INVALID;
#if ENABLE_SEQUENTIAL_LIMITS
if (printer_technology == ptFFF) {
const Print* print = background_process.fff_print();
Polygons polygons;
if (print->config().complete_objects)
Print::sequential_print_horizontal_clearance_valid(*print, &polygons);
view3D->get_canvas3d()->set_sequential_print_clearance(polygons, true);
}
#endif // ENABLE_SEQUENTIAL_LIMITS
} }
} else if (! this->delayed_error_message.empty()) { } else if (! this->delayed_error_message.empty()) {
@ -3077,8 +3097,7 @@ void Plater::priv::update_fff_scene()
if (this->preview != nullptr) if (this->preview != nullptr)
this->preview->reload_print(); this->preview->reload_print();
// In case this was MM print, wipe tower bounding box on 3D tab might need redrawing with exact depth: // In case this was MM print, wipe tower bounding box on 3D tab might need redrawing with exact depth:
view3D->reload_scene(true); view3D->reload_scene(true);
} }
void Plater::priv::update_sla_scene() void Plater::priv::update_sla_scene()

View File

@ -22,7 +22,7 @@
#include <boost/algorithm/string/predicate.hpp> #include <boost/algorithm/string/predicate.hpp>
#include <boost/log/trivial.hpp> #include <boost/log/trivial.hpp>
static const float UNIFORM_SCALE_COLOR[4] = { 0.923f, 0.504f, 0.264f, 1.0f }; static const std::array<float, 4> UNIFORM_SCALE_COLOR = { 0.923f, 0.504f, 0.264f, 1.0f };
namespace Slic3r { namespace Slic3r {
namespace GUI { namespace GUI {
@ -115,20 +115,8 @@ Selection::Selection()
, m_scale_factor(1.0f) , m_scale_factor(1.0f)
{ {
this->set_bounding_boxes_dirty(); this->set_bounding_boxes_dirty();
#if ENABLE_RENDER_SELECTION_CENTER
m_quadric = ::gluNewQuadric();
if (m_quadric != nullptr)
::gluQuadricDrawStyle(m_quadric, GLU_FILL);
#endif // ENABLE_RENDER_SELECTION_CENTER
} }
#if ENABLE_RENDER_SELECTION_CENTER
Selection::~Selection()
{
if (m_quadric != nullptr)
::gluDeleteQuadric(m_quadric);
}
#endif // ENABLE_RENDER_SELECTION_CENTER
void Selection::set_volumes(GLVolumePtrs* volumes) void Selection::set_volumes(GLVolumePtrs* volumes)
{ {
@ -141,6 +129,11 @@ bool Selection::init()
{ {
m_arrow.init_from(straight_arrow(10.0f, 5.0f, 5.0f, 10.0f, 1.0f)); m_arrow.init_from(straight_arrow(10.0f, 5.0f, 5.0f, 10.0f, 1.0f));
m_curved_arrow.init_from(circular_arrow(16, 10.0f, 5.0f, 10.0f, 5.0f, 1.0f)); m_curved_arrow.init_from(circular_arrow(16, 10.0f, 5.0f, 10.0f, 5.0f, 1.0f));
#if ENABLE_RENDER_SELECTION_CENTER
m_vbo_sphere.init_from(make_sphere(0.75, 2*PI/24));
#endif // ENABLE_RENDER_SELECTION_CENTER
return true; return true;
} }
@ -1176,22 +1169,18 @@ void Selection::render(float scale_factor) const
#if ENABLE_RENDER_SELECTION_CENTER #if ENABLE_RENDER_SELECTION_CENTER
void Selection::render_center(bool gizmo_is_dragging) const void Selection::render_center(bool gizmo_is_dragging) const
{ {
if (!m_valid || is_empty() || m_quadric == nullptr) if (!m_valid || is_empty())
return; return;
const Vec3d center = gizmo_is_dragging ? m_cache.dragging_center : get_bounding_box().center(); const Vec3d center = gizmo_is_dragging ? m_cache.dragging_center : get_bounding_box().center();
glsafe(::glDisable(GL_DEPTH_TEST)); glsafe(::glDisable(GL_DEPTH_TEST));
glsafe(::glEnable(GL_LIGHTING));
glsafe(::glColor3f(1.0f, 1.0f, 1.0f)); glsafe(::glColor3f(1.0f, 1.0f, 1.0f));
glsafe(::glPushMatrix()); glsafe(::glPushMatrix());
glsafe(::glTranslated(center(0), center(1), center(2))); glsafe(::glTranslated(center(0), center(1), center(2)));
glsafe(::gluSphere(m_quadric, 0.75, 32, 32)); m_vbo_sphere.render();
glsafe(::glPopMatrix()); glsafe(::glPopMatrix());
glsafe(::glDisable(GL_LIGHTING));
} }
#endif // ENABLE_RENDER_SELECTION_CENTER #endif // ENABLE_RENDER_SELECTION_CENTER
@ -1829,12 +1818,37 @@ void Selection::render_bounding_box(const BoundingBoxf3& box, float* color) cons
glsafe(::glEnd()); glsafe(::glEnd());
} }
#if ENABLE_SEQUENTIAL_LIMITS
static std::array<float, 4> get_color(Axis axis)
{
return { AXES_COLOR[axis][0], AXES_COLOR[axis][1], AXES_COLOR[axis][2], AXES_COLOR[axis][3] };
};
#endif // ENABLE_SEQUENTIAL_LIMITS
void Selection::render_sidebar_position_hints(const std::string& sidebar_field) const void Selection::render_sidebar_position_hints(const std::string& sidebar_field) const
{ {
#if ENABLE_SEQUENTIAL_LIMITS
if (boost::ends_with(sidebar_field, "x")) {
glsafe(::glRotated(-90.0, 0.0, 0.0, 1.0));
const_cast<GLModel*>(&m_arrow)->set_color(-1, get_color(X));
m_arrow.render();
}
else if (boost::ends_with(sidebar_field, "y")) {
const_cast<GLModel*>(&m_arrow)->set_color(-1, get_color(Y));
m_arrow.render();
}
else if (boost::ends_with(sidebar_field, "z")) {
glsafe(::glRotated(90.0, 1.0, 0.0, 0.0));
const_cast<GLModel*>(&m_arrow)->set_color(-1, get_color(Z));
m_arrow.render();
}
#else
auto set_color = [](Axis axis) { auto set_color = [](Axis axis) {
GLShaderProgram* shader = wxGetApp().get_current_shader(); GLShaderProgram* shader = wxGetApp().get_current_shader();
if (shader != nullptr) if (shader != nullptr) {
shader->set_uniform("uniform_color", AXES_COLOR[axis], 4); shader->set_uniform("uniform_color", AXES_COLOR[axis]);
shader->set_uniform("emission_factor", 0.0);
}
}; };
if (boost::ends_with(sidebar_field, "x")) { if (boost::ends_with(sidebar_field, "x")) {
@ -1849,14 +1863,39 @@ void Selection::render_sidebar_position_hints(const std::string& sidebar_field)
glsafe(::glRotated(90.0, 1.0, 0.0, 0.0)); glsafe(::glRotated(90.0, 1.0, 0.0, 0.0));
m_arrow.render(); m_arrow.render();
} }
#endif // ENABLE_SEQUENTIAL_LIMITS
} }
void Selection::render_sidebar_rotation_hints(const std::string& sidebar_field) const void Selection::render_sidebar_rotation_hints(const std::string& sidebar_field) const
{ {
#if ENABLE_SEQUENTIAL_LIMITS
auto render_sidebar_rotation_hint = [this]() {
m_curved_arrow.render();
glsafe(::glRotated(180.0, 0.0, 0.0, 1.0));
m_curved_arrow.render();
};
if (boost::ends_with(sidebar_field, "x")) {
glsafe(::glRotated(90.0, 0.0, 1.0, 0.0));
const_cast<GLModel*>(&m_curved_arrow)->set_color(-1, get_color(X));
render_sidebar_rotation_hint();
}
else if (boost::ends_with(sidebar_field, "y")) {
glsafe(::glRotated(-90.0, 1.0, 0.0, 0.0));
const_cast<GLModel*>(&m_curved_arrow)->set_color(-1, get_color(Y));
render_sidebar_rotation_hint();
}
else if (boost::ends_with(sidebar_field, "z")) {
const_cast<GLModel*>(&m_curved_arrow)->set_color(-1, get_color(Z));
render_sidebar_rotation_hint();
}
#else
auto set_color = [](Axis axis) { auto set_color = [](Axis axis) {
GLShaderProgram* shader = wxGetApp().get_current_shader(); GLShaderProgram* shader = wxGetApp().get_current_shader();
if (shader != nullptr) if (shader != nullptr) {
shader->set_uniform("uniform_color", AXES_COLOR[axis], 4); shader->set_uniform("uniform_color", AXES_COLOR[axis]);
shader->set_uniform("emission_factor", 0.0);
}
}; };
auto render_sidebar_rotation_hint = [this]() { auto render_sidebar_rotation_hint = [this]() {
@ -1877,6 +1916,7 @@ void Selection::render_sidebar_rotation_hints(const std::string& sidebar_field)
set_color(Z); set_color(Z);
render_sidebar_rotation_hint(); render_sidebar_rotation_hint();
} }
#endif // ENABLE_SEQUENTIAL_LIMITS
} }
void Selection::render_sidebar_scale_hints(const std::string& sidebar_field) const void Selection::render_sidebar_scale_hints(const std::string& sidebar_field) const
@ -1884,9 +1924,12 @@ void Selection::render_sidebar_scale_hints(const std::string& sidebar_field) con
bool uniform_scale = requires_uniform_scale() || wxGetApp().obj_manipul()->get_uniform_scaling(); bool uniform_scale = requires_uniform_scale() || wxGetApp().obj_manipul()->get_uniform_scaling();
auto render_sidebar_scale_hint = [this, uniform_scale](Axis axis) { auto render_sidebar_scale_hint = [this, uniform_scale](Axis axis) {
#if ENABLE_SEQUENTIAL_LIMITS
const_cast<GLModel*>(&m_arrow)->set_color(-1, uniform_scale ? UNIFORM_SCALE_COLOR : get_color(axis));
#endif // ENABLE_SEQUENTIAL_LIMITS
GLShaderProgram* shader = wxGetApp().get_current_shader(); GLShaderProgram* shader = wxGetApp().get_current_shader();
if (shader != nullptr) if (shader != nullptr)
shader->set_uniform("uniform_color", uniform_scale ? UNIFORM_SCALE_COLOR : AXES_COLOR[axis], 4); shader->set_uniform("emission_factor", 0.0);
glsafe(::glTranslated(0.0, 5.0, 0.0)); glsafe(::glTranslated(0.0, 5.0, 0.0));
m_arrow.render(); m_arrow.render();

View File

@ -5,11 +5,6 @@
#include "libslic3r/Geometry.hpp" #include "libslic3r/Geometry.hpp"
#include "GLModel.hpp" #include "GLModel.hpp"
#if ENABLE_RENDER_SELECTION_CENTER
class GLUquadric;
typedef class GLUquadric GLUquadricObj;
#endif // ENABLE_RENDER_SELECTION_CENTER
namespace Slic3r { namespace Slic3r {
class Shader; class Shader;
@ -216,7 +211,7 @@ private:
bool m_scaled_instance_bounding_box_dirty; bool m_scaled_instance_bounding_box_dirty;
#if ENABLE_RENDER_SELECTION_CENTER #if ENABLE_RENDER_SELECTION_CENTER
GLUquadricObj* m_quadric; GLModel m_vbo_sphere;
#endif // ENABLE_RENDER_SELECTION_CENTER #endif // ENABLE_RENDER_SELECTION_CENTER
GLModel m_arrow; GLModel m_arrow;
@ -226,9 +221,6 @@ private:
public: public:
Selection(); Selection();
#if ENABLE_RENDER_SELECTION_CENTER
~Selection();
#endif // ENABLE_RENDER_SELECTION_CENTER
void set_volumes(GLVolumePtrs* volumes); void set_volumes(GLVolumePtrs* volumes);
bool init(); bool init();