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
2 changed files with 122 additions and 157 deletions
|
@ -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)
|
||||
{
|
||||
// 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
|
||||
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
|
||||
// IMPROVE: move to job, for big scene it slows down
|
||||
ModelObject *act_model_object = act_model_volume->get_object();
|
||||
m_raycast_manager.actualize(act_model_object, &condition);
|
||||
m_dragging_mouse_offset = priv::calc_mouse_to_center_text_offset(mouse_pos, *m_volume);
|
||||
// INFO: It could slows down for big objects
|
||||
// (may be move to thread and do not show drag until it finish)
|
||||
m_raycast_manager.actualize(m_volume->get_object(), &condition);
|
||||
|
||||
// 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)
|
||||
if (m_job_cancel != nullptr)
|
||||
m_job_cancel->store(true);
|
||||
return false;
|
||||
|
||||
m_parent.enable_moving(false);
|
||||
m_parent.enable_picking(false);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Dragging starts out of window
|
||||
if (!m_dragging_mouse_offset.has_value())
|
||||
if (!m_surface_drag.has_value())
|
||||
return false;
|
||||
|
||||
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();
|
||||
Vec2d offseted_mouse = mouse_pos + *m_dragging_mouse_offset;
|
||||
auto hit = m_raycast_manager.unproject(offseted_mouse, camera, &condition);
|
||||
if (!hit.has_value())
|
||||
return false;
|
||||
TextConfiguration &tc = *m_volume->text_configuration;
|
||||
// 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);
|
||||
auto hit = m_raycast_manager.unproject(offseted_mouse, camera, &m_surface_drag->condition);
|
||||
if (!hit.has_value()) {
|
||||
// cross hair need redraw
|
||||
m_parent.set_as_dirty();
|
||||
return true;
|
||||
}
|
||||
|
||||
// Calculate temporary position
|
||||
Transform3d object_trmat = m_raycast_manager.get_transformation(hit->tr_key);
|
||||
Transform3d trmat = create_transformation_onto_surface(hit->position, hit->normal);
|
||||
|
||||
TextConfiguration &tc = *m_volume->text_configuration;
|
||||
const FontProp& font_prop = tc.style.prop;
|
||||
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())
|
||||
trmat = trmat * (*tc.fix_3mf_tr);
|
||||
|
||||
// temp is in world coors
|
||||
m_temp_transformation = object_trmat * trmat;
|
||||
// volume transfomration in world coor
|
||||
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();
|
||||
|
||||
m_parent.set_as_dirty();
|
||||
return true;
|
||||
} else if (mouse_event.LeftUp()) {
|
||||
// Added because of weird case after double click into scene
|
||||
// with Mesa driver OR on Linux
|
||||
if (!m_temp_transformation.has_value()) return false;
|
||||
|
||||
int instance_idx = m_parent.get_selection().get_instance_idx();
|
||||
const auto &instances = m_volume->get_object()->instances;
|
||||
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 = {};
|
||||
// write transformation from UI into model
|
||||
Selection &s = m_parent.get_selection();
|
||||
Selection::EMode mode = s.get_mode();
|
||||
s.set_mode(Selection::EMode::Volume); // Want to move with all volumes inside of instances
|
||||
m_parent.do_move(L("Surface move"));
|
||||
s.set_mode(mode); // revert setting of mode
|
||||
|
||||
// Update surface by new position
|
||||
if (m_volume->text_configuration->style.prop.use_surface) {
|
||||
// need actual position
|
||||
m_volume->set_transformation(volume_trmat);
|
||||
if (m_volume->text_configuration->style.prop.use_surface)
|
||||
process();
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
@ -619,53 +620,10 @@ void GLGizmoEmboss::on_render() {
|
|||
Selection &selection = m_parent.get_selection();
|
||||
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
|
||||
if (!selection.is_single_volume_or_modifier() &&
|
||||
!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();
|
||||
// Do NOT render rotation grabbers when dragging object
|
||||
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);
|
||||
}
|
||||
#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;
|
||||
float thickness = 4.f;
|
||||
draw_list->AddCircle(center, radius, color, num_segments, thickness);
|
||||
namespace priv {
|
||||
static void draw_cross_hair(const ImVec2 &position,
|
||||
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}};
|
||||
for (const ImVec2 &dir : dirs) {
|
||||
ImVec2 start(
|
||||
center.x + dir.x * 0.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);
|
||||
ImVec2 start(position.x + dir.x * 0.5 * radius, position.y + dir.y * 0.5 * radius);
|
||||
ImVec2 end(position.x + dir.x * 1.5 * radius, position.y + dir.y * 1.5 * radius);
|
||||
draw_list->AddLine(start, end, color, thickness);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace priv
|
||||
|
||||
void GLGizmoEmboss::on_render_input_window(float x, float y, float bottom_limit)
|
||||
{
|
||||
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);
|
||||
|
||||
// Draw origin position of text during dragging
|
||||
if (m_temp_transformation.has_value())
|
||||
priv::draw_origin(m_parent);
|
||||
if (m_surface_drag.has_value()) {
|
||||
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
|
||||
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() {
|
||||
Transform3d to_world = m_temp_transformation.has_value()?
|
||||
*m_temp_transformation :
|
||||
priv::world_matrix(m_parent.get_selection());
|
||||
Transform3d to_world = m_parent.get_selection().get_first_volume()->world_matrix();
|
||||
auto to_world_linear = to_world.linear();
|
||||
auto calc = [&to_world_linear](const Vec3d &axe, std::optional<float>& scale)->bool {
|
||||
Vec3d axe_world = to_world_linear * axe;
|
||||
|
|
|
@ -299,16 +299,29 @@ private:
|
|||
// Value is set only when dragging rotation to calculate actual angle
|
||||
std::optional<float> m_rotate_start_angle;
|
||||
|
||||
// when draging with text object hold screen offset of cursor from object center
|
||||
std::optional<Vec2d> m_dragging_mouse_offset;
|
||||
// Data for drag&drop over surface with mouse
|
||||
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.
|
||||
// May be move to plater?
|
||||
RaycastManager m_raycast_manager;
|
||||
|
||||
// Only when drag text object it stores world position
|
||||
std::optional<Transform3d> m_temp_transformation;
|
||||
|
||||
// For text on scaled objects
|
||||
std::optional<float> m_scale_height;
|
||||
std::optional<float> m_scale_depth;
|
||||
|
|
Loading…
Reference in a new issue