/* Copyright (c) 2019-2022 Péter Magyar Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "mdi_gizmo.h" #include "../mesh_data_resource.h" #include "../nodes/mesh_data_instance.h" #include "./utilities/mdr_ed_mesh_decompose.h" #include "./utilities/mdr_ed_mesh_outline.h" #include "./utilities/mdr_ed_mesh_utils.h" #include "core/math/geometry.h" #include "editor/editor_node.h" #include "modules/mesh_utils/mesh_utils.h" #include "scene/3d/camera.h" void MDIGizmo::setup() { MeshDataInstance *mdi = Object::cast_to(get_spatial_node()); ERR_FAIL_COND(!mdi); mdi->connect("mesh_data_resource_changed", this, "on_mesh_data_resource_changed"); on_mesh_data_resource_changed(mdi->get_mesh_data()); } void MDIGizmo::set_editor_plugin(EditorPlugin *editor_plugin) { _editor_plugin = editor_plugin; _undo_redo = EditorNode::get_undo_redo(); } void MDIGizmo::set_handle(int index, Camera *camera, Vector2 point) { Vector2 relative = point - previous_point; if (!_handle_drag_op) { relative = Vector2(); _handle_drag_op = true; if (edit_mode == EditMode::EDIT_MODE_SCALE) { _drag_op_accumulator = Vector3(1, 1, 1); } else { _drag_op_accumulator = Vector3(); } _drag_op_accumulator_quat = Quat(); _drag_op_orig_verices = copy_mdr_verts_array(); setup_op_drag_indices(); _drag_op_pivot = get_drag_op_pivot(); } if (edit_mode == EditMode::EDIT_MODE_NONE) { return; } else if (edit_mode == EditMode::EDIT_MODE_TRANSLATE) { Vector3 ofs; ofs = camera->get_global_transform().basis.get_axis(0); if ((axis_constraint & AXIS_CONSTRAINT_X) != 0) { ofs.x *= relative.x * 0.01; } else { ofs.x = 0; } if ((axis_constraint & AXIS_CONSTRAINT_Y) != 0) { ofs.y = relative.y * -0.01; } else { ofs.y = 0; } if ((axis_constraint & AXIS_CONSTRAINT_Z) != 0) { ofs.z *= relative.x * 0.01; } else { ofs.z = 0; } _drag_op_accumulator += ofs; add_to_all_selected(_drag_op_accumulator); apply(); redraw(); } else if (edit_mode == EditMode::EDIT_MODE_SCALE) { float r = ((relative.x + relative.y) * 0.05); Vector3 vs; if ((axis_constraint & AXIS_CONSTRAINT_X) != 0) { vs.x = r; } if ((axis_constraint & AXIS_CONSTRAINT_Y) != 0) { vs.y = r; } if ((axis_constraint & AXIS_CONSTRAINT_Z) != 0) { vs.z = r; } _drag_op_accumulator += vs; Basis b = Basis().scaled(_drag_op_accumulator); Transform t = Transform(Basis(), _drag_op_pivot); t *= Transform(b, Vector3()); t *= Transform(Basis(), _drag_op_pivot).inverse(); mul_all_selected_with_transform(t); apply(); redraw(); } else if (edit_mode == EditMode::EDIT_MODE_ROTATE) { Quat yrot = Quat(Vector3(0, 1, 0), relative.x * 0.01); Quat xrot = Quat(camera->get_global_transform().basis.get_axis(0), relative.y * 0.01); _drag_op_accumulator_quat *= yrot; _drag_op_accumulator_quat *= xrot; _drag_op_accumulator_quat = _drag_op_accumulator_quat.normalized(); Basis b = Basis(_drag_op_accumulator_quat); Transform t = Transform(Basis(), _drag_op_pivot); t *= Transform(b, Vector3()); t *= Transform(Basis(), _drag_op_pivot).inverse(); mul_all_selected_with_transform(t); apply(); redraw(); } previous_point = point; } void MDIGizmo::redraw() { clear(); if (!_mdr.is_valid()) { return; } Array array = _mdr->get_array(); if (array.size() != ArrayMesh::ARRAY_MAX) { return; } if (!get_plugin().is_valid()) { return; } Ref handles_material = get_plugin()->get_material("handles", Ref(this)); Ref material = get_plugin()->get_material("main", Ref(this)); Ref seam_material = get_plugin()->get_material("seam", Ref(this)); _mesh_outline_generator->setup(_mdr); if (selection_mode == SELECTION_MODE_EDGE) { _mesh_outline_generator->generate_mark_edges(visual_indicator_outline, visual_indicator_handle); } else if (selection_mode == SELECTION_MODE_FACE) { _mesh_outline_generator->generate_mark_faces(visual_indicator_outline, visual_indicator_handle); } else { _mesh_outline_generator->generate(visual_indicator_outline, visual_indicator_handle); } if (visual_indicator_outline || visual_indicator_handle) { add_lines(_mesh_outline_generator->lines, material, false); } if (visual_indicator_seam) { add_lines(_mesh_outline_generator->seam_lines, seam_material, false); } if (_selected_points.size() > 0) { Vector vs; for (int i = 0; i < _selected_points.size(); ++i) { vs.push_back(_handle_points[_selected_points[i]]); } add_handles(vs, handles_material); } } void MDIGizmo::apply() { if (!_mdr.is_valid()) { return; } disable_change_event(); Array arrs = _mdr->get_array(); arrs[ArrayMesh::ARRAY_VERTEX] = _vertices; arrs[ArrayMesh::ARRAY_INDEX] = _indices; _mdr->set_array(arrs); enable_change_event(); } void MDIGizmo::select_all() { if (_selected_points.size() == _handle_points.size()) { return; } _selected_points.resize(_handle_points.size()); PoolIntArray::Write w = _selected_points.write(); for (int i = 0; i < _selected_points.size(); ++i) { w[i] = i; } redraw(); } bool MDIGizmo::selection_click(int index, Camera *camera, const Ref &event) { if (handle_selection_type == HANDLE_SELECTION_TYPE_FRONT) { return selection_click_select_front_or_back(index, camera, event); } else if (handle_selection_type == HANDLE_SELECTION_TYPE_BACK) { return selection_click_select_front_or_back(index, camera, event); } else { return selection_click_select_through(index, camera, event); } return false; } bool MDIGizmo::is_point_visible(Vector3 point_orig, Vector3 camera_pos, Transform gt) { Vector3 point = gt.xform(point_orig); // go from the given point to the origin (camera_pos -> camera) Vector3 dir = camera_pos - point; dir = dir.normalized(); // Might need to reduce z fighting //point += dir * 0.5 for (int i = 0; i < _indices.size(); i += 3) { int i0 = _indices[i]; int i1 = _indices[i + 1]; int i2 = _indices[i + 2]; Vector3 v0 = _vertices[i0]; Vector3 v1 = _vertices[i1]; Vector3 v2 = _vertices[i2]; v0 = gt.xform(v0); v1 = gt.xform(v1); v2 = gt.xform(v2); bool intersects = Geometry::ray_intersects_triangle(point, dir, v0, v1, v2); if (intersects) { return false; } } return true; } bool MDIGizmo::selection_click_select_front_or_back(int index, Camera *camera, const Ref &event) { Transform gt = get_spatial_node()->get_global_transform(); Vector3 ray_from = camera->get_global_transform().origin; Vector2 gpoint = event->get_position(); float grab_threshold = 8; // select vertex int closest_idx = -1; float closest_dist = 1e10; for (int i = 0; i < _handle_points.size(); ++i) { Vector3 vert_pos_3d = gt.xform(_handle_points[i]); Vector2 vert_pos_2d = camera->unproject_position(vert_pos_3d); float dist_3d = ray_from.distance_to(vert_pos_3d); float dist_2d = gpoint.distance_to(vert_pos_2d); if (dist_2d < grab_threshold && dist_3d < closest_dist) { bool point_visible = is_point_visible(_handle_points[i], ray_from, gt); if (handle_selection_type == HANDLE_SELECTION_TYPE_FRONT) { if (!point_visible) { continue; } } else if (handle_selection_type == HANDLE_SELECTION_TYPE_BACK) { if (point_visible) { continue; } } closest_dist = dist_3d; closest_idx = i; } } if (closest_idx >= 0) { for (int si = 0; si < _selected_points.size(); ++si) { if (_selected_points[si] == closest_idx) { if (event->get_alt() || event->get_control()) { _selected_points.remove(si); return true; } return false; } } if (event->get_alt() || event->get_control()) { return false; } if (event->get_shift()) { _selected_points.append(closest_idx); } else { // Select new point only _selected_points.resize(0); _selected_points.append(closest_idx); } apply(); redraw(); } else { // Don't unselect all if either control or shift is held down if (event->get_shift() || event->get_control() || event->get_alt()) { return false; } if (_selected_points.size() == 0) { return false; } //Unselect all _selected_points.resize(0); redraw(); } } bool MDIGizmo::selection_click_select_through(int index, Camera *camera, const Ref &event) { Transform gt = get_spatial_node()->get_global_transform(); Vector3 ray_from = camera->get_global_transform().origin; Vector2 gpoint = event->get_position(); float grab_threshold = 8; // select vertex int closest_idx = -1; float closest_dist = 1e10; for (int i = 0; i < _handle_points.size(); ++i) { Vector3 vert_pos_3d = gt.xform(_handle_points[i]); Vector2 vert_pos_2d = camera->unproject_position(vert_pos_3d); float dist_3d = ray_from.distance_to(vert_pos_3d); float dist_2d = gpoint.distance_to(vert_pos_2d); if (dist_2d < grab_threshold && dist_3d < closest_dist) { closest_dist = dist_3d; closest_idx = i; } } if (closest_idx >= 0) { for (int si = 0; si < _selected_points.size(); ++si) { if (_selected_points[si] == closest_idx) { if (event->get_alt() || event->get_control()) { _selected_points.remove(si); return true; } return false; } } if (event->get_alt() || event->get_control()) { return false; } if (event->get_shift()) { _selected_points.append(closest_idx); } else { // Select new point only _selected_points.resize(0); _selected_points.append(closest_idx); } apply(); redraw(); } else { // Don't unselect all if either control or shift is held down if (event->get_shift() || event->get_control() || event->get_alt()) { return false; } if (_selected_points.size() == 0) { return false; } //Unselect all _selected_points.resize(0); redraw(); } } void MDIGizmo::selection_drag(int index, Camera *camera, const Ref &event) { if (handle_selection_type == HANDLE_SELECTION_TYPE_FRONT) { selection_drag_rect_select_front_back(index, camera, event); } else if (handle_selection_type == HANDLE_SELECTION_TYPE_BACK) { selection_drag_rect_select_front_back(index, camera, event); } else { selection_drag_rect_select_through(index, camera, event); } } void MDIGizmo::selection_drag_rect_select_front_back(int index, Camera *camera, const Ref &event) { Transform gt = get_spatial_node()->get_global_transform(); Vector3 ray_from = camera->get_global_transform().origin; Vector2 mouse_pos = event->get_position(); Vector2 rect_size = _rect_drag_start_point - mouse_pos; rect_size.x = ABS(rect_size.x); rect_size.y = ABS(rect_size.y); Rect2 rect = Rect2(_rect_drag_start_point, rect_size); // This is needed so selection works even when you drag from bottom to top, and from right to left Vector2 rect_ofs = _rect_drag_start_point - mouse_pos; if (rect_ofs.x > 0) { rect.position.x -= rect_ofs.x; } if (rect_ofs.y > 0) { rect.position.y -= rect_ofs.y; } PoolIntArray selected; for (int i = 0; i < _handle_points.size(); ++i) { Vector3 vert_pos_3d = gt.xform(_handle_points[i]); Vector2 vert_pos_2d = camera->unproject_position(vert_pos_3d); if (rect.has_point(vert_pos_2d)) { bool point_visible = is_point_visible(_handle_points[i], ray_from, gt); if (handle_selection_type == HANDLE_SELECTION_TYPE_FRONT) { if (!point_visible) { continue; } } else if (handle_selection_type == HANDLE_SELECTION_TYPE_BACK) { if (point_visible) { continue; } } selected.push_back(i); } } if (event->get_alt() || event->get_control()) { PoolIntArray::Read r = selected.read(); for (int is = 0; is < selected.size(); ++is) { int isel = r[is]; for (int i = 0; i < _selected_points.size(); ++i) { if (_selected_points[i] == isel) { _selected_points.remove(i); break; } } } r.release(); redraw(); return; } if (event->get_shift()) { PoolIntArray::Read r = selected.read(); for (int is = 0; is < selected.size(); ++is) { int isel = r[is]; if (!pool_int_arr_contains(_selected_points, isel)) { _selected_points.push_back(isel); } } r.release(); redraw(); return; } _selected_points.resize(0); _selected_points.append_array(selected); redraw(); } void MDIGizmo::selection_drag_rect_select_through(int index, Camera *camera, const Ref &event) { /* var gt : Transform = get_spatial_node().global_transform var mouse_pos : Vector2 = event.get_position() var rect_size : Vector2 = _rect_drag_start_point - mouse_pos rect_size.x = abs(rect_size.x) rect_size.y = abs(rect_size.y) var rect : Rect2 = Rect2(_rect_drag_start_point, rect_size) # This is needed so selection works even when you drag from bottom to top, and from right to left var rect_ofs : Vector2 = _rect_drag_start_point - mouse_pos if rect_ofs.x > 0: rect.position.x -= rect_ofs.x if rect_ofs.y > 0: rect.position.y -= rect_ofs.y var selected : PoolIntArray = PoolIntArray() for i in range(_handle_points.size()): var vert_pos_3d : Vector3 = gt.xform(_handle_points[i]) var vert_pos_2d : Vector2 = camera.unproject_position(vert_pos_3d) if rect.has_point(vert_pos_2d): selected.push_back(i) if event.alt || event.control: for isel in selected: for i in range(_selected_points.size()): if _selected_points[i] == isel: _selected_points.remove(i) break redraw() return if event.shift: for isel in selected: if !pool_int_arr_contains(_selected_points, isel): _selected_points.push_back(isel) redraw() return _selected_points.resize(0) _selected_points.append_array(selected) redraw() */ } bool MDIGizmo::forward_spatial_gui_input(int index, Camera *camera, const Ref &event) { /* _last_known_camera_facing = camera.transform.basis.xform(Vector3(0, 0, -1)) if event is InputEventMouseButton: if event.get_button_index() == BUTTON_LEFT: if _handle_drag_op: if !event.is_pressed(): _handle_drag_op = false # If a handle was being dragged only run these if _mdr && _mdr.array.size() == ArrayMesh::ARRAY_MAX && _mdr.array[ArrayMesh::ARRAY_VERTEX] != null && _mdr.array[ArrayMesh::ARRAY_VERTEX].size() == _drag_op_orig_verices.size(): _undo_redo.create_action("Drag") _undo_redo.add_do_method(self, "apply_vertex_array", _mdr, _mdr.array[ArrayMesh::ARRAY_VERTEX]) _undo_redo.add_undo_method(self, "apply_vertex_array", _mdr, _drag_op_orig_verices) _undo_redo.commit_action() # Dont consume the event here, because the handles will get stuck # to the mouse pointer if we return true return false if !event.is_pressed(): # See whether we should check for a click or a selection box var mouse_pos : Vector2 = event.get_position() var rect_size : Vector2 = _rect_drag_start_point - mouse_pos rect_size.x = abs(rect_size.x) rect_size.y = abs(rect_size.y) var had_rect_drag : bool = false if rect_size.x > _rect_drag_min_ofset || rect_size.y > _rect_drag_min_ofset: had_rect_drag = true if !had_rect_drag: return selection_click(index, camera, event) else: selection_drag(index, camera, event) # Always return false here, so the drag rect thing disappears in the editor return false else: # event is pressed _rect_drag = true _rect_drag_start_point = event.get_position() return false */ } void MDIGizmo::add_to_all_selected(Vector3 ofs) { /* for i in _selected_points: var v : Vector3 = _handle_points[i] v += ofs _handle_points.set(i, v) for indx in _drag_op_indices: var v : Vector3 = _drag_op_orig_verices[indx] v += ofs _vertices.set(indx, v) */ } void MDIGizmo::mul_all_selected_with_basis(Basis b) { /* for i in _selected_points: var v : Vector3 = _handle_points[i] v = b * v _handle_points.set(i, v) for indx in _drag_op_indices: var v : Vector3 = _drag_op_orig_verices[indx] v = b * v _vertices.set(indx, v) */ } void MDIGizmo::mul_all_selected_with_transform(Transform t) { /* for i in _selected_points: var v : Vector3 = _handle_points[i] v = t * v _handle_points.set(i, v) for indx in _drag_op_indices: var v : Vector3 = _drag_op_orig_verices[indx] v = t * v _vertices.set(indx, v) */ } void MDIGizmo::mul_all_selected_with_transform_acc(Transform t) { /* for i in _selected_points: var v : Vector3 = _handle_points[i] v = t * v _handle_points.set(i, v) for indx in _drag_op_indices: var v : Vector3 = _vertices[indx] v = t * v _vertices.set(indx, v) */ } void MDIGizmo::set_translate() { edit_mode = EDIT_MODE_TRANSLATE; } void MDIGizmo::set_scale() { edit_mode = EDIT_MODE_SCALE; } void MDIGizmo::set_rotate() { edit_mode = EDIT_MODE_ROTATE; } void MDIGizmo::set_edit_mode(int em) { edit_mode = em; } void MDIGizmo::set_axis_x(bool on) { if (on) { axis_constraint |= AXIS_CONSTRAINT_X; } else { if ((axis_constraint & AXIS_CONSTRAINT_X) != 0) { axis_constraint ^= AXIS_CONSTRAINT_X; } } } void MDIGizmo::set_axis_y(bool on) { if (on) { axis_constraint |= AXIS_CONSTRAINT_Y; } else { if ((axis_constraint & AXIS_CONSTRAINT_Y) != 0) { axis_constraint ^= AXIS_CONSTRAINT_Y; } } } void MDIGizmo::set_axis_z(bool on) { if (on) { axis_constraint |= AXIS_CONSTRAINT_Z; } else { if ((axis_constraint & AXIS_CONSTRAINT_Z) != 0) { axis_constraint ^= AXIS_CONSTRAINT_Z; } } } void MDIGizmo::set_selection_mode_vertex() { if (selection_mode == SELECTION_MODE_VERTEX) { return; } selection_mode = SELECTION_MODE_VERTEX; _selected_points.resize(0); recalculate_handle_points(); redraw(); } void MDIGizmo::set_selection_mode_edge() { if (selection_mode == SELECTION_MODE_EDGE) { return; } selection_mode = SELECTION_MODE_EDGE; _selected_points.resize(0); recalculate_handle_points(); redraw(); } void MDIGizmo::set_selection_mode_face() { if (selection_mode == SELECTION_MODE_FACE) { return; } selection_mode = SELECTION_MODE_FACE; _selected_points.resize(0); recalculate_handle_points(); redraw(); } void MDIGizmo::_notification(int what) { /* if (what == NOTIFICATION_PREDELETE) { if (this != nullptr && get_plugin().is_valid()) { get_plugin()->unregister_gizmo(this); } }*/ } void MDIGizmo::recalculate_handle_points() { /* if !_mdr: _handle_points.resize(0) _handle_to_vertex_map.resize(0) return var mdr_arr : Array = _mdr.array if mdr_arr.size() != ArrayMesh::ARRAY_MAX || mdr_arr[ArrayMesh::ARRAY_VERTEX] == null || mdr_arr[ArrayMesh::ARRAY_VERTEX].size() == 0: _handle_points.resize(0) _handle_to_vertex_map.resize(0) return var arr : Array = Array() arr.resize(ArrayMesh::ARRAY_MAX) arr[ArrayMesh::ARRAY_VERTEX] = mdr_arr[ArrayMesh::ARRAY_VERTEX] arr[ArrayMesh::ARRAY_INDEX] = mdr_arr[ArrayMesh::ARRAY_INDEX] if selection_mode == SELECTION_MODE_VERTEX: var merged_arrays : Array = MeshUtils::merge_mesh_array(arr) _handle_points = merged_arrays[ArrayMesh::ARRAY_VERTEX] _handle_to_vertex_map = MeshDecompose.get_handle_vertex_to_vertex_map(mdr_arr, _handle_points) elif selection_mode == SELECTION_MODE_EDGE: var result : Array = MeshDecompose.get_handle_edge_to_vertex_map(arr) _handle_points = result[0] _handle_to_vertex_map = result[1] elif selection_mode == SELECTION_MODE_FACE: var result : Array = MeshDecompose.get_handle_face_to_vertex_map(arr) _handle_points = result[0] _handle_to_vertex_map = result[1] */ } void MDIGizmo::on_mesh_data_resource_changed(Ref mdr) { /* if _mdr: _mdr.disconnect("changed", self, "on_mdr_changed") _mdr = mdr if _mdr && _mdr.array.size() == ArrayMesh::ARRAY_MAX && _mdr.array[ArrayMesh::ARRAY_VERTEX] != null: _vertices = _mdr.array[ArrayMesh::ARRAY_VERTEX] _indices = _mdr.array[ArrayMesh::ARRAY_INDEX] else: _vertices.resize(0) _indices.resize(0) if _mdr: _mdr.connect("changed", self, "on_mdr_changed") recalculate_handle_points() redraw() */ } void MDIGizmo::on_mdr_changed() { if (!_mdr.is_valid()) { _vertices.resize(0); _indices.resize(0); recalculate_handle_points(); redraw(); } Array arr = _mdr->get_array(); if (arr.size() == ArrayMesh::ARRAY_MAX && !arr[ArrayMesh::ARRAY_VERTEX].is_null()) { _vertices = arr[ArrayMesh::ARRAY_VERTEX]; _indices = arr[ArrayMesh::ARRAY_INDEX]; } else { _vertices.resize(0); _indices.resize(0); } recalculate_handle_points(); redraw(); } void MDIGizmo::disable_change_event() { _mdr->disconnect("changed", this, "on_mdr_changed"); } void MDIGizmo::enable_change_event(bool update = true) { _mdr->connect("changed", this, "on_mdr_changed"); if (update) { on_mdr_changed(); } } void MDIGizmo::add_triangle() { if (_mdr.is_valid()) { Array orig_arr = copy_arrays(_mdr->get_array()); MDREDMeshUtils::add_triangle(_mdr); add_mesh_change_undo_redo(orig_arr, _mdr->get_array(), "Add Triangle"); } } void MDIGizmo::add_quad() { if (_mdr.is_valid()) { Array orig_arr = copy_arrays(_mdr->get_array()); MDREDMeshUtils::add_quad(_mdr); add_mesh_change_undo_redo(orig_arr, _mdr->get_array(), "Add Quad"); } } bool MDIGizmo::is_verts_equal(Vector3 v0, Vector3 v1) { return Math::is_equal_approx(v0.x, v1.x) && Math::is_equal_approx(v0.y, v1.y) && Math::is_equal_approx(v0.z, v1.z); } Vector3 MDIGizmo::find_other_vertex_for_edge(int edge, Vector3 v0) { PoolIntArray ps = _handle_to_vertex_map[edge]; Vector3 vert; for (int i = 0; i < ps.size(); ++i) { vert = _vertices[ps[i]]; if (!is_verts_equal(v0, vert)) { return vert; } } return v0; } Array MDIGizmo::split_edge_indices(int edge) { PoolIntArray ps = _handle_to_vertex_map[edge]; if (ps.size() == 0) { return Array(); } Vector3 v0 = _vertices[ps[0]]; PoolIntArray v0ei; v0ei.append(ps[0]); PoolIntArray v1ei; for (int i = 1; i < ps.size(); ++i) { Vector3 vert = _vertices[ps[i]]; if (is_verts_equal(v0, vert)) { v0ei.append(ps[i]); } else { v1ei.append(ps[i]); } } Array arr; arr.push_back(v0ei); arr.push_back(v1ei); return arr; } bool MDIGizmo::pool_int_arr_contains(PoolIntArray arr, int val) { PoolIntArray::Read r = arr.read(); for (int i = 0; i < arr.size(); ++i) { if (r[i] == val) { return true; } } return false; } PoolIntArray MDIGizmo::find_triangles_for_edge(int edge) { /* var eisarr : Array = split_edge_indices(edge) if eisarr.size() == 0: return PoolIntArray() # these should have the same size var v0ei : PoolIntArray = eisarr[0] var v1ei : PoolIntArray = eisarr[1] var res : PoolIntArray = PoolIntArray() for i in range(0, _indices.size(), 3): var i0 : int = _indices[i] var i1 : int = _indices[i + 1] var i2 : int = _indices[i + 2] if pool_int_arr_contains(v0ei, i0) || pool_int_arr_contains(v0ei, i1) || pool_int_arr_contains(v0ei, i2): if pool_int_arr_contains(v1ei, i0) || pool_int_arr_contains(v1ei, i1) || pool_int_arr_contains(v1ei, i2): res.append(i / 3) return res */ } int MDIGizmo::find_first_triangle_for_edge(int edge) { /* var eisarr : Array = split_edge_indices(edge) if eisarr.size() == 0: return -1 # these should have the same size var v0ei : PoolIntArray = eisarr[0] var v1ei : PoolIntArray = eisarr[1] var res : PoolIntArray = PoolIntArray() for i in range(0, _indices.size(), 3): var i0 : int = _indices[i] var i1 : int = _indices[i + 1] var i2 : int = _indices[i + 2] if pool_int_arr_contains(v0ei, i0) || pool_int_arr_contains(v0ei, i1) || pool_int_arr_contains(v0ei, i2): if pool_int_arr_contains(v1ei, i0) || pool_int_arr_contains(v1ei, i1) || pool_int_arr_contains(v1ei, i2): return i / 3 return -1 */ } void MDIGizmo::add_triangle_to_edge(int edge) { /* var triangle_index : int = find_first_triangle_for_edge(edge) var inds : int = triangle_index * 3 var ti0 : int = _indices[inds] var ti1 : int = _indices[inds + 1] var ti2 : int = _indices[inds + 2] var ps : PoolIntArray = _handle_to_vertex_map[edge] if ps.size() == 0: return var ei0 : int = 0 var ei1 : int = 0 var erefind : int = 0 if !pool_int_arr_contains(ps, ti0): ei0 = ti1 ei1 = ti2 erefind = ti0 elif !pool_int_arr_contains(ps, ti1): ei0 = ti0 ei1 = ti2 erefind = ti1 elif !pool_int_arr_contains(ps, ti2): ei0 = ti0 ei1 = ti1 erefind = ti2 var fo : Vector3 = MDREDMeshUtils::get_face_normal(_vertices[ti0], _vertices[ti1], _vertices[ti2]) var fn : Vector3 = MDREDMeshUtils::get_face_normal(_vertices[ei0], _vertices[ei1], _vertices[erefind]) if fo.dot(fn) < 0: var t : int = ei0 ei0 = ei1 ei1 = t MDREDMeshUtils::append_triangle_to_tri_edge(_mdr, _vertices[ei0], _vertices[ei1], _vertices[erefind]) */ } void MDIGizmo::add_quad_to_edge(int edge) { /* var triangle_index : int = find_first_triangle_for_edge(edge) var inds : int = triangle_index * 3 var ti0 : int = _indices[inds] var ti1 : int = _indices[inds + 1] var ti2 : int = _indices[inds + 2] var ps : PoolIntArray = _handle_to_vertex_map[edge] if ps.size() == 0: return var ei0 : int = 0 var ei1 : int = 0 var erefind : int = 0 if !pool_int_arr_contains(ps, ti0): ei0 = ti1 ei1 = ti2 erefind = ti0 elif !pool_int_arr_contains(ps, ti1): ei0 = ti0 ei1 = ti2 erefind = ti1 elif !pool_int_arr_contains(ps, ti2): ei0 = ti0 ei1 = ti1 erefind = ti2 var fo : Vector3 = MDREDMeshUtils::get_face_normal(_vertices[ti0], _vertices[ti1], _vertices[ti2]) var fn : Vector3 = MDREDMeshUtils::get_face_normal(_vertices[ei0], _vertices[ei1], _vertices[erefind]) if fo.dot(fn) < 0: var t : int = ei0 ei0 = ei1 ei1 = t MDREDMeshUtils::append_quad_to_tri_edge(_mdr, _vertices[ei0], _vertices[ei1], _vertices[erefind]) */ } void MDIGizmo::add_triangle_at() { /* if !_mdr: return if selection_mode == SELECTION_MODE_VERTEX: #todo pass elif selection_mode == SELECTION_MODE_EDGE: disable_change_event() var orig_arr = copy_arrays(_mdr.array) for sp in _selected_points: add_triangle_to_edge(sp) _selected_points.resize(0) add_mesh_change_undo_redo(orig_arr, _mdr.array, "Add Triangle At") enable_change_event() else: add_triangle() */ } void MDIGizmo::add_quad_at() { /* if !_mdr: return if selection_mode == SELECTION_MODE_VERTEX: #todo pass elif selection_mode == SELECTION_MODE_EDGE: disable_change_event() var orig_arr = copy_arrays(_mdr.array) for sp in _selected_points: add_quad_to_edge(sp) _selected_points.resize(0) add_mesh_change_undo_redo(orig_arr, _mdr.array, "Add Quad At") enable_change_event() else: add_quad() */ } void MDIGizmo::extrude() { /* if !_mdr: return if _mdr.array.size() != ArrayMesh::ARRAY_MAX || _mdr.array[ArrayMesh::ARRAY_VERTEX] == null: return if selection_mode == SELECTION_MODE_VERTEX: pass elif selection_mode == SELECTION_MODE_EDGE: disable_change_event() var orig_arr = copy_arrays(_mdr.array) var original_size : int = orig_arr[ArrayMesh::ARRAY_VERTEX].size() for sp in _selected_points: add_quad_to_edge(sp) var arr : Array = _mdr.array # Note: This algorithm depends heavily depends on the inner workings of add_quad_to_edge! var new_verts : PoolVector3Array = arr[ArrayMesh::ARRAY_VERTEX] # every 4 vertex is a quad # 1 ---- 2 # | | # | | # 0 ---- 3 # vertex 1, and 2 are the created new ones, 0, and 3 are duplicated from the original edge # Don't reallocate it every time var found_verts : PoolIntArray = PoolIntArray() # Go through every new created 0th vertex for i in range(original_size, new_verts.size(), 4): var v0 : Vector3 = new_verts[i] found_verts.resize(0) # Find a pair for it (has to be the 3th). for j in range(original_size, new_verts.size(), 4): if i == j: continue # +3 offset to 3rd vert var v3 : Vector3 = new_verts[j + 3] if is_verts_equal(v0, v3): # +2 offset to 2rd vert found_verts.append(j + 2) if found_verts.size() == 0: continue # Also append the first vertex index to simplify logic found_verts.append(i + 1) # Calculate avg var vavg : Vector3 = Vector3() for ind in found_verts: vavg += new_verts[ind] vavg /= found_verts.size() # set back for ind in found_verts: new_verts[ind] = vavg arr[ArrayMesh::ARRAY_VERTEX] = new_verts _mdr.array = arr _selected_points.resize(0) add_mesh_change_undo_redo(orig_arr, _mdr.array, "Extrude") enable_change_event() # The selection alo will take care of the duplicates var new_handle_points : PoolVector3Array = PoolVector3Array() for i in range(original_size, new_verts.size(), 4): var vavg : Vector3 = new_verts[i + 1] vavg += new_verts[i + 2] vavg /= 2 new_handle_points.append(vavg) select_handle_points(new_handle_points) else: add_quad() */ } void MDIGizmo::add_box() { /* if _mdr: var orig_arr = copy_arrays(_mdr.array) MDREDMeshUtils::add_box(_mdr) add_mesh_change_undo_redo(orig_arr, _mdr.array, "Add Box") */ } void MDIGizmo::split() { } void MDIGizmo::disconnect_action() { } int MDIGizmo::get_first_triangle_index_for_vertex(int indx) { /* for i in range(_indices.size()): if _indices[i] == indx: return i / 3 return -1 */ } void MDIGizmo::create_face() { /* if !_mdr: return if _selected_points.size() <= 2: return if selection_mode == SELECTION_MODE_VERTEX: disable_change_event() var orig_arr = copy_arrays(_mdr.array) var points : PoolVector3Array = PoolVector3Array() for sp in _selected_points: points.push_back(_handle_points[sp]) if points.size() == 3: var i0 : int = _handle_to_vertex_map[_selected_points[0]][0] var i1 : int = _handle_to_vertex_map[_selected_points[1]][0] var i2 : int = _handle_to_vertex_map[_selected_points[2]][0] var v0 : Vector3 = points[0] var v1 : Vector3 = points[1] var v2 : Vector3 = points[2] var tfn : Vector3 = Vector3() if orig_arr[ArrayMesh::ARRAY_NORMAL] != null && orig_arr[ArrayMesh::ARRAY_NORMAL].size() == orig_arr[ArrayMesh::ARRAY_VERTEX].size(): var normals : PoolVector3Array = orig_arr[ArrayMesh::ARRAY_NORMAL] tfn += normals[i0] tfn += normals[i1] tfn += normals[i2] tfn /= 3 tfn = tfn.normalized() else: tfn = MDREDMeshUtils::get_face_normal(_vertices[i0], _vertices[i1], _vertices[i2]) var flip : bool = !MDREDMeshUtils::should_triangle_flip(v0, v1, v2, tfn) MDREDMeshUtils::add_triangle_at(_mdr, v0, v1, v2, flip) add_mesh_change_undo_redo(orig_arr, _mdr.array, "Create Face") enable_change_event() return if !MDREDMeshUtils::add_triangulated_mesh_from_points_delaunay(_mdr, points, _last_known_camera_facing): enable_change_event() return add_mesh_change_undo_redo(orig_arr, _mdr.array, "Create Face") #_selected_points.resize(0) enable_change_event() elif selection_mode == SELECTION_MODE_EDGE: pass elif selection_mode == SELECTION_MODE_FACE: pass */ } Array MDIGizmo::split_face_indices(int face) { /* var ps : PoolIntArray = _handle_to_vertex_map[face] if ps.size() == 0: return [ ] var v0 : Vector3 = _vertices[ps[0]] var v1 : Vector3 = Vector3() var v1found : bool = false var v0ei : PoolIntArray = PoolIntArray() v0ei.append(ps[0]) var v1ei : PoolIntArray = PoolIntArray() var v2ei : PoolIntArray = PoolIntArray() for i in range(1, ps.size()): var vert : Vector3 = _vertices[ps[i]] if is_verts_equal(v0, vert): v0ei.append(ps[i]) else: if v1found: if is_verts_equal(v1, vert): v1ei.append(ps[i]) else: v2ei.append(ps[i]) else: v1found = true v1 = _vertices[ps[i]] v1ei.append(ps[i]) return [ v0ei, v1ei, v2ei ] */ } int MDIGizmo::find_first_triangle_index_for_face(int face) { /* var split_indices_arr : Array = split_face_indices(face) if split_indices_arr.size() == 0: return -1 var v0ei : PoolIntArray = split_indices_arr[0] var v1ei : PoolIntArray = split_indices_arr[1] var v2ei : PoolIntArray = split_indices_arr[2] var tri_index : int = -1 for i in range(0, _indices.size(), 3): var i0 : int = _indices[i] var i1 : int = _indices[i + 1] var i2 : int = _indices[i + 2] if pool_int_arr_contains(v0ei, i0) || pool_int_arr_contains(v0ei, i1) || pool_int_arr_contains(v0ei, i2): if pool_int_arr_contains(v1ei, i0) || pool_int_arr_contains(v1ei, i1) || pool_int_arr_contains(v1ei, i2): if pool_int_arr_contains(v2ei, i0) || pool_int_arr_contains(v2ei, i1) || pool_int_arr_contains(v2ei, i2): return i / 3 return -1 */ } void MDIGizmo::delete_selected() { /* if !_mdr: return if _selected_points.size() == 0: return if selection_mode == SELECTION_MODE_VERTEX: #todo pass elif selection_mode == SELECTION_MODE_EDGE: #todo pass elif selection_mode == SELECTION_MODE_FACE: disable_change_event() var orig_arr = copy_arrays(_mdr.array) var triangle_indexes : Array = Array() for sp in _selected_points: var triangle_index : int = find_first_triangle_index_for_face(sp) triangle_indexes.append(triangle_index) #delete in reverse triangle index order triangle_indexes.sort() for i in range(triangle_indexes.size() - 1, -1, -1): var triangle_index : int = triangle_indexes[i] MDREDMeshUtils::remove_triangle(_mdr, triangle_index) add_mesh_change_undo_redo(orig_arr, _mdr.array, "Delete") _selected_points.resize(0) enable_change_event() */ } void MDIGizmo::generate_normals() { /* if !_mdr: return var mdr_arr : Array = _mdr.array if mdr_arr.size() != ArrayMesh::ARRAY_MAX || mdr_arr[ArrayMesh::ARRAY_VERTEX] == null || mdr_arr[ArrayMesh::ARRAY_VERTEX].size() == 0: return disable_change_event() var orig_arr = copy_arrays(_mdr.array) var orig_seams = copy_pool_int_array(_mdr.seams) var seam_points : PoolVector3Array = MDREDMeshUtils::seams_to_points(_mdr) MDREDMeshUtils::generate_normals_mdr(_mdr) MDREDMeshUtils::points_to_seams(_mdr, seam_points) add_mesh_seam_change_undo_redo(orig_arr, orig_seams, _mdr.array, _mdr.seams, "Generate Normals") enable_change_event() */ } void MDIGizmo::generate_tangents() { /* if !_mdr: return var mdr_arr : Array = _mdr.array if mdr_arr.size() != ArrayMesh::ARRAY_MAX || mdr_arr[ArrayMesh::ARRAY_VERTEX] == null || mdr_arr[ArrayMesh::ARRAY_VERTEX].size() == 0: return disable_change_event() var orig_arr = copy_arrays(_mdr.array) var orig_seams = copy_pool_int_array(_mdr.seams) var seam_points : PoolVector3Array = MDREDMeshUtils::seams_to_points(_mdr) MDREDMeshUtils::generate_tangents(_mdr) MDREDMeshUtils::points_to_seams(_mdr, seam_points) add_mesh_seam_change_undo_redo(orig_arr, orig_seams, _mdr.array, _mdr.seams, "Generate Tangents") enable_change_event() */ } void MDIGizmo::remove_doubles() { /* if !_mdr: return var mdr_arr : Array = _mdr.array if mdr_arr.size() != ArrayMesh::ARRAY_MAX || mdr_arr[ArrayMesh::ARRAY_VERTEX] == null || mdr_arr[ArrayMesh::ARRAY_VERTEX].size() == 0: return disable_change_event() var orig_arr = copy_arrays(_mdr.array) var orig_seams = copy_pool_int_array(_mdr.seams) var seam_points : PoolVector3Array = MDREDMeshUtils::seams_to_points(_mdr) var merged_arrays : Array = MeshUtils::remove_doubles(mdr_arr) _mdr.array = merged_arrays MDREDMeshUtils::points_to_seams(_mdr, seam_points) add_mesh_seam_change_undo_redo(orig_arr, orig_seams, _mdr.array, _mdr.seams, "Remove Doubles") enable_change_event() */ } void MDIGizmo::merge_optimize() { /* if !_mdr: return var mdr_arr : Array = _mdr.array if mdr_arr.size() != ArrayMesh::ARRAY_MAX || mdr_arr[ArrayMesh::ARRAY_VERTEX] == null || mdr_arr[ArrayMesh::ARRAY_VERTEX].size() == 0: return disable_change_event() var orig_arr = copy_arrays(_mdr.array) var orig_seams = copy_pool_int_array(_mdr.seams) var seam_points : PoolVector3Array = MDREDMeshUtils::seams_to_points(_mdr) var merged_arrays : Array = MeshUtils::merge_mesh_array(mdr_arr) _mdr.array = merged_arrays MDREDMeshUtils::points_to_seams(_mdr, seam_points) add_mesh_seam_change_undo_redo(orig_arr, orig_seams, _mdr.array, _mdr.seams, "Merge Optimize") enable_change_event() */ } void MDIGizmo::connect_to_first_selected() { /* if !_mdr: return if _selected_points.size() < 2: return var mdr_arr : Array = _mdr.array if mdr_arr.size() != ArrayMesh::ARRAY_MAX || mdr_arr[ArrayMesh::ARRAY_VERTEX] == null || mdr_arr[ArrayMesh::ARRAY_VERTEX].size() == 0: return disable_change_event() var orig_arr = copy_arrays(_mdr.array) var vertices : PoolVector3Array = mdr_arr[ArrayMesh::ARRAY_VERTEX] if selection_mode == SELECTION_MODE_VERTEX: var mpos : Vector3 = _handle_points[_selected_points[0]] for i in range(1, _selected_points.size()): var ps : PoolIntArray = _handle_to_vertex_map[_selected_points[i]] for indx in ps: vertices[indx] = mpos _selected_points.resize(0) mdr_arr[ArrayMesh::ARRAY_VERTEX] = vertices _mdr.array = mdr_arr add_mesh_change_undo_redo(orig_arr, _mdr.array, "Connect to first selected") enable_change_event() elif selection_mode == SELECTION_MODE_EDGE: pass elif selection_mode == SELECTION_MODE_FACE: pass */ } void MDIGizmo::connect_to_avg() { /* if !_mdr: return if _selected_points.size() < 2: return var mdr_arr : Array = _mdr.array if mdr_arr.size() != ArrayMesh::ARRAY_MAX || mdr_arr[ArrayMesh::ARRAY_VERTEX] == null || mdr_arr[ArrayMesh::ARRAY_VERTEX].size() == 0: return disable_change_event() var orig_arr = copy_arrays(_mdr.array) var vertices : PoolVector3Array = mdr_arr[ArrayMesh::ARRAY_VERTEX] if selection_mode == SELECTION_MODE_VERTEX: var mpos : Vector3 = Vector3() for sp in _selected_points: mpos += _handle_points[sp] mpos /= _selected_points.size() for i in range(_selected_points.size()): var ps : PoolIntArray = _handle_to_vertex_map[_selected_points[i]] for indx in ps: vertices[indx] = mpos _selected_points.resize(0) mdr_arr[ArrayMesh::ARRAY_VERTEX] = vertices _mdr.array = mdr_arr add_mesh_change_undo_redo(orig_arr, _mdr.array, "Connect to average") enable_change_event() elif selection_mode == SELECTION_MODE_EDGE: pass elif selection_mode == SELECTION_MODE_FACE: pass */ } void MDIGizmo::connect_to_last_selected() { /* if !_mdr: return if _selected_points.size() < 2: return var orig_arr = copy_arrays(_mdr.array) var mdr_arr : Array = _mdr.array if mdr_arr.size() != ArrayMesh::ARRAY_MAX || mdr_arr[ArrayMesh::ARRAY_VERTEX] == null || mdr_arr[ArrayMesh::ARRAY_VERTEX].size() == 0: return disable_change_event() var vertices : PoolVector3Array = mdr_arr[ArrayMesh::ARRAY_VERTEX] if selection_mode == SELECTION_MODE_VERTEX: var mpos : Vector3 = _handle_points[_selected_points[_selected_points.size() - 1]] for i in range(0, _selected_points.size() - 1): var ps : PoolIntArray = _handle_to_vertex_map[_selected_points[i]] for indx in ps: vertices[indx] = mpos _selected_points.resize(0) mdr_arr[ArrayMesh::ARRAY_VERTEX] = vertices _mdr.array = mdr_arr add_mesh_change_undo_redo(orig_arr, _mdr.array, "Connect to last selected") enable_change_event() elif selection_mode == SELECTION_MODE_EDGE: pass elif selection_mode == SELECTION_MODE_FACE: pass */ } PoolIntArray MDIGizmo::get_first_index_pair_for_edge(int edge) { /* var ret : PoolIntArray = PoolIntArray() var eisarr : Array = split_edge_indices(edge) if eisarr.size() == 0: return ret # these should have the same size var v0ei : PoolIntArray = eisarr[0] var v1ei : PoolIntArray = eisarr[1] var res : PoolIntArray = PoolIntArray() for i in range(0, _indices.size(), 3): var i0 : int = _indices[i] var i1 : int = _indices[i + 1] var i2 : int = _indices[i + 2] if pool_int_arr_contains(v0ei, i0) || pool_int_arr_contains(v0ei, i1) || pool_int_arr_contains(v0ei, i2): if pool_int_arr_contains(v1ei, i0) || pool_int_arr_contains(v1ei, i1) || pool_int_arr_contains(v1ei, i2): if pool_int_arr_contains(v0ei, i0): ret.push_back(i0) elif pool_int_arr_contains(v0ei, i1): ret.push_back(i1) elif pool_int_arr_contains(v0ei, i2): ret.push_back(i2) if pool_int_arr_contains(v1ei, i0): ret.push_back(i0) elif pool_int_arr_contains(v1ei, i1): ret.push_back(i1) elif pool_int_arr_contains(v1ei, i2): ret.push_back(i2) return ret return ret */ } PoolIntArray MDIGizmo::get_all_index_pairs_for_edge(int edge) { /* var ret : PoolIntArray = PoolIntArray() var eisarr : Array = split_edge_indices(edge) if eisarr.size() == 0: return ret # these should have the same size var v0ei : PoolIntArray = eisarr[0] var v1ei : PoolIntArray = eisarr[1] var res : PoolIntArray = PoolIntArray() for i in range(0, _indices.size(), 3): var i0 : int = _indices[i] var i1 : int = _indices[i + 1] var i2 : int = _indices[i + 2] if pool_int_arr_contains(v0ei, i0) || pool_int_arr_contains(v0ei, i1) || pool_int_arr_contains(v0ei, i2): if pool_int_arr_contains(v1ei, i0) || pool_int_arr_contains(v1ei, i1) || pool_int_arr_contains(v1ei, i2): if pool_int_arr_contains(v0ei, i0): ret.push_back(i0) elif pool_int_arr_contains(v0ei, i1): ret.push_back(i1) elif pool_int_arr_contains(v0ei, i2): ret.push_back(i2) if pool_int_arr_contains(v1ei, i0): ret.push_back(i0) elif pool_int_arr_contains(v1ei, i1): ret.push_back(i1) elif pool_int_arr_contains(v1ei, i2): ret.push_back(i2) return ret */ } void MDIGizmo::mark_seam() { /* if !_mdr: return if _selected_points.size() == 0: return if selection_mode == SELECTION_MODE_VERTEX: pass elif selection_mode == SELECTION_MODE_EDGE: disable_change_event() var prev_seams : PoolIntArray = copy_pool_int_array(_mdr.seams) for se in _selected_points: var eis : PoolIntArray = MDREDMeshUtils::order_seam_indices(get_first_index_pair_for_edge(se)) if eis.size() == 0: continue MDREDMeshUtils::add_seam(_mdr, eis[0], eis[1]) _undo_redo.create_action("mark_seam") _undo_redo.add_do_method(self, "set_seam", _mdr, copy_pool_int_array(_mdr.seams)) _undo_redo.add_undo_method(self, "set_seam", _mdr, prev_seams) _undo_redo.commit_action() enable_change_event() elif selection_mode == SELECTION_MODE_FACE: pass */ } void MDIGizmo::unmark_seam() { /* if !_mdr: return if _selected_points.size() == 0: return if selection_mode == SELECTION_MODE_VERTEX: pass elif selection_mode == SELECTION_MODE_EDGE: disable_change_event() var prev_seams : PoolIntArray = copy_pool_int_array(_mdr.seams) for se in _selected_points: var eis : PoolIntArray = MDREDMeshUtils::order_seam_indices(get_all_index_pairs_for_edge(se)) if eis.size() == 0: continue MDREDMeshUtils::remove_seam(_mdr, eis[0], eis[1]) _undo_redo.create_action("unmark_seam") _undo_redo.add_do_method(self, "set_seam", _mdr, copy_pool_int_array(_mdr.seams)) _undo_redo.add_undo_method(self, "set_seam", _mdr, prev_seams) _undo_redo.commit_action() enable_change_event() elif selection_mode == SELECTION_MODE_FACE: pass */ } void MDIGizmo::set_seam(Ref mdr, PoolIntArray arr) { /* mdr.seams = arr */ } void MDIGizmo::apply_seam() { /* if !_mdr: return disable_change_event() var orig_arr : Array = copy_arrays(_mdr.array) MDREDMeshUtils::apply_seam(_mdr) add_mesh_change_undo_redo(orig_arr, _mdr.array, "apply_seam") enable_change_event() */ } void MDIGizmo::clean_mesh() { /* if !_mdr: return var arrays : Array = _mdr.array if arrays.size() != ArrayMesh::ARRAY_MAX: return arrays if arrays[ArrayMesh::ARRAY_VERTEX] == null || arrays[ArrayMesh::ARRAY_INDEX] == null: return arrays var old_vert_size : int = arrays[ArrayMesh::ARRAY_VERTEX].size() disable_change_event() var orig_arr : Array = copy_arrays(arrays) arrays = MDREDMeshUtils::remove_used_vertices(arrays) var new_vert_size : int = arrays[ArrayMesh::ARRAY_VERTEX].size() add_mesh_change_undo_redo(orig_arr, arrays, "clean_mesh") enable_change_event() var d : int = old_vert_size - new_vert_size print("MDRED: Removed " + str(d) + " unused vertices.") */ } void MDIGizmo::uv_unwrap() { if (!_mdr.is_valid()) { return; } Array mdr_arr = _mdr->get_array(); if (mdr_arr.size() != ArrayMesh::ARRAY_MAX || mdr_arr[ArrayMesh::ARRAY_VERTEX].is_null()) { return; } PoolVector3Array verts = mdr_arr[ArrayMesh::ARRAY_VERTEX]; if (verts.size() == 0) { return; } disable_change_event(); PoolVector2Array uvs = MeshUtils::get_singleton()->uv_unwrap(mdr_arr); if (uvs.size() != verts.size()) { ERR_PRINT("Error: Could not unwrap mesh!"); enable_change_event(false); return; } Array orig_arr = copy_arrays(mdr_arr); mdr_arr[ArrayMesh::ARRAY_TEX_UV] = uvs; add_mesh_change_undo_redo(orig_arr, mdr_arr, "uv_unwrap"); enable_change_event(); } void MDIGizmo::flip_selected_faces() { if (!_mdr.is_valid()) { return; } if (_selected_points.size() == 0) { return; } if (selection_mode == SELECTION_MODE_VERTEX) { } else if (selection_mode == SELECTION_MODE_EDGE) { } else if (selection_mode == SELECTION_MODE_FACE) { disable_change_event(); Array orig_arr = copy_arrays(_mdr->get_array()); PoolIntArray::Read r = _selected_points.read(); for (int i = 0; i < _selected_points.size(); ++i) { int sp = r[i]; int triangle_index = find_first_triangle_index_for_face(sp); MDREDMeshUtils::flip_triangle_ti(_mdr, triangle_index); } add_mesh_change_undo_redo(orig_arr, _mdr->get_array(), "Flip Faces"); enable_change_event(); } } void MDIGizmo::add_mesh_change_undo_redo(Array orig_arr, Array new_arr, String action_name) { _undo_redo->create_action(action_name); Array nac = copy_arrays(new_arr); _undo_redo->add_do_method(this, "apply_mesh_change", _mdr, nac); _undo_redo->add_undo_method(this, "apply_mesh_change", _mdr, orig_arr); _undo_redo->commit_action(); } void MDIGizmo::add_mesh_seam_change_undo_redo(Array orig_arr, PoolIntArray orig_seams, Array new_arr, PoolIntArray new_seams, String action_name) { _undo_redo->create_action(action_name); Array nac = copy_arrays(new_arr); _undo_redo->add_do_method(this, "apply_mesh_change", _mdr, nac); _undo_redo->add_undo_method(this, "apply_mesh_change", _mdr, orig_arr); _undo_redo->add_do_method(this, "set_seam", _mdr, copy_pool_int_array(new_seams)); _undo_redo->add_undo_method(this, "set_seam", _mdr, orig_seams); _undo_redo->commit_action(); } void MDIGizmo::apply_mesh_change(Ref mdr, Array arr) { if (!mdr.is_valid()) { return; } mdr->set_array(copy_arrays(arr)); } void MDIGizmo::apply_vertex_array(Ref mdr, PoolVector3Array verts) { if (!mdr.is_valid()) { return; } Array mdr_arr = mdr->get_array(); if (mdr_arr.size() != ArrayMesh::ARRAY_MAX) { return; } mdr_arr[ArrayMesh::ARRAY_VERTEX] = verts; mdr->set_array(mdr_arr); } Array MDIGizmo::copy_arrays(Array arr) { return arr.duplicate(true); } PoolIntArray MDIGizmo::copy_pool_int_array(PoolIntArray pia) { PoolIntArray ret; ret.resize(pia.size()); PoolIntArray::Read r = pia.read(); PoolIntArray::Write w = ret.write(); for (int i = 0; i < pia.size(); ++i) { w[i] = r[i]; } r.release(); w.release(); return ret; } PoolVector3Array MDIGizmo::copy_mdr_verts_array() { PoolVector3Array ret; if (!_mdr.is_valid()) { return ret; } Array mdr_arr = _mdr->get_array(); if (mdr_arr.size() != ArrayMesh::ARRAY_MAX || mdr_arr[ArrayMesh::ARRAY_VERTEX].is_null()) { return ret; } PoolVector3Array vertices = mdr_arr[ArrayMesh::ARRAY_VERTEX]; ret.append_array(vertices); return ret; } void MDIGizmo::setup_op_drag_indices() { _drag_op_indices.resize(0); PoolIntArray::Read r = _selected_points.read(); for (int i = 0; i < _selected_points.size(); ++i) { int sp = r[i]; PoolIntArray pi = _handle_to_vertex_map[sp]; PoolIntArray::Read pir = pi.read(); for (int j = 0; j < pi.size(); ++j) { int indx = pir[j]; if (!pool_int_arr_contains(_drag_op_indices, indx)) { _drag_op_indices.append(indx); } } pir.release(); } } Vector3 MDIGizmo::get_drag_op_pivot() { if (pivot_type == PIVOT_TYPE_AVERAGED) { Vector3 avg = Vector3(); PoolIntArray::Read r = _drag_op_indices.read(); for (int i = 0; i < _drag_op_indices.size(); ++i) { avg += _vertices[r[i]]; } r.release(); avg /= _drag_op_indices.size(); return avg; } else if (pivot_type == PIVOT_TYPE_MDI_ORIGIN) { return Vector3(); } else if (pivot_type == PIVOT_TYPE_WORLD_ORIGIN) { return get_spatial_node()->to_local(Vector3()); } return Vector3(); } void MDIGizmo::select_handle_points(PoolVector3Array points) { _selected_points.resize(0); PoolVector3Array::Read r = points.read(); for (int ip = 0; ip < points.size(); ++ip) { Vector3 p = r[ip]; PoolVector3Array::Read hpr = _handle_points.read(); for (int i = 0; i < _handle_points.size(); ++i) { if (is_verts_equal(p, hpr[i])) { if (!pool_int_arr_contains(_selected_points, i)) { _selected_points.push_back(i); } } } hpr.release(); } redraw(); } void MDIGizmo::set_pivot_averaged() { pivot_type = PIVOT_TYPE_AVERAGED; } void MDIGizmo::set_pivot_mdi_origin() { pivot_type = PIVOT_TYPE_MDI_ORIGIN; } void MDIGizmo::set_pivot_world_origin() { pivot_type = PIVOT_TYPE_WORLD_ORIGIN; } void MDIGizmo::transfer_state_from(const Ref &other) { edit_mode = other->edit_mode; pivot_type = other->pivot_type; axis_constraint = other->axis_constraint; selection_mode = other->selection_mode; handle_selection_type = other->handle_selection_type; visual_indicator_outline = other->visual_indicator_outline; visual_indicator_seam = other->visual_indicator_seam; visual_indicator_handle = other->visual_indicator_handle; } void MDIGizmo::visual_indicator_outline_set(bool on) { visual_indicator_outline = on; redraw(); } void MDIGizmo::visual_indicator_seam_set(bool on) { visual_indicator_seam = on; redraw(); } void MDIGizmo::visual_indicator_handle_set(bool on) { visual_indicator_handle = on; redraw(); } void MDIGizmo::handle_selection_type_front() { handle_selection_type = HANDLE_SELECTION_TYPE_FRONT; } void MDIGizmo::handle_selection_type_back() { handle_selection_type = HANDLE_SELECTION_TYPE_BACK; } void MDIGizmo::handle_selection_type_all() { handle_selection_type = HANDLE_SELECTION_TYPE_ALL; } MDIGizmo::MDIGizmo() { gizmo_size = 3.0; edit_mode = EDIT_MODE_TRANSLATE; pivot_type = PIVOT_TYPE_AVERAGED; axis_constraint = AXIS_CONSTRAINT_X | AXIS_CONSTRAINT_Y | AXIS_CONSTRAINT_Z; selection_mode = SELECTION_MODE_VERTEX; handle_selection_type = HANDLE_SELECTION_TYPE_FRONT; visual_indicator_outline = true; visual_indicator_seam = true; visual_indicator_handle = true; _last_known_camera_facing = Vector3(0, 0, -1); _rect_drag = false; _rect_drag_min_ofset = 10; _mesh_outline_generator.instance(); _handle_drag_op = false; _editor_plugin = nullptr; _undo_redo = nullptr; } MDIGizmo::~MDIGizmo() { } void MDIGizmo::_bind_methods() { }