mirror of
https://git.mirrors.martin98.com/https://github.com/prusa3d/PrusaSlicer.git
synced 2025-08-15 08:45:53 +08:00
Rework dragging over surface to use GlVolume and function do_move
No need for special rendering any more
This commit is contained in:
parent
617c163bd6
commit
baa5a011ee
@ -466,70 +466,77 @@ Vec2d priv::calc_mouse_to_center_text_offset(const Vec2d& mouse, const ModelVolu
|
|||||||
|
|
||||||
bool GLGizmoEmboss::on_mouse_for_translate(const wxMouseEvent &mouse_event)
|
bool GLGizmoEmboss::on_mouse_for_translate(const wxMouseEvent &mouse_event)
|
||||||
{
|
{
|
||||||
// filter events
|
|
||||||
if (!(mouse_event.Dragging() && mouse_event.LeftIsDown()) &&
|
|
||||||
!mouse_event.LeftUp() &&
|
|
||||||
!mouse_event.LeftDown())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// must exist hover object
|
|
||||||
int hovered_id = m_parent.get_first_hover_volume_idx();
|
|
||||||
if (hovered_id < 0) return false;
|
|
||||||
|
|
||||||
GLVolume *gl_volume = m_parent.get_volumes().volumes[hovered_id];
|
|
||||||
const ModelObjectPtrs &objects = wxGetApp().plater()->model().objects;
|
|
||||||
ModelVolume *act_model_volume = priv::get_model_volume(gl_volume, objects);
|
|
||||||
|
|
||||||
// hovered object must be actual text volume
|
|
||||||
if (m_volume != act_model_volume) return false;
|
|
||||||
|
|
||||||
const ModelVolumePtrs &volumes = m_volume->get_object()->volumes;
|
|
||||||
std::vector<size_t> allowed_volumes_id;
|
|
||||||
if (volumes.size() > 1) {
|
|
||||||
allowed_volumes_id.reserve(volumes.size() - 1);
|
|
||||||
for (auto &v : volumes) {
|
|
||||||
if (v->id() == m_volume->id()) continue;
|
|
||||||
if (!v->is_model_part()) continue;
|
|
||||||
allowed_volumes_id.emplace_back(v->id().id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// wxCoord == int --> wx/types.h
|
|
||||||
Vec2i mouse_coord(mouse_event.GetX(), mouse_event.GetY());
|
|
||||||
Vec2d mouse_pos = mouse_coord.cast<double>();
|
|
||||||
RaycastManager::AllowVolumes condition(std::move(allowed_volumes_id));
|
|
||||||
|
|
||||||
// detect start text dragging
|
// detect start text dragging
|
||||||
if (mouse_event.LeftDown()) {
|
if (mouse_event.LeftDown()) {
|
||||||
|
// must exist hover object
|
||||||
|
int hovered_id = m_parent.get_first_hover_volume_idx();
|
||||||
|
if (hovered_id < 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
GLVolume *gl_volume = m_parent.get_volumes().volumes[hovered_id];
|
||||||
|
const ModelObjectPtrs &objects = m_parent.get_model()->objects;
|
||||||
|
|
||||||
|
// hovered object must be actual text volume
|
||||||
|
if (m_volume != priv::get_model_volume(gl_volume, objects))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
const ModelVolumePtrs &volumes = m_volume->get_object()->volumes;
|
||||||
|
std::vector<size_t> allowed_volumes_id;
|
||||||
|
if (volumes.size() > 1) {
|
||||||
|
allowed_volumes_id.reserve(volumes.size() - 1);
|
||||||
|
for (auto &v : volumes) {
|
||||||
|
if (v->id() == m_volume->id())
|
||||||
|
continue;
|
||||||
|
if (!v->is_model_part())
|
||||||
|
continue;
|
||||||
|
allowed_volumes_id.emplace_back(v->id().id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
RaycastManager::AllowVolumes condition(std::move(allowed_volumes_id));
|
||||||
|
|
||||||
// initialize raycasters
|
// initialize raycasters
|
||||||
// IMPROVE: move to job, for big scene it slows down
|
// INFO: It could slows down for big objects
|
||||||
ModelObject *act_model_object = act_model_volume->get_object();
|
// (may be move to thread and do not show drag until it finish)
|
||||||
m_raycast_manager.actualize(act_model_object, &condition);
|
m_raycast_manager.actualize(m_volume->get_object(), &condition);
|
||||||
m_dragging_mouse_offset = priv::calc_mouse_to_center_text_offset(mouse_pos, *m_volume);
|
|
||||||
|
// wxCoord == int --> wx/types.h
|
||||||
|
Vec2i mouse_coord(mouse_event.GetX(), mouse_event.GetY());
|
||||||
|
Vec2d mouse_pos = mouse_coord.cast<double>();
|
||||||
|
Vec2d mouse_offset = priv::calc_mouse_to_center_text_offset(mouse_pos, *m_volume);
|
||||||
|
Transform3d instance_inv = gl_volume->get_instance_transformation().get_matrix().inverse();
|
||||||
|
m_surface_drag = SurfaceDrag{mouse_offset, instance_inv, gl_volume, condition};
|
||||||
|
|
||||||
// Cancel job to prevent interuption of dragging (duplicit result)
|
// Cancel job to prevent interuption of dragging (duplicit result)
|
||||||
if (m_job_cancel != nullptr)
|
if (m_job_cancel != nullptr)
|
||||||
m_job_cancel->store(true);
|
m_job_cancel->store(true);
|
||||||
return false;
|
|
||||||
|
m_parent.enable_moving(false);
|
||||||
|
m_parent.enable_picking(false);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Dragging starts out of window
|
// Dragging starts out of window
|
||||||
if (!m_dragging_mouse_offset.has_value())
|
if (!m_surface_drag.has_value())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (mouse_event.Dragging()) {
|
if (mouse_event.Dragging()) {
|
||||||
|
// wxCoord == int --> wx/types.h
|
||||||
|
Vec2i mouse_coord(mouse_event.GetX(), mouse_event.GetY());
|
||||||
|
Vec2d mouse_pos = mouse_coord.cast<double>();
|
||||||
|
Vec2d offseted_mouse = mouse_pos + m_surface_drag->mouse_offset;
|
||||||
const Camera &camera = wxGetApp().plater()->get_camera();
|
const Camera &camera = wxGetApp().plater()->get_camera();
|
||||||
Vec2d offseted_mouse = mouse_pos + *m_dragging_mouse_offset;
|
auto hit = m_raycast_manager.unproject(offseted_mouse, camera, &m_surface_drag->condition);
|
||||||
auto hit = m_raycast_manager.unproject(offseted_mouse, camera, &condition);
|
if (!hit.has_value()) {
|
||||||
if (!hit.has_value())
|
// cross hair need redraw
|
||||||
return false;
|
m_parent.set_as_dirty();
|
||||||
TextConfiguration &tc = *m_volume->text_configuration;
|
return true;
|
||||||
// INFO: GLVolume is transformed by common movement but we need move over surface
|
}
|
||||||
// so hide common dragging of object
|
|
||||||
m_parent.toggle_model_objects_visibility(false, m_volume->get_object(), gl_volume->instance_idx(), m_volume);
|
|
||||||
|
|
||||||
// Calculate temporary position
|
// Calculate temporary position
|
||||||
Transform3d object_trmat = m_raycast_manager.get_transformation(hit->tr_key);
|
Transform3d object_trmat = m_raycast_manager.get_transformation(hit->tr_key);
|
||||||
Transform3d trmat = create_transformation_onto_surface(hit->position, hit->normal);
|
Transform3d trmat = create_transformation_onto_surface(hit->position, hit->normal);
|
||||||
|
|
||||||
|
TextConfiguration &tc = *m_volume->text_configuration;
|
||||||
const FontProp& font_prop = tc.style.prop;
|
const FontProp& font_prop = tc.style.prop;
|
||||||
apply_transformation(font_prop, trmat);
|
apply_transformation(font_prop, trmat);
|
||||||
|
|
||||||
@ -537,49 +544,43 @@ bool GLGizmoEmboss::on_mouse_for_translate(const wxMouseEvent &mouse_event)
|
|||||||
if (tc.fix_3mf_tr.has_value())
|
if (tc.fix_3mf_tr.has_value())
|
||||||
trmat = trmat * (*tc.fix_3mf_tr);
|
trmat = trmat * (*tc.fix_3mf_tr);
|
||||||
|
|
||||||
// temp is in world coors
|
// volume transfomration in world coor
|
||||||
m_temp_transformation = object_trmat * trmat;
|
Transform3d world = object_trmat * trmat;
|
||||||
|
Transform3d volume_tr = m_surface_drag->instance_inv * world;
|
||||||
|
|
||||||
|
// Update transformation inside of instances
|
||||||
|
for (GLVolume *vol : m_parent.get_volumes().volumes) {
|
||||||
|
if (vol->object_idx() != m_surface_drag->gl_volume->object_idx() ||
|
||||||
|
vol->volume_idx() != m_surface_drag->gl_volume->volume_idx())
|
||||||
|
continue;
|
||||||
|
vol->set_volume_transformation(volume_tr);
|
||||||
|
}
|
||||||
|
|
||||||
// calculate scale
|
// calculate scale
|
||||||
calculate_scale();
|
calculate_scale();
|
||||||
|
|
||||||
|
m_parent.set_as_dirty();
|
||||||
|
return true;
|
||||||
} else if (mouse_event.LeftUp()) {
|
} else if (mouse_event.LeftUp()) {
|
||||||
// Added because of weird case after double click into scene
|
// write transformation from UI into model
|
||||||
// with Mesa driver OR on Linux
|
Selection &s = m_parent.get_selection();
|
||||||
if (!m_temp_transformation.has_value()) return false;
|
Selection::EMode mode = s.get_mode();
|
||||||
|
s.set_mode(Selection::EMode::Volume); // Want to move with all volumes inside of instances
|
||||||
int instance_idx = m_parent.get_selection().get_instance_idx();
|
m_parent.do_move(L("Surface move"));
|
||||||
const auto &instances = m_volume->get_object()->instances;
|
s.set_mode(mode); // revert setting of mode
|
||||||
if (instance_idx < 0 || instance_idx >= instances.size())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// Override of common transformation after draggig by set transformation into gl_volume
|
|
||||||
Transform3d volume_trmat =
|
|
||||||
instances[instance_idx]->get_matrix().inverse() *
|
|
||||||
*m_temp_transformation;
|
|
||||||
|
|
||||||
// ReWrite transformation inside of all instances
|
|
||||||
Geometry::Transformation transformation(volume_trmat);
|
|
||||||
for (GLVolume *vol : m_parent.get_volumes().volumes) {
|
|
||||||
if (vol->object_idx() != gl_volume->object_idx() ||
|
|
||||||
vol->volume_idx() != gl_volume->volume_idx())
|
|
||||||
continue;
|
|
||||||
vol->set_volume_transformation(transformation);
|
|
||||||
}
|
|
||||||
|
|
||||||
m_parent.toggle_model_objects_visibility(true);
|
|
||||||
// Apply temporary position
|
|
||||||
m_temp_transformation = {};
|
|
||||||
m_dragging_mouse_offset = {};
|
|
||||||
|
|
||||||
// Update surface by new position
|
// Update surface by new position
|
||||||
if (m_volume->text_configuration->style.prop.use_surface) {
|
if (m_volume->text_configuration->style.prop.use_surface)
|
||||||
// need actual position
|
|
||||||
m_volume->set_transformation(volume_trmat);
|
|
||||||
process();
|
process();
|
||||||
}
|
|
||||||
|
|
||||||
// calculate scale
|
// calculate scale
|
||||||
calculate_scale();
|
calculate_scale();
|
||||||
|
|
||||||
|
// allow moving and picking again
|
||||||
|
m_parent.enable_moving(true);
|
||||||
|
m_parent.enable_picking(true);
|
||||||
|
m_surface_drag.reset();
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -619,53 +620,10 @@ void GLGizmoEmboss::on_render() {
|
|||||||
Selection &selection = m_parent.get_selection();
|
Selection &selection = m_parent.get_selection();
|
||||||
if (selection.is_empty()) return;
|
if (selection.is_empty()) return;
|
||||||
|
|
||||||
if (m_temp_transformation.has_value()) {
|
|
||||||
// draw text volume on temporary position
|
|
||||||
GLVolume& gl_volume = *selection.get_volume(*selection.get_volume_idxs().begin());
|
|
||||||
GLShaderProgram* shader = wxGetApp().get_shader("gouraud_light");
|
|
||||||
shader->start_using();
|
|
||||||
|
|
||||||
const Camera& camera = wxGetApp().plater()->get_camera();
|
|
||||||
const Transform3d matrix = camera.get_view_matrix() * (*m_temp_transformation);
|
|
||||||
shader->set_uniform("view_model_matrix", matrix);
|
|
||||||
shader->set_uniform("projection_matrix", camera.get_projection_matrix());
|
|
||||||
shader->set_uniform("view_normal_matrix", (Matrix3d) (matrix).matrix().block(0, 0, 3, 3).inverse().transpose());
|
|
||||||
shader->set_uniform("emission_factor", 0.0f);
|
|
||||||
|
|
||||||
// dragging object must be selected so draw it with correct color
|
|
||||||
//auto color = gl_volume.color;
|
|
||||||
//auto color = gl_volume.render_color;
|
|
||||||
auto color = GLVolume::SELECTED_COLOR;
|
|
||||||
// Set transparent color for NEGATIVE_VOLUME & PARAMETER_MODIFIER
|
|
||||||
bool is_transparent = m_volume->type() != ModelVolumeType::MODEL_PART;
|
|
||||||
if (is_transparent) {
|
|
||||||
color.a(0.5f);
|
|
||||||
glsafe(::glEnable(GL_BLEND));
|
|
||||||
glsafe(::glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA));
|
|
||||||
}
|
|
||||||
|
|
||||||
bool is_left_handed = has_reflection(*m_temp_transformation);
|
|
||||||
if (is_left_handed)
|
|
||||||
glsafe(::glFrontFace(GL_CW));
|
|
||||||
|
|
||||||
glsafe(::glEnable(GL_DEPTH_TEST));
|
|
||||||
gl_volume.model.set_color(color);
|
|
||||||
gl_volume.model.render();
|
|
||||||
glsafe(::glDisable(GL_DEPTH_TEST));
|
|
||||||
|
|
||||||
// set it back to pevious state
|
|
||||||
if (is_left_handed)
|
|
||||||
glsafe(::glFrontFace(GL_CCW));
|
|
||||||
if (is_transparent)
|
|
||||||
glsafe(::glDisable(GL_BLEND));
|
|
||||||
|
|
||||||
shader->stop_using();
|
|
||||||
}
|
|
||||||
|
|
||||||
// prevent get local coordinate system on multi volumes
|
// prevent get local coordinate system on multi volumes
|
||||||
if (!selection.is_single_volume_or_modifier() &&
|
if (!selection.is_single_volume_or_modifier() &&
|
||||||
!selection.is_single_volume_instance()) return;
|
!selection.is_single_volume_instance()) return;
|
||||||
bool is_surface_dragging = m_temp_transformation.has_value();
|
bool is_surface_dragging = m_surface_drag.has_value();
|
||||||
bool is_parent_dragging = m_parent.is_mouse_dragging();
|
bool is_parent_dragging = m_parent.is_mouse_dragging();
|
||||||
// Do NOT render rotation grabbers when dragging object
|
// Do NOT render rotation grabbers when dragging object
|
||||||
bool is_rotate_by_grabbers = m_dragging;
|
bool is_rotate_by_grabbers = m_dragging;
|
||||||
@ -737,36 +695,27 @@ static void draw_mouse_offset(const std::optional<Vec2d> &offset)
|
|||||||
draw_list->AddLine(p1, p2, color, thickness);
|
draw_list->AddLine(p1, p2, color, thickness);
|
||||||
}
|
}
|
||||||
#endif // SHOW_OFFSET_DURING_DRAGGING
|
#endif // SHOW_OFFSET_DURING_DRAGGING
|
||||||
namespace priv {
|
|
||||||
static void draw_origin(const GLCanvas3D& canvas) {
|
|
||||||
auto draw_list = ImGui::GetOverlayDrawList();
|
|
||||||
const Selection &selection = canvas.get_selection();
|
|
||||||
Transform3d to_world = priv::world_matrix(selection);
|
|
||||||
Vec3d volume_zero = to_world * Vec3d::Zero();
|
|
||||||
|
|
||||||
const Camera &camera = wxGetApp().plater()->get_camera();
|
|
||||||
Point screen_coor = CameraUtils::project(camera, volume_zero);
|
|
||||||
ImVec2 center(screen_coor.x(), screen_coor.y());
|
|
||||||
float radius = 16.f;
|
|
||||||
ImU32 color = ImGui::GetColorU32(ImVec4(1.f, 1.f, 1.f, .75f));
|
|
||||||
|
|
||||||
int num_segments = 0;
|
namespace priv {
|
||||||
float thickness = 4.f;
|
static void draw_cross_hair(const ImVec2 &position,
|
||||||
draw_list->AddCircle(center, radius, color, num_segments, thickness);
|
float radius = 16.f,
|
||||||
|
ImU32 color = ImGui::GetColorU32(ImVec4(1.f, 1.f, 1.f, .75f)),
|
||||||
|
int num_segments = 0,
|
||||||
|
float thickness = 4.f);
|
||||||
|
} // namespace priv
|
||||||
|
|
||||||
|
void priv::draw_cross_hair(const ImVec2 &position, float radius, ImU32 color, int num_segments, float thickness)
|
||||||
|
{
|
||||||
|
auto draw_list = ImGui::GetOverlayDrawList();
|
||||||
|
draw_list->AddCircle(position, radius, color, num_segments, thickness);
|
||||||
auto dirs = {ImVec2{0, 1}, ImVec2{1, 0}, ImVec2{0, -1}, ImVec2{-1, 0}};
|
auto dirs = {ImVec2{0, 1}, ImVec2{1, 0}, ImVec2{0, -1}, ImVec2{-1, 0}};
|
||||||
for (const ImVec2 &dir : dirs) {
|
for (const ImVec2 &dir : dirs) {
|
||||||
ImVec2 start(
|
ImVec2 start(position.x + dir.x * 0.5 * radius, position.y + dir.y * 0.5 * radius);
|
||||||
center.x + dir.x * 0.5 * radius,
|
ImVec2 end(position.x + dir.x * 1.5 * radius, position.y + dir.y * 1.5 * radius);
|
||||||
center.y + dir.y * 0.5 * radius);
|
|
||||||
ImVec2 end(
|
|
||||||
center.x + dir.x * 1.5 * radius,
|
|
||||||
center.y + dir.y * 1.5 * radius);
|
|
||||||
draw_list->AddLine(start, end, color, thickness);
|
draw_list->AddLine(start, end, color, thickness);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace priv
|
|
||||||
|
|
||||||
void GLGizmoEmboss::on_render_input_window(float x, float y, float bottom_limit)
|
void GLGizmoEmboss::on_render_input_window(float x, float y, float bottom_limit)
|
||||||
{
|
{
|
||||||
if (!m_gui_cfg.has_value()) initialize();
|
if (!m_gui_cfg.has_value()) initialize();
|
||||||
@ -784,8 +733,13 @@ void GLGizmoEmboss::on_render_input_window(float x, float y, float bottom_limit)
|
|||||||
ImGui::PushStyleVar(ImGuiStyleVar_WindowMinSize, min_window_size);
|
ImGui::PushStyleVar(ImGuiStyleVar_WindowMinSize, min_window_size);
|
||||||
|
|
||||||
// Draw origin position of text during dragging
|
// Draw origin position of text during dragging
|
||||||
if (m_temp_transformation.has_value())
|
if (m_surface_drag.has_value()) {
|
||||||
priv::draw_origin(m_parent);
|
ImVec2 mouse_pos = ImGui::GetMousePos();
|
||||||
|
ImVec2 center(
|
||||||
|
mouse_pos.x + m_surface_drag->mouse_offset.x(),
|
||||||
|
mouse_pos.y + m_surface_drag->mouse_offset.y());
|
||||||
|
priv::draw_cross_hair(center);
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef SHOW_FINE_POSITION
|
#ifdef SHOW_FINE_POSITION
|
||||||
draw_fine_position(m_parent.get_selection(), m_parent.get_canvas_size(), min_window_size);
|
draw_fine_position(m_parent.get_selection(), m_parent.get_canvas_size(), min_window_size);
|
||||||
@ -1288,9 +1242,7 @@ bool GLGizmoEmboss::set_volume(ModelVolume *volume)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void GLGizmoEmboss::calculate_scale() {
|
void GLGizmoEmboss::calculate_scale() {
|
||||||
Transform3d to_world = m_temp_transformation.has_value()?
|
Transform3d to_world = m_parent.get_selection().get_first_volume()->world_matrix();
|
||||||
*m_temp_transformation :
|
|
||||||
priv::world_matrix(m_parent.get_selection());
|
|
||||||
auto to_world_linear = to_world.linear();
|
auto to_world_linear = to_world.linear();
|
||||||
auto calc = [&to_world_linear](const Vec3d &axe, std::optional<float>& scale)->bool {
|
auto calc = [&to_world_linear](const Vec3d &axe, std::optional<float>& scale)->bool {
|
||||||
Vec3d axe_world = to_world_linear * axe;
|
Vec3d axe_world = to_world_linear * axe;
|
||||||
|
@ -299,16 +299,29 @@ private:
|
|||||||
// Value is set only when dragging rotation to calculate actual angle
|
// Value is set only when dragging rotation to calculate actual angle
|
||||||
std::optional<float> m_rotate_start_angle;
|
std::optional<float> m_rotate_start_angle;
|
||||||
|
|
||||||
// when draging with text object hold screen offset of cursor from object center
|
// Data for drag&drop over surface with mouse
|
||||||
std::optional<Vec2d> m_dragging_mouse_offset;
|
struct SurfaceDrag
|
||||||
|
{
|
||||||
|
// hold screen coor offset of cursor from object center
|
||||||
|
Vec2d mouse_offset;
|
||||||
|
|
||||||
|
// Invers transformation of text volume instance
|
||||||
|
// Help convert world transformation to instance space
|
||||||
|
Transform3d instance_inv;
|
||||||
|
|
||||||
|
// Dragged gl volume
|
||||||
|
GLVolume *gl_volume;
|
||||||
|
|
||||||
|
// condition for raycaster
|
||||||
|
RaycastManager::AllowVolumes condition;
|
||||||
|
};
|
||||||
|
// Keep data about dragging only during drag&drop
|
||||||
|
std::optional<SurfaceDrag> m_surface_drag;
|
||||||
|
|
||||||
// TODO: it should be accessible by other gizmo too.
|
// TODO: it should be accessible by other gizmo too.
|
||||||
// May be move to plater?
|
// May be move to plater?
|
||||||
RaycastManager m_raycast_manager;
|
RaycastManager m_raycast_manager;
|
||||||
|
|
||||||
// Only when drag text object it stores world position
|
|
||||||
std::optional<Transform3d> m_temp_transformation;
|
|
||||||
|
|
||||||
// For text on scaled objects
|
// For text on scaled objects
|
||||||
std::optional<float> m_scale_height;
|
std::optional<float> m_scale_height;
|
||||||
std::optional<float> m_scale_depth;
|
std::optional<float> m_scale_depth;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user