mirror of
https://git.mirrors.martin98.com/https://github.com/prusa3d/PrusaSlicer.git
synced 2025-08-01 09:01:58 +08:00
175 lines
6.7 KiB
C++
175 lines
6.7 KiB
C++
#include "libslic3r/libslic3r.h"
|
|
#include "GLGizmoSlaBase.hpp"
|
|
#include "slic3r/GUI/Camera.hpp"
|
|
#include "slic3r/GUI/GLCanvas3D.hpp"
|
|
#include "slic3r/GUI/GUI_App.hpp"
|
|
#include "slic3r/GUI/Plater.hpp"
|
|
#include "slic3r/GUI/Gizmos/GLGizmosCommon.hpp"
|
|
|
|
namespace Slic3r {
|
|
namespace GUI {
|
|
|
|
static const ColorRGBA DISABLED_COLOR = ColorRGBA::DARK_GRAY();
|
|
static const int VOLUME_RAYCASTERS_BASE_ID = (int)SceneRaycaster::EIdBase::Gizmo;
|
|
|
|
GLGizmoSlaBase::GLGizmoSlaBase(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id, SLAPrintObjectStep min_step)
|
|
: GLGizmoBase(parent, icon_filename, sprite_id)
|
|
, m_min_sla_print_object_step((int)min_step)
|
|
{}
|
|
|
|
void GLGizmoSlaBase::reslice_until_step(SLAPrintObjectStep step, bool postpone_error_messages)
|
|
{
|
|
wxGetApp().CallAfter([this, step, postpone_error_messages]() {
|
|
wxGetApp().plater()->reslice_SLA_until_step(step, *m_c->selection_info()->model_object(), postpone_error_messages);
|
|
});
|
|
}
|
|
|
|
CommonGizmosDataID GLGizmoSlaBase::on_get_requirements() const
|
|
{
|
|
return CommonGizmosDataID(
|
|
int(CommonGizmosDataID::SelectionInfo)
|
|
| int(CommonGizmosDataID::InstancesHider)
|
|
| int(CommonGizmosDataID::Raycaster)
|
|
| int(CommonGizmosDataID::ObjectClipper));
|
|
}
|
|
|
|
void GLGizmoSlaBase::update_volumes()
|
|
{
|
|
m_volumes.clear();
|
|
unregister_volume_raycasters_for_picking();
|
|
|
|
const ModelObject* mo = m_c->selection_info()->model_object();
|
|
if (mo == nullptr)
|
|
return;
|
|
|
|
const SLAPrintObject* po = m_c->selection_info()->print_object();
|
|
if (po == nullptr)
|
|
return;
|
|
|
|
m_input_enabled = false;
|
|
|
|
TriangleMesh backend_mesh;
|
|
std::shared_ptr<const indexed_triangle_set> preview_mesh_ptr = po->get_mesh_to_print();
|
|
if (preview_mesh_ptr)
|
|
backend_mesh = TriangleMesh{*preview_mesh_ptr};
|
|
|
|
if (!backend_mesh.empty()) {
|
|
// The backend has generated a valid mesh. Use it
|
|
backend_mesh.transform(po->trafo().inverse());
|
|
m_volumes.volumes.emplace_back(new GLVolume());
|
|
GLVolume* new_volume = m_volumes.volumes.back();
|
|
new_volume->model.init_from(backend_mesh);
|
|
new_volume->set_instance_transformation(po->model_object()->instances[m_parent.get_selection().get_instance_idx()]->get_transformation());
|
|
new_volume->set_sla_shift_z(po->get_current_elevation());
|
|
new_volume->mesh_raycaster = std::make_unique<GUI::MeshRaycaster>(backend_mesh);
|
|
auto last_comp_step = static_cast<int>(po->last_completed_step());
|
|
if (last_comp_step == slaposCount)
|
|
last_comp_step = -1;
|
|
|
|
m_input_enabled = last_comp_step >= m_min_sla_print_object_step;
|
|
if (m_input_enabled)
|
|
new_volume->selected = true; // to set the proper color
|
|
else
|
|
new_volume->set_color(DISABLED_COLOR);
|
|
}
|
|
|
|
if (m_volumes.volumes.empty()) {
|
|
// No valid mesh found in the backend. Use the selection to duplicate the volumes
|
|
const Selection& selection = m_parent.get_selection();
|
|
const Selection::IndicesList& idxs = selection.get_volume_idxs();
|
|
for (unsigned int idx : idxs) {
|
|
const GLVolume* v = selection.get_volume(idx);
|
|
if (!v->is_modifier) {
|
|
m_volumes.volumes.emplace_back(new GLVolume());
|
|
GLVolume* new_volume = m_volumes.volumes.back();
|
|
const TriangleMesh& mesh = mo->volumes[v->volume_idx()]->mesh();
|
|
new_volume->model.init_from(mesh);
|
|
new_volume->set_instance_transformation(v->get_instance_transformation());
|
|
new_volume->set_volume_transformation(v->get_volume_transformation());
|
|
new_volume->set_sla_shift_z(v->get_sla_shift_z());
|
|
new_volume->set_color(DISABLED_COLOR);
|
|
new_volume->mesh_raycaster = std::make_unique<GUI::MeshRaycaster>(mesh);
|
|
}
|
|
}
|
|
}
|
|
|
|
register_volume_raycasters_for_picking();
|
|
}
|
|
|
|
void GLGizmoSlaBase::render_volumes()
|
|
{
|
|
GLShaderProgram* shader = wxGetApp().get_shader("gouraud_light_clip");
|
|
if (shader == nullptr)
|
|
return;
|
|
|
|
shader->start_using();
|
|
shader->set_uniform("emission_factor", 0.0f);
|
|
const Camera& camera = wxGetApp().plater()->get_camera();
|
|
|
|
ClippingPlane clipping_plane = (m_c->object_clipper()->get_position() == 0.0) ? ClippingPlane::ClipsNothing() : *m_c->object_clipper()->get_clipping_plane();
|
|
clipping_plane.set_normal(-clipping_plane.get_normal());
|
|
m_volumes.set_clipping_plane(clipping_plane.get_data());
|
|
|
|
m_volumes.render(GLVolumeCollection::ERenderType::Opaque, false, camera.get_view_matrix(), camera.get_projection_matrix());
|
|
shader->stop_using();
|
|
|
|
}
|
|
|
|
void GLGizmoSlaBase::register_volume_raycasters_for_picking()
|
|
{
|
|
for (size_t i = 0; i < m_volumes.volumes.size(); ++i) {
|
|
const GLVolume* v = m_volumes.volumes[i];
|
|
m_volume_raycasters.emplace_back(m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, VOLUME_RAYCASTERS_BASE_ID + (int)i, *v->mesh_raycaster, v->world_matrix()));
|
|
}
|
|
}
|
|
|
|
void GLGizmoSlaBase::unregister_volume_raycasters_for_picking()
|
|
{
|
|
for (size_t i = 0; i < m_volume_raycasters.size(); ++i) {
|
|
m_parent.remove_raycasters_for_picking(SceneRaycaster::EType::Gizmo, VOLUME_RAYCASTERS_BASE_ID + (int)i);
|
|
}
|
|
m_volume_raycasters.clear();
|
|
}
|
|
|
|
// Unprojects the mouse position on the mesh and saves hit point and normal of the facet into pos_and_normal
|
|
// Return false if no intersection was found, true otherwise.
|
|
bool GLGizmoSlaBase::unproject_on_mesh(const Vec2d& mouse_pos, std::pair<Vec3f, Vec3f>& pos_and_normal)
|
|
{
|
|
if (m_c->raycaster()->raycasters().size() != 1)
|
|
return false;
|
|
if (!m_c->raycaster()->raycaster())
|
|
return false;
|
|
if (m_volumes.volumes.empty())
|
|
return false;
|
|
|
|
auto *inst = m_c->selection_info()->model_instance();
|
|
if (!inst)
|
|
return false;
|
|
|
|
Transform3d trafo = m_volumes.volumes.front()->world_matrix();
|
|
if (m_c->selection_info() && m_c->selection_info()->print_object()) {
|
|
double shift_z = m_c->selection_info()->print_object()->get_current_elevation();
|
|
trafo = inst->get_transformation().get_matrix();
|
|
trafo.translation()(2) += shift_z;
|
|
}
|
|
|
|
// The raycaster query
|
|
Vec3f hit;
|
|
Vec3f normal;
|
|
if (m_c->raycaster()->raycaster()->unproject_on_mesh(
|
|
mouse_pos,
|
|
trafo/*m_volumes.volumes.front()->world_matrix()*/,
|
|
wxGetApp().plater()->get_camera(),
|
|
hit,
|
|
normal,
|
|
m_c->object_clipper()->get_position() != 0.0 ? m_c->object_clipper()->get_clipping_plane() : nullptr)) {
|
|
// Return both the point and the facet normal.
|
|
pos_and_normal = std::make_pair(hit, normal);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
} // namespace GUI
|
|
} // namespace Slic3r
|