Path: blob/master/editor/scene/3d/gizmos/gizmo_3d_helper.cpp
9906 views
/**************************************************************************/1/* gizmo_3d_helper.cpp */2/**************************************************************************/3/* This file is part of: */4/* GODOT ENGINE */5/* https://godotengine.org */6/**************************************************************************/7/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */8/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */9/* */10/* Permission is hereby granted, free of charge, to any person obtaining */11/* a copy of this software and associated documentation files (the */12/* "Software"), to deal in the Software without restriction, including */13/* without limitation the rights to use, copy, modify, merge, publish, */14/* distribute, sublicense, and/or sell copies of the Software, and to */15/* permit persons to whom the Software is furnished to do so, subject to */16/* the following conditions: */17/* */18/* The above copyright notice and this permission notice shall be */19/* included in all copies or substantial portions of the Software. */20/* */21/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */22/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */23/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */24/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */25/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */26/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */27/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */28/**************************************************************************/2930#include "gizmo_3d_helper.h"3132#include "editor/editor_undo_redo_manager.h"33#include "editor/scene/3d/node_3d_editor_plugin.h"34#include "scene/3d/camera_3d.h"3536void Gizmo3DHelper::initialize_handle_action(const Variant &p_initial_value, const Transform3D &p_initial_transform) {37initial_value = p_initial_value;38initial_transform = p_initial_transform;39}4041void Gizmo3DHelper::get_segment(Camera3D *p_camera, const Point2 &p_point, Vector3 *r_segment) {42Transform3D gt = initial_transform;43Transform3D gi = gt.affine_inverse();4445Vector3 ray_from = p_camera->project_ray_origin(p_point);46Vector3 ray_dir = p_camera->project_ray_normal(p_point);4748r_segment[0] = gi.xform(ray_from);49r_segment[1] = gi.xform(ray_from + ray_dir * 4096);50}5152Vector<Vector3> Gizmo3DHelper::box_get_handles(const Vector3 &p_box_size) {53Vector<Vector3> handles;54for (int i = 0; i < 3; i++) {55Vector3 ax;56ax[i] = p_box_size[i] / 2;57handles.push_back(ax);58handles.push_back(-ax);59}60return handles;61}6263String Gizmo3DHelper::box_get_handle_name(int p_id) const {64switch (p_id) {65case 0:66case 1:67return "Size X";68case 2:69case 3:70return "Size Y";71case 4:72case 5:73return "Size Z";74}75return "";76}7778void Gizmo3DHelper::box_set_handle(const Vector3 p_segment[2], int p_id, Vector3 &r_box_size, Vector3 &r_box_position) {79int axis = p_id / 2;80int sign = p_id % 2 * -2 + 1;8182Vector3 initial_size = initial_value;83float neg_end = initial_size[axis] * -0.5;84float pos_end = initial_size[axis] * 0.5;8586Vector3 axis_segment[2] = { Vector3(), Vector3() };87axis_segment[0][axis] = 4096.0;88axis_segment[1][axis] = -4096.0;89Vector3 ra, rb;90Geometry3D::get_closest_points_between_segments(axis_segment[0], axis_segment[1], p_segment[0], p_segment[1], ra, rb);9192// Calculate new size.93r_box_size = initial_size;94if (Input::get_singleton()->is_key_pressed(Key::ALT)) {95r_box_size[axis] = ra[axis] * sign * 2;96} else {97r_box_size[axis] = sign > 0 ? ra[axis] - neg_end : pos_end - ra[axis];98}99100// Snap to grid.101if (Node3DEditor::get_singleton()->is_snap_enabled()) {102r_box_size[axis] = Math::snapped(r_box_size[axis], Node3DEditor::get_singleton()->get_translate_snap());103}104r_box_size[axis] = MAX(r_box_size[axis], 0.001);105106// Adjust position.107if (Input::get_singleton()->is_key_pressed(Key::ALT)) {108r_box_position = initial_transform.get_origin();109} else {110if (sign > 0) {111pos_end = neg_end + r_box_size[axis];112} else {113neg_end = pos_end - r_box_size[axis];114}115116Vector3 offset;117offset[axis] = (pos_end + neg_end) * 0.5;118r_box_position = initial_transform.xform(offset);119}120}121122void Gizmo3DHelper::box_commit_handle(const String &p_action_name, bool p_cancel, Object *p_position_object, Object *p_size_object, const StringName &p_position_property, const StringName &p_size_property) {123if (!p_size_object) {124p_size_object = p_position_object;125}126127if (p_cancel) {128p_size_object->set(p_size_property, initial_value);129p_position_object->set(p_position_property, initial_transform.get_origin());130return;131}132133EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();134ur->create_action(p_action_name);135ur->add_do_property(p_size_object, p_size_property, p_size_object->get(p_size_property));136ur->add_do_property(p_position_object, p_position_property, p_position_object->get(p_position_property));137ur->add_undo_property(p_size_object, p_size_property, initial_value);138ur->add_undo_property(p_position_object, p_position_property, initial_transform.get_origin());139ur->commit_action();140}141142Vector<Vector3> Gizmo3DHelper::cylinder_get_handles(real_t p_height, real_t p_radius) {143Vector<Vector3> handles;144handles.push_back(Vector3(p_radius, 0, 0));145handles.push_back(Vector3(0, p_height * 0.5, 0));146handles.push_back(Vector3(0, p_height * -0.5, 0));147return handles;148}149150String Gizmo3DHelper::cylinder_get_handle_name(int p_id) const {151if (p_id == 0) {152return "Radius";153} else {154return "Height";155}156}157158void Gizmo3DHelper::_cylinder_or_capsule_set_handle(const Vector3 p_segment[2], int p_id, real_t &r_height, real_t &r_radius, Vector3 &r_cylinder_position, bool p_is_capsule) {159real_t initial_radius = initial_value.operator Vector2().x;160real_t initial_height = initial_value.operator Vector2().y;161162int sign = p_id == 2 ? -1 : 1;163int axis = p_id == 0 ? 0 : 1;164165Vector3 axis_vector;166axis_vector[axis] = sign;167Vector3 ra, rb;168Geometry3D::get_closest_points_between_segments(axis_vector * -4096, axis_vector * 4096, p_segment[0], p_segment[1], ra, rb);169float d = axis_vector.dot(ra);170171// Snap to grid.172if (Node3DEditor::get_singleton()->is_snap_enabled()) {173d = Math::snapped(d, Node3DEditor::get_singleton()->get_translate_snap());174}175176if (p_id == 0) {177// Adjust radius.178if (d < 0.001) {179d = 0.001;180}181r_radius = d;182r_cylinder_position = initial_transform.get_origin();183184if (p_is_capsule) {185r_height = MAX(initial_height, r_radius * 2.0);186} else {187r_height = initial_height;188}189} else if (p_id == 1 || p_id == 2) {190// Adjust height.191if (Input::get_singleton()->is_key_pressed(Key::ALT)) {192r_height = d * 2.0;193} else {194r_height = (initial_height * 0.5) + d;195}196197if (r_height < 0.001) {198r_height = 0.001;199}200201// Adjust position.202if (Input::get_singleton()->is_key_pressed(Key::ALT)) {203r_cylinder_position = initial_transform.get_origin();204} else {205Vector3 offset;206offset[axis] = (r_height - initial_height) * 0.5 * sign;207r_cylinder_position = initial_transform.xform(offset);208}209210if (p_is_capsule) {211r_radius = MIN(initial_radius, r_height / 2.0);212} else {213r_radius = initial_radius;214}215}216}217218void Gizmo3DHelper::cylinder_commit_handle(int p_id, const String &p_radius_action_name, const String &p_height_action_name, bool p_cancel, Object *p_position_object, Object *p_height_object, Object *p_radius_object, const StringName &p_position_property, const StringName &p_height_property, const StringName &p_radius_property) {219if (!p_height_object) {220p_height_object = p_position_object;221}222if (!p_radius_object) {223p_radius_object = p_position_object;224}225226if (p_cancel) {227p_radius_object->set(p_radius_property, initial_value.operator Vector2().x);228p_height_object->set(p_height_property, initial_value.operator Vector2().y);229p_position_object->set(p_position_property, initial_transform.get_origin());230return;231}232233EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();234ur->create_action(p_id == 0 ? p_radius_action_name : p_height_action_name);235ur->add_do_property(p_radius_object, p_radius_property, p_radius_object->get(p_radius_property));236ur->add_undo_property(p_radius_object, p_radius_property, initial_value.operator Vector2().x);237ur->add_do_property(p_height_object, p_height_property, p_height_object->get(p_height_property));238ur->add_undo_property(p_height_object, p_height_property, initial_value.operator Vector2().y);239ur->add_do_property(p_position_object, p_position_property, p_position_object->get(p_position_property));240ur->add_undo_property(p_position_object, p_position_property, initial_transform.get_origin());241ur->commit_action();242}243244245