Repository: godotengine/godot
File: editor/plugins/path_3d_editor_plugin.cpp (C++)

Code before:
void Path3DGizmo::_update_transform_gizmo() {
	Node3DEditor::get_singleton()->update_transform_gizmo();
}

Path3DGizmo::Path3DGizmo(Path3D *p_path, float p_disk_size) {
	path = p_path;
	disk_size = p_disk_size;
	set_node_3d(p_path);
	orig_in_length = 0;
	orig_out_length = 0;

	// Connecting to a signal once, rather than plaguing the implementation with calls to `Node3DEditor::update_transform_gizmo`.
	path->connect("curve_changed", callable_mp(this, &Path3DGizmo::_update_transform_gizmo));

	Path3DEditorPlugin::singleton->curve_edit->connect(SceneStringName(pressed), callable_mp(this, &Path3DGizmo::redraw));
	Path3DEditorPlugin::singleton->curve_edit_curve->connect(SceneStringName(pressed), callable_mp(this, &Path3DGizmo::redraw));
	Path3DEditorPlugin::singleton->curve_create->connect(SceneStringName(pressed), callable_mp(this, &Path3DGizmo::redraw));
	Path3DEditorPlugin::singleton->curve_del->connect(SceneStringName(pressed), callable_mp(this, &Path3DGizmo::redraw));
	Path3DEditorPlugin::singleton->curve_close->connect(SceneStringName(pressed), callable_mp(this, &Path3DGizmo::redraw));
}

EditorPlugin::AfterGUIInput Path3DEditorPlugin::forward_3d_gui_input(Camera3D *p_camera, const Ref<InputEvent> &p_event) {
	if (!path) {
		return EditorPlugin::AFTER_GUI_INPUT_PASS;
	}
	Ref<Curve3D> c = path->get_curve();
	if (c.is_null()) {
		return EditorPlugin::AFTER_GUI_INPUT_PASS;
	}
	Transform3D gt = path->get_global_transform();
	Transform3D it = gt.affine_inverse();

	static const int click_dist = 10; //should make global

	Ref<InputEventMouseButton> mb = p_event;

	if (mb.is_valid()) {
		Point2 mbpos(mb->get_position().x, mb->get_position().y);

		Node3DEditorViewport *viewport = nullptr;
		for (uint32_t i = 0; i < Node3DEditor::VIEWPORTS_COUNT; i++) {
			Node3DEditorViewport *vp = Node3DEditor::get_singleton()->get_editor_viewport(i);
			if (vp->get_camera_3d() == p_camera) {
				viewport = vp;
				break;
			}
		}

		ERR_FAIL_NULL_V(viewport, EditorPlugin::AFTER_GUI_INPUT_PASS);

		if (!mb->is_pressed()) {

Review comment (suggestion):
```suggestion
			if (!primary_handle_points.is_empty()) {
```

Code after:
			Vector<int> idx;
			idx.resize(pc);
			int *idx_ptr = idx.ptrw();
			for (int j = 0; j < pc; j++) {
				idx_ptr[j] = j;
			}

			// Initialize arrays for first point.
			PackedVector3Array first_pt_handle_point;
			Vector<int> first_pt_id;
			first_pt_handle_point.append(primary_handle_points[0]);
			first_pt_id.append(idx[0]);

			// Initialize arrays and add handle for last point if needed.
			if (pc > 1) {
				PackedVector3Array last_pt_handle_point;
				Vector<int> last_pt_id;
				last_pt_handle_point.append(primary_handle_points[pc - 1]);
				last_pt_id.append(idx[pc - 1]);
				primary_handle_points.remove_at(pc - 1);
				idx.remove_at(pc - 1);
				add_handles(last_pt_handle_point, c->is_closed() ? handles_material : last_pt_handle_material, last_pt_id);
			}

			// Add handle for first point.
			primary_handle_points.remove_at(0);
			idx.remove_at(0);
			add_handles(first_pt_handle_point, c->is_closed() ? closed_pt_handle_material : first_pt_handle_material, first_pt_id);

			// Add handles for remaining intermediate points.
			if (!primary_handle_points.is_empty()) {
				add_handles(primary_handle_points, handles_material, idx);
			}
		}
		if (secondary_handle_points.size()) {
			add_handles(secondary_handle_points, sec_handles_material, collected_secondary_handle_ids, false, true);
		}
		// Draw the gizmo plugin manually, because handles are registered. In which case, the caller code skips drawing the gizmo plugin.
		gizmo_plugin->redraw(this);
	}
}

void Path3DGizmo::_update_transform_gizmo() {
	Node3DEditor::get_singleton()->update_transform_gizmo();
}

Path3DGizmo::Path3DGizmo(Path3D *p_path, float p_disk_size) {
	path = p_path;
	disk_size = p_disk_size;
	set_node_3d(p_path);
	orig_in_length = 0;