From 808af8e8375fb0392523a87db550652fec5b8681 Mon Sep 17 00:00:00 2001 From: smix8 <52464204+smix8@users.noreply.github.com> Date: Thu, 20 Apr 2023 06:34:38 +0200 Subject: [PATCH] Split Node3DGizmos into dedicated files Splits Node3DGizmos into dedicated files. --- editor/plugins/SCsub | 1 + editor/plugins/gizmos/SCsub | 5 + .../gizmos/audio_listener_3d_gizmo_plugin.cpp | 55 + .../gizmos/audio_listener_3d_gizmo_plugin.h | 49 + .../audio_stream_player_3d_gizmo_plugin.cpp | 256 + .../audio_stream_player_3d_gizmo_plugin.h | 53 + .../plugins/gizmos/camera_3d_gizmo_plugin.cpp | 291 + .../plugins/gizmos/camera_3d_gizmo_plugin.h | 57 + .../collision_object_3d_gizmo_plugin.cpp | 86 + .../gizmos/collision_object_3d_gizmo_plugin.h | 48 + .../collision_polygon_3d_gizmo_plugin.cpp | 81 + .../collision_polygon_3d_gizmo_plugin.h | 47 + .../collision_shape_3d_gizmo_plugin.cpp | 646 +++ .../gizmos/collision_shape_3d_gizmo_plugin.h | 53 + .../gizmos/cpu_particles_3d_gizmo_plugin.cpp | 59 + .../gizmos/cpu_particles_3d_gizmo_plugin.h | 48 + editor/plugins/gizmos/decal_gizmo_plugin.cpp | 168 + editor/plugins/gizmos/decal_gizmo_plugin.h | 53 + .../gizmos/fog_volume_gizmo_plugin.cpp | 148 + .../plugins/gizmos/fog_volume_gizmo_plugin.h | 53 + .../gizmos/gpu_particles_3d_gizmo_plugin.cpp | 199 + .../gizmos/gpu_particles_3d_gizmo_plugin.h | 54 + ...pu_particles_collision_3d_gizmo_plugin.cpp | 294 + .../gpu_particles_collision_3d_gizmo_plugin.h | 53 + .../plugins/gizmos/joint_3d_gizmo_plugin.cpp | 714 +++ editor/plugins/gizmos/joint_3d_gizmo_plugin.h | 99 + .../plugins/gizmos/label_3d_gizmo_plugin.cpp | 64 + editor/plugins/gizmos/label_3d_gizmo_plugin.h | 49 + .../plugins/gizmos/light_3d_gizmo_plugin.cpp | 308 ++ editor/plugins/gizmos/light_3d_gizmo_plugin.h | 56 + .../gizmos/lightmap_gi_gizmo_plugin.cpp | 211 + .../plugins/gizmos/lightmap_gi_gizmo_plugin.h | 48 + .../gizmos/lightmap_probe_gizmo_plugin.cpp | 115 + .../gizmos/lightmap_probe_gizmo_plugin.h | 48 + .../plugins/gizmos/marker_3d_gizmo_plugin.cpp | 126 + .../plugins/gizmos/marker_3d_gizmo_plugin.h | 50 + .../gizmos/mesh_instance_3d_gizmo_plugin.cpp | 71 + .../gizmos/mesh_instance_3d_gizmo_plugin.h | 49 + .../navigation_link_3d_gizmo_plugin.cpp | 203 + .../gizmos/navigation_link_3d_gizmo_plugin.h | 53 + .../navigation_region_3d_gizmo_plugin.cpp | 208 + .../navigation_region_3d_gizmo_plugin.h | 61 + .../occluder_instance_3d_gizmo_plugin.cpp | 284 + .../occluder_instance_3d_gizmo_plugin.h | 53 + .../gizmos/physics_bone_3d_gizmo_plugin.cpp | 167 + .../gizmos/physics_bone_3d_gizmo_plugin.h | 48 + .../gizmos/ray_cast_3d_gizmo_plugin.cpp | 71 + .../plugins/gizmos/ray_cast_3d_gizmo_plugin.h | 48 + .../gizmos/reflection_probe_gizmo_plugin.cpp | 224 + .../gizmos/reflection_probe_gizmo_plugin.h | 53 + .../gizmos/shape_cast_3d_gizmo_plugin.cpp | 71 + .../gizmos/shape_cast_3d_gizmo_plugin.h | 48 + .../gizmos/soft_body_3d_gizmo_plugin.cpp | 113 + .../gizmos/soft_body_3d_gizmo_plugin.h | 54 + .../gizmos/spring_arm_3d_gizmo_plugin.cpp | 69 + .../gizmos/spring_arm_3d_gizmo_plugin.h | 48 + .../plugins/gizmos/sprite_3d_gizmo_plugin.cpp | 64 + .../plugins/gizmos/sprite_3d_gizmo_plugin.h | 49 + .../gizmos/vehicle_body_3d_gizmo_plugin.cpp | 104 + .../gizmos/vehicle_body_3d_gizmo_plugin.h | 48 + ...ble_on_screen_notifier_3d_gizmo_plugin.cpp | 194 + ...sible_on_screen_notifier_3d_gizmo_plugin.h | 53 + .../plugins/gizmos/voxel_gi_gizmo_plugin.cpp | 209 + editor/plugins/gizmos/voxel_gi_gizmo_plugin.h | 53 + editor/plugins/node_3d_editor_gizmos.cpp | 4838 ----------------- editor/plugins/node_3d_editor_gizmos.h | 516 -- editor/plugins/node_3d_editor_plugin.cpp | 31 + 67 files changed, 7546 insertions(+), 5354 deletions(-) create mode 100644 editor/plugins/gizmos/SCsub create mode 100644 editor/plugins/gizmos/audio_listener_3d_gizmo_plugin.cpp create mode 100644 editor/plugins/gizmos/audio_listener_3d_gizmo_plugin.h create mode 100644 editor/plugins/gizmos/audio_stream_player_3d_gizmo_plugin.cpp create mode 100644 editor/plugins/gizmos/audio_stream_player_3d_gizmo_plugin.h create mode 100644 editor/plugins/gizmos/camera_3d_gizmo_plugin.cpp create mode 100644 editor/plugins/gizmos/camera_3d_gizmo_plugin.h create mode 100644 editor/plugins/gizmos/collision_object_3d_gizmo_plugin.cpp create mode 100644 editor/plugins/gizmos/collision_object_3d_gizmo_plugin.h create mode 100644 editor/plugins/gizmos/collision_polygon_3d_gizmo_plugin.cpp create mode 100644 editor/plugins/gizmos/collision_polygon_3d_gizmo_plugin.h create mode 100644 editor/plugins/gizmos/collision_shape_3d_gizmo_plugin.cpp create mode 100644 editor/plugins/gizmos/collision_shape_3d_gizmo_plugin.h create mode 100644 editor/plugins/gizmos/cpu_particles_3d_gizmo_plugin.cpp create mode 100644 editor/plugins/gizmos/cpu_particles_3d_gizmo_plugin.h create mode 100644 editor/plugins/gizmos/decal_gizmo_plugin.cpp create mode 100644 editor/plugins/gizmos/decal_gizmo_plugin.h create mode 100644 editor/plugins/gizmos/fog_volume_gizmo_plugin.cpp create mode 100644 editor/plugins/gizmos/fog_volume_gizmo_plugin.h create mode 100644 editor/plugins/gizmos/gpu_particles_3d_gizmo_plugin.cpp create mode 100644 editor/plugins/gizmos/gpu_particles_3d_gizmo_plugin.h create mode 100644 editor/plugins/gizmos/gpu_particles_collision_3d_gizmo_plugin.cpp create mode 100644 editor/plugins/gizmos/gpu_particles_collision_3d_gizmo_plugin.h create mode 100644 editor/plugins/gizmos/joint_3d_gizmo_plugin.cpp create mode 100644 editor/plugins/gizmos/joint_3d_gizmo_plugin.h create mode 100644 editor/plugins/gizmos/label_3d_gizmo_plugin.cpp create mode 100644 editor/plugins/gizmos/label_3d_gizmo_plugin.h create mode 100644 editor/plugins/gizmos/light_3d_gizmo_plugin.cpp create mode 100644 editor/plugins/gizmos/light_3d_gizmo_plugin.h create mode 100644 editor/plugins/gizmos/lightmap_gi_gizmo_plugin.cpp create mode 100644 editor/plugins/gizmos/lightmap_gi_gizmo_plugin.h create mode 100644 editor/plugins/gizmos/lightmap_probe_gizmo_plugin.cpp create mode 100644 editor/plugins/gizmos/lightmap_probe_gizmo_plugin.h create mode 100644 editor/plugins/gizmos/marker_3d_gizmo_plugin.cpp create mode 100644 editor/plugins/gizmos/marker_3d_gizmo_plugin.h create mode 100644 editor/plugins/gizmos/mesh_instance_3d_gizmo_plugin.cpp create mode 100644 editor/plugins/gizmos/mesh_instance_3d_gizmo_plugin.h create mode 100644 editor/plugins/gizmos/navigation_link_3d_gizmo_plugin.cpp create mode 100644 editor/plugins/gizmos/navigation_link_3d_gizmo_plugin.h create mode 100644 editor/plugins/gizmos/navigation_region_3d_gizmo_plugin.cpp create mode 100644 editor/plugins/gizmos/navigation_region_3d_gizmo_plugin.h create mode 100644 editor/plugins/gizmos/occluder_instance_3d_gizmo_plugin.cpp create mode 100644 editor/plugins/gizmos/occluder_instance_3d_gizmo_plugin.h create mode 100644 editor/plugins/gizmos/physics_bone_3d_gizmo_plugin.cpp create mode 100644 editor/plugins/gizmos/physics_bone_3d_gizmo_plugin.h create mode 100644 editor/plugins/gizmos/ray_cast_3d_gizmo_plugin.cpp create mode 100644 editor/plugins/gizmos/ray_cast_3d_gizmo_plugin.h create mode 100644 editor/plugins/gizmos/reflection_probe_gizmo_plugin.cpp create mode 100644 editor/plugins/gizmos/reflection_probe_gizmo_plugin.h create mode 100644 editor/plugins/gizmos/shape_cast_3d_gizmo_plugin.cpp create mode 100644 editor/plugins/gizmos/shape_cast_3d_gizmo_plugin.h create mode 100644 editor/plugins/gizmos/soft_body_3d_gizmo_plugin.cpp create mode 100644 editor/plugins/gizmos/soft_body_3d_gizmo_plugin.h create mode 100644 editor/plugins/gizmos/spring_arm_3d_gizmo_plugin.cpp create mode 100644 editor/plugins/gizmos/spring_arm_3d_gizmo_plugin.h create mode 100644 editor/plugins/gizmos/sprite_3d_gizmo_plugin.cpp create mode 100644 editor/plugins/gizmos/sprite_3d_gizmo_plugin.h create mode 100644 editor/plugins/gizmos/vehicle_body_3d_gizmo_plugin.cpp create mode 100644 editor/plugins/gizmos/vehicle_body_3d_gizmo_plugin.h create mode 100644 editor/plugins/gizmos/visible_on_screen_notifier_3d_gizmo_plugin.cpp create mode 100644 editor/plugins/gizmos/visible_on_screen_notifier_3d_gizmo_plugin.h create mode 100644 editor/plugins/gizmos/voxel_gi_gizmo_plugin.cpp create mode 100644 editor/plugins/gizmos/voxel_gi_gizmo_plugin.h diff --git a/editor/plugins/SCsub b/editor/plugins/SCsub index 10a65b427e5..4b6abf18f94 100644 --- a/editor/plugins/SCsub +++ b/editor/plugins/SCsub @@ -4,4 +4,5 @@ Import("env") env.add_source_files(env.editor_sources, "*.cpp") +SConscript("gizmos/SCsub") SConscript("tiles/SCsub") diff --git a/editor/plugins/gizmos/SCsub b/editor/plugins/gizmos/SCsub new file mode 100644 index 00000000000..359d04e5df2 --- /dev/null +++ b/editor/plugins/gizmos/SCsub @@ -0,0 +1,5 @@ +#!/usr/bin/env python + +Import("env") + +env.add_source_files(env.editor_sources, "*.cpp") diff --git a/editor/plugins/gizmos/audio_listener_3d_gizmo_plugin.cpp b/editor/plugins/gizmos/audio_listener_3d_gizmo_plugin.cpp new file mode 100644 index 00000000000..ed0597efd3e --- /dev/null +++ b/editor/plugins/gizmos/audio_listener_3d_gizmo_plugin.cpp @@ -0,0 +1,55 @@ +/**************************************************************************/ +/* audio_listener_3d_gizmo_plugin.cpp */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* 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 "audio_listener_3d_gizmo_plugin.h" + +#include "editor/plugins/node_3d_editor_plugin.h" +#include "scene/3d/audio_listener_3d.h" + +AudioListener3DGizmoPlugin::AudioListener3DGizmoPlugin() { + create_icon_material("audio_listener_3d_icon", Node3DEditor::get_singleton()->get_theme_icon(SNAME("GizmoAudioListener3D"), SNAME("EditorIcons"))); +} + +bool AudioListener3DGizmoPlugin::has_gizmo(Node3D *p_spatial) { + return Object::cast_to(p_spatial) != nullptr; +} + +String AudioListener3DGizmoPlugin::get_gizmo_name() const { + return "AudioListener3D"; +} + +int AudioListener3DGizmoPlugin::get_priority() const { + return -1; +} + +void AudioListener3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) { + const Ref icon = get_material("audio_listener_3d_icon", p_gizmo); + p_gizmo->add_unscaled_billboard(icon, 0.05); +} diff --git a/editor/plugins/gizmos/audio_listener_3d_gizmo_plugin.h b/editor/plugins/gizmos/audio_listener_3d_gizmo_plugin.h new file mode 100644 index 00000000000..e9c0e29ee3d --- /dev/null +++ b/editor/plugins/gizmos/audio_listener_3d_gizmo_plugin.h @@ -0,0 +1,49 @@ +/**************************************************************************/ +/* audio_listener_3d_gizmo_plugin.h */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* 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. */ +/**************************************************************************/ + +#ifndef AUDIO_LISTENER_3D_GIZMO_PLUGIN_H +#define AUDIO_LISTENER_3D_GIZMO_PLUGIN_H + +#include "editor/plugins/node_3d_editor_gizmos.h" + +class AudioListener3DGizmoPlugin : public EditorNode3DGizmoPlugin { + GDCLASS(AudioListener3DGizmoPlugin, EditorNode3DGizmoPlugin); + +public: + bool has_gizmo(Node3D *p_spatial) override; + String get_gizmo_name() const override; + int get_priority() const override; + + void redraw(EditorNode3DGizmo *p_gizmo) override; + + AudioListener3DGizmoPlugin(); +}; + +#endif // AUDIO_LISTENER_3D_GIZMO_PLUGIN_H diff --git a/editor/plugins/gizmos/audio_stream_player_3d_gizmo_plugin.cpp b/editor/plugins/gizmos/audio_stream_player_3d_gizmo_plugin.cpp new file mode 100644 index 00000000000..611d4b3c1ca --- /dev/null +++ b/editor/plugins/gizmos/audio_stream_player_3d_gizmo_plugin.cpp @@ -0,0 +1,256 @@ +/**************************************************************************/ +/* audio_stream_player_3d_gizmo_plugin.cpp */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* 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 "audio_stream_player_3d_gizmo_plugin.h" + +#include "editor/editor_settings.h" +#include "editor/editor_undo_redo_manager.h" +#include "editor/plugins/node_3d_editor_plugin.h" +#include "scene/3d/audio_stream_player_3d.h" + +AudioStreamPlayer3DGizmoPlugin::AudioStreamPlayer3DGizmoPlugin() { + Color gizmo_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/stream_player_3d", Color(0.4, 0.8, 1)); + + create_icon_material("stream_player_3d_icon", Node3DEditor::get_singleton()->get_theme_icon(SNAME("Gizmo3DSamplePlayer"), SNAME("EditorIcons"))); + create_material("stream_player_3d_material_primary", gizmo_color); + create_material("stream_player_3d_material_secondary", gizmo_color * Color(1, 1, 1, 0.35)); + // Enable vertex colors for the billboard material as the gizmo color depends on the + // AudioStreamPlayer3D attenuation type and source (Unit Size or Max Distance). + create_material("stream_player_3d_material_billboard", Color(1, 1, 1), true, false, true); + create_handle_material("handles"); +} + +bool AudioStreamPlayer3DGizmoPlugin::has_gizmo(Node3D *p_spatial) { + return Object::cast_to(p_spatial) != nullptr; +} + +String AudioStreamPlayer3DGizmoPlugin::get_gizmo_name() const { + return "AudioStreamPlayer3D"; +} + +int AudioStreamPlayer3DGizmoPlugin::get_priority() const { + return -1; +} + +String AudioStreamPlayer3DGizmoPlugin::get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const { + return "Emission Radius"; +} + +Variant AudioStreamPlayer3DGizmoPlugin::get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const { + AudioStreamPlayer3D *player = Object::cast_to(p_gizmo->get_node_3d()); + return player->get_emission_angle(); +} + +void AudioStreamPlayer3DGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, Camera3D *p_camera, const Point2 &p_point) { + AudioStreamPlayer3D *player = Object::cast_to(p_gizmo->get_node_3d()); + + Transform3D gt = player->get_global_transform(); + Transform3D gi = gt.affine_inverse(); + + Vector3 ray_from = p_camera->project_ray_origin(p_point); + Vector3 ray_dir = p_camera->project_ray_normal(p_point); + Vector3 ray_to = ray_from + ray_dir * 4096; + + ray_from = gi.xform(ray_from); + ray_to = gi.xform(ray_to); + + float closest_dist = 1e20; + float closest_angle = 1e20; + + for (int i = 0; i < 180; i++) { + float a = Math::deg_to_rad((float)i); + float an = Math::deg_to_rad((float)(i + 1)); + + Vector3 from(Math::sin(a), 0, -Math::cos(a)); + Vector3 to(Math::sin(an), 0, -Math::cos(an)); + + Vector3 r1, r2; + Geometry3D::get_closest_points_between_segments(from, to, ray_from, ray_to, r1, r2); + float d = r1.distance_to(r2); + if (d < closest_dist) { + closest_dist = d; + closest_angle = i; + } + } + + if (closest_angle < 91) { + player->set_emission_angle(closest_angle); + } +} + +void AudioStreamPlayer3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, const Variant &p_restore, bool p_cancel) { + AudioStreamPlayer3D *player = Object::cast_to(p_gizmo->get_node_3d()); + + if (p_cancel) { + player->set_emission_angle(p_restore); + + } else { + EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton(); + ur->create_action(TTR("Change AudioStreamPlayer3D Emission Angle")); + ur->add_do_method(player, "set_emission_angle", player->get_emission_angle()); + ur->add_undo_method(player, "set_emission_angle", p_restore); + ur->commit_action(); + } +} + +void AudioStreamPlayer3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) { + const AudioStreamPlayer3D *player = Object::cast_to(p_gizmo->get_node_3d()); + + p_gizmo->clear(); + + const Ref icon = get_material("stream_player_3d_icon", p_gizmo); + + if (player->get_attenuation_model() != AudioStreamPlayer3D::ATTENUATION_DISABLED || player->get_max_distance() > CMP_EPSILON) { + // Draw a circle to represent sound volume attenuation. + // Use only a billboard circle to represent radius. + // This helps distinguish AudioStreamPlayer3D gizmos from OmniLight3D gizmos. + const Ref lines_billboard_material = get_material("stream_player_3d_material_billboard", p_gizmo); + + // Soft distance cap varies depending on attenuation model, as some will fade out more aggressively than others. + // Multipliers were empirically determined through testing. + float soft_multiplier; + switch (player->get_attenuation_model()) { + case AudioStreamPlayer3D::ATTENUATION_INVERSE_DISTANCE: + soft_multiplier = 12.0; + break; + case AudioStreamPlayer3D::ATTENUATION_INVERSE_SQUARE_DISTANCE: + soft_multiplier = 4.0; + break; + case AudioStreamPlayer3D::ATTENUATION_LOGARITHMIC: + soft_multiplier = 3.25; + break; + default: + // Ensures Max Distance's radius visualization is not capped by Unit Size + // (when the attenuation mode is Disabled). + soft_multiplier = 10000.0; + break; + } + + // Draw the distance at which the sound can be reasonably heard. + // This can be either a hard distance cap with the Max Distance property (if set above 0.0), + // or a soft distance cap with the Unit Size property (sound never reaches true zero). + // When Max Distance is 0.0, `r` represents the distance above which the + // sound can't be heard in *most* (but not all) scenarios. + float r; + if (player->get_max_distance() > CMP_EPSILON) { + r = MIN(player->get_unit_size() * soft_multiplier, player->get_max_distance()); + } else { + r = player->get_unit_size() * soft_multiplier; + } + Vector points_billboard; + + for (int i = 0; i < 120; i++) { + // Create a circle. + const float ra = Math::deg_to_rad((float)(i * 3)); + const float rb = Math::deg_to_rad((float)((i + 1) * 3)); + const Point2 a = Vector2(Math::sin(ra), Math::cos(ra)) * r; + const Point2 b = Vector2(Math::sin(rb), Math::cos(rb)) * r; + + // Draw a billboarded circle. + points_billboard.push_back(Vector3(a.x, a.y, 0)); + points_billboard.push_back(Vector3(b.x, b.y, 0)); + } + + Color color; + switch (player->get_attenuation_model()) { + // Pick cold colors for all attenuation models (except Disabled), + // so that soft caps can be easily distinguished from hard caps + // (which use warm colors). + case AudioStreamPlayer3D::ATTENUATION_INVERSE_DISTANCE: + color = Color(0.4, 0.8, 1); + break; + case AudioStreamPlayer3D::ATTENUATION_INVERSE_SQUARE_DISTANCE: + color = Color(0.4, 0.5, 1); + break; + case AudioStreamPlayer3D::ATTENUATION_LOGARITHMIC: + color = Color(0.4, 0.2, 1); + break; + default: + // Disabled attenuation mode. + // This is never reached when Max Distance is 0, but the + // hue-inverted form of this color will be used if Max Distance is greater than 0. + color = Color(1, 1, 1); + break; + } + + if (player->get_max_distance() > CMP_EPSILON) { + // Sound is hard-capped by max distance. The attenuation model still matters, + // so invert the hue of the color that was chosen above. + color.set_h(color.get_h() + 0.5); + } + + p_gizmo->add_lines(points_billboard, lines_billboard_material, true, color); + } + + if (player->is_emission_angle_enabled()) { + const float pc = player->get_emission_angle(); + const float ofs = -Math::cos(Math::deg_to_rad(pc)); + const float radius = Math::sin(Math::deg_to_rad(pc)); + + Vector points_primary; + points_primary.resize(200); + + real_t step = Math_TAU / 100.0; + for (int i = 0; i < 100; i++) { + const float a = i * step; + const float an = (i + 1) * step; + + const Vector3 from(Math::sin(a) * radius, Math::cos(a) * radius, ofs); + const Vector3 to(Math::sin(an) * radius, Math::cos(an) * radius, ofs); + + points_primary.write[i * 2 + 0] = from; + points_primary.write[i * 2 + 1] = to; + } + + const Ref material_primary = get_material("stream_player_3d_material_primary", p_gizmo); + p_gizmo->add_lines(points_primary, material_primary); + + Vector points_secondary; + points_secondary.resize(16); + + for (int i = 0; i < 8; i++) { + const float a = i * (Math_TAU / 8.0); + const Vector3 from(Math::sin(a) * radius, Math::cos(a) * radius, ofs); + + points_secondary.write[i * 2 + 0] = from; + points_secondary.write[i * 2 + 1] = Vector3(); + } + + const Ref material_secondary = get_material("stream_player_3d_material_secondary", p_gizmo); + p_gizmo->add_lines(points_secondary, material_secondary); + + Vector handles; + const float ha = Math::deg_to_rad(player->get_emission_angle()); + handles.push_back(Vector3(Math::sin(ha), 0, -Math::cos(ha))); + p_gizmo->add_handles(handles, get_material("handles")); + } + + p_gizmo->add_unscaled_billboard(icon, 0.05); +} diff --git a/editor/plugins/gizmos/audio_stream_player_3d_gizmo_plugin.h b/editor/plugins/gizmos/audio_stream_player_3d_gizmo_plugin.h new file mode 100644 index 00000000000..c818886b663 --- /dev/null +++ b/editor/plugins/gizmos/audio_stream_player_3d_gizmo_plugin.h @@ -0,0 +1,53 @@ +/**************************************************************************/ +/* audio_stream_player_3d_gizmo_plugin.h */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* 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. */ +/**************************************************************************/ + +#ifndef AUDIO_STREAM_PLAYER_3D_GIZMO_PLUGIN_H +#define AUDIO_STREAM_PLAYER_3D_GIZMO_PLUGIN_H + +#include "editor/plugins/node_3d_editor_gizmos.h" + +class AudioStreamPlayer3DGizmoPlugin : public EditorNode3DGizmoPlugin { + GDCLASS(AudioStreamPlayer3DGizmoPlugin, EditorNode3DGizmoPlugin); + +public: + bool has_gizmo(Node3D *p_spatial) override; + String get_gizmo_name() const override; + int get_priority() const override; + + String get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const override; + Variant get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const override; + void set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, Camera3D *p_camera, const Point2 &p_point) override; + void commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, const Variant &p_restore, bool p_cancel = false) override; + void redraw(EditorNode3DGizmo *p_gizmo) override; + + AudioStreamPlayer3DGizmoPlugin(); +}; + +#endif // AUDIO_STREAM_PLAYER_3D_GIZMO_PLUGIN_H diff --git a/editor/plugins/gizmos/camera_3d_gizmo_plugin.cpp b/editor/plugins/gizmos/camera_3d_gizmo_plugin.cpp new file mode 100644 index 00000000000..e4503b9c6fc --- /dev/null +++ b/editor/plugins/gizmos/camera_3d_gizmo_plugin.cpp @@ -0,0 +1,291 @@ +/**************************************************************************/ +/* camera_3d_gizmo_plugin.cpp */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* 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 "camera_3d_gizmo_plugin.h" + +#include "core/config/project_settings.h" +#include "editor/editor_node.h" +#include "editor/editor_settings.h" +#include "editor/editor_undo_redo_manager.h" +#include "editor/plugins/node_3d_editor_plugin.h" +#include "scene/3d/camera_3d.h" + +Camera3DGizmoPlugin::Camera3DGizmoPlugin() { + Color gizmo_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/camera", Color(0.8, 0.4, 0.8)); + + create_material("camera_material", gizmo_color); + create_handle_material("handles"); +} + +Size2i Camera3DGizmoPlugin::_get_viewport_size(Camera3D *p_camera) { + Viewport *viewport = p_camera->get_viewport(); + + Window *window = Object::cast_to(viewport); + if (window) { + return window->get_size(); + } + + SubViewport *sub_viewport = Object::cast_to(viewport); + ERR_FAIL_NULL_V(sub_viewport, Size2i()); + + if (sub_viewport == EditorNode::get_singleton()->get_scene_root()) { + return Size2(GLOBAL_GET("display/window/size/viewport_width"), GLOBAL_GET("display/window/size/viewport_height")); + } + + return sub_viewport->get_size(); +} + +bool Camera3DGizmoPlugin::has_gizmo(Node3D *p_spatial) { + return Object::cast_to(p_spatial) != nullptr; +} + +String Camera3DGizmoPlugin::get_gizmo_name() const { + return "Camera3D"; +} + +int Camera3DGizmoPlugin::get_priority() const { + return -1; +} + +String Camera3DGizmoPlugin::get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const { + Camera3D *camera = Object::cast_to(p_gizmo->get_node_3d()); + + if (camera->get_projection() == Camera3D::PROJECTION_PERSPECTIVE) { + return "FOV"; + } else { + return "Size"; + } +} + +Variant Camera3DGizmoPlugin::get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const { + Camera3D *camera = Object::cast_to(p_gizmo->get_node_3d()); + + if (camera->get_projection() == Camera3D::PROJECTION_PERSPECTIVE) { + return camera->get_fov(); + } else { + return camera->get_size(); + } +} + +void Camera3DGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, Camera3D *p_camera, const Point2 &p_point) { + Camera3D *camera = Object::cast_to(p_gizmo->get_node_3d()); + + Transform3D gt = camera->get_global_transform(); + Transform3D gi = gt.affine_inverse(); + + Vector3 ray_from = p_camera->project_ray_origin(p_point); + Vector3 ray_dir = p_camera->project_ray_normal(p_point); + + Vector3 s[2] = { gi.xform(ray_from), gi.xform(ray_from + ray_dir * 4096) }; + + if (camera->get_projection() == Camera3D::PROJECTION_PERSPECTIVE) { + Transform3D gt2 = camera->get_global_transform(); + float a = _find_closest_angle_to_half_pi_arc(s[0], s[1], 1.0, gt2); + camera->set("fov", CLAMP(a * 2.0, 1, 179)); + } else { + Vector3 ra, rb; + Geometry3D::get_closest_points_between_segments(Vector3(0, 0, -1), Vector3(4096, 0, -1), s[0], s[1], ra, rb); + float d = ra.x * 2; + if (Node3DEditor::get_singleton()->is_snap_enabled()) { + d = Math::snapped(d, Node3DEditor::get_singleton()->get_translate_snap()); + } + + d = CLAMP(d, 0.1, 16384); + + camera->set("size", d); + } +} + +void Camera3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, const Variant &p_restore, bool p_cancel) { + Camera3D *camera = Object::cast_to(p_gizmo->get_node_3d()); + + if (camera->get_projection() == Camera3D::PROJECTION_PERSPECTIVE) { + if (p_cancel) { + camera->set("fov", p_restore); + } else { + EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton(); + ur->create_action(TTR("Change Camera FOV")); + ur->add_do_property(camera, "fov", camera->get_fov()); + ur->add_undo_property(camera, "fov", p_restore); + ur->commit_action(); + } + + } else { + if (p_cancel) { + camera->set("size", p_restore); + } else { + EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton(); + ur->create_action(TTR("Change Camera Size")); + ur->add_do_property(camera, "size", camera->get_size()); + ur->add_undo_property(camera, "size", p_restore); + ur->commit_action(); + } + } +} + +void Camera3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) { + Camera3D *camera = Object::cast_to(p_gizmo->get_node_3d()); + + p_gizmo->clear(); + + Vector lines; + Vector handles; + + Ref material = get_material("camera_material", p_gizmo); + + const Size2i viewport_size = _get_viewport_size(camera); + const real_t viewport_aspect = viewport_size.x > 0 && viewport_size.y > 0 ? viewport_size.aspect() : 1.0; + const Size2 size_factor = viewport_aspect > 1.0 ? Size2(1.0, 1.0 / viewport_aspect) : Size2(viewport_aspect, 1.0); + +#define ADD_TRIANGLE(m_a, m_b, m_c) \ + { \ + lines.push_back(m_a); \ + lines.push_back(m_b); \ + lines.push_back(m_b); \ + lines.push_back(m_c); \ + lines.push_back(m_c); \ + lines.push_back(m_a); \ + } + +#define ADD_QUAD(m_a, m_b, m_c, m_d) \ + { \ + lines.push_back(m_a); \ + lines.push_back(m_b); \ + lines.push_back(m_b); \ + lines.push_back(m_c); \ + lines.push_back(m_c); \ + lines.push_back(m_d); \ + lines.push_back(m_d); \ + lines.push_back(m_a); \ + } + + switch (camera->get_projection()) { + case Camera3D::PROJECTION_PERSPECTIVE: { + // The real FOV is halved for accurate representation + float fov = camera->get_fov() / 2.0; + + const float hsize = Math::sin(Math::deg_to_rad(fov)); + const float depth = -Math::cos(Math::deg_to_rad(fov)); + Vector3 side = Vector3(hsize * size_factor.x, 0, depth); + Vector3 nside = Vector3(-side.x, side.y, side.z); + Vector3 up = Vector3(0, hsize * size_factor.y, 0); + + ADD_TRIANGLE(Vector3(), side + up, side - up); + ADD_TRIANGLE(Vector3(), nside + up, nside - up); + ADD_TRIANGLE(Vector3(), side + up, nside + up); + ADD_TRIANGLE(Vector3(), side - up, nside - up); + + handles.push_back(side); + side.x = MIN(side.x, hsize * 0.25); + nside.x = -side.x; + Vector3 tup(0, up.y + hsize / 2, side.z); + ADD_TRIANGLE(tup, side + up, nside + up); + } break; + + case Camera3D::PROJECTION_ORTHOGONAL: { + float size = camera->get_size(); + + float hsize = size * 0.5; + Vector3 right(hsize * size_factor.x, 0, 0); + Vector3 up(0, hsize * size_factor.y, 0); + Vector3 back(0, 0, -1.0); + Vector3 front(0, 0, 0); + + ADD_QUAD(-up - right, -up + right, up + right, up - right); + ADD_QUAD(-up - right + back, -up + right + back, up + right + back, up - right + back); + ADD_QUAD(up + right, up + right + back, up - right + back, up - right); + ADD_QUAD(-up + right, -up + right + back, -up - right + back, -up - right); + + handles.push_back(right + back); + + right.x = MIN(right.x, hsize * 0.25); + Vector3 tup(0, up.y + hsize / 2, back.z); + ADD_TRIANGLE(tup, right + up + back, -right + up + back); + + } break; + + case Camera3D::PROJECTION_FRUSTUM: { + float hsize = camera->get_size() / 2.0; + + Vector3 side = Vector3(hsize, 0, -camera->get_near()).normalized(); + side.x *= size_factor.x; + Vector3 nside = Vector3(-side.x, side.y, side.z); + Vector3 up = Vector3(0, hsize * size_factor.y, 0); + Vector3 offset = Vector3(camera->get_frustum_offset().x, camera->get_frustum_offset().y, 0.0); + + ADD_TRIANGLE(Vector3(), side + up + offset, side - up + offset); + ADD_TRIANGLE(Vector3(), nside + up + offset, nside - up + offset); + ADD_TRIANGLE(Vector3(), side + up + offset, nside + up + offset); + ADD_TRIANGLE(Vector3(), side - up + offset, nside - up + offset); + + side.x = MIN(side.x, hsize * 0.25); + nside.x = -side.x; + Vector3 tup(0, up.y + hsize / 2, side.z); + ADD_TRIANGLE(tup + offset, side + up + offset, nside + up + offset); + } break; + } + +#undef ADD_TRIANGLE +#undef ADD_QUAD + + p_gizmo->add_lines(lines, material); + p_gizmo->add_collision_segments(lines); + + if (!handles.is_empty()) { + p_gizmo->add_handles(handles, get_material("handles")); + } +} + +float Camera3DGizmoPlugin::_find_closest_angle_to_half_pi_arc(const Vector3 &p_from, const Vector3 &p_to, float p_arc_radius, const Transform3D &p_arc_xform) { + //bleh, discrete is simpler + static const int arc_test_points = 64; + float min_d = 1e20; + Vector3 min_p; + + for (int i = 0; i < arc_test_points; i++) { + float a = i * Math_PI * 0.5 / arc_test_points; + float an = (i + 1) * Math_PI * 0.5 / arc_test_points; + Vector3 p = Vector3(Math::cos(a), 0, -Math::sin(a)) * p_arc_radius; + Vector3 n = Vector3(Math::cos(an), 0, -Math::sin(an)) * p_arc_radius; + + Vector3 ra, rb; + Geometry3D::get_closest_points_between_segments(p, n, p_from, p_to, ra, rb); + + float d = ra.distance_to(rb); + if (d < min_d) { + min_d = d; + min_p = ra; + } + } + + //min_p = p_arc_xform.affine_inverse().xform(min_p); + float a = (Math_PI * 0.5) - Vector2(min_p.x, -min_p.z).angle(); + return Math::rad_to_deg(a); +} diff --git a/editor/plugins/gizmos/camera_3d_gizmo_plugin.h b/editor/plugins/gizmos/camera_3d_gizmo_plugin.h new file mode 100644 index 00000000000..ba65ebb8de6 --- /dev/null +++ b/editor/plugins/gizmos/camera_3d_gizmo_plugin.h @@ -0,0 +1,57 @@ +/**************************************************************************/ +/* camera_3d_gizmo_plugin.h */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* 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. */ +/**************************************************************************/ + +#ifndef CAMERA_3D_GIZMO_PLUGIN_H +#define CAMERA_3D_GIZMO_PLUGIN_H + +#include "editor/plugins/node_3d_editor_gizmos.h" + +class Camera3DGizmoPlugin : public EditorNode3DGizmoPlugin { + GDCLASS(Camera3DGizmoPlugin, EditorNode3DGizmoPlugin); + +private: + static Size2i _get_viewport_size(Camera3D *p_camera); + static float _find_closest_angle_to_half_pi_arc(const Vector3 &p_from, const Vector3 &p_to, float p_arc_radius, const Transform3D &p_arc_xform); + +public: + bool has_gizmo(Node3D *p_spatial) override; + String get_gizmo_name() const override; + int get_priority() const override; + + String get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const override; + Variant get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const override; + void set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, Camera3D *p_camera, const Point2 &p_point) override; + void commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, const Variant &p_restore, bool p_cancel = false) override; + void redraw(EditorNode3DGizmo *p_gizmo) override; + + Camera3DGizmoPlugin(); +}; + +#endif // CAMERA_3D_GIZMO_PLUGIN_H diff --git a/editor/plugins/gizmos/collision_object_3d_gizmo_plugin.cpp b/editor/plugins/gizmos/collision_object_3d_gizmo_plugin.cpp new file mode 100644 index 00000000000..63f2883ed76 --- /dev/null +++ b/editor/plugins/gizmos/collision_object_3d_gizmo_plugin.cpp @@ -0,0 +1,86 @@ +/**************************************************************************/ +/* collision_object_3d_gizmo_plugin.cpp */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* 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 "collision_object_3d_gizmo_plugin.h" + +#include "editor/editor_settings.h" +#include "editor/plugins/node_3d_editor_plugin.h" +#include "scene/3d/collision_object_3d.h" +#include "scene/3d/collision_polygon_3d.h" +#include "scene/3d/collision_shape_3d.h" +#include "scene/resources/surface_tool.h" + +CollisionObject3DGizmoPlugin::CollisionObject3DGizmoPlugin() { + const Color gizmo_color = EDITOR_GET("editors/3d_gizmos/gizmo_colors/shape"); + create_material("shape_material", gizmo_color); + const float gizmo_value = gizmo_color.get_v(); + const Color gizmo_color_disabled = Color(gizmo_value, gizmo_value, gizmo_value, 0.65); + create_material("shape_material_disabled", gizmo_color_disabled); +} + +bool CollisionObject3DGizmoPlugin::has_gizmo(Node3D *p_spatial) { + return Object::cast_to(p_spatial) != nullptr; +} + +String CollisionObject3DGizmoPlugin::get_gizmo_name() const { + return "CollisionObject3D"; +} + +int CollisionObject3DGizmoPlugin::get_priority() const { + return -2; +} + +void CollisionObject3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) { + CollisionObject3D *co = Object::cast_to(p_gizmo->get_node_3d()); + + p_gizmo->clear(); + + List owner_ids; + co->get_shape_owners(&owner_ids); + for (uint32_t &owner_id : owner_ids) { + Transform3D xform = co->shape_owner_get_transform(owner_id); + Object *owner = co->shape_owner_get_owner(owner_id); + // Exclude CollisionShape3D and CollisionPolygon3D as they have their gizmo. + if (!Object::cast_to(owner) && !Object::cast_to(owner)) { + Ref material = get_material(!co->is_shape_owner_disabled(owner_id) ? "shape_material" : "shape_material_disabled", p_gizmo); + for (int shape_id = 0; shape_id < co->shape_owner_get_shape_count(owner_id); shape_id++) { + Ref s = co->shape_owner_get_shape(owner_id, shape_id); + if (s.is_null()) { + continue; + } + SurfaceTool st; + st.append_from(s->get_debug_mesh(), 0, xform); + + p_gizmo->add_mesh(st.commit(), material); + p_gizmo->add_collision_segments(s->get_debug_mesh_lines()); + } + } + } +} diff --git a/editor/plugins/gizmos/collision_object_3d_gizmo_plugin.h b/editor/plugins/gizmos/collision_object_3d_gizmo_plugin.h new file mode 100644 index 00000000000..759b8c3fa9f --- /dev/null +++ b/editor/plugins/gizmos/collision_object_3d_gizmo_plugin.h @@ -0,0 +1,48 @@ +/**************************************************************************/ +/* collision_object_3d_gizmo_plugin.h */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* 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. */ +/**************************************************************************/ + +#ifndef COLLISION_OBJECT_3D_GIZMO_PLUGIN_H +#define COLLISION_OBJECT_3D_GIZMO_PLUGIN_H + +#include "editor/plugins/node_3d_editor_gizmos.h" + +class CollisionObject3DGizmoPlugin : public EditorNode3DGizmoPlugin { + GDCLASS(CollisionObject3DGizmoPlugin, EditorNode3DGizmoPlugin); + +public: + bool has_gizmo(Node3D *p_spatial) override; + String get_gizmo_name() const override; + int get_priority() const override; + void redraw(EditorNode3DGizmo *p_gizmo) override; + + CollisionObject3DGizmoPlugin(); +}; + +#endif // COLLISION_OBJECT_3D_GIZMO_PLUGIN_H diff --git a/editor/plugins/gizmos/collision_polygon_3d_gizmo_plugin.cpp b/editor/plugins/gizmos/collision_polygon_3d_gizmo_plugin.cpp new file mode 100644 index 00000000000..50c10be11d7 --- /dev/null +++ b/editor/plugins/gizmos/collision_polygon_3d_gizmo_plugin.cpp @@ -0,0 +1,81 @@ +/**************************************************************************/ +/* collision_polygon_3d_gizmo_plugin.cpp */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* 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 "collision_polygon_3d_gizmo_plugin.h" + +#include "editor/editor_settings.h" +#include "editor/plugins/node_3d_editor_plugin.h" +#include "scene/3d/collision_polygon_3d.h" + +CollisionPolygon3DGizmoPlugin::CollisionPolygon3DGizmoPlugin() { + const Color gizmo_color = EDITOR_GET("editors/3d_gizmos/gizmo_colors/shape"); + create_material("shape_material", gizmo_color); + const float gizmo_value = gizmo_color.get_v(); + const Color gizmo_color_disabled = Color(gizmo_value, gizmo_value, gizmo_value, 0.65); + create_material("shape_material_disabled", gizmo_color_disabled); +} + +bool CollisionPolygon3DGizmoPlugin::has_gizmo(Node3D *p_spatial) { + return Object::cast_to(p_spatial) != nullptr; +} + +String CollisionPolygon3DGizmoPlugin::get_gizmo_name() const { + return "CollisionPolygon3D"; +} + +int CollisionPolygon3DGizmoPlugin::get_priority() const { + return -1; +} + +void CollisionPolygon3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) { + CollisionPolygon3D *polygon = Object::cast_to(p_gizmo->get_node_3d()); + + p_gizmo->clear(); + + Vector points = polygon->get_polygon(); + float depth = polygon->get_depth() * 0.5; + + Vector lines; + for (int i = 0; i < points.size(); i++) { + int n = (i + 1) % points.size(); + lines.push_back(Vector3(points[i].x, points[i].y, depth)); + lines.push_back(Vector3(points[n].x, points[n].y, depth)); + lines.push_back(Vector3(points[i].x, points[i].y, -depth)); + lines.push_back(Vector3(points[n].x, points[n].y, -depth)); + lines.push_back(Vector3(points[i].x, points[i].y, depth)); + lines.push_back(Vector3(points[i].x, points[i].y, -depth)); + } + + const Ref material = + get_material(!polygon->is_disabled() ? "shape_material" : "shape_material_disabled", p_gizmo); + + p_gizmo->add_lines(lines, material); + p_gizmo->add_collision_segments(lines); +} diff --git a/editor/plugins/gizmos/collision_polygon_3d_gizmo_plugin.h b/editor/plugins/gizmos/collision_polygon_3d_gizmo_plugin.h new file mode 100644 index 00000000000..b8342a25ca5 --- /dev/null +++ b/editor/plugins/gizmos/collision_polygon_3d_gizmo_plugin.h @@ -0,0 +1,47 @@ +/**************************************************************************/ +/* collision_polygon_3d_gizmo_plugin.h */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* 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. */ +/**************************************************************************/ + +#ifndef COLLISION_POLYGON_3D_GIZMO_PLUGIN_H +#define COLLISION_POLYGON_3D_GIZMO_PLUGIN_H + +#include "editor/plugins/node_3d_editor_gizmos.h" + +class CollisionPolygon3DGizmoPlugin : public EditorNode3DGizmoPlugin { + GDCLASS(CollisionPolygon3DGizmoPlugin, EditorNode3DGizmoPlugin); + +public: + bool has_gizmo(Node3D *p_spatial) override; + String get_gizmo_name() const override; + int get_priority() const override; + void redraw(EditorNode3DGizmo *p_gizmo) override; + CollisionPolygon3DGizmoPlugin(); +}; + +#endif // COLLISION_POLYGON_3D_GIZMO_PLUGIN_H diff --git a/editor/plugins/gizmos/collision_shape_3d_gizmo_plugin.cpp b/editor/plugins/gizmos/collision_shape_3d_gizmo_plugin.cpp new file mode 100644 index 00000000000..79f46f7bf70 --- /dev/null +++ b/editor/plugins/gizmos/collision_shape_3d_gizmo_plugin.cpp @@ -0,0 +1,646 @@ +/**************************************************************************/ +/* collision_shape_3d_gizmo_plugin.cpp */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* 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 "collision_shape_3d_gizmo_plugin.h" + +#include "core/math/convex_hull.h" +#include "core/math/geometry_3d.h" +#include "editor/editor_settings.h" +#include "editor/editor_undo_redo_manager.h" +#include "editor/plugins/node_3d_editor_plugin.h" +#include "scene/3d/collision_shape_3d.h" +#include "scene/resources/box_shape_3d.h" +#include "scene/resources/capsule_shape_3d.h" +#include "scene/resources/concave_polygon_shape_3d.h" +#include "scene/resources/convex_polygon_shape_3d.h" +#include "scene/resources/cylinder_shape_3d.h" +#include "scene/resources/height_map_shape_3d.h" +#include "scene/resources/separation_ray_shape_3d.h" +#include "scene/resources/sphere_shape_3d.h" +#include "scene/resources/world_boundary_shape_3d.h" + +CollisionShape3DGizmoPlugin::CollisionShape3DGizmoPlugin() { + const Color gizmo_color = EDITOR_GET("editors/3d_gizmos/gizmo_colors/shape"); + create_material("shape_material", gizmo_color); + const float gizmo_value = gizmo_color.get_v(); + const Color gizmo_color_disabled = Color(gizmo_value, gizmo_value, gizmo_value, 0.65); + create_material("shape_material_disabled", gizmo_color_disabled); + create_handle_material("handles"); +} + +bool CollisionShape3DGizmoPlugin::has_gizmo(Node3D *p_spatial) { + return Object::cast_to(p_spatial) != nullptr; +} + +String CollisionShape3DGizmoPlugin::get_gizmo_name() const { + return "CollisionShape3D"; +} + +int CollisionShape3DGizmoPlugin::get_priority() const { + return -1; +} + +String CollisionShape3DGizmoPlugin::get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const { + const CollisionShape3D *cs = Object::cast_to(p_gizmo->get_node_3d()); + + Ref s = cs->get_shape(); + if (s.is_null()) { + return ""; + } + + if (Object::cast_to(*s)) { + return "Radius"; + } + + if (Object::cast_to(*s)) { + return "Size"; + } + + if (Object::cast_to(*s)) { + return p_id == 0 ? "Radius" : "Height"; + } + + if (Object::cast_to(*s)) { + return p_id == 0 ? "Radius" : "Height"; + } + + if (Object::cast_to(*s)) { + return "Length"; + } + + return ""; +} + +Variant CollisionShape3DGizmoPlugin::get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const { + CollisionShape3D *cs = Object::cast_to(p_gizmo->get_node_3d()); + + Ref s = cs->get_shape(); + if (s.is_null()) { + return Variant(); + } + + if (Object::cast_to(*s)) { + Ref ss = s; + return ss->get_radius(); + } + + if (Object::cast_to(*s)) { + Ref bs = s; + return bs->get_size(); + } + + if (Object::cast_to(*s)) { + Ref cs2 = s; + return Vector2(cs2->get_radius(), cs2->get_height()); + } + + if (Object::cast_to(*s)) { + Ref cs2 = s; + return p_id == 0 ? cs2->get_radius() : cs2->get_height(); + } + + if (Object::cast_to(*s)) { + Ref cs2 = s; + return cs2->get_length(); + } + + return Variant(); +} + +void CollisionShape3DGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, Camera3D *p_camera, const Point2 &p_point) { + CollisionShape3D *cs = Object::cast_to(p_gizmo->get_node_3d()); + + Ref s = cs->get_shape(); + if (s.is_null()) { + return; + } + + Transform3D gt = cs->get_global_transform(); + Transform3D gi = gt.affine_inverse(); + + Vector3 ray_from = p_camera->project_ray_origin(p_point); + Vector3 ray_dir = p_camera->project_ray_normal(p_point); + + Vector3 sg[2] = { gi.xform(ray_from), gi.xform(ray_from + ray_dir * 4096) }; + + if (Object::cast_to(*s)) { + Ref ss = s; + Vector3 ra, rb; + Geometry3D::get_closest_points_between_segments(Vector3(), Vector3(4096, 0, 0), sg[0], sg[1], ra, rb); + float d = ra.x; + if (Node3DEditor::get_singleton()->is_snap_enabled()) { + d = Math::snapped(d, Node3DEditor::get_singleton()->get_translate_snap()); + } + + if (d < 0.001) { + d = 0.001; + } + + ss->set_radius(d); + } + + if (Object::cast_to(*s)) { + Ref rs = s; + Vector3 ra, rb; + Geometry3D::get_closest_points_between_segments(Vector3(), Vector3(0, 0, 4096), sg[0], sg[1], ra, rb); + float d = ra.z; + if (Node3DEditor::get_singleton()->is_snap_enabled()) { + d = Math::snapped(d, Node3DEditor::get_singleton()->get_translate_snap()); + } + + if (d < 0.001) { + d = 0.001; + } + + rs->set_length(d); + } + + if (Object::cast_to(*s)) { + Vector3 axis; + axis[p_id] = 1.0; + Ref bs = s; + Vector3 ra, rb; + Geometry3D::get_closest_points_between_segments(Vector3(), axis * 4096, sg[0], sg[1], ra, rb); + float d = ra[p_id] * 2; + if (Node3DEditor::get_singleton()->is_snap_enabled()) { + d = Math::snapped(d, Node3DEditor::get_singleton()->get_translate_snap()); + } + + if (d < 0.001) { + d = 0.001; + } + + Vector3 he = bs->get_size(); + he[p_id] = d; + bs->set_size(he); + } + + if (Object::cast_to(*s)) { + Vector3 axis; + axis[p_id == 0 ? 0 : 1] = 1.0; + Ref cs2 = s; + Vector3 ra, rb; + Geometry3D::get_closest_points_between_segments(Vector3(), axis * 4096, sg[0], sg[1], ra, rb); + float d = axis.dot(ra); + + if (Node3DEditor::get_singleton()->is_snap_enabled()) { + d = Math::snapped(d, Node3DEditor::get_singleton()->get_translate_snap()); + } + + if (d < 0.001) { + d = 0.001; + } + + if (p_id == 0) { + cs2->set_radius(d); + } else if (p_id == 1) { + cs2->set_height(d * 2.0); + } + } + + if (Object::cast_to(*s)) { + Vector3 axis; + axis[p_id == 0 ? 0 : 1] = 1.0; + Ref cs2 = s; + Vector3 ra, rb; + Geometry3D::get_closest_points_between_segments(Vector3(), axis * 4096, sg[0], sg[1], ra, rb); + float d = axis.dot(ra); + if (Node3DEditor::get_singleton()->is_snap_enabled()) { + d = Math::snapped(d, Node3DEditor::get_singleton()->get_translate_snap()); + } + + if (d < 0.001) { + d = 0.001; + } + + if (p_id == 0) { + cs2->set_radius(d); + } else if (p_id == 1) { + cs2->set_height(d * 2.0); + } + } +} + +void CollisionShape3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, const Variant &p_restore, bool p_cancel) { + CollisionShape3D *cs = Object::cast_to(p_gizmo->get_node_3d()); + + Ref s = cs->get_shape(); + if (s.is_null()) { + return; + } + + if (Object::cast_to(*s)) { + Ref ss = s; + if (p_cancel) { + ss->set_radius(p_restore); + return; + } + + EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton(); + ur->create_action(TTR("Change Sphere Shape Radius")); + ur->add_do_method(ss.ptr(), "set_radius", ss->get_radius()); + ur->add_undo_method(ss.ptr(), "set_radius", p_restore); + ur->commit_action(); + } + + if (Object::cast_to(*s)) { + Ref ss = s; + if (p_cancel) { + ss->set_size(p_restore); + return; + } + + EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton(); + ur->create_action(TTR("Change Box Shape Size")); + ur->add_do_method(ss.ptr(), "set_size", ss->get_size()); + ur->add_undo_method(ss.ptr(), "set_size", p_restore); + ur->commit_action(); + } + + if (Object::cast_to(*s)) { + Ref ss = s; + Vector2 values = p_restore; + + if (p_cancel) { + ss->set_radius(values[0]); + ss->set_height(values[1]); + return; + } + + EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton(); + if (p_id == 0) { + ur->create_action(TTR("Change Capsule Shape Radius")); + ur->add_do_method(ss.ptr(), "set_radius", ss->get_radius()); + } else { + ur->create_action(TTR("Change Capsule Shape Height")); + ur->add_do_method(ss.ptr(), "set_height", ss->get_height()); + } + ur->add_undo_method(ss.ptr(), "set_radius", values[0]); + ur->add_undo_method(ss.ptr(), "set_height", values[1]); + + ur->commit_action(); + } + + if (Object::cast_to(*s)) { + Ref ss = s; + if (p_cancel) { + if (p_id == 0) { + ss->set_radius(p_restore); + } else { + ss->set_height(p_restore); + } + return; + } + + EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton(); + if (p_id == 0) { + ur->create_action(TTR("Change Cylinder Shape Radius")); + ur->add_do_method(ss.ptr(), "set_radius", ss->get_radius()); + ur->add_undo_method(ss.ptr(), "set_radius", p_restore); + } else { + ur->create_action( + /// + + //////// + TTR("Change Cylinder Shape Height")); + ur->add_do_method(ss.ptr(), "set_height", ss->get_height()); + ur->add_undo_method(ss.ptr(), "set_height", p_restore); + } + + ur->commit_action(); + } + + if (Object::cast_to(*s)) { + Ref ss = s; + if (p_cancel) { + ss->set_length(p_restore); + return; + } + + EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton(); + ur->create_action(TTR("Change Separation Ray Shape Length")); + ur->add_do_method(ss.ptr(), "set_length", ss->get_length()); + ur->add_undo_method(ss.ptr(), "set_length", p_restore); + ur->commit_action(); + } +} + +void CollisionShape3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) { + CollisionShape3D *cs = Object::cast_to(p_gizmo->get_node_3d()); + + p_gizmo->clear(); + + Ref s = cs->get_shape(); + if (s.is_null()) { + return; + } + + const Ref material = + get_material(!cs->is_disabled() ? "shape_material" : "shape_material_disabled", p_gizmo); + Ref handles_material = get_material("handles"); + + if (Object::cast_to(*s)) { + Ref sp = s; + float r = sp->get_radius(); + + Vector points; + + for (int i = 0; i <= 360; i++) { + float ra = Math::deg_to_rad((float)i); + float rb = Math::deg_to_rad((float)i + 1); + Point2 a = Vector2(Math::sin(ra), Math::cos(ra)) * r; + Point2 b = Vector2(Math::sin(rb), Math::cos(rb)) * r; + + points.push_back(Vector3(a.x, 0, a.y)); + points.push_back(Vector3(b.x, 0, b.y)); + points.push_back(Vector3(0, a.x, a.y)); + points.push_back(Vector3(0, b.x, b.y)); + points.push_back(Vector3(a.x, a.y, 0)); + points.push_back(Vector3(b.x, b.y, 0)); + } + + Vector collision_segments; + + for (int i = 0; i < 64; i++) { + float ra = i * (Math_TAU / 64.0); + float rb = (i + 1) * (Math_TAU / 64.0); + Point2 a = Vector2(Math::sin(ra), Math::cos(ra)) * r; + Point2 b = Vector2(Math::sin(rb), Math::cos(rb)) * r; + + collision_segments.push_back(Vector3(a.x, 0, a.y)); + collision_segments.push_back(Vector3(b.x, 0, b.y)); + collision_segments.push_back(Vector3(0, a.x, a.y)); + collision_segments.push_back(Vector3(0, b.x, b.y)); + collision_segments.push_back(Vector3(a.x, a.y, 0)); + collision_segments.push_back(Vector3(b.x, b.y, 0)); + } + + p_gizmo->add_lines(points, material); + p_gizmo->add_collision_segments(collision_segments); + Vector handles; + handles.push_back(Vector3(r, 0, 0)); + p_gizmo->add_handles(handles, handles_material); + } + + if (Object::cast_to(*s)) { + Ref bs = s; + Vector lines; + AABB aabb; + aabb.position = -bs->get_size() / 2; + aabb.size = bs->get_size(); + + for (int i = 0; i < 12; i++) { + Vector3 a, b; + aabb.get_edge(i, a, b); + lines.push_back(a); + lines.push_back(b); + } + + Vector handles; + + for (int i = 0; i < 3; i++) { + Vector3 ax; + ax[i] = bs->get_size()[i] / 2; + handles.push_back(ax); + } + + p_gizmo->add_lines(lines, material); + p_gizmo->add_collision_segments(lines); + p_gizmo->add_handles(handles, handles_material); + } + + if (Object::cast_to(*s)) { + Ref cs2 = s; + float radius = cs2->get_radius(); + float height = cs2->get_height(); + + Vector points; + + Vector3 d(0, height * 0.5 - radius, 0); + for (int i = 0; i < 360; i++) { + float ra = Math::deg_to_rad((float)i); + float rb = Math::deg_to_rad((float)i + 1); + Point2 a = Vector2(Math::sin(ra), Math::cos(ra)) * radius; + Point2 b = Vector2(Math::sin(rb), Math::cos(rb)) * radius; + + points.push_back(Vector3(a.x, 0, a.y) + d); + points.push_back(Vector3(b.x, 0, b.y) + d); + + points.push_back(Vector3(a.x, 0, a.y) - d); + points.push_back(Vector3(b.x, 0, b.y) - d); + + if (i % 90 == 0) { + points.push_back(Vector3(a.x, 0, a.y) + d); + points.push_back(Vector3(a.x, 0, a.y) - d); + } + + Vector3 dud = i < 180 ? d : -d; + + points.push_back(Vector3(0, a.x, a.y) + dud); + points.push_back(Vector3(0, b.x, b.y) + dud); + points.push_back(Vector3(a.y, a.x, 0) + dud); + points.push_back(Vector3(b.y, b.x, 0) + dud); + } + + p_gizmo->add_lines(points, material); + + Vector collision_segments; + + for (int i = 0; i < 64; i++) { + float ra = i * (Math_TAU / 64.0); + float rb = (i + 1) * (Math_TAU / 64.0); + Point2 a = Vector2(Math::sin(ra), Math::cos(ra)) * radius; + Point2 b = Vector2(Math::sin(rb), Math::cos(rb)) * radius; + + collision_segments.push_back(Vector3(a.x, 0, a.y) + d); + collision_segments.push_back(Vector3(b.x, 0, b.y) + d); + + collision_segments.push_back(Vector3(a.x, 0, a.y) - d); + collision_segments.push_back(Vector3(b.x, 0, b.y) - d); + + if (i % 16 == 0) { + collision_segments.push_back(Vector3(a.x, 0, a.y) + d); + collision_segments.push_back(Vector3(a.x, 0, a.y) - d); + } + + Vector3 dud = i < 32 ? d : -d; + + collision_segments.push_back(Vector3(0, a.x, a.y) + dud); + collision_segments.push_back(Vector3(0, b.x, b.y) + dud); + collision_segments.push_back(Vector3(a.y, a.x, 0) + dud); + collision_segments.push_back(Vector3(b.y, b.x, 0) + dud); + } + + p_gizmo->add_collision_segments(collision_segments); + + Vector handles = { + Vector3(cs2->get_radius(), 0, 0), + Vector3(0, cs2->get_height() * 0.5, 0) + }; + p_gizmo->add_handles(handles, handles_material); + } + + if (Object::cast_to(*s)) { + Ref cs2 = s; + float radius = cs2->get_radius(); + float height = cs2->get_height(); + + Vector points; + + Vector3 d(0, height * 0.5, 0); + for (int i = 0; i < 360; i++) { + float ra = Math::deg_to_rad((float)i); + float rb = Math::deg_to_rad((float)i + 1); + Point2 a = Vector2(Math::sin(ra), Math::cos(ra)) * radius; + Point2 b = Vector2(Math::sin(rb), Math::cos(rb)) * radius; + + points.push_back(Vector3(a.x, 0, a.y) + d); + points.push_back(Vector3(b.x, 0, b.y) + d); + + points.push_back(Vector3(a.x, 0, a.y) - d); + points.push_back(Vector3(b.x, 0, b.y) - d); + + if (i % 90 == 0) { + points.push_back(Vector3(a.x, 0, a.y) + d); + points.push_back(Vector3(a.x, 0, a.y) - d); + } + } + + p_gizmo->add_lines(points, material); + + Vector collision_segments; + + for (int i = 0; i < 64; i++) { + float ra = i * (Math_TAU / 64.0); + float rb = (i + 1) * (Math_TAU / 64.0); + Point2 a = Vector2(Math::sin(ra), Math::cos(ra)) * radius; + Point2 b = Vector2(Math::sin(rb), Math::cos(rb)) * radius; + + collision_segments.push_back(Vector3(a.x, 0, a.y) + d); + collision_segments.push_back(Vector3(b.x, 0, b.y) + d); + + collision_segments.push_back(Vector3(a.x, 0, a.y) - d); + collision_segments.push_back(Vector3(b.x, 0, b.y) - d); + + if (i % 16 == 0) { + collision_segments.push_back(Vector3(a.x, 0, a.y) + d); + collision_segments.push_back(Vector3(a.x, 0, a.y) - d); + } + } + + p_gizmo->add_collision_segments(collision_segments); + + Vector handles = { + Vector3(cs2->get_radius(), 0, 0), + Vector3(0, cs2->get_height() * 0.5, 0) + }; + p_gizmo->add_handles(handles, handles_material); + } + + if (Object::cast_to(*s)) { + Ref wbs = s; + const Plane &p = wbs->get_plane(); + + Vector3 n1 = p.get_any_perpendicular_normal(); + Vector3 n2 = p.normal.cross(n1).normalized(); + + Vector3 pface[4] = { + p.normal * p.d + n1 * 10.0 + n2 * 10.0, + p.normal * p.d + n1 * 10.0 + n2 * -10.0, + p.normal * p.d + n1 * -10.0 + n2 * -10.0, + p.normal * p.d + n1 * -10.0 + n2 * 10.0, + }; + + Vector points = { + pface[0], + pface[1], + pface[1], + pface[2], + pface[2], + pface[3], + pface[3], + pface[0], + p.normal * p.d, + p.normal * p.d + p.normal * 3 + }; + + p_gizmo->add_lines(points, material); + p_gizmo->add_collision_segments(points); + } + + if (Object::cast_to(*s)) { + Vector points = Object::cast_to(*s)->get_points(); + + if (points.size() > 3) { + Vector varr = Variant(points); + Geometry3D::MeshData md; + Error err = ConvexHullComputer::convex_hull(varr, md); + if (err == OK) { + Vector points2; + points2.resize(md.edges.size() * 2); + for (uint32_t i = 0; i < md.edges.size(); i++) { + points2.write[i * 2 + 0] = md.vertices[md.edges[i].vertex_a]; + points2.write[i * 2 + 1] = md.vertices[md.edges[i].vertex_b]; + } + + p_gizmo->add_lines(points2, material); + p_gizmo->add_collision_segments(points2); + } + } + } + + if (Object::cast_to(*s)) { + Ref cs2 = s; + Ref mesh = cs2->get_debug_mesh(); + p_gizmo->add_mesh(mesh, material); + p_gizmo->add_collision_segments(cs2->get_debug_mesh_lines()); + } + + if (Object::cast_to(*s)) { + Ref rs = s; + + Vector points = { + Vector3(), + Vector3(0, 0, rs->get_length()) + }; + p_gizmo->add_lines(points, material); + p_gizmo->add_collision_segments(points); + Vector handles; + handles.push_back(Vector3(0, 0, rs->get_length())); + p_gizmo->add_handles(handles, handles_material); + } + + if (Object::cast_to(*s)) { + Ref hms = s; + + Ref mesh = hms->get_debug_mesh(); + p_gizmo->add_mesh(mesh, material); + } +} diff --git a/editor/plugins/gizmos/collision_shape_3d_gizmo_plugin.h b/editor/plugins/gizmos/collision_shape_3d_gizmo_plugin.h new file mode 100644 index 00000000000..520295a522c --- /dev/null +++ b/editor/plugins/gizmos/collision_shape_3d_gizmo_plugin.h @@ -0,0 +1,53 @@ +/**************************************************************************/ +/* collision_shape_3d_gizmo_plugin.h */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* 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. */ +/**************************************************************************/ + +#ifndef COLLISION_SHAPE_3D_GIZMO_PLUGIN_H +#define COLLISION_SHAPE_3D_GIZMO_PLUGIN_H + +#include "editor/plugins/node_3d_editor_gizmos.h" + +class CollisionShape3DGizmoPlugin : public EditorNode3DGizmoPlugin { + GDCLASS(CollisionShape3DGizmoPlugin, EditorNode3DGizmoPlugin); + +public: + bool has_gizmo(Node3D *p_spatial) override; + String get_gizmo_name() const override; + int get_priority() const override; + void redraw(EditorNode3DGizmo *p_gizmo) override; + + String get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const override; + Variant get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const override; + void set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, Camera3D *p_camera, const Point2 &p_point) override; + void commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, const Variant &p_restore, bool p_cancel = false) override; + + CollisionShape3DGizmoPlugin(); +}; + +#endif // COLLISION_SHAPE_3D_GIZMO_PLUGIN_H diff --git a/editor/plugins/gizmos/cpu_particles_3d_gizmo_plugin.cpp b/editor/plugins/gizmos/cpu_particles_3d_gizmo_plugin.cpp new file mode 100644 index 00000000000..a8ac8429450 --- /dev/null +++ b/editor/plugins/gizmos/cpu_particles_3d_gizmo_plugin.cpp @@ -0,0 +1,59 @@ +/**************************************************************************/ +/* cpu_particles_3d_gizmo_plugin.cpp */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* 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 "cpu_particles_3d_gizmo_plugin.h" + +#include "editor/plugins/node_3d_editor_plugin.h" +#include "scene/3d/cpu_particles_3d.h" + +CPUParticles3DGizmoPlugin::CPUParticles3DGizmoPlugin() { + create_icon_material("particles_icon", Node3DEditor::get_singleton()->get_theme_icon(SNAME("GizmoCPUParticles3D"), SNAME("EditorIcons"))); +} + +bool CPUParticles3DGizmoPlugin::has_gizmo(Node3D *p_spatial) { + return Object::cast_to(p_spatial) != nullptr; +} + +String CPUParticles3DGizmoPlugin::get_gizmo_name() const { + return "CPUParticles3D"; +} + +int CPUParticles3DGizmoPlugin::get_priority() const { + return -1; +} + +bool CPUParticles3DGizmoPlugin::is_selectable_when_hidden() const { + return true; +} + +void CPUParticles3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) { + Ref icon = get_material("particles_icon", p_gizmo); + p_gizmo->add_unscaled_billboard(icon, 0.05); +} diff --git a/editor/plugins/gizmos/cpu_particles_3d_gizmo_plugin.h b/editor/plugins/gizmos/cpu_particles_3d_gizmo_plugin.h new file mode 100644 index 00000000000..5765d613aac --- /dev/null +++ b/editor/plugins/gizmos/cpu_particles_3d_gizmo_plugin.h @@ -0,0 +1,48 @@ +/**************************************************************************/ +/* cpu_particles_3d_gizmo_plugin.h */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* 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. */ +/**************************************************************************/ + +#ifndef CPU_PARTICLES_3D_GIZMO_PLUGIN_H +#define CPU_PARTICLES_3D_GIZMO_PLUGIN_H + +#include "editor/plugins/node_3d_editor_gizmos.h" + +class CPUParticles3DGizmoPlugin : public EditorNode3DGizmoPlugin { + GDCLASS(CPUParticles3DGizmoPlugin, EditorNode3DGizmoPlugin); + +public: + bool has_gizmo(Node3D *p_spatial) override; + String get_gizmo_name() const override; + int get_priority() const override; + bool is_selectable_when_hidden() const override; + void redraw(EditorNode3DGizmo *p_gizmo) override; + CPUParticles3DGizmoPlugin(); +}; + +#endif // CPU_PARTICLES_3D_GIZMO_PLUGIN_H diff --git a/editor/plugins/gizmos/decal_gizmo_plugin.cpp b/editor/plugins/gizmos/decal_gizmo_plugin.cpp new file mode 100644 index 00000000000..b439598ef4a --- /dev/null +++ b/editor/plugins/gizmos/decal_gizmo_plugin.cpp @@ -0,0 +1,168 @@ +/**************************************************************************/ +/* decal_gizmo_plugin.cpp */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* 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 "decal_gizmo_plugin.h" + +#include "editor/editor_settings.h" +#include "editor/editor_undo_redo_manager.h" +#include "editor/plugins/node_3d_editor_plugin.h" +#include "scene/3d/decal.h" + +DecalGizmoPlugin::DecalGizmoPlugin() { + Color gizmo_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/decal", Color(0.6, 0.5, 1.0)); + + create_material("decal_material", gizmo_color); + + create_handle_material("handles"); +} + +bool DecalGizmoPlugin::has_gizmo(Node3D *p_spatial) { + return Object::cast_to(p_spatial) != nullptr; +} + +String DecalGizmoPlugin::get_gizmo_name() const { + return "Decal"; +} + +int DecalGizmoPlugin::get_priority() const { + return -1; +} + +String DecalGizmoPlugin::get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const { + switch (p_id) { + case 0: + return "Size X"; + case 1: + return "Size Y"; + case 2: + return "Size Z"; + } + + return ""; +} + +Variant DecalGizmoPlugin::get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const { + Decal *decal = Object::cast_to(p_gizmo->get_node_3d()); + return decal->get_size(); +} + +void DecalGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, Camera3D *p_camera, const Point2 &p_point) { + Decal *decal = Object::cast_to(p_gizmo->get_node_3d()); + Transform3D gt = decal->get_global_transform(); + + Transform3D gi = gt.affine_inverse(); + + Vector3 size = decal->get_size(); + + Vector3 ray_from = p_camera->project_ray_origin(p_point); + Vector3 ray_dir = p_camera->project_ray_normal(p_point); + + Vector3 sg[2] = { gi.xform(ray_from), gi.xform(ray_from + ray_dir * 16384) }; + + Vector3 axis; + axis[p_id] = 1.0; + + Vector3 ra, rb; + Geometry3D::get_closest_points_between_segments(Vector3(), axis * 16384, sg[0], sg[1], ra, rb); + float d = ra[p_id] * 2; + if (Node3DEditor::get_singleton()->is_snap_enabled()) { + d = Math::snapped(d, Node3DEditor::get_singleton()->get_translate_snap()); + } + + if (d < 0.001) { + d = 0.001; + } + + size[p_id] = d; + decal->set_size(size); +} + +void DecalGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, const Variant &p_restore, bool p_cancel) { + Decal *decal = Object::cast_to(p_gizmo->get_node_3d()); + + Vector3 restore = p_restore; + + if (p_cancel) { + decal->set_size(restore); + return; + } + + EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton(); + ur->create_action(TTR("Change Decal Size")); + ur->add_do_method(decal, "set_size", decal->get_size()); + ur->add_undo_method(decal, "set_size", restore); + ur->commit_action(); +} + +void DecalGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) { + Decal *decal = Object::cast_to(p_gizmo->get_node_3d()); + + p_gizmo->clear(); + + Vector lines; + Vector3 size = decal->get_size(); + + AABB aabb; + aabb.position = -size / 2; + aabb.size = size; + + for (int i = 0; i < 12; i++) { + Vector3 a, b; + aabb.get_edge(i, a, b); + if (a.y == b.y) { + lines.push_back(a); + lines.push_back(b); + } else { + Vector3 ah = a.lerp(b, 0.2); + lines.push_back(a); + lines.push_back(ah); + Vector3 bh = b.lerp(a, 0.2); + lines.push_back(b); + lines.push_back(bh); + } + } + + float half_size_y = size.y / 2; + lines.push_back(Vector3(0, half_size_y, 0)); + lines.push_back(Vector3(0, half_size_y * 1.2, 0)); + + Vector handles; + + for (int i = 0; i < 3; i++) { + Vector3 ax; + ax[i] = aabb.position[i] + aabb.size[i]; + handles.push_back(ax); + } + + Ref material = get_material("decal_material", p_gizmo); + + p_gizmo->add_lines(lines, material); + p_gizmo->add_handles(handles, get_material("handles")); +} diff --git a/editor/plugins/gizmos/decal_gizmo_plugin.h b/editor/plugins/gizmos/decal_gizmo_plugin.h new file mode 100644 index 00000000000..800a14b2d51 --- /dev/null +++ b/editor/plugins/gizmos/decal_gizmo_plugin.h @@ -0,0 +1,53 @@ +/**************************************************************************/ +/* decal_gizmo_plugin.h */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* 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. */ +/**************************************************************************/ + +#ifndef DECAL_GIZMO_PLUGIN_H +#define DECAL_GIZMO_PLUGIN_H + +#include "editor/plugins/node_3d_editor_gizmos.h" + +class DecalGizmoPlugin : public EditorNode3DGizmoPlugin { + GDCLASS(DecalGizmoPlugin, EditorNode3DGizmoPlugin); + +public: + bool has_gizmo(Node3D *p_spatial) override; + String get_gizmo_name() const override; + int get_priority() const override; + void redraw(EditorNode3DGizmo *p_gizmo) override; + + String get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const override; + Variant get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const override; + void set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, Camera3D *p_camera, const Point2 &p_point) override; + void commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, const Variant &p_restore, bool p_cancel = false) override; + + DecalGizmoPlugin(); +}; + +#endif // DECAL_GIZMO_PLUGIN_H diff --git a/editor/plugins/gizmos/fog_volume_gizmo_plugin.cpp b/editor/plugins/gizmos/fog_volume_gizmo_plugin.cpp new file mode 100644 index 00000000000..8f7cbee4055 --- /dev/null +++ b/editor/plugins/gizmos/fog_volume_gizmo_plugin.cpp @@ -0,0 +1,148 @@ +/**************************************************************************/ +/* fog_volume_gizmo_plugin.cpp */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* 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 "fog_volume_gizmo_plugin.h" + +#include "editor/editor_settings.h" +#include "editor/editor_undo_redo_manager.h" +#include "editor/plugins/node_3d_editor_plugin.h" +#include "scene/3d/fog_volume.h" + +FogVolumeGizmoPlugin::FogVolumeGizmoPlugin() { + Color gizmo_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/fog_volume", Color(0.5, 0.7, 1)); + create_material("shape_material", gizmo_color); + gizmo_color.a = 0.15; + create_material("shape_material_internal", gizmo_color); + + create_handle_material("handles"); +} + +bool FogVolumeGizmoPlugin::has_gizmo(Node3D *p_spatial) { + return (Object::cast_to(p_spatial) != nullptr); +} + +String FogVolumeGizmoPlugin::get_gizmo_name() const { + return "FogVolume"; +} + +int FogVolumeGizmoPlugin::get_priority() const { + return -1; +} + +String FogVolumeGizmoPlugin::get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const { + return "Size"; +} + +Variant FogVolumeGizmoPlugin::get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const { + return Vector3(p_gizmo->get_node_3d()->call("get_size")); +} + +void FogVolumeGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, Camera3D *p_camera, const Point2 &p_point) { + Node3D *sn = p_gizmo->get_node_3d(); + + Transform3D gt = sn->get_global_transform(); + Transform3D gi = gt.affine_inverse(); + + Vector3 ray_from = p_camera->project_ray_origin(p_point); + Vector3 ray_dir = p_camera->project_ray_normal(p_point); + + Vector3 sg[2] = { gi.xform(ray_from), gi.xform(ray_from + ray_dir * 4096) }; + + Vector3 axis; + axis[p_id] = 1.0; + Vector3 ra, rb; + Geometry3D::get_closest_points_between_segments(Vector3(), axis * 4096, sg[0], sg[1], ra, rb); + float d = ra[p_id] * 2; + if (Node3DEditor::get_singleton()->is_snap_enabled()) { + d = Math::snapped(d, Node3DEditor::get_singleton()->get_translate_snap()); + } + + if (d < 0.001) { + d = 0.001; + } + + Vector3 he = sn->call("get_size"); + he[p_id] = d; + sn->call("set_size", he); +} + +void FogVolumeGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, const Variant &p_restore, bool p_cancel) { + Node3D *sn = p_gizmo->get_node_3d(); + + if (p_cancel) { + sn->call("set_size", p_restore); + return; + } + + EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton(); + ur->create_action(TTR("Change Fog Volume Size")); + ur->add_do_method(sn, "set_size", sn->call("get_size")); + ur->add_undo_method(sn, "set_size", p_restore); + ur->commit_action(); +} + +void FogVolumeGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) { + Node3D *cs = p_gizmo->get_node_3d(); + + p_gizmo->clear(); + + if (RS::FogVolumeShape(int(p_gizmo->get_node_3d()->call("get_shape"))) != RS::FOG_VOLUME_SHAPE_WORLD) { + const Ref material = + get_material("shape_material", p_gizmo); + const Ref material_internal = + get_material("shape_material_internal", p_gizmo); + + Ref handles_material = get_material("handles"); + + Vector lines; + AABB aabb; + aabb.size = cs->call("get_size").operator Vector3(); + aabb.position = aabb.size / -2; + + for (int i = 0; i < 12; i++) { + Vector3 a, b; + aabb.get_edge(i, a, b); + lines.push_back(a); + lines.push_back(b); + } + + Vector handles; + + for (int i = 0; i < 3; i++) { + Vector3 ax; + ax[i] = cs->call("get_size").operator Vector3()[i] / 2; + handles.push_back(ax); + } + + p_gizmo->add_lines(lines, material); + p_gizmo->add_collision_segments(lines); + p_gizmo->add_handles(handles, handles_material); + } +} diff --git a/editor/plugins/gizmos/fog_volume_gizmo_plugin.h b/editor/plugins/gizmos/fog_volume_gizmo_plugin.h new file mode 100644 index 00000000000..7f9c68a957c --- /dev/null +++ b/editor/plugins/gizmos/fog_volume_gizmo_plugin.h @@ -0,0 +1,53 @@ +/**************************************************************************/ +/* fog_volume_gizmo_plugin.h */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* 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. */ +/**************************************************************************/ + +#ifndef FOG_VOLUME_GIZMO_PLUGIN_H +#define FOG_VOLUME_GIZMO_PLUGIN_H + +#include "editor/plugins/node_3d_editor_gizmos.h" + +class FogVolumeGizmoPlugin : public EditorNode3DGizmoPlugin { + GDCLASS(FogVolumeGizmoPlugin, EditorNode3DGizmoPlugin); + +public: + bool has_gizmo(Node3D *p_spatial) override; + String get_gizmo_name() const override; + int get_priority() const override; + void redraw(EditorNode3DGizmo *p_gizmo) override; + + String get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const override; + Variant get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const override; + void set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, Camera3D *p_camera, const Point2 &p_point) override; + void commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, const Variant &p_restore, bool p_cancel = false) override; + + FogVolumeGizmoPlugin(); +}; + +#endif // FOG_VOLUME_GIZMO_PLUGIN_H diff --git a/editor/plugins/gizmos/gpu_particles_3d_gizmo_plugin.cpp b/editor/plugins/gizmos/gpu_particles_3d_gizmo_plugin.cpp new file mode 100644 index 00000000000..a46de82e76d --- /dev/null +++ b/editor/plugins/gizmos/gpu_particles_3d_gizmo_plugin.cpp @@ -0,0 +1,199 @@ +/**************************************************************************/ +/* gpu_particles_3d_gizmo_plugin.cpp */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* 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 "gpu_particles_3d_gizmo_plugin.h" + +#include "editor/editor_settings.h" +#include "editor/editor_undo_redo_manager.h" +#include "editor/plugins/node_3d_editor_plugin.h" +#include "scene/3d/gpu_particles_3d.h" + +GPUParticles3DGizmoPlugin::GPUParticles3DGizmoPlugin() { + Color gizmo_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/particles", Color(0.8, 0.7, 0.4)); + create_material("particles_material", gizmo_color); + gizmo_color.a = MAX((gizmo_color.a - 0.2) * 0.02, 0.0); + create_material("particles_solid_material", gizmo_color); + create_icon_material("particles_icon", Node3DEditor::get_singleton()->get_theme_icon(SNAME("GizmoGPUParticles3D"), SNAME("EditorIcons"))); + create_handle_material("handles"); +} + +bool GPUParticles3DGizmoPlugin::has_gizmo(Node3D *p_spatial) { + return Object::cast_to(p_spatial) != nullptr; +} + +String GPUParticles3DGizmoPlugin::get_gizmo_name() const { + return "GPUParticles3D"; +} + +int GPUParticles3DGizmoPlugin::get_priority() const { + return -1; +} + +bool GPUParticles3DGizmoPlugin::is_selectable_when_hidden() const { + return true; +} + +String GPUParticles3DGizmoPlugin::get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const { + switch (p_id) { + case 0: + return "Size X"; + case 1: + return "Size Y"; + case 2: + return "Size Z"; + case 3: + return "Pos X"; + case 4: + return "Pos Y"; + case 5: + return "Pos Z"; + } + + return ""; +} + +Variant GPUParticles3DGizmoPlugin::get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const { + GPUParticles3D *particles = Object::cast_to(p_gizmo->get_node_3d()); + return particles->get_visibility_aabb(); +} + +void GPUParticles3DGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, Camera3D *p_camera, const Point2 &p_point) { + GPUParticles3D *particles = Object::cast_to(p_gizmo->get_node_3d()); + + Transform3D gt = particles->get_global_transform(); + Transform3D gi = gt.affine_inverse(); + + bool move = p_id >= 3; + p_id = p_id % 3; + + AABB aabb = particles->get_visibility_aabb(); + Vector3 ray_from = p_camera->project_ray_origin(p_point); + Vector3 ray_dir = p_camera->project_ray_normal(p_point); + + Vector3 sg[2] = { gi.xform(ray_from), gi.xform(ray_from + ray_dir * 4096) }; + + Vector3 ofs = aabb.get_center(); + + Vector3 axis; + axis[p_id] = 1.0; + + if (move) { + Vector3 ra, rb; + Geometry3D::get_closest_points_between_segments(ofs - axis * 4096, ofs + axis * 4096, sg[0], sg[1], ra, rb); + + float d = ra[p_id]; + if (Node3DEditor::get_singleton()->is_snap_enabled()) { + d = Math::snapped(d, Node3DEditor::get_singleton()->get_translate_snap()); + } + + aabb.position[p_id] = d - 1.0 - aabb.size[p_id] * 0.5; + particles->set_visibility_aabb(aabb); + + } else { + Vector3 ra, rb; + Geometry3D::get_closest_points_between_segments(ofs, ofs + axis * 4096, sg[0], sg[1], ra, rb); + + float d = ra[p_id] - ofs[p_id]; + if (Node3DEditor::get_singleton()->is_snap_enabled()) { + d = Math::snapped(d, Node3DEditor::get_singleton()->get_translate_snap()); + } + + if (d < 0.001) { + d = 0.001; + } + //resize + aabb.position[p_id] = (aabb.position[p_id] + aabb.size[p_id] * 0.5) - d; + aabb.size[p_id] = d * 2; + particles->set_visibility_aabb(aabb); + } +} + +void GPUParticles3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, const Variant &p_restore, bool p_cancel) { + GPUParticles3D *particles = Object::cast_to(p_gizmo->get_node_3d()); + + if (p_cancel) { + particles->set_visibility_aabb(p_restore); + return; + } + + EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton(); + ur->create_action(TTR("Change Particles AABB")); + ur->add_do_method(particles, "set_visibility_aabb", particles->get_visibility_aabb()); + ur->add_undo_method(particles, "set_visibility_aabb", p_restore); + ur->commit_action(); +} + +void GPUParticles3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) { + GPUParticles3D *particles = Object::cast_to(p_gizmo->get_node_3d()); + + p_gizmo->clear(); + + Vector lines; + AABB aabb = particles->get_visibility_aabb(); + + for (int i = 0; i < 12; i++) { + Vector3 a, b; + aabb.get_edge(i, a, b); + lines.push_back(a); + lines.push_back(b); + } + + Vector handles; + + for (int i = 0; i < 3; i++) { + Vector3 ax; + ax[i] = aabb.position[i] + aabb.size[i]; + ax[(i + 1) % 3] = aabb.position[(i + 1) % 3] + aabb.size[(i + 1) % 3] * 0.5; + ax[(i + 2) % 3] = aabb.position[(i + 2) % 3] + aabb.size[(i + 2) % 3] * 0.5; + handles.push_back(ax); + } + + Vector3 center = aabb.get_center(); + for (int i = 0; i < 3; i++) { + Vector3 ax; + ax[i] = 1.0; + handles.push_back(center + ax); + lines.push_back(center); + lines.push_back(center + ax); + } + + Ref material = get_material("particles_material", p_gizmo); + Ref icon = get_material("particles_icon", p_gizmo); + + p_gizmo->add_lines(lines, material); + + if (p_gizmo->is_selected()) { + Ref solid_material = get_material("particles_solid_material", p_gizmo); + p_gizmo->add_solid_box(solid_material, aabb.get_size(), aabb.get_center()); + } + + p_gizmo->add_handles(handles, get_material("handles")); + p_gizmo->add_unscaled_billboard(icon, 0.05); +} diff --git a/editor/plugins/gizmos/gpu_particles_3d_gizmo_plugin.h b/editor/plugins/gizmos/gpu_particles_3d_gizmo_plugin.h new file mode 100644 index 00000000000..530e3fcc5d1 --- /dev/null +++ b/editor/plugins/gizmos/gpu_particles_3d_gizmo_plugin.h @@ -0,0 +1,54 @@ +/**************************************************************************/ +/* gpu_particles_3d_gizmo_plugin.h */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* 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. */ +/**************************************************************************/ + +#ifndef GPU_PARTICLES_3D_GIZMO_PLUGIN_H +#define GPU_PARTICLES_3D_GIZMO_PLUGIN_H + +#include "editor/plugins/node_3d_editor_gizmos.h" + +class GPUParticles3DGizmoPlugin : public EditorNode3DGizmoPlugin { + GDCLASS(GPUParticles3DGizmoPlugin, EditorNode3DGizmoPlugin); + +public: + bool has_gizmo(Node3D *p_spatial) override; + String get_gizmo_name() const override; + int get_priority() const override; + bool is_selectable_when_hidden() const override; + void redraw(EditorNode3DGizmo *p_gizmo) override; + + String get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const override; + Variant get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const override; + void set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, Camera3D *p_camera, const Point2 &p_point) override; + void commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, const Variant &p_restore, bool p_cancel = false) override; + + GPUParticles3DGizmoPlugin(); +}; + +#endif // GPU_PARTICLES_3D_GIZMO_PLUGIN_H diff --git a/editor/plugins/gizmos/gpu_particles_collision_3d_gizmo_plugin.cpp b/editor/plugins/gizmos/gpu_particles_collision_3d_gizmo_plugin.cpp new file mode 100644 index 00000000000..248e15c2c14 --- /dev/null +++ b/editor/plugins/gizmos/gpu_particles_collision_3d_gizmo_plugin.cpp @@ -0,0 +1,294 @@ +/**************************************************************************/ +/* gpu_particles_collision_3d_gizmo_plugin.cpp */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* 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 "gpu_particles_collision_3d_gizmo_plugin.h" + +#include "editor/editor_settings.h" +#include "editor/editor_undo_redo_manager.h" +#include "editor/plugins/node_3d_editor_plugin.h" +#include "scene/3d/gpu_particles_collision_3d.h" + +GPUParticlesCollision3DGizmoPlugin::GPUParticlesCollision3DGizmoPlugin() { + Color gizmo_color_attractor = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/particle_attractor", Color(1, 0.7, 0.5)); + create_material("shape_material_attractor", gizmo_color_attractor); + gizmo_color_attractor.a = 0.15; + create_material("shape_material_attractor_internal", gizmo_color_attractor); + + Color gizmo_color_collision = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/particle_collision", Color(0.5, 0.7, 1)); + create_material("shape_material_collision", gizmo_color_collision); + gizmo_color_collision.a = 0.15; + create_material("shape_material_collision_internal", gizmo_color_collision); + + create_handle_material("handles"); +} + +bool GPUParticlesCollision3DGizmoPlugin::has_gizmo(Node3D *p_spatial) { + return (Object::cast_to(p_spatial) != nullptr) || (Object::cast_to(p_spatial) != nullptr); +} + +String GPUParticlesCollision3DGizmoPlugin::get_gizmo_name() const { + return "GPUParticlesCollision3D"; +} + +int GPUParticlesCollision3DGizmoPlugin::get_priority() const { + return -1; +} + +String GPUParticlesCollision3DGizmoPlugin::get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const { + const Node3D *cs = p_gizmo->get_node_3d(); + + if (Object::cast_to(cs) || Object::cast_to(cs)) { + return "Radius"; + } + + if (Object::cast_to(cs) || Object::cast_to(cs) || Object::cast_to(cs) || Object::cast_to(cs) || Object::cast_to(cs)) { + return "Size"; + } + + return ""; +} + +Variant GPUParticlesCollision3DGizmoPlugin::get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const { + const Node3D *cs = p_gizmo->get_node_3d(); + + if (Object::cast_to(cs) || Object::cast_to(cs)) { + return p_gizmo->get_node_3d()->call("get_radius"); + } + + if (Object::cast_to(cs) || Object::cast_to(cs) || Object::cast_to(cs) || Object::cast_to(cs) || Object::cast_to(cs)) { + return Vector3(p_gizmo->get_node_3d()->call("get_size")); + } + + return Variant(); +} + +void GPUParticlesCollision3DGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, Camera3D *p_camera, const Point2 &p_point) { + Node3D *sn = p_gizmo->get_node_3d(); + + Transform3D gt = sn->get_global_transform(); + Transform3D gi = gt.affine_inverse(); + + Vector3 ray_from = p_camera->project_ray_origin(p_point); + Vector3 ray_dir = p_camera->project_ray_normal(p_point); + + Vector3 sg[2] = { gi.xform(ray_from), gi.xform(ray_from + ray_dir * 4096) }; + + if (Object::cast_to(sn) || Object::cast_to(sn)) { + Vector3 ra, rb; + Geometry3D::get_closest_points_between_segments(Vector3(), Vector3(4096, 0, 0), sg[0], sg[1], ra, rb); + float d = ra.x; + if (Node3DEditor::get_singleton()->is_snap_enabled()) { + d = Math::snapped(d, Node3DEditor::get_singleton()->get_translate_snap()); + } + + if (d < 0.001) { + d = 0.001; + } + + sn->call("set_radius", d); + } + + if (Object::cast_to(sn) || Object::cast_to(sn) || Object::cast_to(sn) || Object::cast_to(sn) || Object::cast_to(sn)) { + Vector3 axis; + axis[p_id] = 1.0; + Vector3 ra, rb; + Geometry3D::get_closest_points_between_segments(Vector3(), axis * 4096, sg[0], sg[1], ra, rb); + float d = ra[p_id] * 2; + if (Node3DEditor::get_singleton()->is_snap_enabled()) { + d = Math::snapped(d, Node3DEditor::get_singleton()->get_translate_snap()); + } + + if (d < 0.001) { + d = 0.001; + } + + Vector3 he = sn->call("get_size"); + he[p_id] = d; + sn->call("set_size", he); + } +} + +void GPUParticlesCollision3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, const Variant &p_restore, bool p_cancel) { + Node3D *sn = p_gizmo->get_node_3d(); + + if (Object::cast_to(sn) || Object::cast_to(sn)) { + if (p_cancel) { + sn->call("set_radius", p_restore); + return; + } + + EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton(); + ur->create_action(TTR("Change Radius")); + ur->add_do_method(sn, "set_radius", sn->call("get_radius")); + ur->add_undo_method(sn, "set_radius", p_restore); + ur->commit_action(); + } + + if (Object::cast_to(sn) || Object::cast_to(sn) || Object::cast_to(sn) || Object::cast_to(sn) || Object::cast_to(sn)) { + if (p_cancel) { + sn->call("set_size", p_restore); + return; + } + + EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton(); + ur->create_action(TTR("Change Box Shape Size")); + ur->add_do_method(sn, "set_size", sn->call("get_size")); + ur->add_undo_method(sn, "set_size", p_restore); + ur->commit_action(); + } +} + +void GPUParticlesCollision3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) { + Node3D *cs = p_gizmo->get_node_3d(); + + p_gizmo->clear(); + + Ref material; + Ref material_internal; + if (Object::cast_to(cs)) { + material = get_material("shape_material_attractor", p_gizmo); + material_internal = get_material("shape_material_attractor_internal", p_gizmo); + } else { + material = get_material("shape_material_collision", p_gizmo); + material_internal = get_material("shape_material_collision_internal", p_gizmo); + } + + const Ref handles_material = get_material("handles"); + + if (Object::cast_to(cs) || Object::cast_to(cs)) { + float r = cs->call("get_radius"); + + Vector points; + + for (int i = 0; i <= 360; i++) { + float ra = Math::deg_to_rad((float)i); + float rb = Math::deg_to_rad((float)i + 1); + Point2 a = Vector2(Math::sin(ra), Math::cos(ra)) * r; + Point2 b = Vector2(Math::sin(rb), Math::cos(rb)) * r; + + points.push_back(Vector3(a.x, 0, a.y)); + points.push_back(Vector3(b.x, 0, b.y)); + points.push_back(Vector3(0, a.x, a.y)); + points.push_back(Vector3(0, b.x, b.y)); + points.push_back(Vector3(a.x, a.y, 0)); + points.push_back(Vector3(b.x, b.y, 0)); + } + + Vector collision_segments; + + for (int i = 0; i < 64; i++) { + float ra = i * (Math_TAU / 64.0); + float rb = (i + 1) * (Math_TAU / 64.0); + Point2 a = Vector2(Math::sin(ra), Math::cos(ra)) * r; + Point2 b = Vector2(Math::sin(rb), Math::cos(rb)) * r; + + collision_segments.push_back(Vector3(a.x, 0, a.y)); + collision_segments.push_back(Vector3(b.x, 0, b.y)); + collision_segments.push_back(Vector3(0, a.x, a.y)); + collision_segments.push_back(Vector3(0, b.x, b.y)); + collision_segments.push_back(Vector3(a.x, a.y, 0)); + collision_segments.push_back(Vector3(b.x, b.y, 0)); + } + + p_gizmo->add_lines(points, material); + p_gizmo->add_collision_segments(collision_segments); + Vector handles; + handles.push_back(Vector3(r, 0, 0)); + p_gizmo->add_handles(handles, handles_material); + } + + if (Object::cast_to(cs) || Object::cast_to(cs) || Object::cast_to(cs) || Object::cast_to(cs) || Object::cast_to(cs)) { + Vector lines; + AABB aabb; + aabb.size = cs->call("get_size").operator Vector3(); + aabb.position = aabb.size / -2; + + for (int i = 0; i < 12; i++) { + Vector3 a, b; + aabb.get_edge(i, a, b); + lines.push_back(a); + lines.push_back(b); + } + + Vector handles; + + for (int i = 0; i < 3; i++) { + Vector3 ax; + ax[i] = cs->call("get_size").operator Vector3()[i] / 2; + handles.push_back(ax); + } + + p_gizmo->add_lines(lines, material); + p_gizmo->add_collision_segments(lines); + p_gizmo->add_handles(handles, handles_material); + + GPUParticlesCollisionSDF3D *col_sdf = Object::cast_to(cs); + if (col_sdf) { + static const int subdivs[GPUParticlesCollisionSDF3D::RESOLUTION_MAX] = { 16, 32, 64, 128, 256, 512 }; + int subdiv = subdivs[col_sdf->get_resolution()]; + float cell_size = aabb.get_longest_axis_size() / subdiv; + + lines.clear(); + + for (int i = 1; i < subdiv; i++) { + for (int j = 0; j < 3; j++) { + if (cell_size * i > aabb.size[j]) { + continue; + } + + int j_n1 = (j + 1) % 3; + int j_n2 = (j + 2) % 3; + + for (int k = 0; k < 4; k++) { + Vector3 from = aabb.position, to = aabb.position; + from[j] += cell_size * i; + to[j] += cell_size * i; + + if (k & 1) { + to[j_n1] += aabb.size[j_n1]; + } else { + to[j_n2] += aabb.size[j_n2]; + } + + if (k & 2) { + from[j_n1] += aabb.size[j_n1]; + from[j_n2] += aabb.size[j_n2]; + } + + lines.push_back(from); + lines.push_back(to); + } + } + } + + p_gizmo->add_lines(lines, material_internal); + } + } +} diff --git a/editor/plugins/gizmos/gpu_particles_collision_3d_gizmo_plugin.h b/editor/plugins/gizmos/gpu_particles_collision_3d_gizmo_plugin.h new file mode 100644 index 00000000000..6045f6e4403 --- /dev/null +++ b/editor/plugins/gizmos/gpu_particles_collision_3d_gizmo_plugin.h @@ -0,0 +1,53 @@ +/**************************************************************************/ +/* gpu_particles_collision_3d_gizmo_plugin.h */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* 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. */ +/**************************************************************************/ + +#ifndef GPU_PARTICLES_COLLISION_3D_GIZMO_PLUGIN_H +#define GPU_PARTICLES_COLLISION_3D_GIZMO_PLUGIN_H + +#include "editor/plugins/node_3d_editor_gizmos.h" + +class GPUParticlesCollision3DGizmoPlugin : public EditorNode3DGizmoPlugin { + GDCLASS(GPUParticlesCollision3DGizmoPlugin, EditorNode3DGizmoPlugin); + +public: + bool has_gizmo(Node3D *p_spatial) override; + String get_gizmo_name() const override; + int get_priority() const override; + void redraw(EditorNode3DGizmo *p_gizmo) override; + + String get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const override; + Variant get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const override; + void set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, Camera3D *p_camera, const Point2 &p_point) override; + void commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, const Variant &p_restore, bool p_cancel = false) override; + + GPUParticlesCollision3DGizmoPlugin(); +}; + +#endif // GPU_PARTICLES_COLLISION_3D_GIZMO_PLUGIN_H diff --git a/editor/plugins/gizmos/joint_3d_gizmo_plugin.cpp b/editor/plugins/gizmos/joint_3d_gizmo_plugin.cpp new file mode 100644 index 00000000000..c4cb44c8fad --- /dev/null +++ b/editor/plugins/gizmos/joint_3d_gizmo_plugin.cpp @@ -0,0 +1,714 @@ +/**************************************************************************/ +/* joint_3d_gizmo_plugin.cpp */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* 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 "joint_3d_gizmo_plugin.h" + +#include "editor/editor_node.h" +#include "editor/editor_settings.h" +#include "editor/plugins/node_3d_editor_plugin.h" +#include "scene/3d/joint_3d.h" + +#define BODY_A_RADIUS 0.25 +#define BODY_B_RADIUS 0.27 + +Basis JointGizmosDrawer::look_body(const Transform3D &p_joint_transform, const Transform3D &p_body_transform) { + const Vector3 &p_eye(p_joint_transform.origin); + const Vector3 &p_target(p_body_transform.origin); + + Vector3 v_x, v_y, v_z; + + // Look the body with X + v_x = p_target - p_eye; + v_x.normalize(); + + v_z = v_x.cross(Vector3(0, 1, 0)); + v_z.normalize(); + + v_y = v_z.cross(v_x); + v_y.normalize(); + + Basis base; + base.set_columns(v_x, v_y, v_z); + + // Absorb current joint transform + base = p_joint_transform.basis.inverse() * base; + + return base; +} + +Basis JointGizmosDrawer::look_body_toward(Vector3::Axis p_axis, const Transform3D &joint_transform, const Transform3D &body_transform) { + switch (p_axis) { + case Vector3::AXIS_X: + return look_body_toward_x(joint_transform, body_transform); + case Vector3::AXIS_Y: + return look_body_toward_y(joint_transform, body_transform); + case Vector3::AXIS_Z: + return look_body_toward_z(joint_transform, body_transform); + default: + return Basis(); + } +} + +Basis JointGizmosDrawer::look_body_toward_x(const Transform3D &p_joint_transform, const Transform3D &p_body_transform) { + const Vector3 &p_eye(p_joint_transform.origin); + const Vector3 &p_target(p_body_transform.origin); + + const Vector3 p_front(p_joint_transform.basis.get_column(0)); + + Vector3 v_x, v_y, v_z; + + // Look the body with X + v_x = p_target - p_eye; + v_x.normalize(); + + v_y = p_front.cross(v_x); + v_y.normalize(); + + v_z = v_y.cross(p_front); + v_z.normalize(); + + // Clamp X to FRONT axis + v_x = p_front; + v_x.normalize(); + + Basis base; + base.set_columns(v_x, v_y, v_z); + + // Absorb current joint transform + base = p_joint_transform.basis.inverse() * base; + + return base; +} + +Basis JointGizmosDrawer::look_body_toward_y(const Transform3D &p_joint_transform, const Transform3D &p_body_transform) { + const Vector3 &p_eye(p_joint_transform.origin); + const Vector3 &p_target(p_body_transform.origin); + + const Vector3 p_up(p_joint_transform.basis.get_column(1)); + + Vector3 v_x, v_y, v_z; + + // Look the body with X + v_x = p_target - p_eye; + v_x.normalize(); + + v_z = v_x.cross(p_up); + v_z.normalize(); + + v_x = p_up.cross(v_z); + v_x.normalize(); + + // Clamp Y to UP axis + v_y = p_up; + v_y.normalize(); + + Basis base; + base.set_columns(v_x, v_y, v_z); + + // Absorb current joint transform + base = p_joint_transform.basis.inverse() * base; + + return base; +} + +Basis JointGizmosDrawer::look_body_toward_z(const Transform3D &p_joint_transform, const Transform3D &p_body_transform) { + const Vector3 &p_eye(p_joint_transform.origin); + const Vector3 &p_target(p_body_transform.origin); + + const Vector3 p_lateral(p_joint_transform.basis.get_column(2)); + + Vector3 v_x, v_y, v_z; + + // Look the body with X + v_x = p_target - p_eye; + v_x.normalize(); + + v_z = p_lateral; + v_z.normalize(); + + v_y = v_z.cross(v_x); + v_y.normalize(); + + // Clamp X to Z axis + v_x = v_y.cross(v_z); + v_x.normalize(); + + Basis base; + base.set_columns(v_x, v_y, v_z); + + // Absorb current joint transform + base = p_joint_transform.basis.inverse() * base; + + return base; +} + +void JointGizmosDrawer::draw_circle(Vector3::Axis p_axis, real_t p_radius, const Transform3D &p_offset, const Basis &p_base, real_t p_limit_lower, real_t p_limit_upper, Vector &r_points, bool p_inverse) { + if (p_limit_lower == p_limit_upper) { + r_points.push_back(p_offset.translated_local(Vector3()).origin); + r_points.push_back(p_offset.translated_local(p_base.xform(Vector3(0.5, 0, 0))).origin); + + } else { + if (p_limit_lower > p_limit_upper) { + p_limit_lower = -Math_PI; + p_limit_upper = Math_PI; + } + + const int points = 32; + + for (int i = 0; i < points; i++) { + real_t s = p_limit_lower + i * (p_limit_upper - p_limit_lower) / points; + real_t n = p_limit_lower + (i + 1) * (p_limit_upper - p_limit_lower) / points; + + Vector3 from; + Vector3 to; + switch (p_axis) { + case Vector3::AXIS_X: + if (p_inverse) { + from = p_base.xform(Vector3(0, Math::sin(s), Math::cos(s))) * p_radius; + to = p_base.xform(Vector3(0, Math::sin(n), Math::cos(n))) * p_radius; + } else { + from = p_base.xform(Vector3(0, -Math::sin(s), Math::cos(s))) * p_radius; + to = p_base.xform(Vector3(0, -Math::sin(n), Math::cos(n))) * p_radius; + } + break; + case Vector3::AXIS_Y: + if (p_inverse) { + from = p_base.xform(Vector3(Math::cos(s), 0, -Math::sin(s))) * p_radius; + to = p_base.xform(Vector3(Math::cos(n), 0, -Math::sin(n))) * p_radius; + } else { + from = p_base.xform(Vector3(Math::cos(s), 0, Math::sin(s))) * p_radius; + to = p_base.xform(Vector3(Math::cos(n), 0, Math::sin(n))) * p_radius; + } + break; + case Vector3::AXIS_Z: + from = p_base.xform(Vector3(Math::cos(s), Math::sin(s), 0)) * p_radius; + to = p_base.xform(Vector3(Math::cos(n), Math::sin(n), 0)) * p_radius; + break; + } + + if (i == points - 1) { + r_points.push_back(p_offset.translated_local(to).origin); + r_points.push_back(p_offset.translated_local(Vector3()).origin); + } + if (i == 0) { + r_points.push_back(p_offset.translated_local(from).origin); + r_points.push_back(p_offset.translated_local(Vector3()).origin); + } + + r_points.push_back(p_offset.translated_local(from).origin); + r_points.push_back(p_offset.translated_local(to).origin); + } + + r_points.push_back(p_offset.translated_local(Vector3(0, p_radius * 1.5, 0)).origin); + r_points.push_back(p_offset.translated_local(Vector3()).origin); + } +} + +void JointGizmosDrawer::draw_cone(const Transform3D &p_offset, const Basis &p_base, real_t p_swing, real_t p_twist, Vector &r_points) { + float r = 1.0; + float w = r * Math::sin(p_swing); + float d = r * Math::cos(p_swing); + + //swing + for (int i = 0; i < 360; i += 10) { + float ra = Math::deg_to_rad((float)i); + float rb = Math::deg_to_rad((float)i + 10); + Point2 a = Vector2(Math::sin(ra), Math::cos(ra)) * w; + Point2 b = Vector2(Math::sin(rb), Math::cos(rb)) * w; + + r_points.push_back(p_offset.translated_local(p_base.xform(Vector3(d, a.x, a.y))).origin); + r_points.push_back(p_offset.translated_local(p_base.xform(Vector3(d, b.x, b.y))).origin); + + if (i % 90 == 0) { + r_points.push_back(p_offset.translated_local(p_base.xform(Vector3(d, a.x, a.y))).origin); + r_points.push_back(p_offset.translated_local(p_base.xform(Vector3())).origin); + } + } + + r_points.push_back(p_offset.translated_local(p_base.xform(Vector3())).origin); + r_points.push_back(p_offset.translated_local(p_base.xform(Vector3(1, 0, 0))).origin); + + /// Twist + float ts = Math::rad_to_deg(p_twist); + ts = MIN(ts, 720); + + for (int i = 0; i < int(ts); i += 5) { + float ra = Math::deg_to_rad((float)i); + float rb = Math::deg_to_rad((float)i + 5); + float c = i / 720.0; + float cn = (i + 5) / 720.0; + Point2 a = Vector2(Math::sin(ra), Math::cos(ra)) * w * c; + Point2 b = Vector2(Math::sin(rb), Math::cos(rb)) * w * cn; + + r_points.push_back(p_offset.translated_local(p_base.xform(Vector3(c, a.x, a.y))).origin); + r_points.push_back(p_offset.translated_local(p_base.xform(Vector3(cn, b.x, b.y))).origin); + } +} + +//// + +Joint3DGizmoPlugin::Joint3DGizmoPlugin() { + create_material("joint_material", EDITOR_GET("editors/3d_gizmos/gizmo_colors/joint")); + create_material("joint_body_a_material", EDITOR_DEF("editors/3d_gizmos/gizmo_colors/joint_body_a", Color(0.6, 0.8, 1))); + create_material("joint_body_b_material", EDITOR_DEF("editors/3d_gizmos/gizmo_colors/joint_body_b", Color(0.6, 0.9, 1))); + + update_timer = memnew(Timer); + update_timer->set_name("JointGizmoUpdateTimer"); + update_timer->set_wait_time(1.0 / 120.0); + update_timer->connect("timeout", callable_mp(this, &Joint3DGizmoPlugin::incremental_update_gizmos)); + update_timer->set_autostart(true); + EditorNode::get_singleton()->call_deferred(SNAME("add_child"), update_timer); +} + +void Joint3DGizmoPlugin::incremental_update_gizmos() { + if (!current_gizmos.is_empty()) { + update_idx++; + update_idx = update_idx % current_gizmos.size(); + redraw(current_gizmos[update_idx]); + } +} + +bool Joint3DGizmoPlugin::has_gizmo(Node3D *p_spatial) { + return Object::cast_to(p_spatial) != nullptr; +} + +String Joint3DGizmoPlugin::get_gizmo_name() const { + return "Joint3D"; +} + +int Joint3DGizmoPlugin::get_priority() const { + return -1; +} + +void Joint3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) { + Joint3D *joint = Object::cast_to(p_gizmo->get_node_3d()); + + p_gizmo->clear(); + + Node3D *node_body_a = nullptr; + if (!joint->get_node_a().is_empty()) { + node_body_a = Object::cast_to(joint->get_node(joint->get_node_a())); + } + + Node3D *node_body_b = nullptr; + if (!joint->get_node_b().is_empty()) { + node_body_b = Object::cast_to(joint->get_node(joint->get_node_b())); + } + + if (!node_body_a && !node_body_b) { + return; + } + + Ref common_material = get_material("joint_material", p_gizmo); + Ref body_a_material = get_material("joint_body_a_material", p_gizmo); + Ref body_b_material = get_material("joint_body_b_material", p_gizmo); + + Vector points; + Vector body_a_points; + Vector body_b_points; + + if (Object::cast_to(joint)) { + CreatePinJointGizmo(Transform3D(), points); + p_gizmo->add_collision_segments(points); + p_gizmo->add_lines(points, common_material); + } + + HingeJoint3D *hinge = Object::cast_to(joint); + if (hinge) { + CreateHingeJointGizmo( + Transform3D(), + hinge->get_global_transform(), + node_body_a ? node_body_a->get_global_transform() : Transform3D(), + node_body_b ? node_body_b->get_global_transform() : Transform3D(), + hinge->get_param(HingeJoint3D::PARAM_LIMIT_LOWER), + hinge->get_param(HingeJoint3D::PARAM_LIMIT_UPPER), + hinge->get_flag(HingeJoint3D::FLAG_USE_LIMIT), + points, + node_body_a ? &body_a_points : nullptr, + node_body_b ? &body_b_points : nullptr); + + p_gizmo->add_collision_segments(points); + p_gizmo->add_collision_segments(body_a_points); + p_gizmo->add_collision_segments(body_b_points); + + p_gizmo->add_lines(points, common_material); + p_gizmo->add_lines(body_a_points, body_a_material); + p_gizmo->add_lines(body_b_points, body_b_material); + } + + SliderJoint3D *slider = Object::cast_to(joint); + if (slider) { + CreateSliderJointGizmo( + Transform3D(), + slider->get_global_transform(), + node_body_a ? node_body_a->get_global_transform() : Transform3D(), + node_body_b ? node_body_b->get_global_transform() : Transform3D(), + slider->get_param(SliderJoint3D::PARAM_ANGULAR_LIMIT_LOWER), + slider->get_param(SliderJoint3D::PARAM_ANGULAR_LIMIT_UPPER), + slider->get_param(SliderJoint3D::PARAM_LINEAR_LIMIT_LOWER), + slider->get_param(SliderJoint3D::PARAM_LINEAR_LIMIT_UPPER), + points, + node_body_a ? &body_a_points : nullptr, + node_body_b ? &body_b_points : nullptr); + + p_gizmo->add_collision_segments(points); + p_gizmo->add_collision_segments(body_a_points); + p_gizmo->add_collision_segments(body_b_points); + + p_gizmo->add_lines(points, common_material); + p_gizmo->add_lines(body_a_points, body_a_material); + p_gizmo->add_lines(body_b_points, body_b_material); + } + + ConeTwistJoint3D *cone = Object::cast_to(joint); + if (cone) { + CreateConeTwistJointGizmo( + Transform3D(), + cone->get_global_transform(), + node_body_a ? node_body_a->get_global_transform() : Transform3D(), + node_body_b ? node_body_b->get_global_transform() : Transform3D(), + cone->get_param(ConeTwistJoint3D::PARAM_SWING_SPAN), + cone->get_param(ConeTwistJoint3D::PARAM_TWIST_SPAN), + node_body_a ? &body_a_points : nullptr, + node_body_b ? &body_b_points : nullptr); + + p_gizmo->add_collision_segments(body_a_points); + p_gizmo->add_collision_segments(body_b_points); + + p_gizmo->add_lines(body_a_points, body_a_material); + p_gizmo->add_lines(body_b_points, body_b_material); + } + + Generic6DOFJoint3D *gen = Object::cast_to(joint); + if (gen) { + CreateGeneric6DOFJointGizmo( + Transform3D(), + gen->get_global_transform(), + node_body_a ? node_body_a->get_global_transform() : Transform3D(), + node_body_b ? node_body_b->get_global_transform() : Transform3D(), + + gen->get_param_x(Generic6DOFJoint3D::PARAM_ANGULAR_LOWER_LIMIT), + gen->get_param_x(Generic6DOFJoint3D::PARAM_ANGULAR_UPPER_LIMIT), + gen->get_param_x(Generic6DOFJoint3D::PARAM_LINEAR_LOWER_LIMIT), + gen->get_param_x(Generic6DOFJoint3D::PARAM_LINEAR_UPPER_LIMIT), + gen->get_flag_x(Generic6DOFJoint3D::FLAG_ENABLE_ANGULAR_LIMIT), + gen->get_flag_x(Generic6DOFJoint3D::FLAG_ENABLE_LINEAR_LIMIT), + + gen->get_param_y(Generic6DOFJoint3D::PARAM_ANGULAR_LOWER_LIMIT), + gen->get_param_y(Generic6DOFJoint3D::PARAM_ANGULAR_UPPER_LIMIT), + gen->get_param_y(Generic6DOFJoint3D::PARAM_LINEAR_LOWER_LIMIT), + gen->get_param_y(Generic6DOFJoint3D::PARAM_LINEAR_UPPER_LIMIT), + gen->get_flag_y(Generic6DOFJoint3D::FLAG_ENABLE_ANGULAR_LIMIT), + gen->get_flag_y(Generic6DOFJoint3D::FLAG_ENABLE_LINEAR_LIMIT), + + gen->get_param_z(Generic6DOFJoint3D::PARAM_ANGULAR_LOWER_LIMIT), + gen->get_param_z(Generic6DOFJoint3D::PARAM_ANGULAR_UPPER_LIMIT), + gen->get_param_z(Generic6DOFJoint3D::PARAM_LINEAR_LOWER_LIMIT), + gen->get_param_z(Generic6DOFJoint3D::PARAM_LINEAR_UPPER_LIMIT), + gen->get_flag_z(Generic6DOFJoint3D::FLAG_ENABLE_ANGULAR_LIMIT), + gen->get_flag_z(Generic6DOFJoint3D::FLAG_ENABLE_LINEAR_LIMIT), + + points, + node_body_a ? &body_a_points : nullptr, + node_body_a ? &body_b_points : nullptr); + + p_gizmo->add_collision_segments(points); + p_gizmo->add_collision_segments(body_a_points); + p_gizmo->add_collision_segments(body_b_points); + + p_gizmo->add_lines(points, common_material); + p_gizmo->add_lines(body_a_points, body_a_material); + p_gizmo->add_lines(body_b_points, body_b_material); + } +} + +void Joint3DGizmoPlugin::CreatePinJointGizmo(const Transform3D &p_offset, Vector &r_cursor_points) { + float cs = 0.25; + + r_cursor_points.push_back(p_offset.translated_local(Vector3(+cs, 0, 0)).origin); + r_cursor_points.push_back(p_offset.translated_local(Vector3(-cs, 0, 0)).origin); + r_cursor_points.push_back(p_offset.translated_local(Vector3(0, +cs, 0)).origin); + r_cursor_points.push_back(p_offset.translated_local(Vector3(0, -cs, 0)).origin); + r_cursor_points.push_back(p_offset.translated_local(Vector3(0, 0, +cs)).origin); + r_cursor_points.push_back(p_offset.translated_local(Vector3(0, 0, -cs)).origin); +} + +void Joint3DGizmoPlugin::CreateHingeJointGizmo(const Transform3D &p_offset, const Transform3D &p_trs_joint, const Transform3D &p_trs_body_a, const Transform3D &p_trs_body_b, real_t p_limit_lower, real_t p_limit_upper, bool p_use_limit, Vector &r_common_points, Vector *r_body_a_points, Vector *r_body_b_points) { + r_common_points.push_back(p_offset.translated_local(Vector3(0, 0, 0.5)).origin); + r_common_points.push_back(p_offset.translated_local(Vector3(0, 0, -0.5)).origin); + + if (!p_use_limit) { + p_limit_upper = -1; + p_limit_lower = 0; + } + + if (r_body_a_points) { + JointGizmosDrawer::draw_circle(Vector3::AXIS_Z, + BODY_A_RADIUS, + p_offset, + JointGizmosDrawer::look_body_toward_z(p_trs_joint, p_trs_body_a), + p_limit_lower, + p_limit_upper, + *r_body_a_points); + } + + if (r_body_b_points) { + JointGizmosDrawer::draw_circle(Vector3::AXIS_Z, + BODY_B_RADIUS, + p_offset, + JointGizmosDrawer::look_body_toward_z(p_trs_joint, p_trs_body_b), + p_limit_lower, + p_limit_upper, + *r_body_b_points); + } +} + +void Joint3DGizmoPlugin::CreateSliderJointGizmo(const Transform3D &p_offset, const Transform3D &p_trs_joint, const Transform3D &p_trs_body_a, const Transform3D &p_trs_body_b, real_t p_angular_limit_lower, real_t p_angular_limit_upper, real_t p_linear_limit_lower, real_t p_linear_limit_upper, Vector &r_points, Vector *r_body_a_points, Vector *r_body_b_points) { + p_linear_limit_lower = -p_linear_limit_lower; + p_linear_limit_upper = -p_linear_limit_upper; + + float cs = 0.25; + r_points.push_back(p_offset.translated_local(Vector3(0, 0, 0.5)).origin); + r_points.push_back(p_offset.translated_local(Vector3(0, 0, -0.5)).origin); + + if (p_linear_limit_lower >= p_linear_limit_upper) { + r_points.push_back(p_offset.translated_local(Vector3(p_linear_limit_upper, 0, 0)).origin); + r_points.push_back(p_offset.translated_local(Vector3(p_linear_limit_lower, 0, 0)).origin); + + r_points.push_back(p_offset.translated_local(Vector3(p_linear_limit_upper, -cs, -cs)).origin); + r_points.push_back(p_offset.translated_local(Vector3(p_linear_limit_upper, -cs, cs)).origin); + r_points.push_back(p_offset.translated_local(Vector3(p_linear_limit_upper, -cs, cs)).origin); + r_points.push_back(p_offset.translated_local(Vector3(p_linear_limit_upper, cs, cs)).origin); + r_points.push_back(p_offset.translated_local(Vector3(p_linear_limit_upper, cs, cs)).origin); + r_points.push_back(p_offset.translated_local(Vector3(p_linear_limit_upper, cs, -cs)).origin); + r_points.push_back(p_offset.translated_local(Vector3(p_linear_limit_upper, cs, -cs)).origin); + r_points.push_back(p_offset.translated_local(Vector3(p_linear_limit_upper, -cs, -cs)).origin); + + r_points.push_back(p_offset.translated_local(Vector3(p_linear_limit_lower, -cs, -cs)).origin); + r_points.push_back(p_offset.translated_local(Vector3(p_linear_limit_lower, -cs, cs)).origin); + r_points.push_back(p_offset.translated_local(Vector3(p_linear_limit_lower, -cs, cs)).origin); + r_points.push_back(p_offset.translated_local(Vector3(p_linear_limit_lower, cs, cs)).origin); + r_points.push_back(p_offset.translated_local(Vector3(p_linear_limit_lower, cs, cs)).origin); + r_points.push_back(p_offset.translated_local(Vector3(p_linear_limit_lower, cs, -cs)).origin); + r_points.push_back(p_offset.translated_local(Vector3(p_linear_limit_lower, cs, -cs)).origin); + r_points.push_back(p_offset.translated_local(Vector3(p_linear_limit_lower, -cs, -cs)).origin); + + } else { + r_points.push_back(p_offset.translated_local(Vector3(+cs * 2, 0, 0)).origin); + r_points.push_back(p_offset.translated_local(Vector3(-cs * 2, 0, 0)).origin); + } + + if (r_body_a_points) { + JointGizmosDrawer::draw_circle( + Vector3::AXIS_X, + BODY_A_RADIUS, + p_offset, + JointGizmosDrawer::look_body_toward(Vector3::AXIS_X, p_trs_joint, p_trs_body_a), + p_angular_limit_lower, + p_angular_limit_upper, + *r_body_a_points); + } + + if (r_body_b_points) { + JointGizmosDrawer::draw_circle( + Vector3::AXIS_X, + BODY_B_RADIUS, + p_offset, + JointGizmosDrawer::look_body_toward(Vector3::AXIS_X, p_trs_joint, p_trs_body_b), + p_angular_limit_lower, + p_angular_limit_upper, + *r_body_b_points, + true); + } +} + +void Joint3DGizmoPlugin::CreateConeTwistJointGizmo(const Transform3D &p_offset, const Transform3D &p_trs_joint, const Transform3D &p_trs_body_a, const Transform3D &p_trs_body_b, real_t p_swing, real_t p_twist, Vector *r_body_a_points, Vector *r_body_b_points) { + if (r_body_a_points) { + JointGizmosDrawer::draw_cone( + p_offset, + JointGizmosDrawer::look_body(p_trs_joint, p_trs_body_a), + p_swing, + p_twist, + *r_body_a_points); + } + + if (r_body_b_points) { + JointGizmosDrawer::draw_cone( + p_offset, + JointGizmosDrawer::look_body(p_trs_joint, p_trs_body_b), + p_swing, + p_twist, + *r_body_b_points); + } +} + +void Joint3DGizmoPlugin::CreateGeneric6DOFJointGizmo( + const Transform3D &p_offset, + const Transform3D &p_trs_joint, + const Transform3D &p_trs_body_a, + const Transform3D &p_trs_body_b, + real_t p_angular_limit_lower_x, + real_t p_angular_limit_upper_x, + real_t p_linear_limit_lower_x, + real_t p_linear_limit_upper_x, + bool p_enable_angular_limit_x, + bool p_enable_linear_limit_x, + real_t p_angular_limit_lower_y, + real_t p_angular_limit_upper_y, + real_t p_linear_limit_lower_y, + real_t p_linear_limit_upper_y, + bool p_enable_angular_limit_y, + bool p_enable_linear_limit_y, + real_t p_angular_limit_lower_z, + real_t p_angular_limit_upper_z, + real_t p_linear_limit_lower_z, + real_t p_linear_limit_upper_z, + bool p_enable_angular_limit_z, + bool p_enable_linear_limit_z, + Vector &r_points, + Vector *r_body_a_points, + Vector *r_body_b_points) { + float cs = 0.25; + + for (int ax = 0; ax < 3; ax++) { + float ll = 0; + float ul = 0; + float lll = 0; + float lul = 0; + + int a1 = 0; + int a2 = 0; + int a3 = 0; + bool enable_ang = false; + bool enable_lin = false; + + switch (ax) { + case 0: + ll = p_angular_limit_lower_x; + ul = p_angular_limit_upper_x; + lll = -p_linear_limit_lower_x; + lul = -p_linear_limit_upper_x; + enable_ang = p_enable_angular_limit_x; + enable_lin = p_enable_linear_limit_x; + a1 = 0; + a2 = 1; + a3 = 2; + break; + case 1: + ll = p_angular_limit_lower_y; + ul = p_angular_limit_upper_y; + lll = -p_linear_limit_lower_y; + lul = -p_linear_limit_upper_y; + enable_ang = p_enable_angular_limit_y; + enable_lin = p_enable_linear_limit_y; + a1 = 1; + a2 = 2; + a3 = 0; + break; + case 2: + ll = p_angular_limit_lower_z; + ul = p_angular_limit_upper_z; + lll = -p_linear_limit_lower_z; + lul = -p_linear_limit_upper_z; + enable_ang = p_enable_angular_limit_z; + enable_lin = p_enable_linear_limit_z; + a1 = 2; + a2 = 0; + a3 = 1; + break; + } + +#define ADD_VTX(x, y, z) \ + { \ + Vector3 v; \ + v[a1] = (x); \ + v[a2] = (y); \ + v[a3] = (z); \ + r_points.push_back(p_offset.translated_local(v).origin); \ + } + + if (enable_lin && lll >= lul) { + ADD_VTX(lul, 0, 0); + ADD_VTX(lll, 0, 0); + + ADD_VTX(lul, -cs, -cs); + ADD_VTX(lul, -cs, cs); + ADD_VTX(lul, -cs, cs); + ADD_VTX(lul, cs, cs); + ADD_VTX(lul, cs, cs); + ADD_VTX(lul, cs, -cs); + ADD_VTX(lul, cs, -cs); + ADD_VTX(lul, -cs, -cs); + + ADD_VTX(lll, -cs, -cs); + ADD_VTX(lll, -cs, cs); + ADD_VTX(lll, -cs, cs); + ADD_VTX(lll, cs, cs); + ADD_VTX(lll, cs, cs); + ADD_VTX(lll, cs, -cs); + ADD_VTX(lll, cs, -cs); + ADD_VTX(lll, -cs, -cs); + + } else { + ADD_VTX(+cs * 2, 0, 0); + ADD_VTX(-cs * 2, 0, 0); + } + + if (!enable_ang) { + ll = 0; + ul = -1; + } + + if (r_body_a_points) { + JointGizmosDrawer::draw_circle( + static_cast(ax), + BODY_A_RADIUS, + p_offset, + JointGizmosDrawer::look_body_toward(static_cast(ax), p_trs_joint, p_trs_body_a), + ll, + ul, + *r_body_a_points, + true); + } + + if (r_body_b_points) { + JointGizmosDrawer::draw_circle( + static_cast(ax), + BODY_B_RADIUS, + p_offset, + JointGizmosDrawer::look_body_toward(static_cast(ax), p_trs_joint, p_trs_body_b), + ll, + ul, + *r_body_b_points); + } + } + +#undef ADD_VTX +} diff --git a/editor/plugins/gizmos/joint_3d_gizmo_plugin.h b/editor/plugins/gizmos/joint_3d_gizmo_plugin.h new file mode 100644 index 00000000000..79fe40d1b2e --- /dev/null +++ b/editor/plugins/gizmos/joint_3d_gizmo_plugin.h @@ -0,0 +1,99 @@ +/**************************************************************************/ +/* joint_3d_gizmo_plugin.h */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* 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. */ +/**************************************************************************/ + +#ifndef JOINT_3D_GIZMO_PLUGIN_H +#define JOINT_3D_GIZMO_PLUGIN_H + +#include "editor/plugins/node_3d_editor_gizmos.h" + +class Joint3DGizmoPlugin : public EditorNode3DGizmoPlugin { + GDCLASS(Joint3DGizmoPlugin, EditorNode3DGizmoPlugin); + + Timer *update_timer = nullptr; + uint64_t update_idx = 0; + + void incremental_update_gizmos(); + +public: + bool has_gizmo(Node3D *p_spatial) override; + String get_gizmo_name() const override; + int get_priority() const override; + void redraw(EditorNode3DGizmo *p_gizmo) override; + + static void CreatePinJointGizmo(const Transform3D &p_offset, Vector &r_cursor_points); + static void CreateHingeJointGizmo(const Transform3D &p_offset, const Transform3D &p_trs_joint, const Transform3D &p_trs_body_a, const Transform3D &p_trs_body_b, real_t p_limit_lower, real_t p_limit_upper, bool p_use_limit, Vector &r_common_points, Vector *r_body_a_points, Vector *r_body_b_points); + static void CreateSliderJointGizmo(const Transform3D &p_offset, const Transform3D &p_trs_joint, const Transform3D &p_trs_body_a, const Transform3D &p_trs_body_b, real_t p_angular_limit_lower, real_t p_angular_limit_upper, real_t p_linear_limit_lower, real_t p_linear_limit_upper, Vector &r_points, Vector *r_body_a_points, Vector *r_body_b_points); + static void CreateConeTwistJointGizmo(const Transform3D &p_offset, const Transform3D &p_trs_joint, const Transform3D &p_trs_body_a, const Transform3D &p_trs_body_b, real_t p_swing, real_t p_twist, Vector *r_body_a_points, Vector *r_body_b_points); + static void CreateGeneric6DOFJointGizmo( + const Transform3D &p_offset, + const Transform3D &p_trs_joint, + const Transform3D &p_trs_body_a, + const Transform3D &p_trs_body_b, + real_t p_angular_limit_lower_x, + real_t p_angular_limit_upper_x, + real_t p_linear_limit_lower_x, + real_t p_linear_limit_upper_x, + bool p_enable_angular_limit_x, + bool p_enable_linear_limit_x, + real_t p_angular_limit_lower_y, + real_t p_angular_limit_upper_y, + real_t p_linear_limit_lower_y, + real_t p_linear_limit_upper_y, + bool p_enable_angular_limit_y, + bool p_enable_linear_limit_y, + real_t p_angular_limit_lower_z, + real_t p_angular_limit_upper_z, + real_t p_linear_limit_lower_z, + real_t p_linear_limit_upper_z, + bool p_enable_angular_limit_z, + bool p_enable_linear_limit_z, + Vector &r_points, + Vector *r_body_a_points, + Vector *r_body_b_points); + + Joint3DGizmoPlugin(); +}; + +class JointGizmosDrawer { +public: + static Basis look_body(const Transform3D &p_joint_transform, const Transform3D &p_body_transform); + static Basis look_body_toward(Vector3::Axis p_axis, const Transform3D &joint_transform, const Transform3D &body_transform); + static Basis look_body_toward_x(const Transform3D &p_joint_transform, const Transform3D &p_body_transform); + static Basis look_body_toward_y(const Transform3D &p_joint_transform, const Transform3D &p_body_transform); + /// Special function just used for physics joints, it returns a basis constrained toward Joint Z axis + /// with axis X and Y that are looking toward the body and oriented toward up + static Basis look_body_toward_z(const Transform3D &p_joint_transform, const Transform3D &p_body_transform); + + // Draw circle around p_axis + static void draw_circle(Vector3::Axis p_axis, real_t p_radius, const Transform3D &p_offset, const Basis &p_base, real_t p_limit_lower, real_t p_limit_upper, Vector &r_points, bool p_inverse = false); + static void draw_cone(const Transform3D &p_offset, const Basis &p_base, real_t p_swing, real_t p_twist, Vector &r_points); +}; + +#endif // JOINT_3D_GIZMO_PLUGIN_H diff --git a/editor/plugins/gizmos/label_3d_gizmo_plugin.cpp b/editor/plugins/gizmos/label_3d_gizmo_plugin.cpp new file mode 100644 index 00000000000..5bd45cb0c89 --- /dev/null +++ b/editor/plugins/gizmos/label_3d_gizmo_plugin.cpp @@ -0,0 +1,64 @@ +/**************************************************************************/ +/* label_3d_gizmo_plugin.cpp */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* 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 "label_3d_gizmo_plugin.h" + +#include "editor/plugins/node_3d_editor_plugin.h" +#include "scene/3d/label_3d.h" + +Label3DGizmoPlugin::Label3DGizmoPlugin() { +} + +bool Label3DGizmoPlugin::has_gizmo(Node3D *p_spatial) { + return Object::cast_to(p_spatial) != nullptr; +} + +String Label3DGizmoPlugin::get_gizmo_name() const { + return "Label3D"; +} + +int Label3DGizmoPlugin::get_priority() const { + return -1; +} + +bool Label3DGizmoPlugin::can_be_hidden() const { + return false; +} + +void Label3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) { + Label3D *label = Object::cast_to(p_gizmo->get_node_3d()); + + p_gizmo->clear(); + + Ref tm = label->generate_triangle_mesh(); + if (tm.is_valid()) { + p_gizmo->add_collision_triangles(tm); + } +} diff --git a/editor/plugins/gizmos/label_3d_gizmo_plugin.h b/editor/plugins/gizmos/label_3d_gizmo_plugin.h new file mode 100644 index 00000000000..979a4b86b24 --- /dev/null +++ b/editor/plugins/gizmos/label_3d_gizmo_plugin.h @@ -0,0 +1,49 @@ +/**************************************************************************/ +/* label_3d_gizmo_plugin.h */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* 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. */ +/**************************************************************************/ + +#ifndef LABEL_3D_GIZMO_PLUGIN_H +#define LABEL_3D_GIZMO_PLUGIN_H + +#include "editor/plugins/node_3d_editor_gizmos.h" + +class Label3DGizmoPlugin : public EditorNode3DGizmoPlugin { + GDCLASS(Label3DGizmoPlugin, EditorNode3DGizmoPlugin); + +public: + bool has_gizmo(Node3D *p_spatial) override; + String get_gizmo_name() const override; + int get_priority() const override; + bool can_be_hidden() const override; + void redraw(EditorNode3DGizmo *p_gizmo) override; + + Label3DGizmoPlugin(); +}; + +#endif // LABEL_3D_GIZMO_PLUGIN_H diff --git a/editor/plugins/gizmos/light_3d_gizmo_plugin.cpp b/editor/plugins/gizmos/light_3d_gizmo_plugin.cpp new file mode 100644 index 00000000000..ff959ae8360 --- /dev/null +++ b/editor/plugins/gizmos/light_3d_gizmo_plugin.cpp @@ -0,0 +1,308 @@ +/**************************************************************************/ +/* light_3d_gizmo_plugin.cpp */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* 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 "light_3d_gizmo_plugin.h" + +#include "core/config/project_settings.h" +#include "editor/editor_node.h" +#include "editor/editor_settings.h" +#include "editor/editor_undo_redo_manager.h" +#include "editor/plugins/node_3d_editor_plugin.h" +#include "scene/3d/light_3d.h" + +Light3DGizmoPlugin::Light3DGizmoPlugin() { + // Enable vertex colors for the materials below as the gizmo color depends on the light color. + create_material("lines_primary", Color(1, 1, 1), false, false, true); + create_material("lines_secondary", Color(1, 1, 1, 0.35), false, false, true); + create_material("lines_billboard", Color(1, 1, 1), true, false, true); + + create_icon_material("light_directional_icon", Node3DEditor::get_singleton()->get_theme_icon(SNAME("GizmoDirectionalLight"), SNAME("EditorIcons"))); + create_icon_material("light_omni_icon", Node3DEditor::get_singleton()->get_theme_icon(SNAME("GizmoLight"), SNAME("EditorIcons"))); + create_icon_material("light_spot_icon", Node3DEditor::get_singleton()->get_theme_icon(SNAME("GizmoSpotLight"), SNAME("EditorIcons"))); + + create_handle_material("handles"); + create_handle_material("handles_billboard", true); +} + +bool Light3DGizmoPlugin::has_gizmo(Node3D *p_spatial) { + return Object::cast_to(p_spatial) != nullptr; +} + +String Light3DGizmoPlugin::get_gizmo_name() const { + return "Light3D"; +} + +int Light3DGizmoPlugin::get_priority() const { + return -1; +} + +String Light3DGizmoPlugin::get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const { + if (p_id == 0) { + return "Radius"; + } else { + return "Aperture"; + } +} + +Variant Light3DGizmoPlugin::get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const { + Light3D *light = Object::cast_to(p_gizmo->get_node_3d()); + if (p_id == 0) { + return light->get_param(Light3D::PARAM_RANGE); + } + if (p_id == 1) { + return light->get_param(Light3D::PARAM_SPOT_ANGLE); + } + + return Variant(); +} + +void Light3DGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, Camera3D *p_camera, const Point2 &p_point) { + Light3D *light = Object::cast_to(p_gizmo->get_node_3d()); + Transform3D gt = light->get_global_transform(); + Transform3D gi = gt.affine_inverse(); + + Vector3 ray_from = p_camera->project_ray_origin(p_point); + Vector3 ray_dir = p_camera->project_ray_normal(p_point); + + Vector3 s[2] = { gi.xform(ray_from), gi.xform(ray_from + ray_dir * 4096) }; + if (p_id == 0) { + if (Object::cast_to(light)) { + Vector3 ra, rb; + Geometry3D::get_closest_points_between_segments(Vector3(), Vector3(0, 0, -4096), s[0], s[1], ra, rb); + + float d = -ra.z; + if (Node3DEditor::get_singleton()->is_snap_enabled()) { + d = Math::snapped(d, Node3DEditor::get_singleton()->get_translate_snap()); + } + + if (d <= 0) { // Equal is here for negative zero. + d = 0; + } + + light->set_param(Light3D::PARAM_RANGE, d); + } else if (Object::cast_to(light)) { + Plane cp = Plane(p_camera->get_transform().basis.get_column(2), gt.origin); + + Vector3 inters; + if (cp.intersects_ray(ray_from, ray_dir, &inters)) { + float r = inters.distance_to(gt.origin); + if (Node3DEditor::get_singleton()->is_snap_enabled()) { + r = Math::snapped(r, Node3DEditor::get_singleton()->get_translate_snap()); + } + + light->set_param(Light3D::PARAM_RANGE, r); + } + } + + } else if (p_id == 1) { + float a = _find_closest_angle_to_half_pi_arc(s[0], s[1], light->get_param(Light3D::PARAM_RANGE), gt); + light->set_param(Light3D::PARAM_SPOT_ANGLE, CLAMP(a, 0.01, 89.99)); + } +} + +void Light3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, const Variant &p_restore, bool p_cancel) { + Light3D *light = Object::cast_to(p_gizmo->get_node_3d()); + if (p_cancel) { + light->set_param(p_id == 0 ? Light3D::PARAM_RANGE : Light3D::PARAM_SPOT_ANGLE, p_restore); + + } else if (p_id == 0) { + EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton(); + ur->create_action(TTR("Change Light Radius")); + ur->add_do_method(light, "set_param", Light3D::PARAM_RANGE, light->get_param(Light3D::PARAM_RANGE)); + ur->add_undo_method(light, "set_param", Light3D::PARAM_RANGE, p_restore); + ur->commit_action(); + } else if (p_id == 1) { + EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton(); + ur->create_action(TTR("Change Light Radius")); + ur->add_do_method(light, "set_param", Light3D::PARAM_SPOT_ANGLE, light->get_param(Light3D::PARAM_SPOT_ANGLE)); + ur->add_undo_method(light, "set_param", Light3D::PARAM_SPOT_ANGLE, p_restore); + ur->commit_action(); + } +} + +void Light3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) { + Light3D *light = Object::cast_to(p_gizmo->get_node_3d()); + + Color color = light->get_color().srgb_to_linear() * light->get_correlated_color().srgb_to_linear(); + color = color.linear_to_srgb(); + // Make the gizmo color as bright as possible for better visibility + color.set_hsv(color.get_h(), color.get_s(), 1); + + p_gizmo->clear(); + + if (Object::cast_to(light)) { + Ref material = get_material("lines_primary", p_gizmo); + Ref icon = get_material("light_directional_icon", p_gizmo); + + const int arrow_points = 7; + const float arrow_length = 1.5; + + Vector3 arrow[arrow_points] = { + Vector3(0, 0, -1), + Vector3(0, 0.8, 0), + Vector3(0, 0.3, 0), + Vector3(0, 0.3, arrow_length), + Vector3(0, -0.3, arrow_length), + Vector3(0, -0.3, 0), + Vector3(0, -0.8, 0) + }; + + int arrow_sides = 2; + + Vector lines; + + for (int i = 0; i < arrow_sides; i++) { + for (int j = 0; j < arrow_points; j++) { + Basis ma(Vector3(0, 0, 1), Math_PI * i / arrow_sides); + + Vector3 v1 = arrow[j] - Vector3(0, 0, arrow_length); + Vector3 v2 = arrow[(j + 1) % arrow_points] - Vector3(0, 0, arrow_length); + + lines.push_back(ma.xform(v1)); + lines.push_back(ma.xform(v2)); + } + } + + p_gizmo->add_lines(lines, material, false, color); + p_gizmo->add_unscaled_billboard(icon, 0.05, color); + } + + if (Object::cast_to(light)) { + // Use both a billboard circle and 3 non-billboard circles for a better sphere-like representation + const Ref lines_material = get_material("lines_secondary", p_gizmo); + const Ref lines_billboard_material = get_material("lines_billboard", p_gizmo); + const Ref icon = get_material("light_omni_icon", p_gizmo); + + OmniLight3D *on = Object::cast_to(light); + const float r = on->get_param(Light3D::PARAM_RANGE); + Vector points; + Vector points_billboard; + + for (int i = 0; i < 120; i++) { + // Create a circle + const float ra = Math::deg_to_rad((float)(i * 3)); + const float rb = Math::deg_to_rad((float)((i + 1) * 3)); + const Point2 a = Vector2(Math::sin(ra), Math::cos(ra)) * r; + const Point2 b = Vector2(Math::sin(rb), Math::cos(rb)) * r; + + // Draw axis-aligned circles + points.push_back(Vector3(a.x, 0, a.y)); + points.push_back(Vector3(b.x, 0, b.y)); + points.push_back(Vector3(0, a.x, a.y)); + points.push_back(Vector3(0, b.x, b.y)); + points.push_back(Vector3(a.x, a.y, 0)); + points.push_back(Vector3(b.x, b.y, 0)); + + // Draw a billboarded circle + points_billboard.push_back(Vector3(a.x, a.y, 0)); + points_billboard.push_back(Vector3(b.x, b.y, 0)); + } + + p_gizmo->add_lines(points, lines_material, true, color); + p_gizmo->add_lines(points_billboard, lines_billboard_material, true, color); + p_gizmo->add_unscaled_billboard(icon, 0.05, color); + + Vector handles; + handles.push_back(Vector3(r, 0, 0)); + p_gizmo->add_handles(handles, get_material("handles_billboard"), Vector(), true); + } + + if (Object::cast_to(light)) { + const Ref material_primary = get_material("lines_primary", p_gizmo); + const Ref material_secondary = get_material("lines_secondary", p_gizmo); + const Ref icon = get_material("light_spot_icon", p_gizmo); + + Vector points_primary; + Vector points_secondary; + SpotLight3D *sl = Object::cast_to(light); + + float r = sl->get_param(Light3D::PARAM_RANGE); + float w = r * Math::sin(Math::deg_to_rad(sl->get_param(Light3D::PARAM_SPOT_ANGLE))); + float d = r * Math::cos(Math::deg_to_rad(sl->get_param(Light3D::PARAM_SPOT_ANGLE))); + + for (int i = 0; i < 120; i++) { + // Draw a circle + const float ra = Math::deg_to_rad((float)(i * 3)); + const float rb = Math::deg_to_rad((float)((i + 1) * 3)); + const Point2 a = Vector2(Math::sin(ra), Math::cos(ra)) * w; + const Point2 b = Vector2(Math::sin(rb), Math::cos(rb)) * w; + + points_primary.push_back(Vector3(a.x, a.y, -d)); + points_primary.push_back(Vector3(b.x, b.y, -d)); + + if (i % 15 == 0) { + // Draw 8 lines from the cone origin to the sides of the circle + points_secondary.push_back(Vector3(a.x, a.y, -d)); + points_secondary.push_back(Vector3()); + } + } + + points_primary.push_back(Vector3(0, 0, -r)); + points_primary.push_back(Vector3()); + + p_gizmo->add_lines(points_primary, material_primary, false, color); + p_gizmo->add_lines(points_secondary, material_secondary, false, color); + + Vector handles = { + Vector3(0, 0, -r), + Vector3(w, 0, -d) + }; + + p_gizmo->add_handles(handles, get_material("handles")); + p_gizmo->add_unscaled_billboard(icon, 0.05, color); + } +} + +float Light3DGizmoPlugin::_find_closest_angle_to_half_pi_arc(const Vector3 &p_from, const Vector3 &p_to, float p_arc_radius, const Transform3D &p_arc_xform) { + //bleh, discrete is simpler + static const int arc_test_points = 64; + float min_d = 1e20; + Vector3 min_p; + + for (int i = 0; i < arc_test_points; i++) { + float a = i * Math_PI * 0.5 / arc_test_points; + float an = (i + 1) * Math_PI * 0.5 / arc_test_points; + Vector3 p = Vector3(Math::cos(a), 0, -Math::sin(a)) * p_arc_radius; + Vector3 n = Vector3(Math::cos(an), 0, -Math::sin(an)) * p_arc_radius; + + Vector3 ra, rb; + Geometry3D::get_closest_points_between_segments(p, n, p_from, p_to, ra, rb); + + float d = ra.distance_to(rb); + if (d < min_d) { + min_d = d; + min_p = ra; + } + } + + //min_p = p_arc_xform.affine_inverse().xform(min_p); + float a = (Math_PI * 0.5) - Vector2(min_p.x, -min_p.z).angle(); + return Math::rad_to_deg(a); +} diff --git a/editor/plugins/gizmos/light_3d_gizmo_plugin.h b/editor/plugins/gizmos/light_3d_gizmo_plugin.h new file mode 100644 index 00000000000..b7eec7fb380 --- /dev/null +++ b/editor/plugins/gizmos/light_3d_gizmo_plugin.h @@ -0,0 +1,56 @@ +/**************************************************************************/ +/* light_3d_gizmo_plugin.h */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* 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. */ +/**************************************************************************/ + +#ifndef LIGHT_3D_GIZMO_PLUGIN_H +#define LIGHT_3D_GIZMO_PLUGIN_H + +#include "editor/plugins/node_3d_editor_gizmos.h" + +class Light3DGizmoPlugin : public EditorNode3DGizmoPlugin { + GDCLASS(Light3DGizmoPlugin, EditorNode3DGizmoPlugin); + +private: + static float _find_closest_angle_to_half_pi_arc(const Vector3 &p_from, const Vector3 &p_to, float p_arc_radius, const Transform3D &p_arc_xform); + +public: + bool has_gizmo(Node3D *p_spatial) override; + String get_gizmo_name() const override; + int get_priority() const override; + + String get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const override; + Variant get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const override; + void set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, Camera3D *p_camera, const Point2 &p_point) override; + void commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, const Variant &p_restore, bool p_cancel = false) override; + void redraw(EditorNode3DGizmo *p_gizmo) override; + + Light3DGizmoPlugin(); +}; + +#endif // LIGHT_3D_GIZMO_PLUGIN_H diff --git a/editor/plugins/gizmos/lightmap_gi_gizmo_plugin.cpp b/editor/plugins/gizmos/lightmap_gi_gizmo_plugin.cpp new file mode 100644 index 00000000000..b16a894e6d6 --- /dev/null +++ b/editor/plugins/gizmos/lightmap_gi_gizmo_plugin.cpp @@ -0,0 +1,211 @@ +/**************************************************************************/ +/* lightmap_gi_gizmo_plugin.cpp */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* 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 "lightmap_gi_gizmo_plugin.h" + +#include "editor/editor_settings.h" +#include "editor/plugins/node_3d_editor_plugin.h" +#include "scene/3d/lightmap_gi.h" + +LightmapGIGizmoPlugin::LightmapGIGizmoPlugin() { + Color gizmo_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/lightmap_lines", Color(0.5, 0.6, 1)); + + gizmo_color.a = 0.1; + create_material("lightmap_lines", gizmo_color); + + Ref mat = memnew(StandardMaterial3D); + mat->set_shading_mode(StandardMaterial3D::SHADING_MODE_UNSHADED); + mat->set_cull_mode(StandardMaterial3D::CULL_DISABLED); + mat->set_flag(StandardMaterial3D::FLAG_ALBEDO_FROM_VERTEX_COLOR, true); + mat->set_flag(StandardMaterial3D::FLAG_SRGB_VERTEX_COLOR, false); + + add_material("lightmap_probe_material", mat); + + create_icon_material("baked_indirect_light_icon", Node3DEditor::get_singleton()->get_theme_icon(SNAME("GizmoLightmapGI"), SNAME("EditorIcons"))); +} + +bool LightmapGIGizmoPlugin::has_gizmo(Node3D *p_spatial) { + return Object::cast_to(p_spatial) != nullptr; +} + +String LightmapGIGizmoPlugin::get_gizmo_name() const { + return "LightmapGI"; +} + +int LightmapGIGizmoPlugin::get_priority() const { + return -1; +} + +void LightmapGIGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) { + Ref icon = get_material("baked_indirect_light_icon", p_gizmo); + LightmapGI *baker = Object::cast_to(p_gizmo->get_node_3d()); + Ref data = baker->get_light_data(); + + p_gizmo->add_unscaled_billboard(icon, 0.05); + + if (data.is_null()) { + return; + } + + Ref material_lines = get_material("lightmap_lines", p_gizmo); + Ref material_probes = get_material("lightmap_probe_material", p_gizmo); + + p_gizmo->clear(); + + Vector lines; + HashSet lines_found; + + Vector points = data->get_capture_points(); + if (points.size() == 0) { + return; + } + Vector sh = data->get_capture_sh(); + if (sh.size() != points.size() * 9) { + return; + } + + Vector tetrahedrons = data->get_capture_tetrahedra(); + + for (int i = 0; i < tetrahedrons.size(); i += 4) { + for (int j = 0; j < 4; j++) { + for (int k = j + 1; k < 4; k++) { + Vector2i pair; + pair.x = tetrahedrons[i + j]; + pair.y = tetrahedrons[i + k]; + + if (pair.y < pair.x) { + SWAP(pair.x, pair.y); + } + if (lines_found.has(pair)) { + continue; + } + lines_found.insert(pair); + lines.push_back(points[pair.x]); + lines.push_back(points[pair.y]); + } + } + } + + p_gizmo->add_lines(lines, material_lines); + + int stack_count = 8; + int sector_count = 16; + + float sector_step = (Math_PI * 2.0) / sector_count; + float stack_step = Math_PI / stack_count; + + Vector vertices; + Vector colors; + Vector indices; + float radius = 0.3; + + for (int p = 0; p < points.size(); p++) { + int vertex_base = vertices.size(); + Vector3 sh_col[9]; + for (int i = 0; i < 9; i++) { + sh_col[i].x = sh[p * 9 + i].r; + sh_col[i].y = sh[p * 9 + i].g; + sh_col[i].z = sh[p * 9 + i].b; + } + + for (int i = 0; i <= stack_count; ++i) { + float stack_angle = Math_PI / 2 - i * stack_step; // starting from pi/2 to -pi/2 + float xy = radius * Math::cos(stack_angle); // r * cos(u) + float z = radius * Math::sin(stack_angle); // r * sin(u) + + // add (sector_count+1) vertices per stack + // the first and last vertices have same position and normal, but different tex coords + for (int j = 0; j <= sector_count; ++j) { + float sector_angle = j * sector_step; // starting from 0 to 2pi + + // vertex position (x, y, z) + float x = xy * Math::cos(sector_angle); // r * cos(u) * cos(v) + float y = xy * Math::sin(sector_angle); // r * cos(u) * sin(v) + + Vector3 n = Vector3(x, z, y); + vertices.push_back(points[p] + n); + n.normalize(); + + const float c1 = 0.429043; + const float c2 = 0.511664; + const float c3 = 0.743125; + const float c4 = 0.886227; + const float c5 = 0.247708; + Vector3 light = (c1 * sh_col[8] * (n.x * n.x - n.y * n.y) + + c3 * sh_col[6] * n.z * n.z + + c4 * sh_col[0] - + c5 * sh_col[6] + + 2.0 * c1 * sh_col[4] * n.x * n.y + + 2.0 * c1 * sh_col[7] * n.x * n.z + + 2.0 * c1 * sh_col[5] * n.y * n.z + + 2.0 * c2 * sh_col[3] * n.x + + 2.0 * c2 * sh_col[1] * n.y + + 2.0 * c2 * sh_col[2] * n.z); + + colors.push_back(Color(light.x, light.y, light.z, 1)); + } + } + + for (int i = 0; i < stack_count; ++i) { + int k1 = i * (sector_count + 1); // beginning of current stack + int k2 = k1 + sector_count + 1; // beginning of next stack + + for (int j = 0; j < sector_count; ++j, ++k1, ++k2) { + // 2 triangles per sector excluding first and last stacks + // k1 => k2 => k1+1 + if (i != 0) { + indices.push_back(vertex_base + k1); + indices.push_back(vertex_base + k2); + indices.push_back(vertex_base + k1 + 1); + } + + // k1+1 => k2 => k2+1 + if (i != (stack_count - 1)) { + indices.push_back(vertex_base + k1 + 1); + indices.push_back(vertex_base + k2); + indices.push_back(vertex_base + k2 + 1); + } + } + } + } + + Array array; + array.resize(RS::ARRAY_MAX); + array[RS::ARRAY_VERTEX] = vertices; + array[RS::ARRAY_INDEX] = indices; + array[RS::ARRAY_COLOR] = colors; + + Ref mesh; + mesh.instantiate(); + mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, array, Array(), Dictionary(), 0); //no compression + mesh->surface_set_material(0, material_probes); + + p_gizmo->add_mesh(mesh); +} diff --git a/editor/plugins/gizmos/lightmap_gi_gizmo_plugin.h b/editor/plugins/gizmos/lightmap_gi_gizmo_plugin.h new file mode 100644 index 00000000000..50ce0425c3d --- /dev/null +++ b/editor/plugins/gizmos/lightmap_gi_gizmo_plugin.h @@ -0,0 +1,48 @@ +/**************************************************************************/ +/* lightmap_gi_gizmo_plugin.h */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* 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. */ +/**************************************************************************/ + +#ifndef LIGHTMAP_GI_GIZMO_PLUGIN_H +#define LIGHTMAP_GI_GIZMO_PLUGIN_H + +#include "editor/plugins/node_3d_editor_gizmos.h" + +class LightmapGIGizmoPlugin : public EditorNode3DGizmoPlugin { + GDCLASS(LightmapGIGizmoPlugin, EditorNode3DGizmoPlugin); + +public: + bool has_gizmo(Node3D *p_spatial) override; + String get_gizmo_name() const override; + int get_priority() const override; + void redraw(EditorNode3DGizmo *p_gizmo) override; + + LightmapGIGizmoPlugin(); +}; + +#endif // LIGHTMAP_GI_GIZMO_PLUGIN_H diff --git a/editor/plugins/gizmos/lightmap_probe_gizmo_plugin.cpp b/editor/plugins/gizmos/lightmap_probe_gizmo_plugin.cpp new file mode 100644 index 00000000000..093beac6a25 --- /dev/null +++ b/editor/plugins/gizmos/lightmap_probe_gizmo_plugin.cpp @@ -0,0 +1,115 @@ +/**************************************************************************/ +/* lightmap_probe_gizmo_plugin.cpp */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* 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 "lightmap_probe_gizmo_plugin.h" + +#include "editor/editor_settings.h" +#include "editor/plugins/node_3d_editor_plugin.h" +#include "scene/3d/lightmap_probe.h" + +LightmapProbeGizmoPlugin::LightmapProbeGizmoPlugin() { + Color gizmo_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/lightprobe_lines", Color(0.5, 0.6, 1)); + + gizmo_color.a = 0.3; + create_material("lightprobe_lines", gizmo_color); +} + +bool LightmapProbeGizmoPlugin::has_gizmo(Node3D *p_spatial) { + return Object::cast_to(p_spatial) != nullptr; +} + +String LightmapProbeGizmoPlugin::get_gizmo_name() const { + return "LightmapProbe"; +} + +int LightmapProbeGizmoPlugin::get_priority() const { + return -1; +} + +void LightmapProbeGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) { + Ref material_lines = get_material("lightprobe_lines", p_gizmo); + + p_gizmo->clear(); + + Vector lines; + + int stack_count = 8; + int sector_count = 16; + + float sector_step = (Math_PI * 2.0) / sector_count; + float stack_step = Math_PI / stack_count; + + Vector vertices; + float radius = 0.2; + + for (int i = 0; i <= stack_count; ++i) { + float stack_angle = Math_PI / 2 - i * stack_step; // starting from pi/2 to -pi/2 + float xy = radius * Math::cos(stack_angle); // r * cos(u) + float z = radius * Math::sin(stack_angle); // r * sin(u) + + // add (sector_count+1) vertices per stack + // the first and last vertices have same position and normal, but different tex coords + for (int j = 0; j <= sector_count; ++j) { + float sector_angle = j * sector_step; // starting from 0 to 2pi + + // vertex position (x, y, z) + float x = xy * Math::cos(sector_angle); // r * cos(u) * cos(v) + float y = xy * Math::sin(sector_angle); // r * cos(u) * sin(v) + + Vector3 n = Vector3(x, z, y); + vertices.push_back(n); + } + } + + for (int i = 0; i < stack_count; ++i) { + int k1 = i * (sector_count + 1); // beginning of current stack + int k2 = k1 + sector_count + 1; // beginning of next stack + + for (int j = 0; j < sector_count; ++j, ++k1, ++k2) { + // 2 triangles per sector excluding first and last stacks + // k1 => k2 => k1+1 + if (i != 0) { + lines.push_back(vertices[k1]); + lines.push_back(vertices[k2]); + lines.push_back(vertices[k1]); + lines.push_back(vertices[k1 + 1]); + } + + if (i != (stack_count - 1)) { + lines.push_back(vertices[k1 + 1]); + lines.push_back(vertices[k2]); + lines.push_back(vertices[k2]); + lines.push_back(vertices[k2 + 1]); + } + } + } + + p_gizmo->add_lines(lines, material_lines); +} diff --git a/editor/plugins/gizmos/lightmap_probe_gizmo_plugin.h b/editor/plugins/gizmos/lightmap_probe_gizmo_plugin.h new file mode 100644 index 00000000000..d14195235f2 --- /dev/null +++ b/editor/plugins/gizmos/lightmap_probe_gizmo_plugin.h @@ -0,0 +1,48 @@ +/**************************************************************************/ +/* lightmap_probe_gizmo_plugin.h */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* 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. */ +/**************************************************************************/ + +#ifndef LIGHTMAP_PROBE_GIZMO_PLUGIN_H +#define LIGHTMAP_PROBE_GIZMO_PLUGIN_H + +#include "editor/plugins/node_3d_editor_gizmos.h" + +class LightmapProbeGizmoPlugin : public EditorNode3DGizmoPlugin { + GDCLASS(LightmapProbeGizmoPlugin, EditorNode3DGizmoPlugin); + +public: + bool has_gizmo(Node3D *p_spatial) override; + String get_gizmo_name() const override; + int get_priority() const override; + void redraw(EditorNode3DGizmo *p_gizmo) override; + + LightmapProbeGizmoPlugin(); +}; + +#endif // LIGHTMAP_PROBE_GIZMO_PLUGIN_H diff --git a/editor/plugins/gizmos/marker_3d_gizmo_plugin.cpp b/editor/plugins/gizmos/marker_3d_gizmo_plugin.cpp new file mode 100644 index 00000000000..50e6f87fcf0 --- /dev/null +++ b/editor/plugins/gizmos/marker_3d_gizmo_plugin.cpp @@ -0,0 +1,126 @@ +/**************************************************************************/ +/* marker_3d_gizmo_plugin.cpp */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* 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 "marker_3d_gizmo_plugin.h" + +#include "editor/editor_node.h" +#include "editor/plugins/node_3d_editor_plugin.h" +#include "scene/3d/marker_3d.h" + +Marker3DGizmoPlugin::Marker3DGizmoPlugin() { + pos3d_mesh = Ref(memnew(ArrayMesh)); + + Vector cursor_points; + Vector cursor_colors; + const float cs = 1.0; + // Add more points to create a "hard stop" in the color gradient. + cursor_points.push_back(Vector3(+cs, 0, 0)); + cursor_points.push_back(Vector3()); + cursor_points.push_back(Vector3()); + cursor_points.push_back(Vector3(-cs, 0, 0)); + + cursor_points.push_back(Vector3(0, +cs, 0)); + cursor_points.push_back(Vector3()); + cursor_points.push_back(Vector3()); + cursor_points.push_back(Vector3(0, -cs, 0)); + + cursor_points.push_back(Vector3(0, 0, +cs)); + cursor_points.push_back(Vector3()); + cursor_points.push_back(Vector3()); + cursor_points.push_back(Vector3(0, 0, -cs)); + + // Use the axis color which is brighter for the positive axis. + // Use a darkened axis color for the negative axis. + // This makes it possible to see in which direction the Marker3D node is rotated + // (which can be important depending on how it's used). + const Color color_x = EditorNode::get_singleton()->get_gui_base()->get_theme_color(SNAME("axis_x_color"), SNAME("Editor")); + cursor_colors.push_back(color_x); + cursor_colors.push_back(color_x); + // FIXME: Use less strong darkening factor once GH-48573 is fixed. + // The current darkening factor compensates for lines being too bright in the 3D editor. + cursor_colors.push_back(color_x.lerp(Color(0, 0, 0), 0.75)); + cursor_colors.push_back(color_x.lerp(Color(0, 0, 0), 0.75)); + + const Color color_y = EditorNode::get_singleton()->get_gui_base()->get_theme_color(SNAME("axis_y_color"), SNAME("Editor")); + cursor_colors.push_back(color_y); + cursor_colors.push_back(color_y); + cursor_colors.push_back(color_y.lerp(Color(0, 0, 0), 0.75)); + cursor_colors.push_back(color_y.lerp(Color(0, 0, 0), 0.75)); + + const Color color_z = EditorNode::get_singleton()->get_gui_base()->get_theme_color(SNAME("axis_z_color"), SNAME("Editor")); + cursor_colors.push_back(color_z); + cursor_colors.push_back(color_z); + cursor_colors.push_back(color_z.lerp(Color(0, 0, 0), 0.75)); + cursor_colors.push_back(color_z.lerp(Color(0, 0, 0), 0.75)); + + Ref mat = memnew(StandardMaterial3D); + mat->set_shading_mode(StandardMaterial3D::SHADING_MODE_UNSHADED); + mat->set_flag(StandardMaterial3D::FLAG_ALBEDO_FROM_VERTEX_COLOR, true); + mat->set_flag(StandardMaterial3D::FLAG_SRGB_VERTEX_COLOR, true); + mat->set_transparency(StandardMaterial3D::TRANSPARENCY_ALPHA); + + Array d; + d.resize(RS::ARRAY_MAX); + d[Mesh::ARRAY_VERTEX] = cursor_points; + d[Mesh::ARRAY_COLOR] = cursor_colors; + pos3d_mesh->add_surface_from_arrays(Mesh::PRIMITIVE_LINES, d); + pos3d_mesh->surface_set_material(0, mat); +} + +bool Marker3DGizmoPlugin::has_gizmo(Node3D *p_spatial) { + return Object::cast_to(p_spatial) != nullptr; +} + +String Marker3DGizmoPlugin::get_gizmo_name() const { + return "Marker3D"; +} + +int Marker3DGizmoPlugin::get_priority() const { + return -1; +} + +void Marker3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) { + const Marker3D *marker = Object::cast_to(p_gizmo->get_node_3d()); + const real_t extents = marker->get_gizmo_extents(); + const Transform3D xform(Basis::from_scale(Vector3(extents, extents, extents))); + + p_gizmo->clear(); + p_gizmo->add_mesh(pos3d_mesh, Ref(), xform); + + const Vector points = { + Vector3(-extents, 0, 0), + Vector3(+extents, 0, 0), + Vector3(0, -extents, 0), + Vector3(0, +extents, 0), + Vector3(0, 0, -extents), + Vector3(0, 0, +extents), + }; + p_gizmo->add_collision_segments(points); +} diff --git a/editor/plugins/gizmos/marker_3d_gizmo_plugin.h b/editor/plugins/gizmos/marker_3d_gizmo_plugin.h new file mode 100644 index 00000000000..912166f85ec --- /dev/null +++ b/editor/plugins/gizmos/marker_3d_gizmo_plugin.h @@ -0,0 +1,50 @@ +/**************************************************************************/ +/* marker_3d_gizmo_plugin.h */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* 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. */ +/**************************************************************************/ + +#ifndef MARKER_3D_GIZMO_PLUGIN_H +#define MARKER_3D_GIZMO_PLUGIN_H + +#include "editor/plugins/node_3d_editor_gizmos.h" + +class Marker3DGizmoPlugin : public EditorNode3DGizmoPlugin { + GDCLASS(Marker3DGizmoPlugin, EditorNode3DGizmoPlugin); + + Ref pos3d_mesh; + +public: + bool has_gizmo(Node3D *p_spatial) override; + String get_gizmo_name() const override; + int get_priority() const override; + void redraw(EditorNode3DGizmo *p_gizmo) override; + + Marker3DGizmoPlugin(); +}; + +#endif // MARKER_3D_GIZMO_PLUGIN_H diff --git a/editor/plugins/gizmos/mesh_instance_3d_gizmo_plugin.cpp b/editor/plugins/gizmos/mesh_instance_3d_gizmo_plugin.cpp new file mode 100644 index 00000000000..e54f429b8d3 --- /dev/null +++ b/editor/plugins/gizmos/mesh_instance_3d_gizmo_plugin.cpp @@ -0,0 +1,71 @@ +/**************************************************************************/ +/* mesh_instance_3d_gizmo_plugin.cpp */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* 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 "mesh_instance_3d_gizmo_plugin.h" + +#include "editor/plugins/node_3d_editor_plugin.h" +#include "scene/3d/mesh_instance_3d.h" +#include "scene/3d/soft_body_3d.h" + +MeshInstance3DGizmoPlugin::MeshInstance3DGizmoPlugin() { +} + +bool MeshInstance3DGizmoPlugin::has_gizmo(Node3D *p_spatial) { + return Object::cast_to(p_spatial) != nullptr && Object::cast_to(p_spatial) == nullptr; +} + +String MeshInstance3DGizmoPlugin::get_gizmo_name() const { + return "MeshInstance3D"; +} + +int MeshInstance3DGizmoPlugin::get_priority() const { + return -1; +} + +bool MeshInstance3DGizmoPlugin::can_be_hidden() const { + return false; +} + +void MeshInstance3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) { + MeshInstance3D *mesh = Object::cast_to(p_gizmo->get_node_3d()); + + p_gizmo->clear(); + + Ref m = mesh->get_mesh(); + + if (!m.is_valid()) { + return; //none + } + + Ref tm = m->generate_triangle_mesh(); + if (tm.is_valid()) { + p_gizmo->add_collision_triangles(tm); + } +} diff --git a/editor/plugins/gizmos/mesh_instance_3d_gizmo_plugin.h b/editor/plugins/gizmos/mesh_instance_3d_gizmo_plugin.h new file mode 100644 index 00000000000..dfc889b3866 --- /dev/null +++ b/editor/plugins/gizmos/mesh_instance_3d_gizmo_plugin.h @@ -0,0 +1,49 @@ +/**************************************************************************/ +/* mesh_instance_3d_gizmo_plugin.h */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* 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. */ +/**************************************************************************/ + +#ifndef MESH_INSTANCE_3D_GIZMO_PLUGIN_H +#define MESH_INSTANCE_3D_GIZMO_PLUGIN_H + +#include "editor/plugins/node_3d_editor_gizmos.h" + +class MeshInstance3DGizmoPlugin : public EditorNode3DGizmoPlugin { + GDCLASS(MeshInstance3DGizmoPlugin, EditorNode3DGizmoPlugin); + +public: + bool has_gizmo(Node3D *p_spatial) override; + String get_gizmo_name() const override; + int get_priority() const override; + bool can_be_hidden() const override; + void redraw(EditorNode3DGizmo *p_gizmo) override; + + MeshInstance3DGizmoPlugin(); +}; + +#endif // MESH_INSTANCE_3D_GIZMO_PLUGIN_H diff --git a/editor/plugins/gizmos/navigation_link_3d_gizmo_plugin.cpp b/editor/plugins/gizmos/navigation_link_3d_gizmo_plugin.cpp new file mode 100644 index 00000000000..3717b4b1a3e --- /dev/null +++ b/editor/plugins/gizmos/navigation_link_3d_gizmo_plugin.cpp @@ -0,0 +1,203 @@ +/**************************************************************************/ +/* navigation_link_3d_gizmo_plugin.cpp */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* 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 "navigation_link_3d_gizmo_plugin.h" + +#include "editor/editor_undo_redo_manager.h" +#include "editor/plugins/node_3d_editor_plugin.h" +#include "scene/3d/navigation_link_3d.h" +#include "servers/navigation_server_3d.h" + +NavigationLink3DGizmoPlugin::NavigationLink3DGizmoPlugin() { + create_material("navigation_link_material", NavigationServer3D::get_singleton()->get_debug_navigation_link_connection_color()); + create_material("navigation_link_material_disabled", NavigationServer3D::get_singleton()->get_debug_navigation_link_connection_disabled_color()); + create_handle_material("handles"); +} + +bool NavigationLink3DGizmoPlugin::has_gizmo(Node3D *p_spatial) { + return Object::cast_to(p_spatial) != nullptr; +} + +String NavigationLink3DGizmoPlugin::get_gizmo_name() const { + return "NavigationLink3D"; +} + +int NavigationLink3DGizmoPlugin::get_priority() const { + return -1; +} + +void NavigationLink3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) { + NavigationLink3D *link = Object::cast_to(p_gizmo->get_node_3d()); + + RID nav_map = link->get_world_3d()->get_navigation_map(); + real_t search_radius = NavigationServer3D::get_singleton()->map_get_link_connection_radius(nav_map); + Vector3 up_vector = NavigationServer3D::get_singleton()->map_get_up(nav_map); + Vector3::Axis up_axis = up_vector.max_axis_index(); + + Vector3 start_position = link->get_start_position(); + Vector3 end_position = link->get_end_position(); + + Ref link_material = get_material("navigation_link_material", p_gizmo); + Ref link_material_disabled = get_material("navigation_link_material_disabled", p_gizmo); + Ref handles_material = get_material("handles"); + + p_gizmo->clear(); + + // Draw line between the points. + Vector lines; + lines.append(start_position); + lines.append(end_position); + + // Draw start position search radius + for (int i = 0; i < 30; i++) { + // Create a circle + const float ra = Math::deg_to_rad((float)(i * 12)); + const float rb = Math::deg_to_rad((float)((i + 1) * 12)); + const Point2 a = Vector2(Math::sin(ra), Math::cos(ra)) * search_radius; + const Point2 b = Vector2(Math::sin(rb), Math::cos(rb)) * search_radius; + + // Draw axis-aligned circle + switch (up_axis) { + case Vector3::AXIS_X: + lines.append(start_position + Vector3(0, a.x, a.y)); + lines.append(start_position + Vector3(0, b.x, b.y)); + break; + case Vector3::AXIS_Y: + lines.append(start_position + Vector3(a.x, 0, a.y)); + lines.append(start_position + Vector3(b.x, 0, b.y)); + break; + case Vector3::AXIS_Z: + lines.append(start_position + Vector3(a.x, a.y, 0)); + lines.append(start_position + Vector3(b.x, b.y, 0)); + break; + } + } + + // Draw end position search radius + for (int i = 0; i < 30; i++) { + // Create a circle + const float ra = Math::deg_to_rad((float)(i * 12)); + const float rb = Math::deg_to_rad((float)((i + 1) * 12)); + const Point2 a = Vector2(Math::sin(ra), Math::cos(ra)) * search_radius; + const Point2 b = Vector2(Math::sin(rb), Math::cos(rb)) * search_radius; + + // Draw axis-aligned circle + switch (up_axis) { + case Vector3::AXIS_X: + lines.append(end_position + Vector3(0, a.x, a.y)); + lines.append(end_position + Vector3(0, b.x, b.y)); + break; + case Vector3::AXIS_Y: + lines.append(end_position + Vector3(a.x, 0, a.y)); + lines.append(end_position + Vector3(b.x, 0, b.y)); + break; + case Vector3::AXIS_Z: + lines.append(end_position + Vector3(a.x, a.y, 0)); + lines.append(end_position + Vector3(b.x, b.y, 0)); + break; + } + } + + p_gizmo->add_lines(lines, link->is_enabled() ? link_material : link_material_disabled); + p_gizmo->add_collision_segments(lines); + + Vector handles; + handles.append(start_position); + handles.append(end_position); + p_gizmo->add_handles(handles, handles_material); +} + +String NavigationLink3DGizmoPlugin::get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const { + return p_id == 0 ? TTR("Start Location") : TTR("End Location"); +} + +Variant NavigationLink3DGizmoPlugin::get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const { + NavigationLink3D *link = Object::cast_to(p_gizmo->get_node_3d()); + return p_id == 0 ? link->get_start_position() : link->get_end_position(); +} + +void NavigationLink3DGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, Camera3D *p_camera, const Point2 &p_point) { + NavigationLink3D *link = Object::cast_to(p_gizmo->get_node_3d()); + + Transform3D gt = link->get_global_transform(); + Transform3D gi = gt.affine_inverse(); + + Transform3D ct = p_camera->get_global_transform(); + Vector3 cam_dir = ct.basis.get_column(Vector3::AXIS_Z); + + Vector3 ray_from = p_camera->project_ray_origin(p_point); + Vector3 ray_dir = p_camera->project_ray_normal(p_point); + + Vector3 position = p_id == 0 ? link->get_start_position() : link->get_end_position(); + Plane move_plane = Plane(cam_dir, gt.xform(position)); + + Vector3 intersection; + if (!move_plane.intersects_ray(ray_from, ray_dir, &intersection)) { + return; + } + + if (Node3DEditor::get_singleton()->is_snap_enabled()) { + double snap = Node3DEditor::get_singleton()->get_translate_snap(); + intersection.snap(Vector3(snap, snap, snap)); + } + + position = gi.xform(intersection); + if (p_id == 0) { + link->set_start_position(position); + } else if (p_id == 1) { + link->set_end_position(position); + } +} + +void NavigationLink3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, const Variant &p_restore, bool p_cancel) { + NavigationLink3D *link = Object::cast_to(p_gizmo->get_node_3d()); + + if (p_cancel) { + if (p_id == 0) { + link->set_start_position(p_restore); + } else { + link->set_end_position(p_restore); + } + return; + } + + EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton(); + if (p_id == 0) { + ur->create_action(TTR("Change Start Position")); + ur->add_do_method(link, "set_start_position", link->get_start_position()); + ur->add_undo_method(link, "set_start_position", p_restore); + } else { + ur->create_action(TTR("Change End Position")); + ur->add_do_method(link, "set_end_position", link->get_end_position()); + ur->add_undo_method(link, "set_end_position", p_restore); + } + + ur->commit_action(); +} diff --git a/editor/plugins/gizmos/navigation_link_3d_gizmo_plugin.h b/editor/plugins/gizmos/navigation_link_3d_gizmo_plugin.h new file mode 100644 index 00000000000..a58301fe8a3 --- /dev/null +++ b/editor/plugins/gizmos/navigation_link_3d_gizmo_plugin.h @@ -0,0 +1,53 @@ +/**************************************************************************/ +/* navigation_link_3d_gizmo_plugin.h */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* 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. */ +/**************************************************************************/ + +#ifndef NAVIGATION_LINK_3D_GIZMO_PLUGIN_H +#define NAVIGATION_LINK_3D_GIZMO_PLUGIN_H + +#include "editor/plugins/node_3d_editor_gizmos.h" + +class NavigationLink3DGizmoPlugin : public EditorNode3DGizmoPlugin { + GDCLASS(NavigationLink3DGizmoPlugin, EditorNode3DGizmoPlugin); + +public: + bool has_gizmo(Node3D *p_spatial) override; + String get_gizmo_name() const override; + int get_priority() const override; + void redraw(EditorNode3DGizmo *p_gizmo) override; + + String get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const override; + Variant get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const override; + void set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, Camera3D *p_camera, const Point2 &p_point) override; + void commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, const Variant &p_restore, bool p_cancel = false) override; + + NavigationLink3DGizmoPlugin(); +}; + +#endif // NAVIGATION_LINK_3D_GIZMO_PLUGIN_H diff --git a/editor/plugins/gizmos/navigation_region_3d_gizmo_plugin.cpp b/editor/plugins/gizmos/navigation_region_3d_gizmo_plugin.cpp new file mode 100644 index 00000000000..088b09ea460 --- /dev/null +++ b/editor/plugins/gizmos/navigation_region_3d_gizmo_plugin.cpp @@ -0,0 +1,208 @@ +/**************************************************************************/ +/* navigation_region_3d_gizmo_plugin.cpp */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* 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 "navigation_region_3d_gizmo_plugin.h" + +#include "editor/plugins/node_3d_editor_plugin.h" +#include "scene/3d/navigation_region_3d.h" +#include "servers/navigation_server_3d.h" + +NavigationRegion3DGizmoPlugin::NavigationRegion3DGizmoPlugin() { + create_material("face_material", NavigationServer3D::get_singleton()->get_debug_navigation_geometry_face_color(), false, false, true); + create_material("face_material_disabled", NavigationServer3D::get_singleton()->get_debug_navigation_geometry_face_disabled_color(), false, false, true); + create_material("edge_material", NavigationServer3D::get_singleton()->get_debug_navigation_geometry_edge_color()); + create_material("edge_material_disabled", NavigationServer3D::get_singleton()->get_debug_navigation_geometry_edge_disabled_color()); + + Color baking_aabb_material_color = Color(0.8, 0.5, 0.7); + baking_aabb_material_color.a = 0.1; + create_material("baking_aabb_material", baking_aabb_material_color); +} + +bool NavigationRegion3DGizmoPlugin::has_gizmo(Node3D *p_spatial) { + return Object::cast_to(p_spatial) != nullptr; +} + +String NavigationRegion3DGizmoPlugin::get_gizmo_name() const { + return "NavigationRegion3D"; +} + +int NavigationRegion3DGizmoPlugin::get_priority() const { + return -1; +} + +void NavigationRegion3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) { + NavigationRegion3D *navigationregion = Object::cast_to(p_gizmo->get_node_3d()); + + p_gizmo->clear(); + Ref navigationmesh = navigationregion->get_navigation_mesh(); + if (navigationmesh.is_null()) { + return; + } + + AABB baking_aabb = navigationmesh->get_filter_baking_aabb(); + if (baking_aabb.has_volume()) { + Vector3 baking_aabb_offset = navigationmesh->get_filter_baking_aabb_offset(); + + if (p_gizmo->is_selected()) { + Ref material = get_material("baking_aabb_material", p_gizmo); + p_gizmo->add_solid_box(material, baking_aabb.get_size(), baking_aabb.get_center() + baking_aabb_offset); + } + } + + Vector vertices = navigationmesh->get_vertices(); + const Vector3 *vr = vertices.ptr(); + List faces; + for (int i = 0; i < navigationmesh->get_polygon_count(); i++) { + Vector p = navigationmesh->get_polygon(i); + + for (int j = 2; j < p.size(); j++) { + Face3 f; + f.vertex[0] = vr[p[0]]; + f.vertex[1] = vr[p[j - 1]]; + f.vertex[2] = vr[p[j]]; + + faces.push_back(f); + } + } + + if (faces.is_empty()) { + return; + } + + HashMap<_EdgeKey, bool, _EdgeKey> edge_map; + Vector tmeshfaces; + tmeshfaces.resize(faces.size() * 3); + + { + Vector3 *tw = tmeshfaces.ptrw(); + int tidx = 0; + + for (const Face3 &f : faces) { + for (int j = 0; j < 3; j++) { + tw[tidx++] = f.vertex[j]; + _EdgeKey ek; + ek.from = f.vertex[j].snapped(Vector3(CMP_EPSILON, CMP_EPSILON, CMP_EPSILON)); + ek.to = f.vertex[(j + 1) % 3].snapped(Vector3(CMP_EPSILON, CMP_EPSILON, CMP_EPSILON)); + if (ek.from < ek.to) { + SWAP(ek.from, ek.to); + } + + HashMap<_EdgeKey, bool, _EdgeKey>::Iterator F = edge_map.find(ek); + + if (F) { + F->value = false; + + } else { + edge_map[ek] = true; + } + } + } + } + Vector lines; + + for (const KeyValue<_EdgeKey, bool> &E : edge_map) { + if (E.value) { + lines.push_back(E.key.from); + lines.push_back(E.key.to); + } + } + + Ref tmesh = memnew(TriangleMesh); + tmesh->create(tmeshfaces); + + p_gizmo->add_collision_triangles(tmesh); + p_gizmo->add_collision_segments(lines); + + Ref debug_mesh = Ref(memnew(ArrayMesh)); + int polygon_count = navigationmesh->get_polygon_count(); + + // build geometry face surface + Vector face_vertex_array; + face_vertex_array.resize(polygon_count * 3); + + for (int i = 0; i < polygon_count; i++) { + Vector polygon = navigationmesh->get_polygon(i); + + face_vertex_array.push_back(vertices[polygon[0]]); + face_vertex_array.push_back(vertices[polygon[1]]); + face_vertex_array.push_back(vertices[polygon[2]]); + } + + Array face_mesh_array; + face_mesh_array.resize(Mesh::ARRAY_MAX); + face_mesh_array[Mesh::ARRAY_VERTEX] = face_vertex_array; + + // if enabled add vertex colors to colorize each face individually + RandomPCG rand; + bool enabled_geometry_face_random_color = NavigationServer3D::get_singleton()->get_debug_navigation_enable_geometry_face_random_color(); + if (enabled_geometry_face_random_color) { + Color debug_navigation_geometry_face_color = NavigationServer3D::get_singleton()->get_debug_navigation_geometry_face_color(); + Color polygon_color = debug_navigation_geometry_face_color; + + Vector face_color_array; + face_color_array.resize(polygon_count * 3); + + for (int i = 0; i < polygon_count; i++) { + // Generate the polygon color, slightly randomly modified from the settings one. + polygon_color.set_hsv(debug_navigation_geometry_face_color.get_h() + rand.random(-1.0, 1.0) * 0.1, debug_navigation_geometry_face_color.get_s(), debug_navigation_geometry_face_color.get_v() + rand.random(-1.0, 1.0) * 0.2); + polygon_color.a = debug_navigation_geometry_face_color.a; + + Vector polygon = navigationmesh->get_polygon(i); + + face_color_array.push_back(polygon_color); + face_color_array.push_back(polygon_color); + face_color_array.push_back(polygon_color); + } + face_mesh_array[Mesh::ARRAY_COLOR] = face_color_array; + } + + debug_mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, face_mesh_array); + p_gizmo->add_mesh(debug_mesh, navigationregion->is_enabled() ? get_material("face_material", p_gizmo) : get_material("face_material_disabled", p_gizmo)); + + // if enabled build geometry edge line surface + bool enabled_edge_lines = NavigationServer3D::get_singleton()->get_debug_navigation_enable_edge_lines(); + if (enabled_edge_lines) { + Vector line_vertex_array; + line_vertex_array.resize(polygon_count * 6); + + for (int i = 0; i < polygon_count; i++) { + Vector polygon = navigationmesh->get_polygon(i); + + line_vertex_array.push_back(vertices[polygon[0]]); + line_vertex_array.push_back(vertices[polygon[1]]); + line_vertex_array.push_back(vertices[polygon[1]]); + line_vertex_array.push_back(vertices[polygon[2]]); + line_vertex_array.push_back(vertices[polygon[2]]); + line_vertex_array.push_back(vertices[polygon[0]]); + } + + p_gizmo->add_lines(line_vertex_array, navigationregion->is_enabled() ? get_material("edge_material", p_gizmo) : get_material("edge_material_disabled", p_gizmo)); + } +} diff --git a/editor/plugins/gizmos/navigation_region_3d_gizmo_plugin.h b/editor/plugins/gizmos/navigation_region_3d_gizmo_plugin.h new file mode 100644 index 00000000000..93d0849ed4c --- /dev/null +++ b/editor/plugins/gizmos/navigation_region_3d_gizmo_plugin.h @@ -0,0 +1,61 @@ +/**************************************************************************/ +/* navigation_region_3d_gizmo_plugin.h */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* 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. */ +/**************************************************************************/ + +#ifndef NAVIGATION_REGION_3D_GIZMO_PLUGIN_H +#define NAVIGATION_REGION_3D_GIZMO_PLUGIN_H + +#include "editor/plugins/node_3d_editor_gizmos.h" + +class NavigationRegion3DGizmoPlugin : public EditorNode3DGizmoPlugin { + GDCLASS(NavigationRegion3DGizmoPlugin, EditorNode3DGizmoPlugin); + + struct _EdgeKey { + Vector3 from; + Vector3 to; + + static uint32_t hash(const _EdgeKey &p_key) { + return HashMapHasherDefault::hash(p_key.from) ^ HashMapHasherDefault::hash(p_key.to); + } + + bool operator==(const _EdgeKey &p_with) const { + return HashMapComparatorDefault::compare(from, p_with.from) && HashMapComparatorDefault::compare(to, p_with.to); + } + }; + +public: + bool has_gizmo(Node3D *p_spatial) override; + String get_gizmo_name() const override; + int get_priority() const override; + void redraw(EditorNode3DGizmo *p_gizmo) override; + + NavigationRegion3DGizmoPlugin(); +}; + +#endif // NAVIGATION_REGION_3D_GIZMO_PLUGIN_H diff --git a/editor/plugins/gizmos/occluder_instance_3d_gizmo_plugin.cpp b/editor/plugins/gizmos/occluder_instance_3d_gizmo_plugin.cpp new file mode 100644 index 00000000000..f9a210b0e7c --- /dev/null +++ b/editor/plugins/gizmos/occluder_instance_3d_gizmo_plugin.cpp @@ -0,0 +1,284 @@ +/**************************************************************************/ +/* occluder_instance_3d_gizmo_plugin.cpp */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* 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 "occluder_instance_3d_gizmo_plugin.h" + +#include "editor/editor_settings.h" +#include "editor/editor_undo_redo_manager.h" +#include "editor/plugins/node_3d_editor_plugin.h" +#include "scene/3d/occluder_instance_3d.h" + +OccluderInstance3DGizmoPlugin::OccluderInstance3DGizmoPlugin() { + create_material("line_material", EDITOR_DEF("editors/3d_gizmos/gizmo_colors/occluder", Color(0.8, 0.5, 1))); + create_handle_material("handles"); +} + +bool OccluderInstance3DGizmoPlugin::has_gizmo(Node3D *p_spatial) { + return Object::cast_to(p_spatial) != nullptr; +} + +String OccluderInstance3DGizmoPlugin::get_gizmo_name() const { + return "OccluderInstance3D"; +} + +int OccluderInstance3DGizmoPlugin::get_priority() const { + return -1; +} + +String OccluderInstance3DGizmoPlugin::get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const { + const OccluderInstance3D *cs = Object::cast_to(p_gizmo->get_node_3d()); + + Ref o = cs->get_occluder(); + if (o.is_null()) { + return ""; + } + + if (Object::cast_to(*o)) { + return "Radius"; + } + + if (Object::cast_to(*o) || Object::cast_to(*o)) { + return "Size"; + } + + return ""; +} + +Variant OccluderInstance3DGizmoPlugin::get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const { + OccluderInstance3D *oi = Object::cast_to(p_gizmo->get_node_3d()); + + Ref o = oi->get_occluder(); + if (o.is_null()) { + return Variant(); + } + + if (Object::cast_to(*o)) { + Ref so = o; + return so->get_radius(); + } + + if (Object::cast_to(*o)) { + Ref bo = o; + return bo->get_size(); + } + + if (Object::cast_to(*o)) { + Ref qo = o; + return qo->get_size(); + } + + return Variant(); +} + +void OccluderInstance3DGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, Camera3D *p_camera, const Point2 &p_point) { + OccluderInstance3D *oi = Object::cast_to(p_gizmo->get_node_3d()); + + Ref o = oi->get_occluder(); + if (o.is_null()) { + return; + } + + Transform3D gt = oi->get_global_transform(); + Transform3D gi = gt.affine_inverse(); + + Vector3 ray_from = p_camera->project_ray_origin(p_point); + Vector3 ray_dir = p_camera->project_ray_normal(p_point); + + Vector3 sg[2] = { gi.xform(ray_from), gi.xform(ray_from + ray_dir * 4096) }; + + bool snap_enabled = Node3DEditor::get_singleton()->is_snap_enabled(); + float snap = Node3DEditor::get_singleton()->get_translate_snap(); + + if (Object::cast_to(*o)) { + Ref so = o; + Vector3 ra, rb; + Geometry3D::get_closest_points_between_segments(Vector3(), Vector3(4096, 0, 0), sg[0], sg[1], ra, rb); + float d = ra.x; + if (snap_enabled) { + d = Math::snapped(d, snap); + } + + if (d < 0.001) { + d = 0.001; + } + + so->set_radius(d); + } + + if (Object::cast_to(*o)) { + Vector3 axis; + axis[p_id] = 1.0; + Ref bo = o; + Vector3 ra, rb; + Geometry3D::get_closest_points_between_segments(Vector3(), axis * 4096, sg[0], sg[1], ra, rb); + float d = ra[p_id] * 2; + if (snap_enabled) { + d = Math::snapped(d, snap); + } + + if (d < 0.001) { + d = 0.001; + } + + Vector3 he = bo->get_size(); + he[p_id] = d; + bo->set_size(he); + } + + if (Object::cast_to(*o)) { + Ref qo = o; + Plane p = Plane(Vector3(0.0f, 0.0f, 1.0f), 0.0f); + Vector3 intersection; + if (!p.intersects_segment(sg[0], sg[1], &intersection)) { + return; + } + + if (p_id == 2) { + Vector2 s = Vector2(intersection.x, intersection.y) * 2.0f; + if (snap_enabled) { + s = s.snapped(Vector2(snap, snap)); + } + s = s.max(Vector2(0.001, 0.001)); + qo->set_size(s); + } else { + float d = intersection[p_id]; + if (snap_enabled) { + d = Math::snapped(d, snap); + } + + if (d < 0.001) { + d = 0.001; + } + + Vector2 he = qo->get_size(); + he[p_id] = d * 2.0f; + qo->set_size(he); + } + } +} + +void OccluderInstance3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, const Variant &p_restore, bool p_cancel) { + OccluderInstance3D *oi = Object::cast_to(p_gizmo->get_node_3d()); + + Ref o = oi->get_occluder(); + if (o.is_null()) { + return; + } + + if (Object::cast_to(*o)) { + Ref so = o; + if (p_cancel) { + so->set_radius(p_restore); + return; + } + + EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton(); + ur->create_action(TTR("Change Sphere Shape Radius")); + ur->add_do_method(so.ptr(), "set_radius", so->get_radius()); + ur->add_undo_method(so.ptr(), "set_radius", p_restore); + ur->commit_action(); + } + + if (Object::cast_to(*o)) { + Ref bo = o; + if (p_cancel) { + bo->set_size(p_restore); + return; + } + + EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton(); + ur->create_action(TTR("Change Box Shape Size")); + ur->add_do_method(bo.ptr(), "set_size", bo->get_size()); + ur->add_undo_method(bo.ptr(), "set_size", p_restore); + ur->commit_action(); + } + + if (Object::cast_to(*o)) { + Ref qo = o; + if (p_cancel) { + qo->set_size(p_restore); + return; + } + + EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton(); + ur->create_action(TTR("Change Box Shape Size")); + ur->add_do_method(qo.ptr(), "set_size", qo->get_size()); + ur->add_undo_method(qo.ptr(), "set_size", p_restore); + ur->commit_action(); + } +} + +void OccluderInstance3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) { + OccluderInstance3D *occluder_instance = Object::cast_to(p_gizmo->get_node_3d()); + + p_gizmo->clear(); + + Ref o = occluder_instance->get_occluder(); + + if (!o.is_valid()) { + return; + } + + Vector lines = o->get_debug_lines(); + if (!lines.is_empty()) { + Ref material = get_material("line_material", p_gizmo); + p_gizmo->add_lines(lines, material); + p_gizmo->add_collision_segments(lines); + } + + Ref handles_material = get_material("handles"); + if (Object::cast_to(*o)) { + Ref so = o; + float r = so->get_radius(); + Vector handles = { Vector3(r, 0, 0) }; + p_gizmo->add_handles(handles, handles_material); + } + + if (Object::cast_to(*o)) { + Ref bo = o; + + Vector handles; + for (int i = 0; i < 3; i++) { + Vector3 ax; + ax[i] = bo->get_size()[i] / 2; + handles.push_back(ax); + } + + p_gizmo->add_handles(handles, handles_material); + } + + if (Object::cast_to(*o)) { + Ref qo = o; + Vector2 size = qo->get_size(); + Vector3 s = Vector3(size.x, size.y, 0.0f) / 2.0f; + Vector handles = { Vector3(s.x, 0.0f, 0.0f), Vector3(0.0f, s.y, 0.0f), Vector3(s.x, s.y, 0.0f) }; + p_gizmo->add_handles(handles, handles_material); + } +} diff --git a/editor/plugins/gizmos/occluder_instance_3d_gizmo_plugin.h b/editor/plugins/gizmos/occluder_instance_3d_gizmo_plugin.h new file mode 100644 index 00000000000..1555ffd40fd --- /dev/null +++ b/editor/plugins/gizmos/occluder_instance_3d_gizmo_plugin.h @@ -0,0 +1,53 @@ +/**************************************************************************/ +/* occluder_instance_3d_gizmo_plugin.h */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* 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. */ +/**************************************************************************/ + +#ifndef OCCLUDER_INSTANCE_3D_GIZMO_PLUGIN_H +#define OCCLUDER_INSTANCE_3D_GIZMO_PLUGIN_H + +#include "editor/plugins/node_3d_editor_gizmos.h" + +class OccluderInstance3DGizmoPlugin : public EditorNode3DGizmoPlugin { + GDCLASS(OccluderInstance3DGizmoPlugin, EditorNode3DGizmoPlugin); + +public: + bool has_gizmo(Node3D *p_spatial) override; + String get_gizmo_name() const override; + int get_priority() const override; + void redraw(EditorNode3DGizmo *p_gizmo) override; + + String get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const override; + Variant get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const override; + void set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, Camera3D *p_camera, const Point2 &p_point) override; + void commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, const Variant &p_restore, bool p_cancel = false) override; + + OccluderInstance3DGizmoPlugin(); +}; + +#endif // OCCLUDER_INSTANCE_3D_GIZMO_PLUGIN_H diff --git a/editor/plugins/gizmos/physics_bone_3d_gizmo_plugin.cpp b/editor/plugins/gizmos/physics_bone_3d_gizmo_plugin.cpp new file mode 100644 index 00000000000..d1511a5f76d --- /dev/null +++ b/editor/plugins/gizmos/physics_bone_3d_gizmo_plugin.cpp @@ -0,0 +1,167 @@ +/**************************************************************************/ +/* physics_bone_3d_gizmo_plugin.cpp */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* 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 "physics_bone_3d_gizmo_plugin.h" + +#include "editor/editor_settings.h" +#include "editor/plugins/gizmos/joint_3d_gizmo_plugin.h" +#include "editor/plugins/node_3d_editor_plugin.h" +#include "scene/3d/physics_body_3d.h" + +PhysicalBone3DGizmoPlugin::PhysicalBone3DGizmoPlugin() { + create_material("joint_material", EDITOR_GET("editors/3d_gizmos/gizmo_colors/joint")); +} + +bool PhysicalBone3DGizmoPlugin::has_gizmo(Node3D *p_spatial) { + return Object::cast_to(p_spatial) != nullptr; +} + +String PhysicalBone3DGizmoPlugin::get_gizmo_name() const { + return "PhysicalBone3D"; +} + +int PhysicalBone3DGizmoPlugin::get_priority() const { + return -1; +} + +void PhysicalBone3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) { + p_gizmo->clear(); + + PhysicalBone3D *physical_bone = Object::cast_to(p_gizmo->get_node_3d()); + + if (!physical_bone) { + return; + } + + Skeleton3D *sk(physical_bone->find_skeleton_parent()); + if (!sk) { + return; + } + + PhysicalBone3D *pb(sk->get_physical_bone(physical_bone->get_bone_id())); + if (!pb) { + return; + } + + PhysicalBone3D *pbp(sk->get_physical_bone_parent(physical_bone->get_bone_id())); + if (!pbp) { + return; + } + + Vector points; + + switch (physical_bone->get_joint_type()) { + case PhysicalBone3D::JOINT_TYPE_PIN: { + Joint3DGizmoPlugin::CreatePinJointGizmo(physical_bone->get_joint_offset(), points); + } break; + case PhysicalBone3D::JOINT_TYPE_CONE: { + const PhysicalBone3D::ConeJointData *cjd(static_cast(physical_bone->get_joint_data())); + Joint3DGizmoPlugin::CreateConeTwistJointGizmo( + physical_bone->get_joint_offset(), + physical_bone->get_global_transform() * physical_bone->get_joint_offset(), + pb->get_global_transform(), + pbp->get_global_transform(), + cjd->swing_span, + cjd->twist_span, + &points, + &points); + } break; + case PhysicalBone3D::JOINT_TYPE_HINGE: { + const PhysicalBone3D::HingeJointData *hjd(static_cast(physical_bone->get_joint_data())); + Joint3DGizmoPlugin::CreateHingeJointGizmo( + physical_bone->get_joint_offset(), + physical_bone->get_global_transform() * physical_bone->get_joint_offset(), + pb->get_global_transform(), + pbp->get_global_transform(), + hjd->angular_limit_lower, + hjd->angular_limit_upper, + hjd->angular_limit_enabled, + points, + &points, + &points); + } break; + case PhysicalBone3D::JOINT_TYPE_SLIDER: { + const PhysicalBone3D::SliderJointData *sjd(static_cast(physical_bone->get_joint_data())); + Joint3DGizmoPlugin::CreateSliderJointGizmo( + physical_bone->get_joint_offset(), + physical_bone->get_global_transform() * physical_bone->get_joint_offset(), + pb->get_global_transform(), + pbp->get_global_transform(), + sjd->angular_limit_lower, + sjd->angular_limit_upper, + sjd->linear_limit_lower, + sjd->linear_limit_upper, + points, + &points, + &points); + } break; + case PhysicalBone3D::JOINT_TYPE_6DOF: { + const PhysicalBone3D::SixDOFJointData *sdofjd(static_cast(physical_bone->get_joint_data())); + Joint3DGizmoPlugin::CreateGeneric6DOFJointGizmo( + physical_bone->get_joint_offset(), + + physical_bone->get_global_transform() * physical_bone->get_joint_offset(), + pb->get_global_transform(), + pbp->get_global_transform(), + + sdofjd->axis_data[0].angular_limit_lower, + sdofjd->axis_data[0].angular_limit_upper, + sdofjd->axis_data[0].linear_limit_lower, + sdofjd->axis_data[0].linear_limit_upper, + sdofjd->axis_data[0].angular_limit_enabled, + sdofjd->axis_data[0].linear_limit_enabled, + + sdofjd->axis_data[1].angular_limit_lower, + sdofjd->axis_data[1].angular_limit_upper, + sdofjd->axis_data[1].linear_limit_lower, + sdofjd->axis_data[1].linear_limit_upper, + sdofjd->axis_data[1].angular_limit_enabled, + sdofjd->axis_data[1].linear_limit_enabled, + + sdofjd->axis_data[2].angular_limit_lower, + sdofjd->axis_data[2].angular_limit_upper, + sdofjd->axis_data[2].linear_limit_lower, + sdofjd->axis_data[2].linear_limit_upper, + sdofjd->axis_data[2].angular_limit_enabled, + sdofjd->axis_data[2].linear_limit_enabled, + + points, + &points, + &points); + } break; + default: + return; + } + + Ref material = get_material("joint_material", p_gizmo); + + p_gizmo->add_collision_segments(points); + p_gizmo->add_lines(points, material); +} diff --git a/editor/plugins/gizmos/physics_bone_3d_gizmo_plugin.h b/editor/plugins/gizmos/physics_bone_3d_gizmo_plugin.h new file mode 100644 index 00000000000..bd551c98ef6 --- /dev/null +++ b/editor/plugins/gizmos/physics_bone_3d_gizmo_plugin.h @@ -0,0 +1,48 @@ +/**************************************************************************/ +/* physics_bone_3d_gizmo_plugin.h */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* 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. */ +/**************************************************************************/ + +#ifndef PHYSICS_BONE_3D_GIZMO_PLUGIN_H +#define PHYSICS_BONE_3D_GIZMO_PLUGIN_H + +#include "editor/plugins/node_3d_editor_gizmos.h" + +class PhysicalBone3DGizmoPlugin : public EditorNode3DGizmoPlugin { + GDCLASS(PhysicalBone3DGizmoPlugin, EditorNode3DGizmoPlugin); + +public: + bool has_gizmo(Node3D *p_spatial) override; + String get_gizmo_name() const override; + int get_priority() const override; + void redraw(EditorNode3DGizmo *p_gizmo) override; + + PhysicalBone3DGizmoPlugin(); +}; + +#endif // PHYSICS_BONE_3D_GIZMO_PLUGIN_H diff --git a/editor/plugins/gizmos/ray_cast_3d_gizmo_plugin.cpp b/editor/plugins/gizmos/ray_cast_3d_gizmo_plugin.cpp new file mode 100644 index 00000000000..eb9e54fe1d6 --- /dev/null +++ b/editor/plugins/gizmos/ray_cast_3d_gizmo_plugin.cpp @@ -0,0 +1,71 @@ +/**************************************************************************/ +/* ray_cast_3d_gizmo_plugin.cpp */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* 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 "ray_cast_3d_gizmo_plugin.h" + +#include "editor/editor_settings.h" +#include "editor/plugins/node_3d_editor_plugin.h" +#include "scene/3d/ray_cast_3d.h" + +RayCast3DGizmoPlugin::RayCast3DGizmoPlugin() { + const Color gizmo_color = EDITOR_GET("editors/3d_gizmos/gizmo_colors/shape"); + create_material("shape_material", gizmo_color); + const float gizmo_value = gizmo_color.get_v(); + const Color gizmo_color_disabled = Color(gizmo_value, gizmo_value, gizmo_value, 0.65); + create_material("shape_material_disabled", gizmo_color_disabled); +} + +bool RayCast3DGizmoPlugin::has_gizmo(Node3D *p_spatial) { + return Object::cast_to(p_spatial) != nullptr; +} + +String RayCast3DGizmoPlugin::get_gizmo_name() const { + return "RayCast3D"; +} + +int RayCast3DGizmoPlugin::get_priority() const { + return -1; +} + +void RayCast3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) { + RayCast3D *raycast = Object::cast_to(p_gizmo->get_node_3d()); + + p_gizmo->clear(); + + const Ref material = raycast->is_enabled() ? raycast->get_debug_material() : get_material("shape_material_disabled"); + + p_gizmo->add_lines(raycast->get_debug_line_vertices(), material); + + if (raycast->get_debug_shape_thickness() > 1) { + p_gizmo->add_vertices(raycast->get_debug_shape_vertices(), material, Mesh::PRIMITIVE_TRIANGLE_STRIP); + } + + p_gizmo->add_collision_segments(raycast->get_debug_line_vertices()); +} diff --git a/editor/plugins/gizmos/ray_cast_3d_gizmo_plugin.h b/editor/plugins/gizmos/ray_cast_3d_gizmo_plugin.h new file mode 100644 index 00000000000..133476a388d --- /dev/null +++ b/editor/plugins/gizmos/ray_cast_3d_gizmo_plugin.h @@ -0,0 +1,48 @@ +/**************************************************************************/ +/* ray_cast_3d_gizmo_plugin.h */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* 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. */ +/**************************************************************************/ + +#ifndef RAY_CAST_3D_GIZMO_PLUGIN_H +#define RAY_CAST_3D_GIZMO_PLUGIN_H + +#include "editor/plugins/node_3d_editor_gizmos.h" + +class RayCast3DGizmoPlugin : public EditorNode3DGizmoPlugin { + GDCLASS(RayCast3DGizmoPlugin, EditorNode3DGizmoPlugin); + +public: + bool has_gizmo(Node3D *p_spatial) override; + String get_gizmo_name() const override; + int get_priority() const override; + void redraw(EditorNode3DGizmo *p_gizmo) override; + + RayCast3DGizmoPlugin(); +}; + +#endif // RAY_CAST_3D_GIZMO_PLUGIN_H diff --git a/editor/plugins/gizmos/reflection_probe_gizmo_plugin.cpp b/editor/plugins/gizmos/reflection_probe_gizmo_plugin.cpp new file mode 100644 index 00000000000..8d61eb07115 --- /dev/null +++ b/editor/plugins/gizmos/reflection_probe_gizmo_plugin.cpp @@ -0,0 +1,224 @@ +/**************************************************************************/ +/* reflection_probe_gizmo_plugin.cpp */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* 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 "reflection_probe_gizmo_plugin.h" + +#include "editor/editor_settings.h" +#include "editor/editor_undo_redo_manager.h" +#include "editor/plugins/node_3d_editor_plugin.h" +#include "scene/3d/reflection_probe.h" + +ReflectionProbeGizmoPlugin::ReflectionProbeGizmoPlugin() { + Color gizmo_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/reflection_probe", Color(0.6, 1, 0.5)); + + create_material("reflection_probe_material", gizmo_color); + + gizmo_color.a = 0.5; + create_material("reflection_internal_material", gizmo_color); + + gizmo_color.a = 0.1; + create_material("reflection_probe_solid_material", gizmo_color); + + create_icon_material("reflection_probe_icon", Node3DEditor::get_singleton()->get_theme_icon(SNAME("GizmoReflectionProbe"), SNAME("EditorIcons"))); + create_handle_material("handles"); +} + +bool ReflectionProbeGizmoPlugin::has_gizmo(Node3D *p_spatial) { + return Object::cast_to(p_spatial) != nullptr; +} + +String ReflectionProbeGizmoPlugin::get_gizmo_name() const { + return "ReflectionProbe"; +} + +int ReflectionProbeGizmoPlugin::get_priority() const { + return -1; +} + +String ReflectionProbeGizmoPlugin::get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const { + switch (p_id) { + case 0: + return "Size X"; + case 1: + return "Size Y"; + case 2: + return "Size Z"; + case 3: + return "Origin X"; + case 4: + return "Origin Y"; + case 5: + return "Origin Z"; + } + + return ""; +} + +Variant ReflectionProbeGizmoPlugin::get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const { + ReflectionProbe *probe = Object::cast_to(p_gizmo->get_node_3d()); + return AABB(probe->get_origin_offset(), probe->get_size()); +} + +void ReflectionProbeGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, Camera3D *p_camera, const Point2 &p_point) { + ReflectionProbe *probe = Object::cast_to(p_gizmo->get_node_3d()); + Transform3D gt = probe->get_global_transform(); + + Transform3D gi = gt.affine_inverse(); + + if (p_id < 3) { + Vector3 size = probe->get_size(); + + Vector3 ray_from = p_camera->project_ray_origin(p_point); + Vector3 ray_dir = p_camera->project_ray_normal(p_point); + + Vector3 sg[2] = { gi.xform(ray_from), gi.xform(ray_from + ray_dir * 16384) }; + + Vector3 axis; + axis[p_id] = 1.0; + + Vector3 ra, rb; + Geometry3D::get_closest_points_between_segments(Vector3(), axis * 16384, sg[0], sg[1], ra, rb); + float d = ra[p_id] * 2; + if (Node3DEditor::get_singleton()->is_snap_enabled()) { + d = Math::snapped(d, Node3DEditor::get_singleton()->get_translate_snap()); + } + + if (d < 0.001) { + d = 0.001; + } + + size[p_id] = d; + probe->set_size(size); + } else { + p_id -= 3; + + Vector3 origin = probe->get_origin_offset(); + origin[p_id] = 0; + + Vector3 ray_from = p_camera->project_ray_origin(p_point); + Vector3 ray_dir = p_camera->project_ray_normal(p_point); + + Vector3 sg[2] = { gi.xform(ray_from), gi.xform(ray_from + ray_dir * 16384) }; + + Vector3 axis; + axis[p_id] = 1.0; + + Vector3 ra, rb; + Geometry3D::get_closest_points_between_segments(origin - axis * 16384, origin + axis * 16384, sg[0], sg[1], ra, rb); + // Adjust the actual position to account for the gizmo handle position + float d = ra[p_id] + 0.25; + if (Node3DEditor::get_singleton()->is_snap_enabled()) { + d = Math::snapped(d, Node3DEditor::get_singleton()->get_translate_snap()); + } + + origin[p_id] = d; + probe->set_origin_offset(origin); + } +} + +void ReflectionProbeGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, const Variant &p_restore, bool p_cancel) { + ReflectionProbe *probe = Object::cast_to(p_gizmo->get_node_3d()); + + AABB restore = p_restore; + + if (p_cancel) { + probe->set_origin_offset(restore.position); + probe->set_size(restore.size); + return; + } + + EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton(); + ur->create_action(TTR("Change Probe Size")); + ur->add_do_method(probe, "set_size", probe->get_size()); + ur->add_do_method(probe, "set_origin_offset", probe->get_origin_offset()); + ur->add_undo_method(probe, "set_size", restore.size); + ur->add_undo_method(probe, "set_origin_offset", restore.position); + ur->commit_action(); +} + +void ReflectionProbeGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) { + ReflectionProbe *probe = Object::cast_to(p_gizmo->get_node_3d()); + + p_gizmo->clear(); + + Vector lines; + Vector internal_lines; + Vector3 size = probe->get_size(); + + AABB aabb; + aabb.position = -size / 2; + aabb.size = size; + + for (int i = 0; i < 12; i++) { + Vector3 a, b; + aabb.get_edge(i, a, b); + lines.push_back(a); + lines.push_back(b); + } + + for (int i = 0; i < 8; i++) { + Vector3 ep = aabb.get_endpoint(i); + internal_lines.push_back(probe->get_origin_offset()); + internal_lines.push_back(ep); + } + + Vector handles; + + for (int i = 0; i < 3; i++) { + Vector3 ax; + ax[i] = aabb.position[i] + aabb.size[i]; + handles.push_back(ax); + } + + for (int i = 0; i < 3; i++) { + Vector3 orig_handle = probe->get_origin_offset(); + orig_handle[i] -= 0.25; + lines.push_back(orig_handle); + handles.push_back(orig_handle); + + orig_handle[i] += 0.5; + lines.push_back(orig_handle); + } + + Ref material = get_material("reflection_probe_material", p_gizmo); + Ref material_internal = get_material("reflection_internal_material", p_gizmo); + Ref icon = get_material("reflection_probe_icon", p_gizmo); + + p_gizmo->add_lines(lines, material); + p_gizmo->add_lines(internal_lines, material_internal); + + if (p_gizmo->is_selected()) { + Ref solid_material = get_material("reflection_probe_solid_material", p_gizmo); + p_gizmo->add_solid_box(solid_material, probe->get_size()); + } + + p_gizmo->add_unscaled_billboard(icon, 0.05); + p_gizmo->add_handles(handles, get_material("handles")); +} diff --git a/editor/plugins/gizmos/reflection_probe_gizmo_plugin.h b/editor/plugins/gizmos/reflection_probe_gizmo_plugin.h new file mode 100644 index 00000000000..bc9840b27cd --- /dev/null +++ b/editor/plugins/gizmos/reflection_probe_gizmo_plugin.h @@ -0,0 +1,53 @@ +/**************************************************************************/ +/* reflection_probe_gizmo_plugin.h */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* 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. */ +/**************************************************************************/ + +#ifndef REFLECTION_PROBE_GIZMO_PLUGIN_H +#define REFLECTION_PROBE_GIZMO_PLUGIN_H + +#include "editor/plugins/node_3d_editor_gizmos.h" + +class ReflectionProbeGizmoPlugin : public EditorNode3DGizmoPlugin { + GDCLASS(ReflectionProbeGizmoPlugin, EditorNode3DGizmoPlugin); + +public: + bool has_gizmo(Node3D *p_spatial) override; + String get_gizmo_name() const override; + int get_priority() const override; + void redraw(EditorNode3DGizmo *p_gizmo) override; + + String get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const override; + Variant get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const override; + void set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, Camera3D *p_camera, const Point2 &p_point) override; + void commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, const Variant &p_restore, bool p_cancel = false) override; + + ReflectionProbeGizmoPlugin(); +}; + +#endif // REFLECTION_PROBE_GIZMO_PLUGIN_H diff --git a/editor/plugins/gizmos/shape_cast_3d_gizmo_plugin.cpp b/editor/plugins/gizmos/shape_cast_3d_gizmo_plugin.cpp new file mode 100644 index 00000000000..23a224fc014 --- /dev/null +++ b/editor/plugins/gizmos/shape_cast_3d_gizmo_plugin.cpp @@ -0,0 +1,71 @@ +/**************************************************************************/ +/* shape_cast_3d_gizmo_plugin.cpp */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* 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 "shape_cast_3d_gizmo_plugin.h" + +#include "editor/editor_settings.h" +#include "editor/plugins/node_3d_editor_plugin.h" +#include "scene/3d/shape_cast_3d.h" + +ShapeCast3DGizmoPlugin::ShapeCast3DGizmoPlugin() { + const Color gizmo_color = EDITOR_GET("editors/3d_gizmos/gizmo_colors/shape"); + create_material("shape_material", gizmo_color); + const float gizmo_value = gizmo_color.get_v(); + const Color gizmo_color_disabled = Color(gizmo_value, gizmo_value, gizmo_value, 0.65); + create_material("shape_material_disabled", gizmo_color_disabled); +} + +bool ShapeCast3DGizmoPlugin::has_gizmo(Node3D *p_spatial) { + return Object::cast_to(p_spatial) != nullptr; +} + +String ShapeCast3DGizmoPlugin::get_gizmo_name() const { + return "ShapeCast3D"; +} + +int ShapeCast3DGizmoPlugin::get_priority() const { + return -1; +} + +void ShapeCast3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) { + ShapeCast3D *shapecast = Object::cast_to(p_gizmo->get_node_3d()); + + p_gizmo->clear(); + + const Ref material = shapecast->is_enabled() ? shapecast->get_debug_material() : get_material("shape_material_disabled"); + + p_gizmo->add_lines(shapecast->get_debug_line_vertices(), material); + + if (shapecast->get_shape().is_valid()) { + p_gizmo->add_lines(shapecast->get_debug_shape_vertices(), material); + } + + p_gizmo->add_collision_segments(shapecast->get_debug_line_vertices()); +} diff --git a/editor/plugins/gizmos/shape_cast_3d_gizmo_plugin.h b/editor/plugins/gizmos/shape_cast_3d_gizmo_plugin.h new file mode 100644 index 00000000000..9e4a802bc66 --- /dev/null +++ b/editor/plugins/gizmos/shape_cast_3d_gizmo_plugin.h @@ -0,0 +1,48 @@ +/**************************************************************************/ +/* shape_cast_3d_gizmo_plugin.h */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* 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. */ +/**************************************************************************/ + +#ifndef SHAPE_CAST_3D_GIZMO_PLUGIN_H +#define SHAPE_CAST_3D_GIZMO_PLUGIN_H + +#include "editor/plugins/node_3d_editor_gizmos.h" + +class ShapeCast3DGizmoPlugin : public EditorNode3DGizmoPlugin { + GDCLASS(ShapeCast3DGizmoPlugin, EditorNode3DGizmoPlugin); + +public: + bool has_gizmo(Node3D *p_spatial) override; + String get_gizmo_name() const override; + int get_priority() const override; + void redraw(EditorNode3DGizmo *p_gizmo) override; + + ShapeCast3DGizmoPlugin(); +}; + +#endif // SHAPE_CAST_3D_GIZMO_PLUGIN_H diff --git a/editor/plugins/gizmos/soft_body_3d_gizmo_plugin.cpp b/editor/plugins/gizmos/soft_body_3d_gizmo_plugin.cpp new file mode 100644 index 00000000000..be48e3764a4 --- /dev/null +++ b/editor/plugins/gizmos/soft_body_3d_gizmo_plugin.cpp @@ -0,0 +1,113 @@ +/**************************************************************************/ +/* soft_body_3d_gizmo_plugin.cpp */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* 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 "soft_body_3d_gizmo_plugin.h" + +#include "editor/editor_settings.h" +#include "editor/plugins/node_3d_editor_plugin.h" +#include "scene/3d/soft_body_3d.h" + +SoftBody3DGizmoPlugin::SoftBody3DGizmoPlugin() { + Color gizmo_color = EDITOR_GET("editors/3d_gizmos/gizmo_colors/shape"); + create_material("shape_material", gizmo_color); + create_handle_material("handles"); +} + +bool SoftBody3DGizmoPlugin::has_gizmo(Node3D *p_spatial) { + return Object::cast_to(p_spatial) != nullptr; +} + +String SoftBody3DGizmoPlugin::get_gizmo_name() const { + return "SoftBody3D"; +} + +int SoftBody3DGizmoPlugin::get_priority() const { + return -1; +} + +bool SoftBody3DGizmoPlugin::is_selectable_when_hidden() const { + return true; +} + +void SoftBody3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) { + SoftBody3D *soft_body = Object::cast_to(p_gizmo->get_node_3d()); + + p_gizmo->clear(); + + if (!soft_body || soft_body->get_mesh().is_null()) { + return; + } + + // find mesh + + Vector lines; + + soft_body->get_mesh()->generate_debug_mesh_lines(lines); + + if (!lines.size()) { + return; + } + + Ref tm = soft_body->get_mesh()->generate_triangle_mesh(); + + Vector points; + for (int i = 0; i < soft_body->get_mesh()->get_surface_count(); i++) { + Array arrays = soft_body->get_mesh()->surface_get_arrays(i); + ERR_CONTINUE(arrays.is_empty()); + + const Vector &vertices = arrays[Mesh::ARRAY_VERTEX]; + points.append_array(vertices); + } + + Ref material = get_material("shape_material", p_gizmo); + + p_gizmo->add_lines(lines, material); + p_gizmo->add_handles(points, get_material("handles")); + p_gizmo->add_collision_triangles(tm); +} + +String SoftBody3DGizmoPlugin::get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const { + return "SoftBody3D pin point"; +} + +Variant SoftBody3DGizmoPlugin::get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const { + SoftBody3D *soft_body = Object::cast_to(p_gizmo->get_node_3d()); + return Variant(soft_body->is_point_pinned(p_id)); +} + +void SoftBody3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, const Variant &p_restore, bool p_cancel) { + SoftBody3D *soft_body = Object::cast_to(p_gizmo->get_node_3d()); + soft_body->pin_point_toggle(p_id); +} + +bool SoftBody3DGizmoPlugin::is_handle_highlighted(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const { + SoftBody3D *soft_body = Object::cast_to(p_gizmo->get_node_3d()); + return soft_body->is_point_pinned(p_id); +} diff --git a/editor/plugins/gizmos/soft_body_3d_gizmo_plugin.h b/editor/plugins/gizmos/soft_body_3d_gizmo_plugin.h new file mode 100644 index 00000000000..f56e15287e7 --- /dev/null +++ b/editor/plugins/gizmos/soft_body_3d_gizmo_plugin.h @@ -0,0 +1,54 @@ +/**************************************************************************/ +/* soft_body_3d_gizmo_plugin.h */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* 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. */ +/**************************************************************************/ + +#ifndef SOFT_BODY_3D_GIZMO_PLUGIN_H +#define SOFT_BODY_3D_GIZMO_PLUGIN_H + +#include "editor/plugins/node_3d_editor_gizmos.h" + +class SoftBody3DGizmoPlugin : public EditorNode3DGizmoPlugin { + GDCLASS(SoftBody3DGizmoPlugin, EditorNode3DGizmoPlugin); + +public: + bool has_gizmo(Node3D *p_spatial) override; + String get_gizmo_name() const override; + int get_priority() const override; + bool is_selectable_when_hidden() const override; + void redraw(EditorNode3DGizmo *p_gizmo) override; + + String get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const override; + Variant get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const override; + void commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, const Variant &p_restore, bool p_cancel = false) override; + bool is_handle_highlighted(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const override; + + SoftBody3DGizmoPlugin(); +}; + +#endif // SOFT_BODY_3D_GIZMO_PLUGIN_H diff --git a/editor/plugins/gizmos/spring_arm_3d_gizmo_plugin.cpp b/editor/plugins/gizmos/spring_arm_3d_gizmo_plugin.cpp new file mode 100644 index 00000000000..cf022fc30f5 --- /dev/null +++ b/editor/plugins/gizmos/spring_arm_3d_gizmo_plugin.cpp @@ -0,0 +1,69 @@ +/**************************************************************************/ +/* spring_arm_3d_gizmo_plugin.cpp */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* 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 "spring_arm_3d_gizmo_plugin.h" + +#include "editor/editor_settings.h" +#include "editor/plugins/node_3d_editor_plugin.h" +#include "scene/3d/spring_arm_3d.h" +#include "scene/resources/shape_3d.h" + +void SpringArm3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) { + SpringArm3D *spring_arm = Object::cast_to(p_gizmo->get_node_3d()); + + p_gizmo->clear(); + + Vector lines = { + Vector3(), + Vector3(0, 0, 1.0) * spring_arm->get_length() + }; + + Ref material = get_material("shape_material", p_gizmo); + + p_gizmo->add_lines(lines, material); + p_gizmo->add_collision_segments(lines); +} + +SpringArm3DGizmoPlugin::SpringArm3DGizmoPlugin() { + Color gizmo_color = EDITOR_GET("editors/3d_gizmos/gizmo_colors/shape"); + create_material("shape_material", gizmo_color); +} + +bool SpringArm3DGizmoPlugin::has_gizmo(Node3D *p_spatial) { + return Object::cast_to(p_spatial) != nullptr; +} + +String SpringArm3DGizmoPlugin::get_gizmo_name() const { + return "SpringArm3D"; +} + +int SpringArm3DGizmoPlugin::get_priority() const { + return -1; +} diff --git a/editor/plugins/gizmos/spring_arm_3d_gizmo_plugin.h b/editor/plugins/gizmos/spring_arm_3d_gizmo_plugin.h new file mode 100644 index 00000000000..cbb7c163706 --- /dev/null +++ b/editor/plugins/gizmos/spring_arm_3d_gizmo_plugin.h @@ -0,0 +1,48 @@ +/**************************************************************************/ +/* spring_arm_3d_gizmo_plugin.h */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* 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. */ +/**************************************************************************/ + +#ifndef SPRING_ARM_3D_GIZMO_PLUGIN_H +#define SPRING_ARM_3D_GIZMO_PLUGIN_H + +#include "editor/plugins/node_3d_editor_gizmos.h" + +class SpringArm3DGizmoPlugin : public EditorNode3DGizmoPlugin { + GDCLASS(SpringArm3DGizmoPlugin, EditorNode3DGizmoPlugin); + +public: + bool has_gizmo(Node3D *p_spatial) override; + String get_gizmo_name() const override; + int get_priority() const override; + void redraw(EditorNode3DGizmo *p_gizmo) override; + + SpringArm3DGizmoPlugin(); +}; + +#endif // SPRING_ARM_3D_GIZMO_PLUGIN_H diff --git a/editor/plugins/gizmos/sprite_3d_gizmo_plugin.cpp b/editor/plugins/gizmos/sprite_3d_gizmo_plugin.cpp new file mode 100644 index 00000000000..2dde65c249f --- /dev/null +++ b/editor/plugins/gizmos/sprite_3d_gizmo_plugin.cpp @@ -0,0 +1,64 @@ +/**************************************************************************/ +/* sprite_3d_gizmo_plugin.cpp */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* 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 "sprite_3d_gizmo_plugin.h" + +#include "editor/plugins/node_3d_editor_plugin.h" +#include "scene/3d/sprite_3d.h" + +Sprite3DGizmoPlugin::Sprite3DGizmoPlugin() { +} + +bool Sprite3DGizmoPlugin::has_gizmo(Node3D *p_spatial) { + return Object::cast_to(p_spatial) != nullptr; +} + +String Sprite3DGizmoPlugin::get_gizmo_name() const { + return "Sprite3D"; +} + +int Sprite3DGizmoPlugin::get_priority() const { + return -1; +} + +bool Sprite3DGizmoPlugin::can_be_hidden() const { + return false; +} + +void Sprite3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) { + Sprite3D *sprite = Object::cast_to(p_gizmo->get_node_3d()); + + p_gizmo->clear(); + + Ref tm = sprite->generate_triangle_mesh(); + if (tm.is_valid()) { + p_gizmo->add_collision_triangles(tm); + } +} diff --git a/editor/plugins/gizmos/sprite_3d_gizmo_plugin.h b/editor/plugins/gizmos/sprite_3d_gizmo_plugin.h new file mode 100644 index 00000000000..47ce5a448e3 --- /dev/null +++ b/editor/plugins/gizmos/sprite_3d_gizmo_plugin.h @@ -0,0 +1,49 @@ +/**************************************************************************/ +/* sprite_3d_gizmo_plugin.h */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* 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. */ +/**************************************************************************/ + +#ifndef SPRITE_3D_GIZMO_PLUGIN_H +#define SPRITE_3D_GIZMO_PLUGIN_H + +#include "editor/plugins/node_3d_editor_gizmos.h" + +class Sprite3DGizmoPlugin : public EditorNode3DGizmoPlugin { + GDCLASS(Sprite3DGizmoPlugin, EditorNode3DGizmoPlugin); + +public: + bool has_gizmo(Node3D *p_spatial) override; + String get_gizmo_name() const override; + int get_priority() const override; + bool can_be_hidden() const override; + void redraw(EditorNode3DGizmo *p_gizmo) override; + + Sprite3DGizmoPlugin(); +}; + +#endif // SPRITE_3D_GIZMO_PLUGIN_H diff --git a/editor/plugins/gizmos/vehicle_body_3d_gizmo_plugin.cpp b/editor/plugins/gizmos/vehicle_body_3d_gizmo_plugin.cpp new file mode 100644 index 00000000000..ef6cd88868f --- /dev/null +++ b/editor/plugins/gizmos/vehicle_body_3d_gizmo_plugin.cpp @@ -0,0 +1,104 @@ +/**************************************************************************/ +/* vehicle_body_3d_gizmo_plugin.cpp */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* 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 "vehicle_body_3d_gizmo_plugin.h" + +#include "editor/editor_settings.h" +#include "editor/plugins/node_3d_editor_plugin.h" +#include "scene/3d/vehicle_body_3d.h" + +VehicleWheel3DGizmoPlugin::VehicleWheel3DGizmoPlugin() { + Color gizmo_color = EDITOR_GET("editors/3d_gizmos/gizmo_colors/shape"); + create_material("shape_material", gizmo_color); +} + +bool VehicleWheel3DGizmoPlugin::has_gizmo(Node3D *p_spatial) { + return Object::cast_to(p_spatial) != nullptr; +} + +String VehicleWheel3DGizmoPlugin::get_gizmo_name() const { + return "VehicleWheel3D"; +} + +int VehicleWheel3DGizmoPlugin::get_priority() const { + return -1; +} + +void VehicleWheel3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) { + VehicleWheel3D *car_wheel = Object::cast_to(p_gizmo->get_node_3d()); + + p_gizmo->clear(); + + Vector points; + + float r = car_wheel->get_radius(); + const int skip = 10; + for (int i = 0; i <= 360; i += skip) { + float ra = Math::deg_to_rad((float)i); + float rb = Math::deg_to_rad((float)i + skip); + Point2 a = Vector2(Math::sin(ra), Math::cos(ra)) * r; + Point2 b = Vector2(Math::sin(rb), Math::cos(rb)) * r; + + points.push_back(Vector3(0, a.x, a.y)); + points.push_back(Vector3(0, b.x, b.y)); + + const int springsec = 4; + + for (int j = 0; j < springsec; j++) { + float t = car_wheel->get_suspension_rest_length() * 5; + points.push_back(Vector3(a.x, i / 360.0 * t / springsec + j * (t / springsec), a.y) * 0.2); + points.push_back(Vector3(b.x, (i + skip) / 360.0 * t / springsec + j * (t / springsec), b.y) * 0.2); + } + } + + //travel + points.push_back(Vector3(0, 0, 0)); + points.push_back(Vector3(0, car_wheel->get_suspension_rest_length(), 0)); + + //axis + points.push_back(Vector3(r * 0.2, car_wheel->get_suspension_rest_length(), 0)); + points.push_back(Vector3(-r * 0.2, car_wheel->get_suspension_rest_length(), 0)); + //axis + points.push_back(Vector3(r * 0.2, 0, 0)); + points.push_back(Vector3(-r * 0.2, 0, 0)); + + //forward line + points.push_back(Vector3(0, -r, 0)); + points.push_back(Vector3(0, -r, r * 2)); + points.push_back(Vector3(0, -r, r * 2)); + points.push_back(Vector3(r * 2 * 0.2, -r, r * 2 * 0.8)); + points.push_back(Vector3(0, -r, r * 2)); + points.push_back(Vector3(-r * 2 * 0.2, -r, r * 2 * 0.8)); + + Ref material = get_material("shape_material", p_gizmo); + + p_gizmo->add_lines(points, material); + p_gizmo->add_collision_segments(points); +} diff --git a/editor/plugins/gizmos/vehicle_body_3d_gizmo_plugin.h b/editor/plugins/gizmos/vehicle_body_3d_gizmo_plugin.h new file mode 100644 index 00000000000..8c5f8bd415b --- /dev/null +++ b/editor/plugins/gizmos/vehicle_body_3d_gizmo_plugin.h @@ -0,0 +1,48 @@ +/**************************************************************************/ +/* vehicle_body_3d_gizmo_plugin.h */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* 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. */ +/**************************************************************************/ + +#ifndef VEHICLE_BODY_3D_GIZMO_PLUGIN_H +#define VEHICLE_BODY_3D_GIZMO_PLUGIN_H + +#include "editor/plugins/node_3d_editor_gizmos.h" + +class VehicleWheel3DGizmoPlugin : public EditorNode3DGizmoPlugin { + GDCLASS(VehicleWheel3DGizmoPlugin, EditorNode3DGizmoPlugin); + +public: + bool has_gizmo(Node3D *p_spatial) override; + String get_gizmo_name() const override; + int get_priority() const override; + void redraw(EditorNode3DGizmo *p_gizmo) override; + + VehicleWheel3DGizmoPlugin(); +}; + +#endif // VEHICLE_BODY_3D_GIZMO_PLUGIN_H diff --git a/editor/plugins/gizmos/visible_on_screen_notifier_3d_gizmo_plugin.cpp b/editor/plugins/gizmos/visible_on_screen_notifier_3d_gizmo_plugin.cpp new file mode 100644 index 00000000000..315f8aed53a --- /dev/null +++ b/editor/plugins/gizmos/visible_on_screen_notifier_3d_gizmo_plugin.cpp @@ -0,0 +1,194 @@ +/**************************************************************************/ +/* visible_on_screen_notifier_3d_gizmo_plugin.cpp */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* 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 "visible_on_screen_notifier_3d_gizmo_plugin.h" + +#include "editor/editor_settings.h" +#include "editor/editor_undo_redo_manager.h" +#include "editor/plugins/node_3d_editor_plugin.h" +#include "scene/3d/visible_on_screen_notifier_3d.h" + +VisibleOnScreenNotifier3DGizmoPlugin::VisibleOnScreenNotifier3DGizmoPlugin() { + Color gizmo_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/visibility_notifier", Color(0.8, 0.5, 0.7)); + create_material("visibility_notifier_material", gizmo_color); + gizmo_color.a = 0.1; + create_material("visibility_notifier_solid_material", gizmo_color); + create_handle_material("handles"); +} + +bool VisibleOnScreenNotifier3DGizmoPlugin::has_gizmo(Node3D *p_spatial) { + return Object::cast_to(p_spatial) != nullptr; +} + +String VisibleOnScreenNotifier3DGizmoPlugin::get_gizmo_name() const { + return "VisibleOnScreenNotifier3D"; +} + +int VisibleOnScreenNotifier3DGizmoPlugin::get_priority() const { + return -1; +} + +String VisibleOnScreenNotifier3DGizmoPlugin::get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const { + switch (p_id) { + case 0: + return "Size X"; + case 1: + return "Size Y"; + case 2: + return "Size Z"; + case 3: + return "Pos X"; + case 4: + return "Pos Y"; + case 5: + return "Pos Z"; + } + + return ""; +} + +Variant VisibleOnScreenNotifier3DGizmoPlugin::get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const { + VisibleOnScreenNotifier3D *notifier = Object::cast_to(p_gizmo->get_node_3d()); + return notifier->get_aabb(); +} + +void VisibleOnScreenNotifier3DGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, Camera3D *p_camera, const Point2 &p_point) { + VisibleOnScreenNotifier3D *notifier = Object::cast_to(p_gizmo->get_node_3d()); + + Transform3D gt = notifier->get_global_transform(); + + Transform3D gi = gt.affine_inverse(); + + bool move = p_id >= 3; + p_id = p_id % 3; + + AABB aabb = notifier->get_aabb(); + Vector3 ray_from = p_camera->project_ray_origin(p_point); + Vector3 ray_dir = p_camera->project_ray_normal(p_point); + + Vector3 sg[2] = { gi.xform(ray_from), gi.xform(ray_from + ray_dir * 4096) }; + + Vector3 ofs = aabb.get_center(); + + Vector3 axis; + axis[p_id] = 1.0; + + if (move) { + Vector3 ra, rb; + Geometry3D::get_closest_points_between_segments(ofs - axis * 4096, ofs + axis * 4096, sg[0], sg[1], ra, rb); + + float d = ra[p_id]; + if (Node3DEditor::get_singleton()->is_snap_enabled()) { + d = Math::snapped(d, Node3DEditor::get_singleton()->get_translate_snap()); + } + + aabb.position[p_id] = d - 1.0 - aabb.size[p_id] * 0.5; + notifier->set_aabb(aabb); + + } else { + Vector3 ra, rb; + Geometry3D::get_closest_points_between_segments(ofs, ofs + axis * 4096, sg[0], sg[1], ra, rb); + + float d = ra[p_id] - ofs[p_id]; + if (Node3DEditor::get_singleton()->is_snap_enabled()) { + d = Math::snapped(d, Node3DEditor::get_singleton()->get_translate_snap()); + } + + if (d < 0.001) { + d = 0.001; + } + //resize + aabb.position[p_id] = (aabb.position[p_id] + aabb.size[p_id] * 0.5) - d; + aabb.size[p_id] = d * 2; + notifier->set_aabb(aabb); + } +} + +void VisibleOnScreenNotifier3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, const Variant &p_restore, bool p_cancel) { + VisibleOnScreenNotifier3D *notifier = Object::cast_to(p_gizmo->get_node_3d()); + + if (p_cancel) { + notifier->set_aabb(p_restore); + return; + } + + EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton(); + ur->create_action(TTR("Change Notifier AABB")); + ur->add_do_method(notifier, "set_aabb", notifier->get_aabb()); + ur->add_undo_method(notifier, "set_aabb", p_restore); + ur->commit_action(); +} + +void VisibleOnScreenNotifier3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) { + VisibleOnScreenNotifier3D *notifier = Object::cast_to(p_gizmo->get_node_3d()); + + p_gizmo->clear(); + + Vector lines; + AABB aabb = notifier->get_aabb(); + + for (int i = 0; i < 12; i++) { + Vector3 a, b; + aabb.get_edge(i, a, b); + lines.push_back(a); + lines.push_back(b); + } + + Vector handles; + + for (int i = 0; i < 3; i++) { + Vector3 ax; + ax[i] = aabb.position[i] + aabb.size[i]; + ax[(i + 1) % 3] = aabb.position[(i + 1) % 3] + aabb.size[(i + 1) % 3] * 0.5; + ax[(i + 2) % 3] = aabb.position[(i + 2) % 3] + aabb.size[(i + 2) % 3] * 0.5; + handles.push_back(ax); + } + + Vector3 center = aabb.get_center(); + for (int i = 0; i < 3; i++) { + Vector3 ax; + ax[i] = 1.0; + handles.push_back(center + ax); + lines.push_back(center); + lines.push_back(center + ax); + } + + Ref material = get_material("visibility_notifier_material", p_gizmo); + + p_gizmo->add_lines(lines, material); + p_gizmo->add_collision_segments(lines); + + if (p_gizmo->is_selected()) { + Ref solid_material = get_material("visibility_notifier_solid_material", p_gizmo); + p_gizmo->add_solid_box(solid_material, aabb.get_size(), aabb.get_center()); + } + + p_gizmo->add_handles(handles, get_material("handles")); +} diff --git a/editor/plugins/gizmos/visible_on_screen_notifier_3d_gizmo_plugin.h b/editor/plugins/gizmos/visible_on_screen_notifier_3d_gizmo_plugin.h new file mode 100644 index 00000000000..bf3d9909c85 --- /dev/null +++ b/editor/plugins/gizmos/visible_on_screen_notifier_3d_gizmo_plugin.h @@ -0,0 +1,53 @@ +/**************************************************************************/ +/* visible_on_screen_notifier_3d_gizmo_plugin.h */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* 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. */ +/**************************************************************************/ + +#ifndef VISIBLE_ON_SCREEN_NOTIFIER_3D_GIZMO_PLUGIN_H +#define VISIBLE_ON_SCREEN_NOTIFIER_3D_GIZMO_PLUGIN_H + +#include "editor/plugins/node_3d_editor_gizmos.h" + +class VisibleOnScreenNotifier3DGizmoPlugin : public EditorNode3DGizmoPlugin { + GDCLASS(VisibleOnScreenNotifier3DGizmoPlugin, EditorNode3DGizmoPlugin); + +public: + bool has_gizmo(Node3D *p_spatial) override; + String get_gizmo_name() const override; + int get_priority() const override; + void redraw(EditorNode3DGizmo *p_gizmo) override; + + String get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const override; + Variant get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const override; + void set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, Camera3D *p_camera, const Point2 &p_point) override; + void commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, const Variant &p_restore, bool p_cancel = false) override; + + VisibleOnScreenNotifier3DGizmoPlugin(); +}; + +#endif // VISIBLE_ON_SCREEN_NOTIFIER_3D_GIZMO_PLUGIN_H diff --git a/editor/plugins/gizmos/voxel_gi_gizmo_plugin.cpp b/editor/plugins/gizmos/voxel_gi_gizmo_plugin.cpp new file mode 100644 index 00000000000..dfcee00eecb --- /dev/null +++ b/editor/plugins/gizmos/voxel_gi_gizmo_plugin.cpp @@ -0,0 +1,209 @@ +/**************************************************************************/ +/* voxel_gi_gizmo_plugin.cpp */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* 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 "voxel_gi_gizmo_plugin.h" + +#include "editor/editor_settings.h" +#include "editor/editor_undo_redo_manager.h" +#include "editor/plugins/node_3d_editor_plugin.h" +#include "scene/3d/voxel_gi.h" + +VoxelGIGizmoPlugin::VoxelGIGizmoPlugin() { + Color gizmo_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/voxel_gi", Color(0.5, 1, 0.6)); + + create_material("voxel_gi_material", gizmo_color); + + // This gizmo draws a lot of lines. Use a low opacity to make it not too intrusive. + gizmo_color.a = 0.1; + create_material("voxel_gi_internal_material", gizmo_color); + + gizmo_color.a = 0.05; + create_material("voxel_gi_solid_material", gizmo_color); + + create_icon_material("voxel_gi_icon", Node3DEditor::get_singleton()->get_theme_icon(SNAME("GizmoVoxelGI"), SNAME("EditorIcons"))); + create_handle_material("handles"); +} + +bool VoxelGIGizmoPlugin::has_gizmo(Node3D *p_spatial) { + return Object::cast_to(p_spatial) != nullptr; +} + +String VoxelGIGizmoPlugin::get_gizmo_name() const { + return "VoxelGI"; +} + +int VoxelGIGizmoPlugin::get_priority() const { + return -1; +} + +String VoxelGIGizmoPlugin::get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const { + switch (p_id) { + case 0: + return "Size X"; + case 1: + return "Size Y"; + case 2: + return "Size Z"; + } + + return ""; +} + +Variant VoxelGIGizmoPlugin::get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const { + VoxelGI *probe = Object::cast_to(p_gizmo->get_node_3d()); + return probe->get_size(); +} + +void VoxelGIGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, Camera3D *p_camera, const Point2 &p_point) { + VoxelGI *probe = Object::cast_to(p_gizmo->get_node_3d()); + + Transform3D gt = probe->get_global_transform(); + Transform3D gi = gt.affine_inverse(); + + Vector3 size = probe->get_size(); + + Vector3 ray_from = p_camera->project_ray_origin(p_point); + Vector3 ray_dir = p_camera->project_ray_normal(p_point); + + Vector3 sg[2] = { gi.xform(ray_from), gi.xform(ray_from + ray_dir * 16384) }; + + Vector3 axis; + axis[p_id] = 1.0; + + Vector3 ra, rb; + Geometry3D::get_closest_points_between_segments(Vector3(), axis * 16384, sg[0], sg[1], ra, rb); + float d = ra[p_id] * 2; + if (Node3DEditor::get_singleton()->is_snap_enabled()) { + d = Math::snapped(d, Node3DEditor::get_singleton()->get_translate_snap()); + } + + if (d < 0.001) { + d = 0.001; + } + + size[p_id] = d; + probe->set_size(size); +} + +void VoxelGIGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, const Variant &p_restore, bool p_cancel) { + VoxelGI *probe = Object::cast_to(p_gizmo->get_node_3d()); + + Vector3 restore = p_restore; + + if (p_cancel) { + probe->set_size(restore); + return; + } + + EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton(); + ur->create_action(TTR("Change Probe Size")); + ur->add_do_method(probe, "set_size", probe->get_size()); + ur->add_undo_method(probe, "set_size", restore); + ur->commit_action(); +} + +void VoxelGIGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) { + VoxelGI *probe = Object::cast_to(p_gizmo->get_node_3d()); + + Ref material = get_material("voxel_gi_material", p_gizmo); + Ref icon = get_material("voxel_gi_icon", p_gizmo); + Ref material_internal = get_material("voxel_gi_internal_material", p_gizmo); + + p_gizmo->clear(); + + Vector lines; + Vector3 size = probe->get_size(); + + static const int subdivs[VoxelGI::SUBDIV_MAX] = { 64, 128, 256, 512 }; + + AABB aabb = AABB(-size / 2, size); + int subdiv = subdivs[probe->get_subdiv()]; + float cell_size = aabb.get_longest_axis_size() / subdiv; + + for (int i = 0; i < 12; i++) { + Vector3 a, b; + aabb.get_edge(i, a, b); + lines.push_back(a); + lines.push_back(b); + } + + p_gizmo->add_lines(lines, material); + + lines.clear(); + + for (int i = 1; i < subdiv; i++) { + for (int j = 0; j < 3; j++) { + if (cell_size * i > aabb.size[j]) { + continue; + } + + int j_n1 = (j + 1) % 3; + int j_n2 = (j + 2) % 3; + + for (int k = 0; k < 4; k++) { + Vector3 from = aabb.position, to = aabb.position; + from[j] += cell_size * i; + to[j] += cell_size * i; + + if (k & 1) { + to[j_n1] += aabb.size[j_n1]; + } else { + to[j_n2] += aabb.size[j_n2]; + } + + if (k & 2) { + from[j_n1] += aabb.size[j_n1]; + from[j_n2] += aabb.size[j_n2]; + } + + lines.push_back(from); + lines.push_back(to); + } + } + } + + p_gizmo->add_lines(lines, material_internal); + + Vector handles; + + for (int i = 0; i < 3; i++) { + Vector3 ax; + ax[i] = aabb.position[i] + aabb.size[i]; + handles.push_back(ax); + } + + if (p_gizmo->is_selected()) { + Ref solid_material = get_material("voxel_gi_solid_material", p_gizmo); + p_gizmo->add_solid_box(solid_material, aabb.get_size()); + } + + p_gizmo->add_unscaled_billboard(icon, 0.05); + p_gizmo->add_handles(handles, get_material("handles")); +} diff --git a/editor/plugins/gizmos/voxel_gi_gizmo_plugin.h b/editor/plugins/gizmos/voxel_gi_gizmo_plugin.h new file mode 100644 index 00000000000..4d1f282bd60 --- /dev/null +++ b/editor/plugins/gizmos/voxel_gi_gizmo_plugin.h @@ -0,0 +1,53 @@ +/**************************************************************************/ +/* voxel_gi_gizmo_plugin.h */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* 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. */ +/**************************************************************************/ + +#ifndef VOXEL_GI_GIZMO_PLUGIN_H +#define VOXEL_GI_GIZMO_PLUGIN_H + +#include "editor/plugins/node_3d_editor_gizmos.h" + +class VoxelGIGizmoPlugin : public EditorNode3DGizmoPlugin { + GDCLASS(VoxelGIGizmoPlugin, EditorNode3DGizmoPlugin); + +public: + bool has_gizmo(Node3D *p_spatial) override; + String get_gizmo_name() const override; + int get_priority() const override; + void redraw(EditorNode3DGizmo *p_gizmo) override; + + String get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const override; + Variant get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const override; + void set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, Camera3D *p_camera, const Point2 &p_point) override; + void commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, const Variant &p_restore, bool p_cancel = false) override; + + VoxelGIGizmoPlugin(); +}; + +#endif // VOXEL_GI_GIZMO_PLUGIN_H diff --git a/editor/plugins/node_3d_editor_gizmos.cpp b/editor/plugins/node_3d_editor_gizmos.cpp index bcb94b0f32f..0da6fd3c413 100644 --- a/editor/plugins/node_3d_editor_gizmos.cpp +++ b/editor/plugins/node_3d_editor_gizmos.cpp @@ -30,55 +30,12 @@ #include "node_3d_editor_gizmos.h" -#include "core/config/project_settings.h" -#include "core/math/convex_hull.h" #include "core/math/geometry_2d.h" #include "core/math/geometry_3d.h" #include "editor/editor_node.h" #include "editor/editor_settings.h" -#include "editor/editor_undo_redo_manager.h" #include "editor/plugins/node_3d_editor_plugin.h" -#include "scene/3d/audio_listener_3d.h" -#include "scene/3d/audio_stream_player_3d.h" -#include "scene/3d/camera_3d.h" -#include "scene/3d/collision_polygon_3d.h" -#include "scene/3d/collision_shape_3d.h" -#include "scene/3d/cpu_particles_3d.h" -#include "scene/3d/decal.h" -#include "scene/3d/fog_volume.h" -#include "scene/3d/gpu_particles_3d.h" -#include "scene/3d/gpu_particles_collision_3d.h" -#include "scene/3d/joint_3d.h" -#include "scene/3d/label_3d.h" -#include "scene/3d/light_3d.h" -#include "scene/3d/lightmap_gi.h" -#include "scene/3d/lightmap_probe.h" -#include "scene/3d/marker_3d.h" -#include "scene/3d/mesh_instance_3d.h" -#include "scene/3d/navigation_link_3d.h" -#include "scene/3d/navigation_region_3d.h" -#include "scene/3d/occluder_instance_3d.h" -#include "scene/3d/ray_cast_3d.h" -#include "scene/3d/reflection_probe.h" -#include "scene/3d/shape_cast_3d.h" -#include "scene/3d/soft_body_3d.h" -#include "scene/3d/spring_arm_3d.h" -#include "scene/3d/sprite_3d.h" -#include "scene/3d/vehicle_body_3d.h" -#include "scene/3d/visible_on_screen_notifier_3d.h" -#include "scene/3d/voxel_gi.h" -#include "scene/resources/box_shape_3d.h" -#include "scene/resources/capsule_shape_3d.h" -#include "scene/resources/concave_polygon_shape_3d.h" -#include "scene/resources/convex_polygon_shape_3d.h" -#include "scene/resources/cylinder_shape_3d.h" -#include "scene/resources/height_map_shape_3d.h" #include "scene/resources/primitive_meshes.h" -#include "scene/resources/separation_ray_shape_3d.h" -#include "scene/resources/sphere_shape_3d.h" -#include "scene/resources/surface_tool.h" -#include "scene/resources/world_boundary_shape_3d.h" -#include "servers/navigation_server_3d.h" #define HANDLE_HALF_SIZE 9.5 @@ -1212,4799 +1169,4 @@ EditorNode3DGizmoPlugin::~EditorNode3DGizmoPlugin() { } } -//// light gizmo - -Light3DGizmoPlugin::Light3DGizmoPlugin() { - // Enable vertex colors for the materials below as the gizmo color depends on the light color. - create_material("lines_primary", Color(1, 1, 1), false, false, true); - create_material("lines_secondary", Color(1, 1, 1, 0.35), false, false, true); - create_material("lines_billboard", Color(1, 1, 1), true, false, true); - - create_icon_material("light_directional_icon", Node3DEditor::get_singleton()->get_theme_icon(SNAME("GizmoDirectionalLight"), SNAME("EditorIcons"))); - create_icon_material("light_omni_icon", Node3DEditor::get_singleton()->get_theme_icon(SNAME("GizmoLight"), SNAME("EditorIcons"))); - create_icon_material("light_spot_icon", Node3DEditor::get_singleton()->get_theme_icon(SNAME("GizmoSpotLight"), SNAME("EditorIcons"))); - - create_handle_material("handles"); - create_handle_material("handles_billboard", true); -} - -bool Light3DGizmoPlugin::has_gizmo(Node3D *p_spatial) { - return Object::cast_to(p_spatial) != nullptr; -} - -String Light3DGizmoPlugin::get_gizmo_name() const { - return "Light3D"; -} - -int Light3DGizmoPlugin::get_priority() const { - return -1; -} - -String Light3DGizmoPlugin::get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const { - if (p_id == 0) { - return "Radius"; - } else { - return "Aperture"; - } -} - -Variant Light3DGizmoPlugin::get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const { - Light3D *light = Object::cast_to(p_gizmo->get_node_3d()); - if (p_id == 0) { - return light->get_param(Light3D::PARAM_RANGE); - } - if (p_id == 1) { - return light->get_param(Light3D::PARAM_SPOT_ANGLE); - } - - return Variant(); -} - -static float _find_closest_angle_to_half_pi_arc(const Vector3 &p_from, const Vector3 &p_to, float p_arc_radius, const Transform3D &p_arc_xform) { - //bleh, discrete is simpler - static const int arc_test_points = 64; - float min_d = 1e20; - Vector3 min_p; - - for (int i = 0; i < arc_test_points; i++) { - float a = i * Math_PI * 0.5 / arc_test_points; - float an = (i + 1) * Math_PI * 0.5 / arc_test_points; - Vector3 p = Vector3(Math::cos(a), 0, -Math::sin(a)) * p_arc_radius; - Vector3 n = Vector3(Math::cos(an), 0, -Math::sin(an)) * p_arc_radius; - - Vector3 ra, rb; - Geometry3D::get_closest_points_between_segments(p, n, p_from, p_to, ra, rb); - - float d = ra.distance_to(rb); - if (d < min_d) { - min_d = d; - min_p = ra; - } - } - - //min_p = p_arc_xform.affine_inverse().xform(min_p); - float a = (Math_PI * 0.5) - Vector2(min_p.x, -min_p.z).angle(); - return Math::rad_to_deg(a); -} - -void Light3DGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, Camera3D *p_camera, const Point2 &p_point) { - Light3D *light = Object::cast_to(p_gizmo->get_node_3d()); - Transform3D gt = light->get_global_transform(); - Transform3D gi = gt.affine_inverse(); - - Vector3 ray_from = p_camera->project_ray_origin(p_point); - Vector3 ray_dir = p_camera->project_ray_normal(p_point); - - Vector3 s[2] = { gi.xform(ray_from), gi.xform(ray_from + ray_dir * 4096) }; - if (p_id == 0) { - if (Object::cast_to(light)) { - Vector3 ra, rb; - Geometry3D::get_closest_points_between_segments(Vector3(), Vector3(0, 0, -4096), s[0], s[1], ra, rb); - - float d = -ra.z; - if (Node3DEditor::get_singleton()->is_snap_enabled()) { - d = Math::snapped(d, Node3DEditor::get_singleton()->get_translate_snap()); - } - - if (d <= 0) { // Equal is here for negative zero. - d = 0; - } - - light->set_param(Light3D::PARAM_RANGE, d); - } else if (Object::cast_to(light)) { - Plane cp = Plane(p_camera->get_transform().basis.get_column(2), gt.origin); - - Vector3 inters; - if (cp.intersects_ray(ray_from, ray_dir, &inters)) { - float r = inters.distance_to(gt.origin); - if (Node3DEditor::get_singleton()->is_snap_enabled()) { - r = Math::snapped(r, Node3DEditor::get_singleton()->get_translate_snap()); - } - - light->set_param(Light3D::PARAM_RANGE, r); - } - } - - } else if (p_id == 1) { - float a = _find_closest_angle_to_half_pi_arc(s[0], s[1], light->get_param(Light3D::PARAM_RANGE), gt); - light->set_param(Light3D::PARAM_SPOT_ANGLE, CLAMP(a, 0.01, 89.99)); - } -} - -void Light3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, const Variant &p_restore, bool p_cancel) { - Light3D *light = Object::cast_to(p_gizmo->get_node_3d()); - if (p_cancel) { - light->set_param(p_id == 0 ? Light3D::PARAM_RANGE : Light3D::PARAM_SPOT_ANGLE, p_restore); - - } else if (p_id == 0) { - EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton(); - ur->create_action(TTR("Change Light Radius")); - ur->add_do_method(light, "set_param", Light3D::PARAM_RANGE, light->get_param(Light3D::PARAM_RANGE)); - ur->add_undo_method(light, "set_param", Light3D::PARAM_RANGE, p_restore); - ur->commit_action(); - } else if (p_id == 1) { - EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton(); - ur->create_action(TTR("Change Light Radius")); - ur->add_do_method(light, "set_param", Light3D::PARAM_SPOT_ANGLE, light->get_param(Light3D::PARAM_SPOT_ANGLE)); - ur->add_undo_method(light, "set_param", Light3D::PARAM_SPOT_ANGLE, p_restore); - ur->commit_action(); - } -} - -void Light3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) { - Light3D *light = Object::cast_to(p_gizmo->get_node_3d()); - - Color color = light->get_color().srgb_to_linear() * light->get_correlated_color().srgb_to_linear(); - color = color.linear_to_srgb(); - // Make the gizmo color as bright as possible for better visibility - color.set_hsv(color.get_h(), color.get_s(), 1); - - p_gizmo->clear(); - - if (Object::cast_to(light)) { - Ref material = get_material("lines_primary", p_gizmo); - Ref icon = get_material("light_directional_icon", p_gizmo); - - const int arrow_points = 7; - const float arrow_length = 1.5; - - Vector3 arrow[arrow_points] = { - Vector3(0, 0, -1), - Vector3(0, 0.8, 0), - Vector3(0, 0.3, 0), - Vector3(0, 0.3, arrow_length), - Vector3(0, -0.3, arrow_length), - Vector3(0, -0.3, 0), - Vector3(0, -0.8, 0) - }; - - int arrow_sides = 2; - - Vector lines; - - for (int i = 0; i < arrow_sides; i++) { - for (int j = 0; j < arrow_points; j++) { - Basis ma(Vector3(0, 0, 1), Math_PI * i / arrow_sides); - - Vector3 v1 = arrow[j] - Vector3(0, 0, arrow_length); - Vector3 v2 = arrow[(j + 1) % arrow_points] - Vector3(0, 0, arrow_length); - - lines.push_back(ma.xform(v1)); - lines.push_back(ma.xform(v2)); - } - } - - p_gizmo->add_lines(lines, material, false, color); - p_gizmo->add_unscaled_billboard(icon, 0.05, color); - } - - if (Object::cast_to(light)) { - // Use both a billboard circle and 3 non-billboard circles for a better sphere-like representation - const Ref lines_material = get_material("lines_secondary", p_gizmo); - const Ref lines_billboard_material = get_material("lines_billboard", p_gizmo); - const Ref icon = get_material("light_omni_icon", p_gizmo); - - OmniLight3D *on = Object::cast_to(light); - const float r = on->get_param(Light3D::PARAM_RANGE); - Vector points; - Vector points_billboard; - - for (int i = 0; i < 120; i++) { - // Create a circle - const float ra = Math::deg_to_rad((float)(i * 3)); - const float rb = Math::deg_to_rad((float)((i + 1) * 3)); - const Point2 a = Vector2(Math::sin(ra), Math::cos(ra)) * r; - const Point2 b = Vector2(Math::sin(rb), Math::cos(rb)) * r; - - // Draw axis-aligned circles - points.push_back(Vector3(a.x, 0, a.y)); - points.push_back(Vector3(b.x, 0, b.y)); - points.push_back(Vector3(0, a.x, a.y)); - points.push_back(Vector3(0, b.x, b.y)); - points.push_back(Vector3(a.x, a.y, 0)); - points.push_back(Vector3(b.x, b.y, 0)); - - // Draw a billboarded circle - points_billboard.push_back(Vector3(a.x, a.y, 0)); - points_billboard.push_back(Vector3(b.x, b.y, 0)); - } - - p_gizmo->add_lines(points, lines_material, true, color); - p_gizmo->add_lines(points_billboard, lines_billboard_material, true, color); - p_gizmo->add_unscaled_billboard(icon, 0.05, color); - - Vector handles; - handles.push_back(Vector3(r, 0, 0)); - p_gizmo->add_handles(handles, get_material("handles_billboard"), Vector(), true); - } - - if (Object::cast_to(light)) { - const Ref material_primary = get_material("lines_primary", p_gizmo); - const Ref material_secondary = get_material("lines_secondary", p_gizmo); - const Ref icon = get_material("light_spot_icon", p_gizmo); - - Vector points_primary; - Vector points_secondary; - SpotLight3D *sl = Object::cast_to(light); - - float r = sl->get_param(Light3D::PARAM_RANGE); - float w = r * Math::sin(Math::deg_to_rad(sl->get_param(Light3D::PARAM_SPOT_ANGLE))); - float d = r * Math::cos(Math::deg_to_rad(sl->get_param(Light3D::PARAM_SPOT_ANGLE))); - - for (int i = 0; i < 120; i++) { - // Draw a circle - const float ra = Math::deg_to_rad((float)(i * 3)); - const float rb = Math::deg_to_rad((float)((i + 1) * 3)); - const Point2 a = Vector2(Math::sin(ra), Math::cos(ra)) * w; - const Point2 b = Vector2(Math::sin(rb), Math::cos(rb)) * w; - - points_primary.push_back(Vector3(a.x, a.y, -d)); - points_primary.push_back(Vector3(b.x, b.y, -d)); - - if (i % 15 == 0) { - // Draw 8 lines from the cone origin to the sides of the circle - points_secondary.push_back(Vector3(a.x, a.y, -d)); - points_secondary.push_back(Vector3()); - } - } - - points_primary.push_back(Vector3(0, 0, -r)); - points_primary.push_back(Vector3()); - - p_gizmo->add_lines(points_primary, material_primary, false, color); - p_gizmo->add_lines(points_secondary, material_secondary, false, color); - - Vector handles = { - Vector3(0, 0, -r), - Vector3(w, 0, -d) - }; - - p_gizmo->add_handles(handles, get_material("handles")); - p_gizmo->add_unscaled_billboard(icon, 0.05, color); - } -} - -//// player gizmo -AudioStreamPlayer3DGizmoPlugin::AudioStreamPlayer3DGizmoPlugin() { - Color gizmo_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/stream_player_3d", Color(0.4, 0.8, 1)); - - create_icon_material("stream_player_3d_icon", Node3DEditor::get_singleton()->get_theme_icon(SNAME("Gizmo3DSamplePlayer"), SNAME("EditorIcons"))); - create_material("stream_player_3d_material_primary", gizmo_color); - create_material("stream_player_3d_material_secondary", gizmo_color * Color(1, 1, 1, 0.35)); - // Enable vertex colors for the billboard material as the gizmo color depends on the - // AudioStreamPlayer3D attenuation type and source (Unit Size or Max Distance). - create_material("stream_player_3d_material_billboard", Color(1, 1, 1), true, false, true); - create_handle_material("handles"); -} - -bool AudioStreamPlayer3DGizmoPlugin::has_gizmo(Node3D *p_spatial) { - return Object::cast_to(p_spatial) != nullptr; -} - -String AudioStreamPlayer3DGizmoPlugin::get_gizmo_name() const { - return "AudioStreamPlayer3D"; -} - -int AudioStreamPlayer3DGizmoPlugin::get_priority() const { - return -1; -} - -String AudioStreamPlayer3DGizmoPlugin::get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const { - return "Emission Radius"; -} - -Variant AudioStreamPlayer3DGizmoPlugin::get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const { - AudioStreamPlayer3D *player = Object::cast_to(p_gizmo->get_node_3d()); - return player->get_emission_angle(); -} - -void AudioStreamPlayer3DGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, Camera3D *p_camera, const Point2 &p_point) { - AudioStreamPlayer3D *player = Object::cast_to(p_gizmo->get_node_3d()); - - Transform3D gt = player->get_global_transform(); - Transform3D gi = gt.affine_inverse(); - - Vector3 ray_from = p_camera->project_ray_origin(p_point); - Vector3 ray_dir = p_camera->project_ray_normal(p_point); - Vector3 ray_to = ray_from + ray_dir * 4096; - - ray_from = gi.xform(ray_from); - ray_to = gi.xform(ray_to); - - float closest_dist = 1e20; - float closest_angle = 1e20; - - for (int i = 0; i < 180; i++) { - float a = Math::deg_to_rad((float)i); - float an = Math::deg_to_rad((float)(i + 1)); - - Vector3 from(Math::sin(a), 0, -Math::cos(a)); - Vector3 to(Math::sin(an), 0, -Math::cos(an)); - - Vector3 r1, r2; - Geometry3D::get_closest_points_between_segments(from, to, ray_from, ray_to, r1, r2); - float d = r1.distance_to(r2); - if (d < closest_dist) { - closest_dist = d; - closest_angle = i; - } - } - - if (closest_angle < 91) { - player->set_emission_angle(closest_angle); - } -} - -void AudioStreamPlayer3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, const Variant &p_restore, bool p_cancel) { - AudioStreamPlayer3D *player = Object::cast_to(p_gizmo->get_node_3d()); - - if (p_cancel) { - player->set_emission_angle(p_restore); - - } else { - EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton(); - ur->create_action(TTR("Change AudioStreamPlayer3D Emission Angle")); - ur->add_do_method(player, "set_emission_angle", player->get_emission_angle()); - ur->add_undo_method(player, "set_emission_angle", p_restore); - ur->commit_action(); - } -} - -void AudioStreamPlayer3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) { - const AudioStreamPlayer3D *player = Object::cast_to(p_gizmo->get_node_3d()); - - p_gizmo->clear(); - - const Ref icon = get_material("stream_player_3d_icon", p_gizmo); - - if (player->get_attenuation_model() != AudioStreamPlayer3D::ATTENUATION_DISABLED || player->get_max_distance() > CMP_EPSILON) { - // Draw a circle to represent sound volume attenuation. - // Use only a billboard circle to represent radius. - // This helps distinguish AudioStreamPlayer3D gizmos from OmniLight3D gizmos. - const Ref lines_billboard_material = get_material("stream_player_3d_material_billboard", p_gizmo); - - // Soft distance cap varies depending on attenuation model, as some will fade out more aggressively than others. - // Multipliers were empirically determined through testing. - float soft_multiplier; - switch (player->get_attenuation_model()) { - case AudioStreamPlayer3D::ATTENUATION_INVERSE_DISTANCE: - soft_multiplier = 12.0; - break; - case AudioStreamPlayer3D::ATTENUATION_INVERSE_SQUARE_DISTANCE: - soft_multiplier = 4.0; - break; - case AudioStreamPlayer3D::ATTENUATION_LOGARITHMIC: - soft_multiplier = 3.25; - break; - default: - // Ensures Max Distance's radius visualization is not capped by Unit Size - // (when the attenuation mode is Disabled). - soft_multiplier = 10000.0; - break; - } - - // Draw the distance at which the sound can be reasonably heard. - // This can be either a hard distance cap with the Max Distance property (if set above 0.0), - // or a soft distance cap with the Unit Size property (sound never reaches true zero). - // When Max Distance is 0.0, `r` represents the distance above which the - // sound can't be heard in *most* (but not all) scenarios. - float r; - if (player->get_max_distance() > CMP_EPSILON) { - r = MIN(player->get_unit_size() * soft_multiplier, player->get_max_distance()); - } else { - r = player->get_unit_size() * soft_multiplier; - } - Vector points_billboard; - - for (int i = 0; i < 120; i++) { - // Create a circle. - const float ra = Math::deg_to_rad((float)(i * 3)); - const float rb = Math::deg_to_rad((float)((i + 1) * 3)); - const Point2 a = Vector2(Math::sin(ra), Math::cos(ra)) * r; - const Point2 b = Vector2(Math::sin(rb), Math::cos(rb)) * r; - - // Draw a billboarded circle. - points_billboard.push_back(Vector3(a.x, a.y, 0)); - points_billboard.push_back(Vector3(b.x, b.y, 0)); - } - - Color color; - switch (player->get_attenuation_model()) { - // Pick cold colors for all attenuation models (except Disabled), - // so that soft caps can be easily distinguished from hard caps - // (which use warm colors). - case AudioStreamPlayer3D::ATTENUATION_INVERSE_DISTANCE: - color = Color(0.4, 0.8, 1); - break; - case AudioStreamPlayer3D::ATTENUATION_INVERSE_SQUARE_DISTANCE: - color = Color(0.4, 0.5, 1); - break; - case AudioStreamPlayer3D::ATTENUATION_LOGARITHMIC: - color = Color(0.4, 0.2, 1); - break; - default: - // Disabled attenuation mode. - // This is never reached when Max Distance is 0, but the - // hue-inverted form of this color will be used if Max Distance is greater than 0. - color = Color(1, 1, 1); - break; - } - - if (player->get_max_distance() > CMP_EPSILON) { - // Sound is hard-capped by max distance. The attenuation model still matters, - // so invert the hue of the color that was chosen above. - color.set_h(color.get_h() + 0.5); - } - - p_gizmo->add_lines(points_billboard, lines_billboard_material, true, color); - } - - if (player->is_emission_angle_enabled()) { - const float pc = player->get_emission_angle(); - const float ofs = -Math::cos(Math::deg_to_rad(pc)); - const float radius = Math::sin(Math::deg_to_rad(pc)); - - Vector points_primary; - points_primary.resize(200); - - real_t step = Math_TAU / 100.0; - for (int i = 0; i < 100; i++) { - const float a = i * step; - const float an = (i + 1) * step; - - const Vector3 from(Math::sin(a) * radius, Math::cos(a) * radius, ofs); - const Vector3 to(Math::sin(an) * radius, Math::cos(an) * radius, ofs); - - points_primary.write[i * 2 + 0] = from; - points_primary.write[i * 2 + 1] = to; - } - - const Ref material_primary = get_material("stream_player_3d_material_primary", p_gizmo); - p_gizmo->add_lines(points_primary, material_primary); - - Vector points_secondary; - points_secondary.resize(16); - - for (int i = 0; i < 8; i++) { - const float a = i * (Math_TAU / 8.0); - const Vector3 from(Math::sin(a) * radius, Math::cos(a) * radius, ofs); - - points_secondary.write[i * 2 + 0] = from; - points_secondary.write[i * 2 + 1] = Vector3(); - } - - const Ref material_secondary = get_material("stream_player_3d_material_secondary", p_gizmo); - p_gizmo->add_lines(points_secondary, material_secondary); - - Vector handles; - const float ha = Math::deg_to_rad(player->get_emission_angle()); - handles.push_back(Vector3(Math::sin(ha), 0, -Math::cos(ha))); - p_gizmo->add_handles(handles, get_material("handles")); - } - - p_gizmo->add_unscaled_billboard(icon, 0.05); -} - ////// - -AudioListener3DGizmoPlugin::AudioListener3DGizmoPlugin() { - create_icon_material("audio_listener_3d_icon", Node3DEditor::get_singleton()->get_theme_icon(SNAME("GizmoAudioListener3D"), SNAME("EditorIcons"))); -} - -bool AudioListener3DGizmoPlugin::has_gizmo(Node3D *p_spatial) { - return Object::cast_to(p_spatial) != nullptr; -} - -String AudioListener3DGizmoPlugin::get_gizmo_name() const { - return "AudioListener3D"; -} - -int AudioListener3DGizmoPlugin::get_priority() const { - return -1; -} - -void AudioListener3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) { - const Ref icon = get_material("audio_listener_3d_icon", p_gizmo); - p_gizmo->add_unscaled_billboard(icon, 0.05); -} - -////// - -Camera3DGizmoPlugin::Camera3DGizmoPlugin() { - Color gizmo_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/camera", Color(0.8, 0.4, 0.8)); - - create_material("camera_material", gizmo_color); - create_handle_material("handles"); -} - -Size2i Camera3DGizmoPlugin::_get_viewport_size(Camera3D *p_camera) { - Viewport *viewport = p_camera->get_viewport(); - - Window *window = Object::cast_to(viewport); - if (window) { - return window->get_size(); - } - - SubViewport *sub_viewport = Object::cast_to(viewport); - ERR_FAIL_NULL_V(sub_viewport, Size2i()); - - if (sub_viewport == EditorNode::get_singleton()->get_scene_root()) { - return Size2(GLOBAL_GET("display/window/size/viewport_width"), GLOBAL_GET("display/window/size/viewport_height")); - } - - return sub_viewport->get_size(); -} - -bool Camera3DGizmoPlugin::has_gizmo(Node3D *p_spatial) { - return Object::cast_to(p_spatial) != nullptr; -} - -String Camera3DGizmoPlugin::get_gizmo_name() const { - return "Camera3D"; -} - -int Camera3DGizmoPlugin::get_priority() const { - return -1; -} - -String Camera3DGizmoPlugin::get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const { - Camera3D *camera = Object::cast_to(p_gizmo->get_node_3d()); - - if (camera->get_projection() == Camera3D::PROJECTION_PERSPECTIVE) { - return "FOV"; - } else { - return "Size"; - } -} - -Variant Camera3DGizmoPlugin::get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const { - Camera3D *camera = Object::cast_to(p_gizmo->get_node_3d()); - - if (camera->get_projection() == Camera3D::PROJECTION_PERSPECTIVE) { - return camera->get_fov(); - } else { - return camera->get_size(); - } -} - -void Camera3DGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, Camera3D *p_camera, const Point2 &p_point) { - Camera3D *camera = Object::cast_to(p_gizmo->get_node_3d()); - - Transform3D gt = camera->get_global_transform(); - Transform3D gi = gt.affine_inverse(); - - Vector3 ray_from = p_camera->project_ray_origin(p_point); - Vector3 ray_dir = p_camera->project_ray_normal(p_point); - - Vector3 s[2] = { gi.xform(ray_from), gi.xform(ray_from + ray_dir * 4096) }; - - if (camera->get_projection() == Camera3D::PROJECTION_PERSPECTIVE) { - Transform3D gt2 = camera->get_global_transform(); - float a = _find_closest_angle_to_half_pi_arc(s[0], s[1], 1.0, gt2); - camera->set("fov", CLAMP(a * 2.0, 1, 179)); - } else { - Vector3 ra, rb; - Geometry3D::get_closest_points_between_segments(Vector3(0, 0, -1), Vector3(4096, 0, -1), s[0], s[1], ra, rb); - float d = ra.x * 2; - if (Node3DEditor::get_singleton()->is_snap_enabled()) { - d = Math::snapped(d, Node3DEditor::get_singleton()->get_translate_snap()); - } - - d = CLAMP(d, 0.1, 16384); - - camera->set("size", d); - } -} - -void Camera3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, const Variant &p_restore, bool p_cancel) { - Camera3D *camera = Object::cast_to(p_gizmo->get_node_3d()); - - if (camera->get_projection() == Camera3D::PROJECTION_PERSPECTIVE) { - if (p_cancel) { - camera->set("fov", p_restore); - } else { - EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton(); - ur->create_action(TTR("Change Camera FOV")); - ur->add_do_property(camera, "fov", camera->get_fov()); - ur->add_undo_property(camera, "fov", p_restore); - ur->commit_action(); - } - - } else { - if (p_cancel) { - camera->set("size", p_restore); - } else { - EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton(); - ur->create_action(TTR("Change Camera Size")); - ur->add_do_property(camera, "size", camera->get_size()); - ur->add_undo_property(camera, "size", p_restore); - ur->commit_action(); - } - } -} - -void Camera3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) { - Camera3D *camera = Object::cast_to(p_gizmo->get_node_3d()); - - p_gizmo->clear(); - - Vector lines; - Vector handles; - - Ref material = get_material("camera_material", p_gizmo); - - const Size2i viewport_size = _get_viewport_size(camera); - const real_t viewport_aspect = viewport_size.x > 0 && viewport_size.y > 0 ? viewport_size.aspect() : 1.0; - const Size2 size_factor = viewport_aspect > 1.0 ? Size2(1.0, 1.0 / viewport_aspect) : Size2(viewport_aspect, 1.0); - -#define ADD_TRIANGLE(m_a, m_b, m_c) \ - { \ - lines.push_back(m_a); \ - lines.push_back(m_b); \ - lines.push_back(m_b); \ - lines.push_back(m_c); \ - lines.push_back(m_c); \ - lines.push_back(m_a); \ - } - -#define ADD_QUAD(m_a, m_b, m_c, m_d) \ - { \ - lines.push_back(m_a); \ - lines.push_back(m_b); \ - lines.push_back(m_b); \ - lines.push_back(m_c); \ - lines.push_back(m_c); \ - lines.push_back(m_d); \ - lines.push_back(m_d); \ - lines.push_back(m_a); \ - } - - switch (camera->get_projection()) { - case Camera3D::PROJECTION_PERSPECTIVE: { - // The real FOV is halved for accurate representation - float fov = camera->get_fov() / 2.0; - - const float hsize = Math::sin(Math::deg_to_rad(fov)); - const float depth = -Math::cos(Math::deg_to_rad(fov)); - Vector3 side = Vector3(hsize * size_factor.x, 0, depth); - Vector3 nside = Vector3(-side.x, side.y, side.z); - Vector3 up = Vector3(0, hsize * size_factor.y, 0); - - ADD_TRIANGLE(Vector3(), side + up, side - up); - ADD_TRIANGLE(Vector3(), nside + up, nside - up); - ADD_TRIANGLE(Vector3(), side + up, nside + up); - ADD_TRIANGLE(Vector3(), side - up, nside - up); - - handles.push_back(side); - side.x = MIN(side.x, hsize * 0.25); - nside.x = -side.x; - Vector3 tup(0, up.y + hsize / 2, side.z); - ADD_TRIANGLE(tup, side + up, nside + up); - } break; - - case Camera3D::PROJECTION_ORTHOGONAL: { - float size = camera->get_size(); - - float hsize = size * 0.5; - Vector3 right(hsize * size_factor.x, 0, 0); - Vector3 up(0, hsize * size_factor.y, 0); - Vector3 back(0, 0, -1.0); - Vector3 front(0, 0, 0); - - ADD_QUAD(-up - right, -up + right, up + right, up - right); - ADD_QUAD(-up - right + back, -up + right + back, up + right + back, up - right + back); - ADD_QUAD(up + right, up + right + back, up - right + back, up - right); - ADD_QUAD(-up + right, -up + right + back, -up - right + back, -up - right); - - handles.push_back(right + back); - - right.x = MIN(right.x, hsize * 0.25); - Vector3 tup(0, up.y + hsize / 2, back.z); - ADD_TRIANGLE(tup, right + up + back, -right + up + back); - - } break; - - case Camera3D::PROJECTION_FRUSTUM: { - float hsize = camera->get_size() / 2.0; - - Vector3 side = Vector3(hsize, 0, -camera->get_near()).normalized(); - side.x *= size_factor.x; - Vector3 nside = Vector3(-side.x, side.y, side.z); - Vector3 up = Vector3(0, hsize * size_factor.y, 0); - Vector3 offset = Vector3(camera->get_frustum_offset().x, camera->get_frustum_offset().y, 0.0); - - ADD_TRIANGLE(Vector3(), side + up + offset, side - up + offset); - ADD_TRIANGLE(Vector3(), nside + up + offset, nside - up + offset); - ADD_TRIANGLE(Vector3(), side + up + offset, nside + up + offset); - ADD_TRIANGLE(Vector3(), side - up + offset, nside - up + offset); - - side.x = MIN(side.x, hsize * 0.25); - nside.x = -side.x; - Vector3 tup(0, up.y + hsize / 2, side.z); - ADD_TRIANGLE(tup + offset, side + up + offset, nside + up + offset); - } break; - } - -#undef ADD_TRIANGLE -#undef ADD_QUAD - - p_gizmo->add_lines(lines, material); - p_gizmo->add_collision_segments(lines); - - if (!handles.is_empty()) { - p_gizmo->add_handles(handles, get_material("handles")); - } -} - -////// - -MeshInstance3DGizmoPlugin::MeshInstance3DGizmoPlugin() { -} - -bool MeshInstance3DGizmoPlugin::has_gizmo(Node3D *p_spatial) { - return Object::cast_to(p_spatial) != nullptr && Object::cast_to(p_spatial) == nullptr; -} - -String MeshInstance3DGizmoPlugin::get_gizmo_name() const { - return "MeshInstance3D"; -} - -int MeshInstance3DGizmoPlugin::get_priority() const { - return -1; -} - -bool MeshInstance3DGizmoPlugin::can_be_hidden() const { - return false; -} - -void MeshInstance3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) { - MeshInstance3D *mesh = Object::cast_to(p_gizmo->get_node_3d()); - - p_gizmo->clear(); - - Ref m = mesh->get_mesh(); - - if (!m.is_valid()) { - return; //none - } - - Ref tm = m->generate_triangle_mesh(); - if (tm.is_valid()) { - p_gizmo->add_collision_triangles(tm); - } -} - -///// - -OccluderInstance3DGizmoPlugin::OccluderInstance3DGizmoPlugin() { - create_material("line_material", EDITOR_DEF("editors/3d_gizmos/gizmo_colors/occluder", Color(0.8, 0.5, 1))); - create_handle_material("handles"); -} - -bool OccluderInstance3DGizmoPlugin::has_gizmo(Node3D *p_spatial) { - return Object::cast_to(p_spatial) != nullptr; -} - -String OccluderInstance3DGizmoPlugin::get_gizmo_name() const { - return "OccluderInstance3D"; -} - -int OccluderInstance3DGizmoPlugin::get_priority() const { - return -1; -} - -String OccluderInstance3DGizmoPlugin::get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const { - const OccluderInstance3D *cs = Object::cast_to(p_gizmo->get_node_3d()); - - Ref o = cs->get_occluder(); - if (o.is_null()) { - return ""; - } - - if (Object::cast_to(*o)) { - return "Radius"; - } - - if (Object::cast_to(*o) || Object::cast_to(*o)) { - return "Size"; - } - - return ""; -} - -Variant OccluderInstance3DGizmoPlugin::get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const { - OccluderInstance3D *oi = Object::cast_to(p_gizmo->get_node_3d()); - - Ref o = oi->get_occluder(); - if (o.is_null()) { - return Variant(); - } - - if (Object::cast_to(*o)) { - Ref so = o; - return so->get_radius(); - } - - if (Object::cast_to(*o)) { - Ref bo = o; - return bo->get_size(); - } - - if (Object::cast_to(*o)) { - Ref qo = o; - return qo->get_size(); - } - - return Variant(); -} - -void OccluderInstance3DGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, Camera3D *p_camera, const Point2 &p_point) { - OccluderInstance3D *oi = Object::cast_to(p_gizmo->get_node_3d()); - - Ref o = oi->get_occluder(); - if (o.is_null()) { - return; - } - - Transform3D gt = oi->get_global_transform(); - Transform3D gi = gt.affine_inverse(); - - Vector3 ray_from = p_camera->project_ray_origin(p_point); - Vector3 ray_dir = p_camera->project_ray_normal(p_point); - - Vector3 sg[2] = { gi.xform(ray_from), gi.xform(ray_from + ray_dir * 4096) }; - - bool snap_enabled = Node3DEditor::get_singleton()->is_snap_enabled(); - float snap = Node3DEditor::get_singleton()->get_translate_snap(); - - if (Object::cast_to(*o)) { - Ref so = o; - Vector3 ra, rb; - Geometry3D::get_closest_points_between_segments(Vector3(), Vector3(4096, 0, 0), sg[0], sg[1], ra, rb); - float d = ra.x; - if (snap_enabled) { - d = Math::snapped(d, snap); - } - - if (d < 0.001) { - d = 0.001; - } - - so->set_radius(d); - } - - if (Object::cast_to(*o)) { - Vector3 axis; - axis[p_id] = 1.0; - Ref bo = o; - Vector3 ra, rb; - Geometry3D::get_closest_points_between_segments(Vector3(), axis * 4096, sg[0], sg[1], ra, rb); - float d = ra[p_id] * 2; - if (snap_enabled) { - d = Math::snapped(d, snap); - } - - if (d < 0.001) { - d = 0.001; - } - - Vector3 he = bo->get_size(); - he[p_id] = d; - bo->set_size(he); - } - - if (Object::cast_to(*o)) { - Ref qo = o; - Plane p = Plane(Vector3(0.0f, 0.0f, 1.0f), 0.0f); - Vector3 intersection; - if (!p.intersects_segment(sg[0], sg[1], &intersection)) { - return; - } - - if (p_id == 2) { - Vector2 s = Vector2(intersection.x, intersection.y) * 2.0f; - if (snap_enabled) { - s = s.snapped(Vector2(snap, snap)); - } - s = s.max(Vector2(0.001, 0.001)); - qo->set_size(s); - } else { - float d = intersection[p_id]; - if (snap_enabled) { - d = Math::snapped(d, snap); - } - - if (d < 0.001) { - d = 0.001; - } - - Vector2 he = qo->get_size(); - he[p_id] = d * 2.0f; - qo->set_size(he); - } - } -} - -void OccluderInstance3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, const Variant &p_restore, bool p_cancel) { - OccluderInstance3D *oi = Object::cast_to(p_gizmo->get_node_3d()); - - Ref o = oi->get_occluder(); - if (o.is_null()) { - return; - } - - if (Object::cast_to(*o)) { - Ref so = o; - if (p_cancel) { - so->set_radius(p_restore); - return; - } - - EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton(); - ur->create_action(TTR("Change Sphere Shape Radius")); - ur->add_do_method(so.ptr(), "set_radius", so->get_radius()); - ur->add_undo_method(so.ptr(), "set_radius", p_restore); - ur->commit_action(); - } - - if (Object::cast_to(*o)) { - Ref bo = o; - if (p_cancel) { - bo->set_size(p_restore); - return; - } - - EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton(); - ur->create_action(TTR("Change Box Shape Size")); - ur->add_do_method(bo.ptr(), "set_size", bo->get_size()); - ur->add_undo_method(bo.ptr(), "set_size", p_restore); - ur->commit_action(); - } - - if (Object::cast_to(*o)) { - Ref qo = o; - if (p_cancel) { - qo->set_size(p_restore); - return; - } - - EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton(); - ur->create_action(TTR("Change Box Shape Size")); - ur->add_do_method(qo.ptr(), "set_size", qo->get_size()); - ur->add_undo_method(qo.ptr(), "set_size", p_restore); - ur->commit_action(); - } -} - -void OccluderInstance3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) { - OccluderInstance3D *occluder_instance = Object::cast_to(p_gizmo->get_node_3d()); - - p_gizmo->clear(); - - Ref o = occluder_instance->get_occluder(); - - if (!o.is_valid()) { - return; - } - - Vector lines = o->get_debug_lines(); - if (!lines.is_empty()) { - Ref material = get_material("line_material", p_gizmo); - p_gizmo->add_lines(lines, material); - p_gizmo->add_collision_segments(lines); - } - - Ref handles_material = get_material("handles"); - if (Object::cast_to(*o)) { - Ref so = o; - float r = so->get_radius(); - Vector handles = { Vector3(r, 0, 0) }; - p_gizmo->add_handles(handles, handles_material); - } - - if (Object::cast_to(*o)) { - Ref bo = o; - - Vector handles; - for (int i = 0; i < 3; i++) { - Vector3 ax; - ax[i] = bo->get_size()[i] / 2; - handles.push_back(ax); - } - - p_gizmo->add_handles(handles, handles_material); - } - - if (Object::cast_to(*o)) { - Ref qo = o; - Vector2 size = qo->get_size(); - Vector3 s = Vector3(size.x, size.y, 0.0f) / 2.0f; - Vector handles = { Vector3(s.x, 0.0f, 0.0f), Vector3(0.0f, s.y, 0.0f), Vector3(s.x, s.y, 0.0f) }; - p_gizmo->add_handles(handles, handles_material); - } -} - -///// - -Sprite3DGizmoPlugin::Sprite3DGizmoPlugin() { -} - -bool Sprite3DGizmoPlugin::has_gizmo(Node3D *p_spatial) { - return Object::cast_to(p_spatial) != nullptr; -} - -String Sprite3DGizmoPlugin::get_gizmo_name() const { - return "Sprite3D"; -} - -int Sprite3DGizmoPlugin::get_priority() const { - return -1; -} - -bool Sprite3DGizmoPlugin::can_be_hidden() const { - return false; -} - -void Sprite3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) { - Sprite3D *sprite = Object::cast_to(p_gizmo->get_node_3d()); - - p_gizmo->clear(); - - Ref tm = sprite->generate_triangle_mesh(); - if (tm.is_valid()) { - p_gizmo->add_collision_triangles(tm); - } -} - -/// - -Label3DGizmoPlugin::Label3DGizmoPlugin() { -} - -bool Label3DGizmoPlugin::has_gizmo(Node3D *p_spatial) { - return Object::cast_to(p_spatial) != nullptr; -} - -String Label3DGizmoPlugin::get_gizmo_name() const { - return "Label3D"; -} - -int Label3DGizmoPlugin::get_priority() const { - return -1; -} - -bool Label3DGizmoPlugin::can_be_hidden() const { - return false; -} - -void Label3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) { - Label3D *label = Object::cast_to(p_gizmo->get_node_3d()); - - p_gizmo->clear(); - - Ref tm = label->generate_triangle_mesh(); - if (tm.is_valid()) { - p_gizmo->add_collision_triangles(tm); - } -} - -/// - -Marker3DGizmoPlugin::Marker3DGizmoPlugin() { - pos3d_mesh = Ref(memnew(ArrayMesh)); - - Vector cursor_points; - Vector cursor_colors; - const float cs = 1.0; - // Add more points to create a "hard stop" in the color gradient. - cursor_points.push_back(Vector3(+cs, 0, 0)); - cursor_points.push_back(Vector3()); - cursor_points.push_back(Vector3()); - cursor_points.push_back(Vector3(-cs, 0, 0)); - - cursor_points.push_back(Vector3(0, +cs, 0)); - cursor_points.push_back(Vector3()); - cursor_points.push_back(Vector3()); - cursor_points.push_back(Vector3(0, -cs, 0)); - - cursor_points.push_back(Vector3(0, 0, +cs)); - cursor_points.push_back(Vector3()); - cursor_points.push_back(Vector3()); - cursor_points.push_back(Vector3(0, 0, -cs)); - - // Use the axis color which is brighter for the positive axis. - // Use a darkened axis color for the negative axis. - // This makes it possible to see in which direction the Marker3D node is rotated - // (which can be important depending on how it's used). - const Color color_x = EditorNode::get_singleton()->get_gui_base()->get_theme_color(SNAME("axis_x_color"), SNAME("Editor")); - cursor_colors.push_back(color_x); - cursor_colors.push_back(color_x); - // FIXME: Use less strong darkening factor once GH-48573 is fixed. - // The current darkening factor compensates for lines being too bright in the 3D editor. - cursor_colors.push_back(color_x.lerp(Color(0, 0, 0), 0.75)); - cursor_colors.push_back(color_x.lerp(Color(0, 0, 0), 0.75)); - - const Color color_y = EditorNode::get_singleton()->get_gui_base()->get_theme_color(SNAME("axis_y_color"), SNAME("Editor")); - cursor_colors.push_back(color_y); - cursor_colors.push_back(color_y); - cursor_colors.push_back(color_y.lerp(Color(0, 0, 0), 0.75)); - cursor_colors.push_back(color_y.lerp(Color(0, 0, 0), 0.75)); - - const Color color_z = EditorNode::get_singleton()->get_gui_base()->get_theme_color(SNAME("axis_z_color"), SNAME("Editor")); - cursor_colors.push_back(color_z); - cursor_colors.push_back(color_z); - cursor_colors.push_back(color_z.lerp(Color(0, 0, 0), 0.75)); - cursor_colors.push_back(color_z.lerp(Color(0, 0, 0), 0.75)); - - Ref mat = memnew(StandardMaterial3D); - mat->set_shading_mode(StandardMaterial3D::SHADING_MODE_UNSHADED); - mat->set_flag(StandardMaterial3D::FLAG_ALBEDO_FROM_VERTEX_COLOR, true); - mat->set_flag(StandardMaterial3D::FLAG_SRGB_VERTEX_COLOR, true); - mat->set_transparency(StandardMaterial3D::TRANSPARENCY_ALPHA); - - Array d; - d.resize(RS::ARRAY_MAX); - d[Mesh::ARRAY_VERTEX] = cursor_points; - d[Mesh::ARRAY_COLOR] = cursor_colors; - pos3d_mesh->add_surface_from_arrays(Mesh::PRIMITIVE_LINES, d); - pos3d_mesh->surface_set_material(0, mat); -} - -bool Marker3DGizmoPlugin::has_gizmo(Node3D *p_spatial) { - return Object::cast_to(p_spatial) != nullptr; -} - -String Marker3DGizmoPlugin::get_gizmo_name() const { - return "Marker3D"; -} - -int Marker3DGizmoPlugin::get_priority() const { - return -1; -} - -void Marker3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) { - const Marker3D *marker = Object::cast_to(p_gizmo->get_node_3d()); - const real_t extents = marker->get_gizmo_extents(); - const Transform3D xform(Basis::from_scale(Vector3(extents, extents, extents))); - - p_gizmo->clear(); - p_gizmo->add_mesh(pos3d_mesh, Ref(), xform); - - const Vector points = { - Vector3(-extents, 0, 0), - Vector3(+extents, 0, 0), - Vector3(0, -extents, 0), - Vector3(0, +extents, 0), - Vector3(0, 0, -extents), - Vector3(0, 0, +extents), - }; - p_gizmo->add_collision_segments(points); -} - -//// - -PhysicalBone3DGizmoPlugin::PhysicalBone3DGizmoPlugin() { - create_material("joint_material", EDITOR_GET("editors/3d_gizmos/gizmo_colors/joint")); -} - -bool PhysicalBone3DGizmoPlugin::has_gizmo(Node3D *p_spatial) { - return Object::cast_to(p_spatial) != nullptr; -} - -String PhysicalBone3DGizmoPlugin::get_gizmo_name() const { - return "PhysicalBone3D"; -} - -int PhysicalBone3DGizmoPlugin::get_priority() const { - return -1; -} - -void PhysicalBone3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) { - p_gizmo->clear(); - - PhysicalBone3D *physical_bone = Object::cast_to(p_gizmo->get_node_3d()); - - if (!physical_bone) { - return; - } - - Skeleton3D *sk(physical_bone->find_skeleton_parent()); - if (!sk) { - return; - } - - PhysicalBone3D *pb(sk->get_physical_bone(physical_bone->get_bone_id())); - if (!pb) { - return; - } - - PhysicalBone3D *pbp(sk->get_physical_bone_parent(physical_bone->get_bone_id())); - if (!pbp) { - return; - } - - Vector points; - - switch (physical_bone->get_joint_type()) { - case PhysicalBone3D::JOINT_TYPE_PIN: { - Joint3DGizmoPlugin::CreatePinJointGizmo(physical_bone->get_joint_offset(), points); - } break; - case PhysicalBone3D::JOINT_TYPE_CONE: { - const PhysicalBone3D::ConeJointData *cjd(static_cast(physical_bone->get_joint_data())); - Joint3DGizmoPlugin::CreateConeTwistJointGizmo( - physical_bone->get_joint_offset(), - physical_bone->get_global_transform() * physical_bone->get_joint_offset(), - pb->get_global_transform(), - pbp->get_global_transform(), - cjd->swing_span, - cjd->twist_span, - &points, - &points); - } break; - case PhysicalBone3D::JOINT_TYPE_HINGE: { - const PhysicalBone3D::HingeJointData *hjd(static_cast(physical_bone->get_joint_data())); - Joint3DGizmoPlugin::CreateHingeJointGizmo( - physical_bone->get_joint_offset(), - physical_bone->get_global_transform() * physical_bone->get_joint_offset(), - pb->get_global_transform(), - pbp->get_global_transform(), - hjd->angular_limit_lower, - hjd->angular_limit_upper, - hjd->angular_limit_enabled, - points, - &points, - &points); - } break; - case PhysicalBone3D::JOINT_TYPE_SLIDER: { - const PhysicalBone3D::SliderJointData *sjd(static_cast(physical_bone->get_joint_data())); - Joint3DGizmoPlugin::CreateSliderJointGizmo( - physical_bone->get_joint_offset(), - physical_bone->get_global_transform() * physical_bone->get_joint_offset(), - pb->get_global_transform(), - pbp->get_global_transform(), - sjd->angular_limit_lower, - sjd->angular_limit_upper, - sjd->linear_limit_lower, - sjd->linear_limit_upper, - points, - &points, - &points); - } break; - case PhysicalBone3D::JOINT_TYPE_6DOF: { - const PhysicalBone3D::SixDOFJointData *sdofjd(static_cast(physical_bone->get_joint_data())); - Joint3DGizmoPlugin::CreateGeneric6DOFJointGizmo( - physical_bone->get_joint_offset(), - - physical_bone->get_global_transform() * physical_bone->get_joint_offset(), - pb->get_global_transform(), - pbp->get_global_transform(), - - sdofjd->axis_data[0].angular_limit_lower, - sdofjd->axis_data[0].angular_limit_upper, - sdofjd->axis_data[0].linear_limit_lower, - sdofjd->axis_data[0].linear_limit_upper, - sdofjd->axis_data[0].angular_limit_enabled, - sdofjd->axis_data[0].linear_limit_enabled, - - sdofjd->axis_data[1].angular_limit_lower, - sdofjd->axis_data[1].angular_limit_upper, - sdofjd->axis_data[1].linear_limit_lower, - sdofjd->axis_data[1].linear_limit_upper, - sdofjd->axis_data[1].angular_limit_enabled, - sdofjd->axis_data[1].linear_limit_enabled, - - sdofjd->axis_data[2].angular_limit_lower, - sdofjd->axis_data[2].angular_limit_upper, - sdofjd->axis_data[2].linear_limit_lower, - sdofjd->axis_data[2].linear_limit_upper, - sdofjd->axis_data[2].angular_limit_enabled, - sdofjd->axis_data[2].linear_limit_enabled, - - points, - &points, - &points); - } break; - default: - return; - } - - Ref material = get_material("joint_material", p_gizmo); - - p_gizmo->add_collision_segments(points); - p_gizmo->add_lines(points, material); -} - -///// - -RayCast3DGizmoPlugin::RayCast3DGizmoPlugin() { - const Color gizmo_color = EDITOR_GET("editors/3d_gizmos/gizmo_colors/shape"); - create_material("shape_material", gizmo_color); - const float gizmo_value = gizmo_color.get_v(); - const Color gizmo_color_disabled = Color(gizmo_value, gizmo_value, gizmo_value, 0.65); - create_material("shape_material_disabled", gizmo_color_disabled); -} - -bool RayCast3DGizmoPlugin::has_gizmo(Node3D *p_spatial) { - return Object::cast_to(p_spatial) != nullptr; -} - -String RayCast3DGizmoPlugin::get_gizmo_name() const { - return "RayCast3D"; -} - -int RayCast3DGizmoPlugin::get_priority() const { - return -1; -} - -void RayCast3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) { - RayCast3D *raycast = Object::cast_to(p_gizmo->get_node_3d()); - - p_gizmo->clear(); - - const Ref material = raycast->is_enabled() ? raycast->get_debug_material() : get_material("shape_material_disabled"); - - p_gizmo->add_lines(raycast->get_debug_line_vertices(), material); - - if (raycast->get_debug_shape_thickness() > 1) { - p_gizmo->add_vertices(raycast->get_debug_shape_vertices(), material, Mesh::PRIMITIVE_TRIANGLE_STRIP); - } - - p_gizmo->add_collision_segments(raycast->get_debug_line_vertices()); -} - -///// - -ShapeCast3DGizmoPlugin::ShapeCast3DGizmoPlugin() { - const Color gizmo_color = EDITOR_GET("editors/3d_gizmos/gizmo_colors/shape"); - create_material("shape_material", gizmo_color); - const float gizmo_value = gizmo_color.get_v(); - const Color gizmo_color_disabled = Color(gizmo_value, gizmo_value, gizmo_value, 0.65); - create_material("shape_material_disabled", gizmo_color_disabled); -} - -bool ShapeCast3DGizmoPlugin::has_gizmo(Node3D *p_spatial) { - return Object::cast_to(p_spatial) != nullptr; -} - -String ShapeCast3DGizmoPlugin::get_gizmo_name() const { - return "ShapeCast3D"; -} - -int ShapeCast3DGizmoPlugin::get_priority() const { - return -1; -} - -void ShapeCast3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) { - ShapeCast3D *shapecast = Object::cast_to(p_gizmo->get_node_3d()); - - p_gizmo->clear(); - - const Ref material = shapecast->is_enabled() ? shapecast->get_debug_material() : get_material("shape_material_disabled"); - - p_gizmo->add_lines(shapecast->get_debug_line_vertices(), material); - - if (shapecast->get_shape().is_valid()) { - p_gizmo->add_lines(shapecast->get_debug_shape_vertices(), material); - } - - p_gizmo->add_collision_segments(shapecast->get_debug_line_vertices()); -} - -///// - -void SpringArm3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) { - SpringArm3D *spring_arm = Object::cast_to(p_gizmo->get_node_3d()); - - p_gizmo->clear(); - - Vector lines = { - Vector3(), - Vector3(0, 0, 1.0) * spring_arm->get_length() - }; - - Ref material = get_material("shape_material", p_gizmo); - - p_gizmo->add_lines(lines, material); - p_gizmo->add_collision_segments(lines); -} - -SpringArm3DGizmoPlugin::SpringArm3DGizmoPlugin() { - Color gizmo_color = EDITOR_GET("editors/3d_gizmos/gizmo_colors/shape"); - create_material("shape_material", gizmo_color); -} - -bool SpringArm3DGizmoPlugin::has_gizmo(Node3D *p_spatial) { - return Object::cast_to(p_spatial) != nullptr; -} - -String SpringArm3DGizmoPlugin::get_gizmo_name() const { - return "SpringArm3D"; -} - -int SpringArm3DGizmoPlugin::get_priority() const { - return -1; -} - -///// - -VehicleWheel3DGizmoPlugin::VehicleWheel3DGizmoPlugin() { - Color gizmo_color = EDITOR_GET("editors/3d_gizmos/gizmo_colors/shape"); - create_material("shape_material", gizmo_color); -} - -bool VehicleWheel3DGizmoPlugin::has_gizmo(Node3D *p_spatial) { - return Object::cast_to(p_spatial) != nullptr; -} - -String VehicleWheel3DGizmoPlugin::get_gizmo_name() const { - return "VehicleWheel3D"; -} - -int VehicleWheel3DGizmoPlugin::get_priority() const { - return -1; -} - -void VehicleWheel3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) { - VehicleWheel3D *car_wheel = Object::cast_to(p_gizmo->get_node_3d()); - - p_gizmo->clear(); - - Vector points; - - float r = car_wheel->get_radius(); - const int skip = 10; - for (int i = 0; i <= 360; i += skip) { - float ra = Math::deg_to_rad((float)i); - float rb = Math::deg_to_rad((float)i + skip); - Point2 a = Vector2(Math::sin(ra), Math::cos(ra)) * r; - Point2 b = Vector2(Math::sin(rb), Math::cos(rb)) * r; - - points.push_back(Vector3(0, a.x, a.y)); - points.push_back(Vector3(0, b.x, b.y)); - - const int springsec = 4; - - for (int j = 0; j < springsec; j++) { - float t = car_wheel->get_suspension_rest_length() * 5; - points.push_back(Vector3(a.x, i / 360.0 * t / springsec + j * (t / springsec), a.y) * 0.2); - points.push_back(Vector3(b.x, (i + skip) / 360.0 * t / springsec + j * (t / springsec), b.y) * 0.2); - } - } - - //travel - points.push_back(Vector3(0, 0, 0)); - points.push_back(Vector3(0, car_wheel->get_suspension_rest_length(), 0)); - - //axis - points.push_back(Vector3(r * 0.2, car_wheel->get_suspension_rest_length(), 0)); - points.push_back(Vector3(-r * 0.2, car_wheel->get_suspension_rest_length(), 0)); - //axis - points.push_back(Vector3(r * 0.2, 0, 0)); - points.push_back(Vector3(-r * 0.2, 0, 0)); - - //forward line - points.push_back(Vector3(0, -r, 0)); - points.push_back(Vector3(0, -r, r * 2)); - points.push_back(Vector3(0, -r, r * 2)); - points.push_back(Vector3(r * 2 * 0.2, -r, r * 2 * 0.8)); - points.push_back(Vector3(0, -r, r * 2)); - points.push_back(Vector3(-r * 2 * 0.2, -r, r * 2 * 0.8)); - - Ref material = get_material("shape_material", p_gizmo); - - p_gizmo->add_lines(points, material); - p_gizmo->add_collision_segments(points); -} - -/////////// - -SoftBody3DGizmoPlugin::SoftBody3DGizmoPlugin() { - Color gizmo_color = EDITOR_GET("editors/3d_gizmos/gizmo_colors/shape"); - create_material("shape_material", gizmo_color); - create_handle_material("handles"); -} - -bool SoftBody3DGizmoPlugin::has_gizmo(Node3D *p_spatial) { - return Object::cast_to(p_spatial) != nullptr; -} - -String SoftBody3DGizmoPlugin::get_gizmo_name() const { - return "SoftBody3D"; -} - -int SoftBody3DGizmoPlugin::get_priority() const { - return -1; -} - -bool SoftBody3DGizmoPlugin::is_selectable_when_hidden() const { - return true; -} - -void SoftBody3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) { - SoftBody3D *soft_body = Object::cast_to(p_gizmo->get_node_3d()); - - p_gizmo->clear(); - - if (!soft_body || soft_body->get_mesh().is_null()) { - return; - } - - // find mesh - - Vector lines; - - soft_body->get_mesh()->generate_debug_mesh_lines(lines); - - if (!lines.size()) { - return; - } - - Ref tm = soft_body->get_mesh()->generate_triangle_mesh(); - - Vector points; - for (int i = 0; i < soft_body->get_mesh()->get_surface_count(); i++) { - Array arrays = soft_body->get_mesh()->surface_get_arrays(i); - ERR_CONTINUE(arrays.is_empty()); - - const Vector &vertices = arrays[Mesh::ARRAY_VERTEX]; - points.append_array(vertices); - } - - Ref material = get_material("shape_material", p_gizmo); - - p_gizmo->add_lines(lines, material); - p_gizmo->add_handles(points, get_material("handles")); - p_gizmo->add_collision_triangles(tm); -} - -String SoftBody3DGizmoPlugin::get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const { - return "SoftBody3D pin point"; -} - -Variant SoftBody3DGizmoPlugin::get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const { - SoftBody3D *soft_body = Object::cast_to(p_gizmo->get_node_3d()); - return Variant(soft_body->is_point_pinned(p_id)); -} - -void SoftBody3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, const Variant &p_restore, bool p_cancel) { - SoftBody3D *soft_body = Object::cast_to(p_gizmo->get_node_3d()); - soft_body->pin_point_toggle(p_id); -} - -bool SoftBody3DGizmoPlugin::is_handle_highlighted(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const { - SoftBody3D *soft_body = Object::cast_to(p_gizmo->get_node_3d()); - return soft_body->is_point_pinned(p_id); -} - -/////////// - -VisibleOnScreenNotifier3DGizmoPlugin::VisibleOnScreenNotifier3DGizmoPlugin() { - Color gizmo_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/visibility_notifier", Color(0.8, 0.5, 0.7)); - create_material("visibility_notifier_material", gizmo_color); - gizmo_color.a = 0.1; - create_material("visibility_notifier_solid_material", gizmo_color); - create_handle_material("handles"); -} - -bool VisibleOnScreenNotifier3DGizmoPlugin::has_gizmo(Node3D *p_spatial) { - return Object::cast_to(p_spatial) != nullptr; -} - -String VisibleOnScreenNotifier3DGizmoPlugin::get_gizmo_name() const { - return "VisibleOnScreenNotifier3D"; -} - -int VisibleOnScreenNotifier3DGizmoPlugin::get_priority() const { - return -1; -} - -String VisibleOnScreenNotifier3DGizmoPlugin::get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const { - switch (p_id) { - case 0: - return "Size X"; - case 1: - return "Size Y"; - case 2: - return "Size Z"; - case 3: - return "Pos X"; - case 4: - return "Pos Y"; - case 5: - return "Pos Z"; - } - - return ""; -} - -Variant VisibleOnScreenNotifier3DGizmoPlugin::get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const { - VisibleOnScreenNotifier3D *notifier = Object::cast_to(p_gizmo->get_node_3d()); - return notifier->get_aabb(); -} - -void VisibleOnScreenNotifier3DGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, Camera3D *p_camera, const Point2 &p_point) { - VisibleOnScreenNotifier3D *notifier = Object::cast_to(p_gizmo->get_node_3d()); - - Transform3D gt = notifier->get_global_transform(); - - Transform3D gi = gt.affine_inverse(); - - bool move = p_id >= 3; - p_id = p_id % 3; - - AABB aabb = notifier->get_aabb(); - Vector3 ray_from = p_camera->project_ray_origin(p_point); - Vector3 ray_dir = p_camera->project_ray_normal(p_point); - - Vector3 sg[2] = { gi.xform(ray_from), gi.xform(ray_from + ray_dir * 4096) }; - - Vector3 ofs = aabb.get_center(); - - Vector3 axis; - axis[p_id] = 1.0; - - if (move) { - Vector3 ra, rb; - Geometry3D::get_closest_points_between_segments(ofs - axis * 4096, ofs + axis * 4096, sg[0], sg[1], ra, rb); - - float d = ra[p_id]; - if (Node3DEditor::get_singleton()->is_snap_enabled()) { - d = Math::snapped(d, Node3DEditor::get_singleton()->get_translate_snap()); - } - - aabb.position[p_id] = d - 1.0 - aabb.size[p_id] * 0.5; - notifier->set_aabb(aabb); - - } else { - Vector3 ra, rb; - Geometry3D::get_closest_points_between_segments(ofs, ofs + axis * 4096, sg[0], sg[1], ra, rb); - - float d = ra[p_id] - ofs[p_id]; - if (Node3DEditor::get_singleton()->is_snap_enabled()) { - d = Math::snapped(d, Node3DEditor::get_singleton()->get_translate_snap()); - } - - if (d < 0.001) { - d = 0.001; - } - //resize - aabb.position[p_id] = (aabb.position[p_id] + aabb.size[p_id] * 0.5) - d; - aabb.size[p_id] = d * 2; - notifier->set_aabb(aabb); - } -} - -void VisibleOnScreenNotifier3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, const Variant &p_restore, bool p_cancel) { - VisibleOnScreenNotifier3D *notifier = Object::cast_to(p_gizmo->get_node_3d()); - - if (p_cancel) { - notifier->set_aabb(p_restore); - return; - } - - EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton(); - ur->create_action(TTR("Change Notifier AABB")); - ur->add_do_method(notifier, "set_aabb", notifier->get_aabb()); - ur->add_undo_method(notifier, "set_aabb", p_restore); - ur->commit_action(); -} - -void VisibleOnScreenNotifier3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) { - VisibleOnScreenNotifier3D *notifier = Object::cast_to(p_gizmo->get_node_3d()); - - p_gizmo->clear(); - - Vector lines; - AABB aabb = notifier->get_aabb(); - - for (int i = 0; i < 12; i++) { - Vector3 a, b; - aabb.get_edge(i, a, b); - lines.push_back(a); - lines.push_back(b); - } - - Vector handles; - - for (int i = 0; i < 3; i++) { - Vector3 ax; - ax[i] = aabb.position[i] + aabb.size[i]; - ax[(i + 1) % 3] = aabb.position[(i + 1) % 3] + aabb.size[(i + 1) % 3] * 0.5; - ax[(i + 2) % 3] = aabb.position[(i + 2) % 3] + aabb.size[(i + 2) % 3] * 0.5; - handles.push_back(ax); - } - - Vector3 center = aabb.get_center(); - for (int i = 0; i < 3; i++) { - Vector3 ax; - ax[i] = 1.0; - handles.push_back(center + ax); - lines.push_back(center); - lines.push_back(center + ax); - } - - Ref material = get_material("visibility_notifier_material", p_gizmo); - - p_gizmo->add_lines(lines, material); - p_gizmo->add_collision_segments(lines); - - if (p_gizmo->is_selected()) { - Ref solid_material = get_material("visibility_notifier_solid_material", p_gizmo); - p_gizmo->add_solid_box(solid_material, aabb.get_size(), aabb.get_center()); - } - - p_gizmo->add_handles(handles, get_material("handles")); -} - -//// - -CPUParticles3DGizmoPlugin::CPUParticles3DGizmoPlugin() { - create_icon_material("particles_icon", Node3DEditor::get_singleton()->get_theme_icon(SNAME("GizmoCPUParticles3D"), SNAME("EditorIcons"))); -} - -bool CPUParticles3DGizmoPlugin::has_gizmo(Node3D *p_spatial) { - return Object::cast_to(p_spatial) != nullptr; -} - -String CPUParticles3DGizmoPlugin::get_gizmo_name() const { - return "CPUParticles3D"; -} - -int CPUParticles3DGizmoPlugin::get_priority() const { - return -1; -} - -bool CPUParticles3DGizmoPlugin::is_selectable_when_hidden() const { - return true; -} - -void CPUParticles3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) { - Ref icon = get_material("particles_icon", p_gizmo); - p_gizmo->add_unscaled_billboard(icon, 0.05); -} - -//// - -GPUParticles3DGizmoPlugin::GPUParticles3DGizmoPlugin() { - Color gizmo_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/particles", Color(0.8, 0.7, 0.4)); - create_material("particles_material", gizmo_color); - gizmo_color.a = MAX((gizmo_color.a - 0.2) * 0.02, 0.0); - create_material("particles_solid_material", gizmo_color); - create_icon_material("particles_icon", Node3DEditor::get_singleton()->get_theme_icon(SNAME("GizmoGPUParticles3D"), SNAME("EditorIcons"))); - create_handle_material("handles"); -} - -bool GPUParticles3DGizmoPlugin::has_gizmo(Node3D *p_spatial) { - return Object::cast_to(p_spatial) != nullptr; -} - -String GPUParticles3DGizmoPlugin::get_gizmo_name() const { - return "GPUParticles3D"; -} - -int GPUParticles3DGizmoPlugin::get_priority() const { - return -1; -} - -bool GPUParticles3DGizmoPlugin::is_selectable_when_hidden() const { - return true; -} - -String GPUParticles3DGizmoPlugin::get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const { - switch (p_id) { - case 0: - return "Size X"; - case 1: - return "Size Y"; - case 2: - return "Size Z"; - case 3: - return "Pos X"; - case 4: - return "Pos Y"; - case 5: - return "Pos Z"; - } - - return ""; -} - -Variant GPUParticles3DGizmoPlugin::get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const { - GPUParticles3D *particles = Object::cast_to(p_gizmo->get_node_3d()); - return particles->get_visibility_aabb(); -} - -void GPUParticles3DGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, Camera3D *p_camera, const Point2 &p_point) { - GPUParticles3D *particles = Object::cast_to(p_gizmo->get_node_3d()); - - Transform3D gt = particles->get_global_transform(); - Transform3D gi = gt.affine_inverse(); - - bool move = p_id >= 3; - p_id = p_id % 3; - - AABB aabb = particles->get_visibility_aabb(); - Vector3 ray_from = p_camera->project_ray_origin(p_point); - Vector3 ray_dir = p_camera->project_ray_normal(p_point); - - Vector3 sg[2] = { gi.xform(ray_from), gi.xform(ray_from + ray_dir * 4096) }; - - Vector3 ofs = aabb.get_center(); - - Vector3 axis; - axis[p_id] = 1.0; - - if (move) { - Vector3 ra, rb; - Geometry3D::get_closest_points_between_segments(ofs - axis * 4096, ofs + axis * 4096, sg[0], sg[1], ra, rb); - - float d = ra[p_id]; - if (Node3DEditor::get_singleton()->is_snap_enabled()) { - d = Math::snapped(d, Node3DEditor::get_singleton()->get_translate_snap()); - } - - aabb.position[p_id] = d - 1.0 - aabb.size[p_id] * 0.5; - particles->set_visibility_aabb(aabb); - - } else { - Vector3 ra, rb; - Geometry3D::get_closest_points_between_segments(ofs, ofs + axis * 4096, sg[0], sg[1], ra, rb); - - float d = ra[p_id] - ofs[p_id]; - if (Node3DEditor::get_singleton()->is_snap_enabled()) { - d = Math::snapped(d, Node3DEditor::get_singleton()->get_translate_snap()); - } - - if (d < 0.001) { - d = 0.001; - } - //resize - aabb.position[p_id] = (aabb.position[p_id] + aabb.size[p_id] * 0.5) - d; - aabb.size[p_id] = d * 2; - particles->set_visibility_aabb(aabb); - } -} - -void GPUParticles3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, const Variant &p_restore, bool p_cancel) { - GPUParticles3D *particles = Object::cast_to(p_gizmo->get_node_3d()); - - if (p_cancel) { - particles->set_visibility_aabb(p_restore); - return; - } - - EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton(); - ur->create_action(TTR("Change Particles AABB")); - ur->add_do_method(particles, "set_visibility_aabb", particles->get_visibility_aabb()); - ur->add_undo_method(particles, "set_visibility_aabb", p_restore); - ur->commit_action(); -} - -void GPUParticles3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) { - GPUParticles3D *particles = Object::cast_to(p_gizmo->get_node_3d()); - - p_gizmo->clear(); - - Vector lines; - AABB aabb = particles->get_visibility_aabb(); - - for (int i = 0; i < 12; i++) { - Vector3 a, b; - aabb.get_edge(i, a, b); - lines.push_back(a); - lines.push_back(b); - } - - Vector handles; - - for (int i = 0; i < 3; i++) { - Vector3 ax; - ax[i] = aabb.position[i] + aabb.size[i]; - ax[(i + 1) % 3] = aabb.position[(i + 1) % 3] + aabb.size[(i + 1) % 3] * 0.5; - ax[(i + 2) % 3] = aabb.position[(i + 2) % 3] + aabb.size[(i + 2) % 3] * 0.5; - handles.push_back(ax); - } - - Vector3 center = aabb.get_center(); - for (int i = 0; i < 3; i++) { - Vector3 ax; - ax[i] = 1.0; - handles.push_back(center + ax); - lines.push_back(center); - lines.push_back(center + ax); - } - - Ref material = get_material("particles_material", p_gizmo); - Ref icon = get_material("particles_icon", p_gizmo); - - p_gizmo->add_lines(lines, material); - - if (p_gizmo->is_selected()) { - Ref solid_material = get_material("particles_solid_material", p_gizmo); - p_gizmo->add_solid_box(solid_material, aabb.get_size(), aabb.get_center()); - } - - p_gizmo->add_handles(handles, get_material("handles")); - p_gizmo->add_unscaled_billboard(icon, 0.05); -} - -//// - -GPUParticlesCollision3DGizmoPlugin::GPUParticlesCollision3DGizmoPlugin() { - Color gizmo_color_attractor = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/particle_attractor", Color(1, 0.7, 0.5)); - create_material("shape_material_attractor", gizmo_color_attractor); - gizmo_color_attractor.a = 0.15; - create_material("shape_material_attractor_internal", gizmo_color_attractor); - - Color gizmo_color_collision = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/particle_collision", Color(0.5, 0.7, 1)); - create_material("shape_material_collision", gizmo_color_collision); - gizmo_color_collision.a = 0.15; - create_material("shape_material_collision_internal", gizmo_color_collision); - - create_handle_material("handles"); -} - -bool GPUParticlesCollision3DGizmoPlugin::has_gizmo(Node3D *p_spatial) { - return (Object::cast_to(p_spatial) != nullptr) || (Object::cast_to(p_spatial) != nullptr); -} - -String GPUParticlesCollision3DGizmoPlugin::get_gizmo_name() const { - return "GPUParticlesCollision3D"; -} - -int GPUParticlesCollision3DGizmoPlugin::get_priority() const { - return -1; -} - -String GPUParticlesCollision3DGizmoPlugin::get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const { - const Node3D *cs = p_gizmo->get_node_3d(); - - if (Object::cast_to(cs) || Object::cast_to(cs)) { - return "Radius"; - } - - if (Object::cast_to(cs) || Object::cast_to(cs) || Object::cast_to(cs) || Object::cast_to(cs) || Object::cast_to(cs)) { - return "Size"; - } - - return ""; -} - -Variant GPUParticlesCollision3DGizmoPlugin::get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const { - const Node3D *cs = p_gizmo->get_node_3d(); - - if (Object::cast_to(cs) || Object::cast_to(cs)) { - return p_gizmo->get_node_3d()->call("get_radius"); - } - - if (Object::cast_to(cs) || Object::cast_to(cs) || Object::cast_to(cs) || Object::cast_to(cs) || Object::cast_to(cs)) { - return Vector3(p_gizmo->get_node_3d()->call("get_size")); - } - - return Variant(); -} - -void GPUParticlesCollision3DGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, Camera3D *p_camera, const Point2 &p_point) { - Node3D *sn = p_gizmo->get_node_3d(); - - Transform3D gt = sn->get_global_transform(); - Transform3D gi = gt.affine_inverse(); - - Vector3 ray_from = p_camera->project_ray_origin(p_point); - Vector3 ray_dir = p_camera->project_ray_normal(p_point); - - Vector3 sg[2] = { gi.xform(ray_from), gi.xform(ray_from + ray_dir * 4096) }; - - if (Object::cast_to(sn) || Object::cast_to(sn)) { - Vector3 ra, rb; - Geometry3D::get_closest_points_between_segments(Vector3(), Vector3(4096, 0, 0), sg[0], sg[1], ra, rb); - float d = ra.x; - if (Node3DEditor::get_singleton()->is_snap_enabled()) { - d = Math::snapped(d, Node3DEditor::get_singleton()->get_translate_snap()); - } - - if (d < 0.001) { - d = 0.001; - } - - sn->call("set_radius", d); - } - - if (Object::cast_to(sn) || Object::cast_to(sn) || Object::cast_to(sn) || Object::cast_to(sn) || Object::cast_to(sn)) { - Vector3 axis; - axis[p_id] = 1.0; - Vector3 ra, rb; - Geometry3D::get_closest_points_between_segments(Vector3(), axis * 4096, sg[0], sg[1], ra, rb); - float d = ra[p_id] * 2; - if (Node3DEditor::get_singleton()->is_snap_enabled()) { - d = Math::snapped(d, Node3DEditor::get_singleton()->get_translate_snap()); - } - - if (d < 0.001) { - d = 0.001; - } - - Vector3 he = sn->call("get_size"); - he[p_id] = d; - sn->call("set_size", he); - } -} - -void GPUParticlesCollision3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, const Variant &p_restore, bool p_cancel) { - Node3D *sn = p_gizmo->get_node_3d(); - - if (Object::cast_to(sn) || Object::cast_to(sn)) { - if (p_cancel) { - sn->call("set_radius", p_restore); - return; - } - - EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton(); - ur->create_action(TTR("Change Radius")); - ur->add_do_method(sn, "set_radius", sn->call("get_radius")); - ur->add_undo_method(sn, "set_radius", p_restore); - ur->commit_action(); - } - - if (Object::cast_to(sn) || Object::cast_to(sn) || Object::cast_to(sn) || Object::cast_to(sn) || Object::cast_to(sn)) { - if (p_cancel) { - sn->call("set_size", p_restore); - return; - } - - EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton(); - ur->create_action(TTR("Change Box Shape Size")); - ur->add_do_method(sn, "set_size", sn->call("get_size")); - ur->add_undo_method(sn, "set_size", p_restore); - ur->commit_action(); - } -} - -void GPUParticlesCollision3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) { - Node3D *cs = p_gizmo->get_node_3d(); - - p_gizmo->clear(); - - Ref material; - Ref material_internal; - if (Object::cast_to(cs)) { - material = get_material("shape_material_attractor", p_gizmo); - material_internal = get_material("shape_material_attractor_internal", p_gizmo); - } else { - material = get_material("shape_material_collision", p_gizmo); - material_internal = get_material("shape_material_collision_internal", p_gizmo); - } - - const Ref handles_material = get_material("handles"); - - if (Object::cast_to(cs) || Object::cast_to(cs)) { - float r = cs->call("get_radius"); - - Vector points; - - for (int i = 0; i <= 360; i++) { - float ra = Math::deg_to_rad((float)i); - float rb = Math::deg_to_rad((float)i + 1); - Point2 a = Vector2(Math::sin(ra), Math::cos(ra)) * r; - Point2 b = Vector2(Math::sin(rb), Math::cos(rb)) * r; - - points.push_back(Vector3(a.x, 0, a.y)); - points.push_back(Vector3(b.x, 0, b.y)); - points.push_back(Vector3(0, a.x, a.y)); - points.push_back(Vector3(0, b.x, b.y)); - points.push_back(Vector3(a.x, a.y, 0)); - points.push_back(Vector3(b.x, b.y, 0)); - } - - Vector collision_segments; - - for (int i = 0; i < 64; i++) { - float ra = i * (Math_TAU / 64.0); - float rb = (i + 1) * (Math_TAU / 64.0); - Point2 a = Vector2(Math::sin(ra), Math::cos(ra)) * r; - Point2 b = Vector2(Math::sin(rb), Math::cos(rb)) * r; - - collision_segments.push_back(Vector3(a.x, 0, a.y)); - collision_segments.push_back(Vector3(b.x, 0, b.y)); - collision_segments.push_back(Vector3(0, a.x, a.y)); - collision_segments.push_back(Vector3(0, b.x, b.y)); - collision_segments.push_back(Vector3(a.x, a.y, 0)); - collision_segments.push_back(Vector3(b.x, b.y, 0)); - } - - p_gizmo->add_lines(points, material); - p_gizmo->add_collision_segments(collision_segments); - Vector handles; - handles.push_back(Vector3(r, 0, 0)); - p_gizmo->add_handles(handles, handles_material); - } - - if (Object::cast_to(cs) || Object::cast_to(cs) || Object::cast_to(cs) || Object::cast_to(cs) || Object::cast_to(cs)) { - Vector lines; - AABB aabb; - aabb.size = cs->call("get_size").operator Vector3(); - aabb.position = aabb.size / -2; - - for (int i = 0; i < 12; i++) { - Vector3 a, b; - aabb.get_edge(i, a, b); - lines.push_back(a); - lines.push_back(b); - } - - Vector handles; - - for (int i = 0; i < 3; i++) { - Vector3 ax; - ax[i] = cs->call("get_size").operator Vector3()[i] / 2; - handles.push_back(ax); - } - - p_gizmo->add_lines(lines, material); - p_gizmo->add_collision_segments(lines); - p_gizmo->add_handles(handles, handles_material); - - GPUParticlesCollisionSDF3D *col_sdf = Object::cast_to(cs); - if (col_sdf) { - static const int subdivs[GPUParticlesCollisionSDF3D::RESOLUTION_MAX] = { 16, 32, 64, 128, 256, 512 }; - int subdiv = subdivs[col_sdf->get_resolution()]; - float cell_size = aabb.get_longest_axis_size() / subdiv; - - lines.clear(); - - for (int i = 1; i < subdiv; i++) { - for (int j = 0; j < 3; j++) { - if (cell_size * i > aabb.size[j]) { - continue; - } - - int j_n1 = (j + 1) % 3; - int j_n2 = (j + 2) % 3; - - for (int k = 0; k < 4; k++) { - Vector3 from = aabb.position, to = aabb.position; - from[j] += cell_size * i; - to[j] += cell_size * i; - - if (k & 1) { - to[j_n1] += aabb.size[j_n1]; - } else { - to[j_n2] += aabb.size[j_n2]; - } - - if (k & 2) { - from[j_n1] += aabb.size[j_n1]; - from[j_n2] += aabb.size[j_n2]; - } - - lines.push_back(from); - lines.push_back(to); - } - } - } - - p_gizmo->add_lines(lines, material_internal); - } - } -} - -///// - -//// - -ReflectionProbeGizmoPlugin::ReflectionProbeGizmoPlugin() { - Color gizmo_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/reflection_probe", Color(0.6, 1, 0.5)); - - create_material("reflection_probe_material", gizmo_color); - - gizmo_color.a = 0.5; - create_material("reflection_internal_material", gizmo_color); - - gizmo_color.a = 0.1; - create_material("reflection_probe_solid_material", gizmo_color); - - create_icon_material("reflection_probe_icon", Node3DEditor::get_singleton()->get_theme_icon(SNAME("GizmoReflectionProbe"), SNAME("EditorIcons"))); - create_handle_material("handles"); -} - -bool ReflectionProbeGizmoPlugin::has_gizmo(Node3D *p_spatial) { - return Object::cast_to(p_spatial) != nullptr; -} - -String ReflectionProbeGizmoPlugin::get_gizmo_name() const { - return "ReflectionProbe"; -} - -int ReflectionProbeGizmoPlugin::get_priority() const { - return -1; -} - -String ReflectionProbeGizmoPlugin::get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const { - switch (p_id) { - case 0: - return "Size X"; - case 1: - return "Size Y"; - case 2: - return "Size Z"; - case 3: - return "Origin X"; - case 4: - return "Origin Y"; - case 5: - return "Origin Z"; - } - - return ""; -} - -Variant ReflectionProbeGizmoPlugin::get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const { - ReflectionProbe *probe = Object::cast_to(p_gizmo->get_node_3d()); - return AABB(probe->get_origin_offset(), probe->get_size()); -} - -void ReflectionProbeGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, Camera3D *p_camera, const Point2 &p_point) { - ReflectionProbe *probe = Object::cast_to(p_gizmo->get_node_3d()); - Transform3D gt = probe->get_global_transform(); - - Transform3D gi = gt.affine_inverse(); - - if (p_id < 3) { - Vector3 size = probe->get_size(); - - Vector3 ray_from = p_camera->project_ray_origin(p_point); - Vector3 ray_dir = p_camera->project_ray_normal(p_point); - - Vector3 sg[2] = { gi.xform(ray_from), gi.xform(ray_from + ray_dir * 16384) }; - - Vector3 axis; - axis[p_id] = 1.0; - - Vector3 ra, rb; - Geometry3D::get_closest_points_between_segments(Vector3(), axis * 16384, sg[0], sg[1], ra, rb); - float d = ra[p_id] * 2; - if (Node3DEditor::get_singleton()->is_snap_enabled()) { - d = Math::snapped(d, Node3DEditor::get_singleton()->get_translate_snap()); - } - - if (d < 0.001) { - d = 0.001; - } - - size[p_id] = d; - probe->set_size(size); - } else { - p_id -= 3; - - Vector3 origin = probe->get_origin_offset(); - origin[p_id] = 0; - - Vector3 ray_from = p_camera->project_ray_origin(p_point); - Vector3 ray_dir = p_camera->project_ray_normal(p_point); - - Vector3 sg[2] = { gi.xform(ray_from), gi.xform(ray_from + ray_dir * 16384) }; - - Vector3 axis; - axis[p_id] = 1.0; - - Vector3 ra, rb; - Geometry3D::get_closest_points_between_segments(origin - axis * 16384, origin + axis * 16384, sg[0], sg[1], ra, rb); - // Adjust the actual position to account for the gizmo handle position - float d = ra[p_id] + 0.25; - if (Node3DEditor::get_singleton()->is_snap_enabled()) { - d = Math::snapped(d, Node3DEditor::get_singleton()->get_translate_snap()); - } - - origin[p_id] = d; - probe->set_origin_offset(origin); - } -} - -void ReflectionProbeGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, const Variant &p_restore, bool p_cancel) { - ReflectionProbe *probe = Object::cast_to(p_gizmo->get_node_3d()); - - AABB restore = p_restore; - - if (p_cancel) { - probe->set_origin_offset(restore.position); - probe->set_size(restore.size); - return; - } - - EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton(); - ur->create_action(TTR("Change Probe Size")); - ur->add_do_method(probe, "set_size", probe->get_size()); - ur->add_do_method(probe, "set_origin_offset", probe->get_origin_offset()); - ur->add_undo_method(probe, "set_size", restore.size); - ur->add_undo_method(probe, "set_origin_offset", restore.position); - ur->commit_action(); -} - -void ReflectionProbeGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) { - ReflectionProbe *probe = Object::cast_to(p_gizmo->get_node_3d()); - - p_gizmo->clear(); - - Vector lines; - Vector internal_lines; - Vector3 size = probe->get_size(); - - AABB aabb; - aabb.position = -size / 2; - aabb.size = size; - - for (int i = 0; i < 12; i++) { - Vector3 a, b; - aabb.get_edge(i, a, b); - lines.push_back(a); - lines.push_back(b); - } - - for (int i = 0; i < 8; i++) { - Vector3 ep = aabb.get_endpoint(i); - internal_lines.push_back(probe->get_origin_offset()); - internal_lines.push_back(ep); - } - - Vector handles; - - for (int i = 0; i < 3; i++) { - Vector3 ax; - ax[i] = aabb.position[i] + aabb.size[i]; - handles.push_back(ax); - } - - for (int i = 0; i < 3; i++) { - Vector3 orig_handle = probe->get_origin_offset(); - orig_handle[i] -= 0.25; - lines.push_back(orig_handle); - handles.push_back(orig_handle); - - orig_handle[i] += 0.5; - lines.push_back(orig_handle); - } - - Ref material = get_material("reflection_probe_material", p_gizmo); - Ref material_internal = get_material("reflection_internal_material", p_gizmo); - Ref icon = get_material("reflection_probe_icon", p_gizmo); - - p_gizmo->add_lines(lines, material); - p_gizmo->add_lines(internal_lines, material_internal); - - if (p_gizmo->is_selected()) { - Ref solid_material = get_material("reflection_probe_solid_material", p_gizmo); - p_gizmo->add_solid_box(solid_material, probe->get_size()); - } - - p_gizmo->add_unscaled_billboard(icon, 0.05); - p_gizmo->add_handles(handles, get_material("handles")); -} - -/////////////////////////////// - -//// - -DecalGizmoPlugin::DecalGizmoPlugin() { - Color gizmo_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/decal", Color(0.6, 0.5, 1.0)); - - create_material("decal_material", gizmo_color); - - create_handle_material("handles"); -} - -bool DecalGizmoPlugin::has_gizmo(Node3D *p_spatial) { - return Object::cast_to(p_spatial) != nullptr; -} - -String DecalGizmoPlugin::get_gizmo_name() const { - return "Decal"; -} - -int DecalGizmoPlugin::get_priority() const { - return -1; -} - -String DecalGizmoPlugin::get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const { - switch (p_id) { - case 0: - return "Size X"; - case 1: - return "Size Y"; - case 2: - return "Size Z"; - } - - return ""; -} - -Variant DecalGizmoPlugin::get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const { - Decal *decal = Object::cast_to(p_gizmo->get_node_3d()); - return decal->get_size(); -} - -void DecalGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, Camera3D *p_camera, const Point2 &p_point) { - Decal *decal = Object::cast_to(p_gizmo->get_node_3d()); - Transform3D gt = decal->get_global_transform(); - - Transform3D gi = gt.affine_inverse(); - - Vector3 size = decal->get_size(); - - Vector3 ray_from = p_camera->project_ray_origin(p_point); - Vector3 ray_dir = p_camera->project_ray_normal(p_point); - - Vector3 sg[2] = { gi.xform(ray_from), gi.xform(ray_from + ray_dir * 16384) }; - - Vector3 axis; - axis[p_id] = 1.0; - - Vector3 ra, rb; - Geometry3D::get_closest_points_between_segments(Vector3(), axis * 16384, sg[0], sg[1], ra, rb); - float d = ra[p_id] * 2; - if (Node3DEditor::get_singleton()->is_snap_enabled()) { - d = Math::snapped(d, Node3DEditor::get_singleton()->get_translate_snap()); - } - - if (d < 0.001) { - d = 0.001; - } - - size[p_id] = d; - decal->set_size(size); -} - -void DecalGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, const Variant &p_restore, bool p_cancel) { - Decal *decal = Object::cast_to(p_gizmo->get_node_3d()); - - Vector3 restore = p_restore; - - if (p_cancel) { - decal->set_size(restore); - return; - } - - EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton(); - ur->create_action(TTR("Change Decal Size")); - ur->add_do_method(decal, "set_size", decal->get_size()); - ur->add_undo_method(decal, "set_size", restore); - ur->commit_action(); -} - -void DecalGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) { - Decal *decal = Object::cast_to(p_gizmo->get_node_3d()); - - p_gizmo->clear(); - - Vector lines; - Vector3 size = decal->get_size(); - - AABB aabb; - aabb.position = -size / 2; - aabb.size = size; - - for (int i = 0; i < 12; i++) { - Vector3 a, b; - aabb.get_edge(i, a, b); - if (a.y == b.y) { - lines.push_back(a); - lines.push_back(b); - } else { - Vector3 ah = a.lerp(b, 0.2); - lines.push_back(a); - lines.push_back(ah); - Vector3 bh = b.lerp(a, 0.2); - lines.push_back(b); - lines.push_back(bh); - } - } - - float half_size_y = size.y / 2; - lines.push_back(Vector3(0, half_size_y, 0)); - lines.push_back(Vector3(0, half_size_y * 1.2, 0)); - - Vector handles; - - for (int i = 0; i < 3; i++) { - Vector3 ax; - ax[i] = aabb.position[i] + aabb.size[i]; - handles.push_back(ax); - } - - Ref material = get_material("decal_material", p_gizmo); - - p_gizmo->add_lines(lines, material); - p_gizmo->add_handles(handles, get_material("handles")); -} - -/////////////////////////////// -VoxelGIGizmoPlugin::VoxelGIGizmoPlugin() { - Color gizmo_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/voxel_gi", Color(0.5, 1, 0.6)); - - create_material("voxel_gi_material", gizmo_color); - - // This gizmo draws a lot of lines. Use a low opacity to make it not too intrusive. - gizmo_color.a = 0.1; - create_material("voxel_gi_internal_material", gizmo_color); - - gizmo_color.a = 0.05; - create_material("voxel_gi_solid_material", gizmo_color); - - create_icon_material("voxel_gi_icon", Node3DEditor::get_singleton()->get_theme_icon(SNAME("GizmoVoxelGI"), SNAME("EditorIcons"))); - create_handle_material("handles"); -} - -bool VoxelGIGizmoPlugin::has_gizmo(Node3D *p_spatial) { - return Object::cast_to(p_spatial) != nullptr; -} - -String VoxelGIGizmoPlugin::get_gizmo_name() const { - return "VoxelGI"; -} - -int VoxelGIGizmoPlugin::get_priority() const { - return -1; -} - -String VoxelGIGizmoPlugin::get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const { - switch (p_id) { - case 0: - return "Size X"; - case 1: - return "Size Y"; - case 2: - return "Size Z"; - } - - return ""; -} - -Variant VoxelGIGizmoPlugin::get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const { - VoxelGI *probe = Object::cast_to(p_gizmo->get_node_3d()); - return probe->get_size(); -} - -void VoxelGIGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, Camera3D *p_camera, const Point2 &p_point) { - VoxelGI *probe = Object::cast_to(p_gizmo->get_node_3d()); - - Transform3D gt = probe->get_global_transform(); - Transform3D gi = gt.affine_inverse(); - - Vector3 size = probe->get_size(); - - Vector3 ray_from = p_camera->project_ray_origin(p_point); - Vector3 ray_dir = p_camera->project_ray_normal(p_point); - - Vector3 sg[2] = { gi.xform(ray_from), gi.xform(ray_from + ray_dir * 16384) }; - - Vector3 axis; - axis[p_id] = 1.0; - - Vector3 ra, rb; - Geometry3D::get_closest_points_between_segments(Vector3(), axis * 16384, sg[0], sg[1], ra, rb); - float d = ra[p_id] * 2; - if (Node3DEditor::get_singleton()->is_snap_enabled()) { - d = Math::snapped(d, Node3DEditor::get_singleton()->get_translate_snap()); - } - - if (d < 0.001) { - d = 0.001; - } - - size[p_id] = d; - probe->set_size(size); -} - -void VoxelGIGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, const Variant &p_restore, bool p_cancel) { - VoxelGI *probe = Object::cast_to(p_gizmo->get_node_3d()); - - Vector3 restore = p_restore; - - if (p_cancel) { - probe->set_size(restore); - return; - } - - EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton(); - ur->create_action(TTR("Change Probe Size")); - ur->add_do_method(probe, "set_size", probe->get_size()); - ur->add_undo_method(probe, "set_size", restore); - ur->commit_action(); -} - -void VoxelGIGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) { - VoxelGI *probe = Object::cast_to(p_gizmo->get_node_3d()); - - Ref material = get_material("voxel_gi_material", p_gizmo); - Ref icon = get_material("voxel_gi_icon", p_gizmo); - Ref material_internal = get_material("voxel_gi_internal_material", p_gizmo); - - p_gizmo->clear(); - - Vector lines; - Vector3 size = probe->get_size(); - - static const int subdivs[VoxelGI::SUBDIV_MAX] = { 64, 128, 256, 512 }; - - AABB aabb = AABB(-size / 2, size); - int subdiv = subdivs[probe->get_subdiv()]; - float cell_size = aabb.get_longest_axis_size() / subdiv; - - for (int i = 0; i < 12; i++) { - Vector3 a, b; - aabb.get_edge(i, a, b); - lines.push_back(a); - lines.push_back(b); - } - - p_gizmo->add_lines(lines, material); - - lines.clear(); - - for (int i = 1; i < subdiv; i++) { - for (int j = 0; j < 3; j++) { - if (cell_size * i > aabb.size[j]) { - continue; - } - - int j_n1 = (j + 1) % 3; - int j_n2 = (j + 2) % 3; - - for (int k = 0; k < 4; k++) { - Vector3 from = aabb.position, to = aabb.position; - from[j] += cell_size * i; - to[j] += cell_size * i; - - if (k & 1) { - to[j_n1] += aabb.size[j_n1]; - } else { - to[j_n2] += aabb.size[j_n2]; - } - - if (k & 2) { - from[j_n1] += aabb.size[j_n1]; - from[j_n2] += aabb.size[j_n2]; - } - - lines.push_back(from); - lines.push_back(to); - } - } - } - - p_gizmo->add_lines(lines, material_internal); - - Vector handles; - - for (int i = 0; i < 3; i++) { - Vector3 ax; - ax[i] = aabb.position[i] + aabb.size[i]; - handles.push_back(ax); - } - - if (p_gizmo->is_selected()) { - Ref solid_material = get_material("voxel_gi_solid_material", p_gizmo); - p_gizmo->add_solid_box(solid_material, aabb.get_size()); - } - - p_gizmo->add_unscaled_billboard(icon, 0.05); - p_gizmo->add_handles(handles, get_material("handles")); -} - -//// - -LightmapGIGizmoPlugin::LightmapGIGizmoPlugin() { - Color gizmo_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/lightmap_lines", Color(0.5, 0.6, 1)); - - gizmo_color.a = 0.1; - create_material("lightmap_lines", gizmo_color); - - Ref mat = memnew(StandardMaterial3D); - mat->set_shading_mode(StandardMaterial3D::SHADING_MODE_UNSHADED); - mat->set_cull_mode(StandardMaterial3D::CULL_DISABLED); - mat->set_flag(StandardMaterial3D::FLAG_ALBEDO_FROM_VERTEX_COLOR, true); - mat->set_flag(StandardMaterial3D::FLAG_SRGB_VERTEX_COLOR, false); - - add_material("lightmap_probe_material", mat); - - create_icon_material("baked_indirect_light_icon", Node3DEditor::get_singleton()->get_theme_icon(SNAME("GizmoLightmapGI"), SNAME("EditorIcons"))); -} - -bool LightmapGIGizmoPlugin::has_gizmo(Node3D *p_spatial) { - return Object::cast_to(p_spatial) != nullptr; -} - -String LightmapGIGizmoPlugin::get_gizmo_name() const { - return "LightmapGI"; -} - -int LightmapGIGizmoPlugin::get_priority() const { - return -1; -} - -void LightmapGIGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) { - Ref icon = get_material("baked_indirect_light_icon", p_gizmo); - LightmapGI *baker = Object::cast_to(p_gizmo->get_node_3d()); - Ref data = baker->get_light_data(); - - p_gizmo->add_unscaled_billboard(icon, 0.05); - - if (data.is_null()) { - return; - } - - Ref material_lines = get_material("lightmap_lines", p_gizmo); - Ref material_probes = get_material("lightmap_probe_material", p_gizmo); - - p_gizmo->clear(); - - Vector lines; - HashSet lines_found; - - Vector points = data->get_capture_points(); - if (points.size() == 0) { - return; - } - Vector sh = data->get_capture_sh(); - if (sh.size() != points.size() * 9) { - return; - } - - Vector tetrahedrons = data->get_capture_tetrahedra(); - - for (int i = 0; i < tetrahedrons.size(); i += 4) { - for (int j = 0; j < 4; j++) { - for (int k = j + 1; k < 4; k++) { - Vector2i pair; - pair.x = tetrahedrons[i + j]; - pair.y = tetrahedrons[i + k]; - - if (pair.y < pair.x) { - SWAP(pair.x, pair.y); - } - if (lines_found.has(pair)) { - continue; - } - lines_found.insert(pair); - lines.push_back(points[pair.x]); - lines.push_back(points[pair.y]); - } - } - } - - p_gizmo->add_lines(lines, material_lines); - - int stack_count = 8; - int sector_count = 16; - - float sector_step = (Math_PI * 2.0) / sector_count; - float stack_step = Math_PI / stack_count; - - Vector vertices; - Vector colors; - Vector indices; - float radius = 0.3; - - for (int p = 0; p < points.size(); p++) { - int vertex_base = vertices.size(); - Vector3 sh_col[9]; - for (int i = 0; i < 9; i++) { - sh_col[i].x = sh[p * 9 + i].r; - sh_col[i].y = sh[p * 9 + i].g; - sh_col[i].z = sh[p * 9 + i].b; - } - - for (int i = 0; i <= stack_count; ++i) { - float stack_angle = Math_PI / 2 - i * stack_step; // starting from pi/2 to -pi/2 - float xy = radius * Math::cos(stack_angle); // r * cos(u) - float z = radius * Math::sin(stack_angle); // r * sin(u) - - // add (sector_count+1) vertices per stack - // the first and last vertices have same position and normal, but different tex coords - for (int j = 0; j <= sector_count; ++j) { - float sector_angle = j * sector_step; // starting from 0 to 2pi - - // vertex position (x, y, z) - float x = xy * Math::cos(sector_angle); // r * cos(u) * cos(v) - float y = xy * Math::sin(sector_angle); // r * cos(u) * sin(v) - - Vector3 n = Vector3(x, z, y); - vertices.push_back(points[p] + n); - n.normalize(); - - const float c1 = 0.429043; - const float c2 = 0.511664; - const float c3 = 0.743125; - const float c4 = 0.886227; - const float c5 = 0.247708; - Vector3 light = (c1 * sh_col[8] * (n.x * n.x - n.y * n.y) + - c3 * sh_col[6] * n.z * n.z + - c4 * sh_col[0] - - c5 * sh_col[6] + - 2.0 * c1 * sh_col[4] * n.x * n.y + - 2.0 * c1 * sh_col[7] * n.x * n.z + - 2.0 * c1 * sh_col[5] * n.y * n.z + - 2.0 * c2 * sh_col[3] * n.x + - 2.0 * c2 * sh_col[1] * n.y + - 2.0 * c2 * sh_col[2] * n.z); - - colors.push_back(Color(light.x, light.y, light.z, 1)); - } - } - - for (int i = 0; i < stack_count; ++i) { - int k1 = i * (sector_count + 1); // beginning of current stack - int k2 = k1 + sector_count + 1; // beginning of next stack - - for (int j = 0; j < sector_count; ++j, ++k1, ++k2) { - // 2 triangles per sector excluding first and last stacks - // k1 => k2 => k1+1 - if (i != 0) { - indices.push_back(vertex_base + k1); - indices.push_back(vertex_base + k2); - indices.push_back(vertex_base + k1 + 1); - } - - // k1+1 => k2 => k2+1 - if (i != (stack_count - 1)) { - indices.push_back(vertex_base + k1 + 1); - indices.push_back(vertex_base + k2); - indices.push_back(vertex_base + k2 + 1); - } - } - } - } - - Array array; - array.resize(RS::ARRAY_MAX); - array[RS::ARRAY_VERTEX] = vertices; - array[RS::ARRAY_INDEX] = indices; - array[RS::ARRAY_COLOR] = colors; - - Ref mesh; - mesh.instantiate(); - mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, array, Array(), Dictionary(), 0); //no compression - mesh->surface_set_material(0, material_probes); - - p_gizmo->add_mesh(mesh); -} - -///////// - -LightmapProbeGizmoPlugin::LightmapProbeGizmoPlugin() { - Color gizmo_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/lightprobe_lines", Color(0.5, 0.6, 1)); - - gizmo_color.a = 0.3; - create_material("lightprobe_lines", gizmo_color); -} - -bool LightmapProbeGizmoPlugin::has_gizmo(Node3D *p_spatial) { - return Object::cast_to(p_spatial) != nullptr; -} - -String LightmapProbeGizmoPlugin::get_gizmo_name() const { - return "LightmapProbe"; -} - -int LightmapProbeGizmoPlugin::get_priority() const { - return -1; -} - -void LightmapProbeGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) { - Ref material_lines = get_material("lightprobe_lines", p_gizmo); - - p_gizmo->clear(); - - Vector lines; - - int stack_count = 8; - int sector_count = 16; - - float sector_step = (Math_PI * 2.0) / sector_count; - float stack_step = Math_PI / stack_count; - - Vector vertices; - float radius = 0.2; - - for (int i = 0; i <= stack_count; ++i) { - float stack_angle = Math_PI / 2 - i * stack_step; // starting from pi/2 to -pi/2 - float xy = radius * Math::cos(stack_angle); // r * cos(u) - float z = radius * Math::sin(stack_angle); // r * sin(u) - - // add (sector_count+1) vertices per stack - // the first and last vertices have same position and normal, but different tex coords - for (int j = 0; j <= sector_count; ++j) { - float sector_angle = j * sector_step; // starting from 0 to 2pi - - // vertex position (x, y, z) - float x = xy * Math::cos(sector_angle); // r * cos(u) * cos(v) - float y = xy * Math::sin(sector_angle); // r * cos(u) * sin(v) - - Vector3 n = Vector3(x, z, y); - vertices.push_back(n); - } - } - - for (int i = 0; i < stack_count; ++i) { - int k1 = i * (sector_count + 1); // beginning of current stack - int k2 = k1 + sector_count + 1; // beginning of next stack - - for (int j = 0; j < sector_count; ++j, ++k1, ++k2) { - // 2 triangles per sector excluding first and last stacks - // k1 => k2 => k1+1 - if (i != 0) { - lines.push_back(vertices[k1]); - lines.push_back(vertices[k2]); - lines.push_back(vertices[k1]); - lines.push_back(vertices[k1 + 1]); - } - - if (i != (stack_count - 1)) { - lines.push_back(vertices[k1 + 1]); - lines.push_back(vertices[k2]); - lines.push_back(vertices[k2]); - lines.push_back(vertices[k2 + 1]); - } - } - } - - p_gizmo->add_lines(lines, material_lines); -} - -//// - -CollisionObject3DGizmoPlugin::CollisionObject3DGizmoPlugin() { - const Color gizmo_color = EDITOR_GET("editors/3d_gizmos/gizmo_colors/shape"); - create_material("shape_material", gizmo_color); - const float gizmo_value = gizmo_color.get_v(); - const Color gizmo_color_disabled = Color(gizmo_value, gizmo_value, gizmo_value, 0.65); - create_material("shape_material_disabled", gizmo_color_disabled); -} - -bool CollisionObject3DGizmoPlugin::has_gizmo(Node3D *p_spatial) { - return Object::cast_to(p_spatial) != nullptr; -} - -String CollisionObject3DGizmoPlugin::get_gizmo_name() const { - return "CollisionObject3D"; -} - -int CollisionObject3DGizmoPlugin::get_priority() const { - return -2; -} - -void CollisionObject3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) { - CollisionObject3D *co = Object::cast_to(p_gizmo->get_node_3d()); - - p_gizmo->clear(); - - List owner_ids; - co->get_shape_owners(&owner_ids); - for (uint32_t &owner_id : owner_ids) { - Transform3D xform = co->shape_owner_get_transform(owner_id); - Object *owner = co->shape_owner_get_owner(owner_id); - // Exclude CollisionShape3D and CollisionPolygon3D as they have their gizmo. - if (!Object::cast_to(owner) && !Object::cast_to(owner)) { - Ref material = get_material(!co->is_shape_owner_disabled(owner_id) ? "shape_material" : "shape_material_disabled", p_gizmo); - for (int shape_id = 0; shape_id < co->shape_owner_get_shape_count(owner_id); shape_id++) { - Ref s = co->shape_owner_get_shape(owner_id, shape_id); - if (s.is_null()) { - continue; - } - SurfaceTool st; - st.append_from(s->get_debug_mesh(), 0, xform); - - p_gizmo->add_mesh(st.commit(), material); - p_gizmo->add_collision_segments(s->get_debug_mesh_lines()); - } - } - } -} - -//// - -CollisionShape3DGizmoPlugin::CollisionShape3DGizmoPlugin() { - const Color gizmo_color = EDITOR_GET("editors/3d_gizmos/gizmo_colors/shape"); - create_material("shape_material", gizmo_color); - const float gizmo_value = gizmo_color.get_v(); - const Color gizmo_color_disabled = Color(gizmo_value, gizmo_value, gizmo_value, 0.65); - create_material("shape_material_disabled", gizmo_color_disabled); - create_handle_material("handles"); -} - -bool CollisionShape3DGizmoPlugin::has_gizmo(Node3D *p_spatial) { - return Object::cast_to(p_spatial) != nullptr; -} - -String CollisionShape3DGizmoPlugin::get_gizmo_name() const { - return "CollisionShape3D"; -} - -int CollisionShape3DGizmoPlugin::get_priority() const { - return -1; -} - -String CollisionShape3DGizmoPlugin::get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const { - const CollisionShape3D *cs = Object::cast_to(p_gizmo->get_node_3d()); - - Ref s = cs->get_shape(); - if (s.is_null()) { - return ""; - } - - if (Object::cast_to(*s)) { - return "Radius"; - } - - if (Object::cast_to(*s)) { - return "Size"; - } - - if (Object::cast_to(*s)) { - return p_id == 0 ? "Radius" : "Height"; - } - - if (Object::cast_to(*s)) { - return p_id == 0 ? "Radius" : "Height"; - } - - if (Object::cast_to(*s)) { - return "Length"; - } - - return ""; -} - -Variant CollisionShape3DGizmoPlugin::get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const { - CollisionShape3D *cs = Object::cast_to(p_gizmo->get_node_3d()); - - Ref s = cs->get_shape(); - if (s.is_null()) { - return Variant(); - } - - if (Object::cast_to(*s)) { - Ref ss = s; - return ss->get_radius(); - } - - if (Object::cast_to(*s)) { - Ref bs = s; - return bs->get_size(); - } - - if (Object::cast_to(*s)) { - Ref cs2 = s; - return Vector2(cs2->get_radius(), cs2->get_height()); - } - - if (Object::cast_to(*s)) { - Ref cs2 = s; - return p_id == 0 ? cs2->get_radius() : cs2->get_height(); - } - - if (Object::cast_to(*s)) { - Ref cs2 = s; - return cs2->get_length(); - } - - return Variant(); -} - -void CollisionShape3DGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, Camera3D *p_camera, const Point2 &p_point) { - CollisionShape3D *cs = Object::cast_to(p_gizmo->get_node_3d()); - - Ref s = cs->get_shape(); - if (s.is_null()) { - return; - } - - Transform3D gt = cs->get_global_transform(); - Transform3D gi = gt.affine_inverse(); - - Vector3 ray_from = p_camera->project_ray_origin(p_point); - Vector3 ray_dir = p_camera->project_ray_normal(p_point); - - Vector3 sg[2] = { gi.xform(ray_from), gi.xform(ray_from + ray_dir * 4096) }; - - if (Object::cast_to(*s)) { - Ref ss = s; - Vector3 ra, rb; - Geometry3D::get_closest_points_between_segments(Vector3(), Vector3(4096, 0, 0), sg[0], sg[1], ra, rb); - float d = ra.x; - if (Node3DEditor::get_singleton()->is_snap_enabled()) { - d = Math::snapped(d, Node3DEditor::get_singleton()->get_translate_snap()); - } - - if (d < 0.001) { - d = 0.001; - } - - ss->set_radius(d); - } - - if (Object::cast_to(*s)) { - Ref rs = s; - Vector3 ra, rb; - Geometry3D::get_closest_points_between_segments(Vector3(), Vector3(0, 0, 4096), sg[0], sg[1], ra, rb); - float d = ra.z; - if (Node3DEditor::get_singleton()->is_snap_enabled()) { - d = Math::snapped(d, Node3DEditor::get_singleton()->get_translate_snap()); - } - - if (d < 0.001) { - d = 0.001; - } - - rs->set_length(d); - } - - if (Object::cast_to(*s)) { - Vector3 axis; - axis[p_id] = 1.0; - Ref bs = s; - Vector3 ra, rb; - Geometry3D::get_closest_points_between_segments(Vector3(), axis * 4096, sg[0], sg[1], ra, rb); - float d = ra[p_id] * 2; - if (Node3DEditor::get_singleton()->is_snap_enabled()) { - d = Math::snapped(d, Node3DEditor::get_singleton()->get_translate_snap()); - } - - if (d < 0.001) { - d = 0.001; - } - - Vector3 he = bs->get_size(); - he[p_id] = d; - bs->set_size(he); - } - - if (Object::cast_to(*s)) { - Vector3 axis; - axis[p_id == 0 ? 0 : 1] = 1.0; - Ref cs2 = s; - Vector3 ra, rb; - Geometry3D::get_closest_points_between_segments(Vector3(), axis * 4096, sg[0], sg[1], ra, rb); - float d = axis.dot(ra); - - if (Node3DEditor::get_singleton()->is_snap_enabled()) { - d = Math::snapped(d, Node3DEditor::get_singleton()->get_translate_snap()); - } - - if (d < 0.001) { - d = 0.001; - } - - if (p_id == 0) { - cs2->set_radius(d); - } else if (p_id == 1) { - cs2->set_height(d * 2.0); - } - } - - if (Object::cast_to(*s)) { - Vector3 axis; - axis[p_id == 0 ? 0 : 1] = 1.0; - Ref cs2 = s; - Vector3 ra, rb; - Geometry3D::get_closest_points_between_segments(Vector3(), axis * 4096, sg[0], sg[1], ra, rb); - float d = axis.dot(ra); - if (Node3DEditor::get_singleton()->is_snap_enabled()) { - d = Math::snapped(d, Node3DEditor::get_singleton()->get_translate_snap()); - } - - if (d < 0.001) { - d = 0.001; - } - - if (p_id == 0) { - cs2->set_radius(d); - } else if (p_id == 1) { - cs2->set_height(d * 2.0); - } - } -} - -void CollisionShape3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, const Variant &p_restore, bool p_cancel) { - CollisionShape3D *cs = Object::cast_to(p_gizmo->get_node_3d()); - - Ref s = cs->get_shape(); - if (s.is_null()) { - return; - } - - if (Object::cast_to(*s)) { - Ref ss = s; - if (p_cancel) { - ss->set_radius(p_restore); - return; - } - - EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton(); - ur->create_action(TTR("Change Sphere Shape Radius")); - ur->add_do_method(ss.ptr(), "set_radius", ss->get_radius()); - ur->add_undo_method(ss.ptr(), "set_radius", p_restore); - ur->commit_action(); - } - - if (Object::cast_to(*s)) { - Ref ss = s; - if (p_cancel) { - ss->set_size(p_restore); - return; - } - - EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton(); - ur->create_action(TTR("Change Box Shape Size")); - ur->add_do_method(ss.ptr(), "set_size", ss->get_size()); - ur->add_undo_method(ss.ptr(), "set_size", p_restore); - ur->commit_action(); - } - - if (Object::cast_to(*s)) { - Ref ss = s; - Vector2 values = p_restore; - - if (p_cancel) { - ss->set_radius(values[0]); - ss->set_height(values[1]); - return; - } - - EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton(); - if (p_id == 0) { - ur->create_action(TTR("Change Capsule Shape Radius")); - ur->add_do_method(ss.ptr(), "set_radius", ss->get_radius()); - } else { - ur->create_action(TTR("Change Capsule Shape Height")); - ur->add_do_method(ss.ptr(), "set_height", ss->get_height()); - } - ur->add_undo_method(ss.ptr(), "set_radius", values[0]); - ur->add_undo_method(ss.ptr(), "set_height", values[1]); - - ur->commit_action(); - } - - if (Object::cast_to(*s)) { - Ref ss = s; - if (p_cancel) { - if (p_id == 0) { - ss->set_radius(p_restore); - } else { - ss->set_height(p_restore); - } - return; - } - - EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton(); - if (p_id == 0) { - ur->create_action(TTR("Change Cylinder Shape Radius")); - ur->add_do_method(ss.ptr(), "set_radius", ss->get_radius()); - ur->add_undo_method(ss.ptr(), "set_radius", p_restore); - } else { - ur->create_action( - /// - - //////// - TTR("Change Cylinder Shape Height")); - ur->add_do_method(ss.ptr(), "set_height", ss->get_height()); - ur->add_undo_method(ss.ptr(), "set_height", p_restore); - } - - ur->commit_action(); - } - - if (Object::cast_to(*s)) { - Ref ss = s; - if (p_cancel) { - ss->set_length(p_restore); - return; - } - - EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton(); - ur->create_action(TTR("Change Separation Ray Shape Length")); - ur->add_do_method(ss.ptr(), "set_length", ss->get_length()); - ur->add_undo_method(ss.ptr(), "set_length", p_restore); - ur->commit_action(); - } -} - -void CollisionShape3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) { - CollisionShape3D *cs = Object::cast_to(p_gizmo->get_node_3d()); - - p_gizmo->clear(); - - Ref s = cs->get_shape(); - if (s.is_null()) { - return; - } - - const Ref material = - get_material(!cs->is_disabled() ? "shape_material" : "shape_material_disabled", p_gizmo); - Ref handles_material = get_material("handles"); - - if (Object::cast_to(*s)) { - Ref sp = s; - float r = sp->get_radius(); - - Vector points; - - for (int i = 0; i <= 360; i++) { - float ra = Math::deg_to_rad((float)i); - float rb = Math::deg_to_rad((float)i + 1); - Point2 a = Vector2(Math::sin(ra), Math::cos(ra)) * r; - Point2 b = Vector2(Math::sin(rb), Math::cos(rb)) * r; - - points.push_back(Vector3(a.x, 0, a.y)); - points.push_back(Vector3(b.x, 0, b.y)); - points.push_back(Vector3(0, a.x, a.y)); - points.push_back(Vector3(0, b.x, b.y)); - points.push_back(Vector3(a.x, a.y, 0)); - points.push_back(Vector3(b.x, b.y, 0)); - } - - Vector collision_segments; - - for (int i = 0; i < 64; i++) { - float ra = i * (Math_TAU / 64.0); - float rb = (i + 1) * (Math_TAU / 64.0); - Point2 a = Vector2(Math::sin(ra), Math::cos(ra)) * r; - Point2 b = Vector2(Math::sin(rb), Math::cos(rb)) * r; - - collision_segments.push_back(Vector3(a.x, 0, a.y)); - collision_segments.push_back(Vector3(b.x, 0, b.y)); - collision_segments.push_back(Vector3(0, a.x, a.y)); - collision_segments.push_back(Vector3(0, b.x, b.y)); - collision_segments.push_back(Vector3(a.x, a.y, 0)); - collision_segments.push_back(Vector3(b.x, b.y, 0)); - } - - p_gizmo->add_lines(points, material); - p_gizmo->add_collision_segments(collision_segments); - Vector handles; - handles.push_back(Vector3(r, 0, 0)); - p_gizmo->add_handles(handles, handles_material); - } - - if (Object::cast_to(*s)) { - Ref bs = s; - Vector lines; - AABB aabb; - aabb.position = -bs->get_size() / 2; - aabb.size = bs->get_size(); - - for (int i = 0; i < 12; i++) { - Vector3 a, b; - aabb.get_edge(i, a, b); - lines.push_back(a); - lines.push_back(b); - } - - Vector handles; - - for (int i = 0; i < 3; i++) { - Vector3 ax; - ax[i] = bs->get_size()[i] / 2; - handles.push_back(ax); - } - - p_gizmo->add_lines(lines, material); - p_gizmo->add_collision_segments(lines); - p_gizmo->add_handles(handles, handles_material); - } - - if (Object::cast_to(*s)) { - Ref cs2 = s; - float radius = cs2->get_radius(); - float height = cs2->get_height(); - - Vector points; - - Vector3 d(0, height * 0.5 - radius, 0); - for (int i = 0; i < 360; i++) { - float ra = Math::deg_to_rad((float)i); - float rb = Math::deg_to_rad((float)i + 1); - Point2 a = Vector2(Math::sin(ra), Math::cos(ra)) * radius; - Point2 b = Vector2(Math::sin(rb), Math::cos(rb)) * radius; - - points.push_back(Vector3(a.x, 0, a.y) + d); - points.push_back(Vector3(b.x, 0, b.y) + d); - - points.push_back(Vector3(a.x, 0, a.y) - d); - points.push_back(Vector3(b.x, 0, b.y) - d); - - if (i % 90 == 0) { - points.push_back(Vector3(a.x, 0, a.y) + d); - points.push_back(Vector3(a.x, 0, a.y) - d); - } - - Vector3 dud = i < 180 ? d : -d; - - points.push_back(Vector3(0, a.x, a.y) + dud); - points.push_back(Vector3(0, b.x, b.y) + dud); - points.push_back(Vector3(a.y, a.x, 0) + dud); - points.push_back(Vector3(b.y, b.x, 0) + dud); - } - - p_gizmo->add_lines(points, material); - - Vector collision_segments; - - for (int i = 0; i < 64; i++) { - float ra = i * (Math_TAU / 64.0); - float rb = (i + 1) * (Math_TAU / 64.0); - Point2 a = Vector2(Math::sin(ra), Math::cos(ra)) * radius; - Point2 b = Vector2(Math::sin(rb), Math::cos(rb)) * radius; - - collision_segments.push_back(Vector3(a.x, 0, a.y) + d); - collision_segments.push_back(Vector3(b.x, 0, b.y) + d); - - collision_segments.push_back(Vector3(a.x, 0, a.y) - d); - collision_segments.push_back(Vector3(b.x, 0, b.y) - d); - - if (i % 16 == 0) { - collision_segments.push_back(Vector3(a.x, 0, a.y) + d); - collision_segments.push_back(Vector3(a.x, 0, a.y) - d); - } - - Vector3 dud = i < 32 ? d : -d; - - collision_segments.push_back(Vector3(0, a.x, a.y) + dud); - collision_segments.push_back(Vector3(0, b.x, b.y) + dud); - collision_segments.push_back(Vector3(a.y, a.x, 0) + dud); - collision_segments.push_back(Vector3(b.y, b.x, 0) + dud); - } - - p_gizmo->add_collision_segments(collision_segments); - - Vector handles = { - Vector3(cs2->get_radius(), 0, 0), - Vector3(0, cs2->get_height() * 0.5, 0) - }; - p_gizmo->add_handles(handles, handles_material); - } - - if (Object::cast_to(*s)) { - Ref cs2 = s; - float radius = cs2->get_radius(); - float height = cs2->get_height(); - - Vector points; - - Vector3 d(0, height * 0.5, 0); - for (int i = 0; i < 360; i++) { - float ra = Math::deg_to_rad((float)i); - float rb = Math::deg_to_rad((float)i + 1); - Point2 a = Vector2(Math::sin(ra), Math::cos(ra)) * radius; - Point2 b = Vector2(Math::sin(rb), Math::cos(rb)) * radius; - - points.push_back(Vector3(a.x, 0, a.y) + d); - points.push_back(Vector3(b.x, 0, b.y) + d); - - points.push_back(Vector3(a.x, 0, a.y) - d); - points.push_back(Vector3(b.x, 0, b.y) - d); - - if (i % 90 == 0) { - points.push_back(Vector3(a.x, 0, a.y) + d); - points.push_back(Vector3(a.x, 0, a.y) - d); - } - } - - p_gizmo->add_lines(points, material); - - Vector collision_segments; - - for (int i = 0; i < 64; i++) { - float ra = i * (Math_TAU / 64.0); - float rb = (i + 1) * (Math_TAU / 64.0); - Point2 a = Vector2(Math::sin(ra), Math::cos(ra)) * radius; - Point2 b = Vector2(Math::sin(rb), Math::cos(rb)) * radius; - - collision_segments.push_back(Vector3(a.x, 0, a.y) + d); - collision_segments.push_back(Vector3(b.x, 0, b.y) + d); - - collision_segments.push_back(Vector3(a.x, 0, a.y) - d); - collision_segments.push_back(Vector3(b.x, 0, b.y) - d); - - if (i % 16 == 0) { - collision_segments.push_back(Vector3(a.x, 0, a.y) + d); - collision_segments.push_back(Vector3(a.x, 0, a.y) - d); - } - } - - p_gizmo->add_collision_segments(collision_segments); - - Vector handles = { - Vector3(cs2->get_radius(), 0, 0), - Vector3(0, cs2->get_height() * 0.5, 0) - }; - p_gizmo->add_handles(handles, handles_material); - } - - if (Object::cast_to(*s)) { - Ref wbs = s; - const Plane &p = wbs->get_plane(); - - Vector3 n1 = p.get_any_perpendicular_normal(); - Vector3 n2 = p.normal.cross(n1).normalized(); - - Vector3 pface[4] = { - p.normal * p.d + n1 * 10.0 + n2 * 10.0, - p.normal * p.d + n1 * 10.0 + n2 * -10.0, - p.normal * p.d + n1 * -10.0 + n2 * -10.0, - p.normal * p.d + n1 * -10.0 + n2 * 10.0, - }; - - Vector points = { - pface[0], - pface[1], - pface[1], - pface[2], - pface[2], - pface[3], - pface[3], - pface[0], - p.normal * p.d, - p.normal * p.d + p.normal * 3 - }; - - p_gizmo->add_lines(points, material); - p_gizmo->add_collision_segments(points); - } - - if (Object::cast_to(*s)) { - Vector points = Object::cast_to(*s)->get_points(); - - if (points.size() > 3) { - Vector varr = Variant(points); - Geometry3D::MeshData md; - Error err = ConvexHullComputer::convex_hull(varr, md); - if (err == OK) { - Vector points2; - points2.resize(md.edges.size() * 2); - for (uint32_t i = 0; i < md.edges.size(); i++) { - points2.write[i * 2 + 0] = md.vertices[md.edges[i].vertex_a]; - points2.write[i * 2 + 1] = md.vertices[md.edges[i].vertex_b]; - } - - p_gizmo->add_lines(points2, material); - p_gizmo->add_collision_segments(points2); - } - } - } - - if (Object::cast_to(*s)) { - Ref cs2 = s; - Ref mesh = cs2->get_debug_mesh(); - p_gizmo->add_mesh(mesh, material); - p_gizmo->add_collision_segments(cs2->get_debug_mesh_lines()); - } - - if (Object::cast_to(*s)) { - Ref rs = s; - - Vector points = { - Vector3(), - Vector3(0, 0, rs->get_length()) - }; - p_gizmo->add_lines(points, material); - p_gizmo->add_collision_segments(points); - Vector handles; - handles.push_back(Vector3(0, 0, rs->get_length())); - p_gizmo->add_handles(handles, handles_material); - } - - if (Object::cast_to(*s)) { - Ref hms = s; - - Ref mesh = hms->get_debug_mesh(); - p_gizmo->add_mesh(mesh, material); - } -} - -///// - -CollisionPolygon3DGizmoPlugin::CollisionPolygon3DGizmoPlugin() { - const Color gizmo_color = EDITOR_GET("editors/3d_gizmos/gizmo_colors/shape"); - create_material("shape_material", gizmo_color); - const float gizmo_value = gizmo_color.get_v(); - const Color gizmo_color_disabled = Color(gizmo_value, gizmo_value, gizmo_value, 0.65); - create_material("shape_material_disabled", gizmo_color_disabled); -} - -bool CollisionPolygon3DGizmoPlugin::has_gizmo(Node3D *p_spatial) { - return Object::cast_to(p_spatial) != nullptr; -} - -String CollisionPolygon3DGizmoPlugin::get_gizmo_name() const { - return "CollisionPolygon3D"; -} - -int CollisionPolygon3DGizmoPlugin::get_priority() const { - return -1; -} - -void CollisionPolygon3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) { - CollisionPolygon3D *polygon = Object::cast_to(p_gizmo->get_node_3d()); - - p_gizmo->clear(); - - Vector points = polygon->get_polygon(); - float depth = polygon->get_depth() * 0.5; - - Vector lines; - for (int i = 0; i < points.size(); i++) { - int n = (i + 1) % points.size(); - lines.push_back(Vector3(points[i].x, points[i].y, depth)); - lines.push_back(Vector3(points[n].x, points[n].y, depth)); - lines.push_back(Vector3(points[i].x, points[i].y, -depth)); - lines.push_back(Vector3(points[n].x, points[n].y, -depth)); - lines.push_back(Vector3(points[i].x, points[i].y, depth)); - lines.push_back(Vector3(points[i].x, points[i].y, -depth)); - } - - const Ref material = - get_material(!polygon->is_disabled() ? "shape_material" : "shape_material_disabled", p_gizmo); - - p_gizmo->add_lines(lines, material); - p_gizmo->add_collision_segments(lines); -} - -//// - -NavigationRegion3DGizmoPlugin::NavigationRegion3DGizmoPlugin() { - create_material("face_material", NavigationServer3D::get_singleton()->get_debug_navigation_geometry_face_color(), false, false, true); - create_material("face_material_disabled", NavigationServer3D::get_singleton()->get_debug_navigation_geometry_face_disabled_color(), false, false, true); - create_material("edge_material", NavigationServer3D::get_singleton()->get_debug_navigation_geometry_edge_color()); - create_material("edge_material_disabled", NavigationServer3D::get_singleton()->get_debug_navigation_geometry_edge_disabled_color()); - - Color baking_aabb_material_color = Color(0.8, 0.5, 0.7); - baking_aabb_material_color.a = 0.1; - create_material("baking_aabb_material", baking_aabb_material_color); -} - -bool NavigationRegion3DGizmoPlugin::has_gizmo(Node3D *p_spatial) { - return Object::cast_to(p_spatial) != nullptr; -} - -String NavigationRegion3DGizmoPlugin::get_gizmo_name() const { - return "NavigationRegion3D"; -} - -int NavigationRegion3DGizmoPlugin::get_priority() const { - return -1; -} - -void NavigationRegion3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) { - NavigationRegion3D *navigationregion = Object::cast_to(p_gizmo->get_node_3d()); - - p_gizmo->clear(); - Ref navigationmesh = navigationregion->get_navigation_mesh(); - if (navigationmesh.is_null()) { - return; - } - - AABB baking_aabb = navigationmesh->get_filter_baking_aabb(); - if (baking_aabb.has_volume()) { - Vector3 baking_aabb_offset = navigationmesh->get_filter_baking_aabb_offset(); - - if (p_gizmo->is_selected()) { - Ref material = get_material("baking_aabb_material", p_gizmo); - p_gizmo->add_solid_box(material, baking_aabb.get_size(), baking_aabb.get_center() + baking_aabb_offset); - } - } - - Vector vertices = navigationmesh->get_vertices(); - const Vector3 *vr = vertices.ptr(); - List faces; - for (int i = 0; i < navigationmesh->get_polygon_count(); i++) { - Vector p = navigationmesh->get_polygon(i); - - for (int j = 2; j < p.size(); j++) { - Face3 f; - f.vertex[0] = vr[p[0]]; - f.vertex[1] = vr[p[j - 1]]; - f.vertex[2] = vr[p[j]]; - - faces.push_back(f); - } - } - - if (faces.is_empty()) { - return; - } - - HashMap<_EdgeKey, bool, _EdgeKey> edge_map; - Vector tmeshfaces; - tmeshfaces.resize(faces.size() * 3); - - { - Vector3 *tw = tmeshfaces.ptrw(); - int tidx = 0; - - for (const Face3 &f : faces) { - for (int j = 0; j < 3; j++) { - tw[tidx++] = f.vertex[j]; - _EdgeKey ek; - ek.from = f.vertex[j].snapped(Vector3(CMP_EPSILON, CMP_EPSILON, CMP_EPSILON)); - ek.to = f.vertex[(j + 1) % 3].snapped(Vector3(CMP_EPSILON, CMP_EPSILON, CMP_EPSILON)); - if (ek.from < ek.to) { - SWAP(ek.from, ek.to); - } - - HashMap<_EdgeKey, bool, _EdgeKey>::Iterator F = edge_map.find(ek); - - if (F) { - F->value = false; - - } else { - edge_map[ek] = true; - } - } - } - } - Vector lines; - - for (const KeyValue<_EdgeKey, bool> &E : edge_map) { - if (E.value) { - lines.push_back(E.key.from); - lines.push_back(E.key.to); - } - } - - Ref tmesh = memnew(TriangleMesh); - tmesh->create(tmeshfaces); - - p_gizmo->add_collision_triangles(tmesh); - p_gizmo->add_collision_segments(lines); - - Ref debug_mesh = Ref(memnew(ArrayMesh)); - int polygon_count = navigationmesh->get_polygon_count(); - - // build geometry face surface - Vector face_vertex_array; - face_vertex_array.resize(polygon_count * 3); - - for (int i = 0; i < polygon_count; i++) { - Vector polygon = navigationmesh->get_polygon(i); - - face_vertex_array.push_back(vertices[polygon[0]]); - face_vertex_array.push_back(vertices[polygon[1]]); - face_vertex_array.push_back(vertices[polygon[2]]); - } - - Array face_mesh_array; - face_mesh_array.resize(Mesh::ARRAY_MAX); - face_mesh_array[Mesh::ARRAY_VERTEX] = face_vertex_array; - - // if enabled add vertex colors to colorize each face individually - RandomPCG rand; - bool enabled_geometry_face_random_color = NavigationServer3D::get_singleton()->get_debug_navigation_enable_geometry_face_random_color(); - if (enabled_geometry_face_random_color) { - Color debug_navigation_geometry_face_color = NavigationServer3D::get_singleton()->get_debug_navigation_geometry_face_color(); - Color polygon_color = debug_navigation_geometry_face_color; - - Vector face_color_array; - face_color_array.resize(polygon_count * 3); - - for (int i = 0; i < polygon_count; i++) { - // Generate the polygon color, slightly randomly modified from the settings one. - polygon_color.set_hsv(debug_navigation_geometry_face_color.get_h() + rand.random(-1.0, 1.0) * 0.1, debug_navigation_geometry_face_color.get_s(), debug_navigation_geometry_face_color.get_v() + rand.random(-1.0, 1.0) * 0.2); - polygon_color.a = debug_navigation_geometry_face_color.a; - - Vector polygon = navigationmesh->get_polygon(i); - - face_color_array.push_back(polygon_color); - face_color_array.push_back(polygon_color); - face_color_array.push_back(polygon_color); - } - face_mesh_array[Mesh::ARRAY_COLOR] = face_color_array; - } - - debug_mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, face_mesh_array); - p_gizmo->add_mesh(debug_mesh, navigationregion->is_enabled() ? get_material("face_material", p_gizmo) : get_material("face_material_disabled", p_gizmo)); - - // if enabled build geometry edge line surface - bool enabled_edge_lines = NavigationServer3D::get_singleton()->get_debug_navigation_enable_edge_lines(); - if (enabled_edge_lines) { - Vector line_vertex_array; - line_vertex_array.resize(polygon_count * 6); - - for (int i = 0; i < polygon_count; i++) { - Vector polygon = navigationmesh->get_polygon(i); - - line_vertex_array.push_back(vertices[polygon[0]]); - line_vertex_array.push_back(vertices[polygon[1]]); - line_vertex_array.push_back(vertices[polygon[1]]); - line_vertex_array.push_back(vertices[polygon[2]]); - line_vertex_array.push_back(vertices[polygon[2]]); - line_vertex_array.push_back(vertices[polygon[0]]); - } - - p_gizmo->add_lines(line_vertex_array, navigationregion->is_enabled() ? get_material("edge_material", p_gizmo) : get_material("edge_material_disabled", p_gizmo)); - } -} - -//// - -NavigationLink3DGizmoPlugin::NavigationLink3DGizmoPlugin() { - create_material("navigation_link_material", NavigationServer3D::get_singleton()->get_debug_navigation_link_connection_color()); - create_material("navigation_link_material_disabled", NavigationServer3D::get_singleton()->get_debug_navigation_link_connection_disabled_color()); - create_handle_material("handles"); -} - -bool NavigationLink3DGizmoPlugin::has_gizmo(Node3D *p_spatial) { - return Object::cast_to(p_spatial) != nullptr; -} - -String NavigationLink3DGizmoPlugin::get_gizmo_name() const { - return "NavigationLink3D"; -} - -int NavigationLink3DGizmoPlugin::get_priority() const { - return -1; -} - -void NavigationLink3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) { - NavigationLink3D *link = Object::cast_to(p_gizmo->get_node_3d()); - - RID nav_map = link->get_world_3d()->get_navigation_map(); - real_t search_radius = NavigationServer3D::get_singleton()->map_get_link_connection_radius(nav_map); - Vector3 up_vector = NavigationServer3D::get_singleton()->map_get_up(nav_map); - Vector3::Axis up_axis = up_vector.max_axis_index(); - - Vector3 start_position = link->get_start_position(); - Vector3 end_position = link->get_end_position(); - - Ref link_material = get_material("navigation_link_material", p_gizmo); - Ref link_material_disabled = get_material("navigation_link_material_disabled", p_gizmo); - Ref handles_material = get_material("handles"); - - p_gizmo->clear(); - - // Draw line between the points. - Vector lines; - lines.append(start_position); - lines.append(end_position); - - // Draw start position search radius - for (int i = 0; i < 30; i++) { - // Create a circle - const float ra = Math::deg_to_rad((float)(i * 12)); - const float rb = Math::deg_to_rad((float)((i + 1) * 12)); - const Point2 a = Vector2(Math::sin(ra), Math::cos(ra)) * search_radius; - const Point2 b = Vector2(Math::sin(rb), Math::cos(rb)) * search_radius; - - // Draw axis-aligned circle - switch (up_axis) { - case Vector3::AXIS_X: - lines.append(start_position + Vector3(0, a.x, a.y)); - lines.append(start_position + Vector3(0, b.x, b.y)); - break; - case Vector3::AXIS_Y: - lines.append(start_position + Vector3(a.x, 0, a.y)); - lines.append(start_position + Vector3(b.x, 0, b.y)); - break; - case Vector3::AXIS_Z: - lines.append(start_position + Vector3(a.x, a.y, 0)); - lines.append(start_position + Vector3(b.x, b.y, 0)); - break; - } - } - - // Draw end position search radius - for (int i = 0; i < 30; i++) { - // Create a circle - const float ra = Math::deg_to_rad((float)(i * 12)); - const float rb = Math::deg_to_rad((float)((i + 1) * 12)); - const Point2 a = Vector2(Math::sin(ra), Math::cos(ra)) * search_radius; - const Point2 b = Vector2(Math::sin(rb), Math::cos(rb)) * search_radius; - - // Draw axis-aligned circle - switch (up_axis) { - case Vector3::AXIS_X: - lines.append(end_position + Vector3(0, a.x, a.y)); - lines.append(end_position + Vector3(0, b.x, b.y)); - break; - case Vector3::AXIS_Y: - lines.append(end_position + Vector3(a.x, 0, a.y)); - lines.append(end_position + Vector3(b.x, 0, b.y)); - break; - case Vector3::AXIS_Z: - lines.append(end_position + Vector3(a.x, a.y, 0)); - lines.append(end_position + Vector3(b.x, b.y, 0)); - break; - } - } - - p_gizmo->add_lines(lines, link->is_enabled() ? link_material : link_material_disabled); - p_gizmo->add_collision_segments(lines); - - Vector handles; - handles.append(start_position); - handles.append(end_position); - p_gizmo->add_handles(handles, handles_material); -} - -String NavigationLink3DGizmoPlugin::get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const { - return p_id == 0 ? TTR("Start Location") : TTR("End Location"); -} - -Variant NavigationLink3DGizmoPlugin::get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const { - NavigationLink3D *link = Object::cast_to(p_gizmo->get_node_3d()); - return p_id == 0 ? link->get_start_position() : link->get_end_position(); -} - -void NavigationLink3DGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, Camera3D *p_camera, const Point2 &p_point) { - NavigationLink3D *link = Object::cast_to(p_gizmo->get_node_3d()); - - Transform3D gt = link->get_global_transform(); - Transform3D gi = gt.affine_inverse(); - - Transform3D ct = p_camera->get_global_transform(); - Vector3 cam_dir = ct.basis.get_column(Vector3::AXIS_Z); - - Vector3 ray_from = p_camera->project_ray_origin(p_point); - Vector3 ray_dir = p_camera->project_ray_normal(p_point); - - Vector3 position = p_id == 0 ? link->get_start_position() : link->get_end_position(); - Plane move_plane = Plane(cam_dir, gt.xform(position)); - - Vector3 intersection; - if (!move_plane.intersects_ray(ray_from, ray_dir, &intersection)) { - return; - } - - if (Node3DEditor::get_singleton()->is_snap_enabled()) { - double snap = Node3DEditor::get_singleton()->get_translate_snap(); - intersection.snap(Vector3(snap, snap, snap)); - } - - position = gi.xform(intersection); - if (p_id == 0) { - link->set_start_position(position); - } else if (p_id == 1) { - link->set_end_position(position); - } -} - -void NavigationLink3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, const Variant &p_restore, bool p_cancel) { - NavigationLink3D *link = Object::cast_to(p_gizmo->get_node_3d()); - - if (p_cancel) { - if (p_id == 0) { - link->set_start_position(p_restore); - } else { - link->set_end_position(p_restore); - } - return; - } - - EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton(); - if (p_id == 0) { - ur->create_action(TTR("Change Start Position")); - ur->add_do_method(link, "set_start_position", link->get_start_position()); - ur->add_undo_method(link, "set_start_position", p_restore); - } else { - ur->create_action(TTR("Change End Position")); - ur->add_do_method(link, "set_end_position", link->get_end_position()); - ur->add_undo_method(link, "set_end_position", p_restore); - } - - ur->commit_action(); -} - -////// - -#define BODY_A_RADIUS 0.25 -#define BODY_B_RADIUS 0.27 - -Basis JointGizmosDrawer::look_body(const Transform3D &p_joint_transform, const Transform3D &p_body_transform) { - const Vector3 &p_eye(p_joint_transform.origin); - const Vector3 &p_target(p_body_transform.origin); - - Vector3 v_x, v_y, v_z; - - // Look the body with X - v_x = p_target - p_eye; - v_x.normalize(); - - v_z = v_x.cross(Vector3(0, 1, 0)); - v_z.normalize(); - - v_y = v_z.cross(v_x); - v_y.normalize(); - - Basis base; - base.set_columns(v_x, v_y, v_z); - - // Absorb current joint transform - base = p_joint_transform.basis.inverse() * base; - - return base; -} - -Basis JointGizmosDrawer::look_body_toward(Vector3::Axis p_axis, const Transform3D &joint_transform, const Transform3D &body_transform) { - switch (p_axis) { - case Vector3::AXIS_X: - return look_body_toward_x(joint_transform, body_transform); - case Vector3::AXIS_Y: - return look_body_toward_y(joint_transform, body_transform); - case Vector3::AXIS_Z: - return look_body_toward_z(joint_transform, body_transform); - default: - return Basis(); - } -} - -Basis JointGizmosDrawer::look_body_toward_x(const Transform3D &p_joint_transform, const Transform3D &p_body_transform) { - const Vector3 &p_eye(p_joint_transform.origin); - const Vector3 &p_target(p_body_transform.origin); - - const Vector3 p_front(p_joint_transform.basis.get_column(0)); - - Vector3 v_x, v_y, v_z; - - // Look the body with X - v_x = p_target - p_eye; - v_x.normalize(); - - v_y = p_front.cross(v_x); - v_y.normalize(); - - v_z = v_y.cross(p_front); - v_z.normalize(); - - // Clamp X to FRONT axis - v_x = p_front; - v_x.normalize(); - - Basis base; - base.set_columns(v_x, v_y, v_z); - - // Absorb current joint transform - base = p_joint_transform.basis.inverse() * base; - - return base; -} - -Basis JointGizmosDrawer::look_body_toward_y(const Transform3D &p_joint_transform, const Transform3D &p_body_transform) { - const Vector3 &p_eye(p_joint_transform.origin); - const Vector3 &p_target(p_body_transform.origin); - - const Vector3 p_up(p_joint_transform.basis.get_column(1)); - - Vector3 v_x, v_y, v_z; - - // Look the body with X - v_x = p_target - p_eye; - v_x.normalize(); - - v_z = v_x.cross(p_up); - v_z.normalize(); - - v_x = p_up.cross(v_z); - v_x.normalize(); - - // Clamp Y to UP axis - v_y = p_up; - v_y.normalize(); - - Basis base; - base.set_columns(v_x, v_y, v_z); - - // Absorb current joint transform - base = p_joint_transform.basis.inverse() * base; - - return base; -} - -Basis JointGizmosDrawer::look_body_toward_z(const Transform3D &p_joint_transform, const Transform3D &p_body_transform) { - const Vector3 &p_eye(p_joint_transform.origin); - const Vector3 &p_target(p_body_transform.origin); - - const Vector3 p_lateral(p_joint_transform.basis.get_column(2)); - - Vector3 v_x, v_y, v_z; - - // Look the body with X - v_x = p_target - p_eye; - v_x.normalize(); - - v_z = p_lateral; - v_z.normalize(); - - v_y = v_z.cross(v_x); - v_y.normalize(); - - // Clamp X to Z axis - v_x = v_y.cross(v_z); - v_x.normalize(); - - Basis base; - base.set_columns(v_x, v_y, v_z); - - // Absorb current joint transform - base = p_joint_transform.basis.inverse() * base; - - return base; -} - -void JointGizmosDrawer::draw_circle(Vector3::Axis p_axis, real_t p_radius, const Transform3D &p_offset, const Basis &p_base, real_t p_limit_lower, real_t p_limit_upper, Vector &r_points, bool p_inverse) { - if (p_limit_lower == p_limit_upper) { - r_points.push_back(p_offset.translated_local(Vector3()).origin); - r_points.push_back(p_offset.translated_local(p_base.xform(Vector3(0.5, 0, 0))).origin); - - } else { - if (p_limit_lower > p_limit_upper) { - p_limit_lower = -Math_PI; - p_limit_upper = Math_PI; - } - - const int points = 32; - - for (int i = 0; i < points; i++) { - real_t s = p_limit_lower + i * (p_limit_upper - p_limit_lower) / points; - real_t n = p_limit_lower + (i + 1) * (p_limit_upper - p_limit_lower) / points; - - Vector3 from; - Vector3 to; - switch (p_axis) { - case Vector3::AXIS_X: - if (p_inverse) { - from = p_base.xform(Vector3(0, Math::sin(s), Math::cos(s))) * p_radius; - to = p_base.xform(Vector3(0, Math::sin(n), Math::cos(n))) * p_radius; - } else { - from = p_base.xform(Vector3(0, -Math::sin(s), Math::cos(s))) * p_radius; - to = p_base.xform(Vector3(0, -Math::sin(n), Math::cos(n))) * p_radius; - } - break; - case Vector3::AXIS_Y: - if (p_inverse) { - from = p_base.xform(Vector3(Math::cos(s), 0, -Math::sin(s))) * p_radius; - to = p_base.xform(Vector3(Math::cos(n), 0, -Math::sin(n))) * p_radius; - } else { - from = p_base.xform(Vector3(Math::cos(s), 0, Math::sin(s))) * p_radius; - to = p_base.xform(Vector3(Math::cos(n), 0, Math::sin(n))) * p_radius; - } - break; - case Vector3::AXIS_Z: - from = p_base.xform(Vector3(Math::cos(s), Math::sin(s), 0)) * p_radius; - to = p_base.xform(Vector3(Math::cos(n), Math::sin(n), 0)) * p_radius; - break; - } - - if (i == points - 1) { - r_points.push_back(p_offset.translated_local(to).origin); - r_points.push_back(p_offset.translated_local(Vector3()).origin); - } - if (i == 0) { - r_points.push_back(p_offset.translated_local(from).origin); - r_points.push_back(p_offset.translated_local(Vector3()).origin); - } - - r_points.push_back(p_offset.translated_local(from).origin); - r_points.push_back(p_offset.translated_local(to).origin); - } - - r_points.push_back(p_offset.translated_local(Vector3(0, p_radius * 1.5, 0)).origin); - r_points.push_back(p_offset.translated_local(Vector3()).origin); - } -} - -void JointGizmosDrawer::draw_cone(const Transform3D &p_offset, const Basis &p_base, real_t p_swing, real_t p_twist, Vector &r_points) { - float r = 1.0; - float w = r * Math::sin(p_swing); - float d = r * Math::cos(p_swing); - - //swing - for (int i = 0; i < 360; i += 10) { - float ra = Math::deg_to_rad((float)i); - float rb = Math::deg_to_rad((float)i + 10); - Point2 a = Vector2(Math::sin(ra), Math::cos(ra)) * w; - Point2 b = Vector2(Math::sin(rb), Math::cos(rb)) * w; - - r_points.push_back(p_offset.translated_local(p_base.xform(Vector3(d, a.x, a.y))).origin); - r_points.push_back(p_offset.translated_local(p_base.xform(Vector3(d, b.x, b.y))).origin); - - if (i % 90 == 0) { - r_points.push_back(p_offset.translated_local(p_base.xform(Vector3(d, a.x, a.y))).origin); - r_points.push_back(p_offset.translated_local(p_base.xform(Vector3())).origin); - } - } - - r_points.push_back(p_offset.translated_local(p_base.xform(Vector3())).origin); - r_points.push_back(p_offset.translated_local(p_base.xform(Vector3(1, 0, 0))).origin); - - /// Twist - float ts = Math::rad_to_deg(p_twist); - ts = MIN(ts, 720); - - for (int i = 0; i < int(ts); i += 5) { - float ra = Math::deg_to_rad((float)i); - float rb = Math::deg_to_rad((float)i + 5); - float c = i / 720.0; - float cn = (i + 5) / 720.0; - Point2 a = Vector2(Math::sin(ra), Math::cos(ra)) * w * c; - Point2 b = Vector2(Math::sin(rb), Math::cos(rb)) * w * cn; - - r_points.push_back(p_offset.translated_local(p_base.xform(Vector3(c, a.x, a.y))).origin); - r_points.push_back(p_offset.translated_local(p_base.xform(Vector3(cn, b.x, b.y))).origin); - } -} - -//// - -Joint3DGizmoPlugin::Joint3DGizmoPlugin() { - create_material("joint_material", EDITOR_GET("editors/3d_gizmos/gizmo_colors/joint")); - create_material("joint_body_a_material", EDITOR_DEF("editors/3d_gizmos/gizmo_colors/joint_body_a", Color(0.6, 0.8, 1))); - create_material("joint_body_b_material", EDITOR_DEF("editors/3d_gizmos/gizmo_colors/joint_body_b", Color(0.6, 0.9, 1))); - - update_timer = memnew(Timer); - update_timer->set_name("JointGizmoUpdateTimer"); - update_timer->set_wait_time(1.0 / 120.0); - update_timer->connect("timeout", callable_mp(this, &Joint3DGizmoPlugin::incremental_update_gizmos)); - update_timer->set_autostart(true); - EditorNode::get_singleton()->call_deferred(SNAME("add_child"), update_timer); -} - -void Joint3DGizmoPlugin::incremental_update_gizmos() { - if (!current_gizmos.is_empty()) { - update_idx++; - update_idx = update_idx % current_gizmos.size(); - redraw(current_gizmos[update_idx]); - } -} - -bool Joint3DGizmoPlugin::has_gizmo(Node3D *p_spatial) { - return Object::cast_to(p_spatial) != nullptr; -} - -String Joint3DGizmoPlugin::get_gizmo_name() const { - return "Joint3D"; -} - -int Joint3DGizmoPlugin::get_priority() const { - return -1; -} - -void Joint3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) { - Joint3D *joint = Object::cast_to(p_gizmo->get_node_3d()); - - p_gizmo->clear(); - - Node3D *node_body_a = nullptr; - if (!joint->get_node_a().is_empty()) { - node_body_a = Object::cast_to(joint->get_node(joint->get_node_a())); - } - - Node3D *node_body_b = nullptr; - if (!joint->get_node_b().is_empty()) { - node_body_b = Object::cast_to(joint->get_node(joint->get_node_b())); - } - - if (!node_body_a && !node_body_b) { - return; - } - - Ref common_material = get_material("joint_material", p_gizmo); - Ref body_a_material = get_material("joint_body_a_material", p_gizmo); - Ref body_b_material = get_material("joint_body_b_material", p_gizmo); - - Vector points; - Vector body_a_points; - Vector body_b_points; - - if (Object::cast_to(joint)) { - CreatePinJointGizmo(Transform3D(), points); - p_gizmo->add_collision_segments(points); - p_gizmo->add_lines(points, common_material); - } - - HingeJoint3D *hinge = Object::cast_to(joint); - if (hinge) { - CreateHingeJointGizmo( - Transform3D(), - hinge->get_global_transform(), - node_body_a ? node_body_a->get_global_transform() : Transform3D(), - node_body_b ? node_body_b->get_global_transform() : Transform3D(), - hinge->get_param(HingeJoint3D::PARAM_LIMIT_LOWER), - hinge->get_param(HingeJoint3D::PARAM_LIMIT_UPPER), - hinge->get_flag(HingeJoint3D::FLAG_USE_LIMIT), - points, - node_body_a ? &body_a_points : nullptr, - node_body_b ? &body_b_points : nullptr); - - p_gizmo->add_collision_segments(points); - p_gizmo->add_collision_segments(body_a_points); - p_gizmo->add_collision_segments(body_b_points); - - p_gizmo->add_lines(points, common_material); - p_gizmo->add_lines(body_a_points, body_a_material); - p_gizmo->add_lines(body_b_points, body_b_material); - } - - SliderJoint3D *slider = Object::cast_to(joint); - if (slider) { - CreateSliderJointGizmo( - Transform3D(), - slider->get_global_transform(), - node_body_a ? node_body_a->get_global_transform() : Transform3D(), - node_body_b ? node_body_b->get_global_transform() : Transform3D(), - slider->get_param(SliderJoint3D::PARAM_ANGULAR_LIMIT_LOWER), - slider->get_param(SliderJoint3D::PARAM_ANGULAR_LIMIT_UPPER), - slider->get_param(SliderJoint3D::PARAM_LINEAR_LIMIT_LOWER), - slider->get_param(SliderJoint3D::PARAM_LINEAR_LIMIT_UPPER), - points, - node_body_a ? &body_a_points : nullptr, - node_body_b ? &body_b_points : nullptr); - - p_gizmo->add_collision_segments(points); - p_gizmo->add_collision_segments(body_a_points); - p_gizmo->add_collision_segments(body_b_points); - - p_gizmo->add_lines(points, common_material); - p_gizmo->add_lines(body_a_points, body_a_material); - p_gizmo->add_lines(body_b_points, body_b_material); - } - - ConeTwistJoint3D *cone = Object::cast_to(joint); - if (cone) { - CreateConeTwistJointGizmo( - Transform3D(), - cone->get_global_transform(), - node_body_a ? node_body_a->get_global_transform() : Transform3D(), - node_body_b ? node_body_b->get_global_transform() : Transform3D(), - cone->get_param(ConeTwistJoint3D::PARAM_SWING_SPAN), - cone->get_param(ConeTwistJoint3D::PARAM_TWIST_SPAN), - node_body_a ? &body_a_points : nullptr, - node_body_b ? &body_b_points : nullptr); - - p_gizmo->add_collision_segments(body_a_points); - p_gizmo->add_collision_segments(body_b_points); - - p_gizmo->add_lines(body_a_points, body_a_material); - p_gizmo->add_lines(body_b_points, body_b_material); - } - - Generic6DOFJoint3D *gen = Object::cast_to(joint); - if (gen) { - CreateGeneric6DOFJointGizmo( - Transform3D(), - gen->get_global_transform(), - node_body_a ? node_body_a->get_global_transform() : Transform3D(), - node_body_b ? node_body_b->get_global_transform() : Transform3D(), - - gen->get_param_x(Generic6DOFJoint3D::PARAM_ANGULAR_LOWER_LIMIT), - gen->get_param_x(Generic6DOFJoint3D::PARAM_ANGULAR_UPPER_LIMIT), - gen->get_param_x(Generic6DOFJoint3D::PARAM_LINEAR_LOWER_LIMIT), - gen->get_param_x(Generic6DOFJoint3D::PARAM_LINEAR_UPPER_LIMIT), - gen->get_flag_x(Generic6DOFJoint3D::FLAG_ENABLE_ANGULAR_LIMIT), - gen->get_flag_x(Generic6DOFJoint3D::FLAG_ENABLE_LINEAR_LIMIT), - - gen->get_param_y(Generic6DOFJoint3D::PARAM_ANGULAR_LOWER_LIMIT), - gen->get_param_y(Generic6DOFJoint3D::PARAM_ANGULAR_UPPER_LIMIT), - gen->get_param_y(Generic6DOFJoint3D::PARAM_LINEAR_LOWER_LIMIT), - gen->get_param_y(Generic6DOFJoint3D::PARAM_LINEAR_UPPER_LIMIT), - gen->get_flag_y(Generic6DOFJoint3D::FLAG_ENABLE_ANGULAR_LIMIT), - gen->get_flag_y(Generic6DOFJoint3D::FLAG_ENABLE_LINEAR_LIMIT), - - gen->get_param_z(Generic6DOFJoint3D::PARAM_ANGULAR_LOWER_LIMIT), - gen->get_param_z(Generic6DOFJoint3D::PARAM_ANGULAR_UPPER_LIMIT), - gen->get_param_z(Generic6DOFJoint3D::PARAM_LINEAR_LOWER_LIMIT), - gen->get_param_z(Generic6DOFJoint3D::PARAM_LINEAR_UPPER_LIMIT), - gen->get_flag_z(Generic6DOFJoint3D::FLAG_ENABLE_ANGULAR_LIMIT), - gen->get_flag_z(Generic6DOFJoint3D::FLAG_ENABLE_LINEAR_LIMIT), - - points, - node_body_a ? &body_a_points : nullptr, - node_body_a ? &body_b_points : nullptr); - - p_gizmo->add_collision_segments(points); - p_gizmo->add_collision_segments(body_a_points); - p_gizmo->add_collision_segments(body_b_points); - - p_gizmo->add_lines(points, common_material); - p_gizmo->add_lines(body_a_points, body_a_material); - p_gizmo->add_lines(body_b_points, body_b_material); - } -} - -void Joint3DGizmoPlugin::CreatePinJointGizmo(const Transform3D &p_offset, Vector &r_cursor_points) { - float cs = 0.25; - - r_cursor_points.push_back(p_offset.translated_local(Vector3(+cs, 0, 0)).origin); - r_cursor_points.push_back(p_offset.translated_local(Vector3(-cs, 0, 0)).origin); - r_cursor_points.push_back(p_offset.translated_local(Vector3(0, +cs, 0)).origin); - r_cursor_points.push_back(p_offset.translated_local(Vector3(0, -cs, 0)).origin); - r_cursor_points.push_back(p_offset.translated_local(Vector3(0, 0, +cs)).origin); - r_cursor_points.push_back(p_offset.translated_local(Vector3(0, 0, -cs)).origin); -} - -void Joint3DGizmoPlugin::CreateHingeJointGizmo(const Transform3D &p_offset, const Transform3D &p_trs_joint, const Transform3D &p_trs_body_a, const Transform3D &p_trs_body_b, real_t p_limit_lower, real_t p_limit_upper, bool p_use_limit, Vector &r_common_points, Vector *r_body_a_points, Vector *r_body_b_points) { - r_common_points.push_back(p_offset.translated_local(Vector3(0, 0, 0.5)).origin); - r_common_points.push_back(p_offset.translated_local(Vector3(0, 0, -0.5)).origin); - - if (!p_use_limit) { - p_limit_upper = -1; - p_limit_lower = 0; - } - - if (r_body_a_points) { - JointGizmosDrawer::draw_circle(Vector3::AXIS_Z, - BODY_A_RADIUS, - p_offset, - JointGizmosDrawer::look_body_toward_z(p_trs_joint, p_trs_body_a), - p_limit_lower, - p_limit_upper, - *r_body_a_points); - } - - if (r_body_b_points) { - JointGizmosDrawer::draw_circle(Vector3::AXIS_Z, - BODY_B_RADIUS, - p_offset, - JointGizmosDrawer::look_body_toward_z(p_trs_joint, p_trs_body_b), - p_limit_lower, - p_limit_upper, - *r_body_b_points); - } -} - -void Joint3DGizmoPlugin::CreateSliderJointGizmo(const Transform3D &p_offset, const Transform3D &p_trs_joint, const Transform3D &p_trs_body_a, const Transform3D &p_trs_body_b, real_t p_angular_limit_lower, real_t p_angular_limit_upper, real_t p_linear_limit_lower, real_t p_linear_limit_upper, Vector &r_points, Vector *r_body_a_points, Vector *r_body_b_points) { - p_linear_limit_lower = -p_linear_limit_lower; - p_linear_limit_upper = -p_linear_limit_upper; - - float cs = 0.25; - r_points.push_back(p_offset.translated_local(Vector3(0, 0, 0.5)).origin); - r_points.push_back(p_offset.translated_local(Vector3(0, 0, -0.5)).origin); - - if (p_linear_limit_lower >= p_linear_limit_upper) { - r_points.push_back(p_offset.translated_local(Vector3(p_linear_limit_upper, 0, 0)).origin); - r_points.push_back(p_offset.translated_local(Vector3(p_linear_limit_lower, 0, 0)).origin); - - r_points.push_back(p_offset.translated_local(Vector3(p_linear_limit_upper, -cs, -cs)).origin); - r_points.push_back(p_offset.translated_local(Vector3(p_linear_limit_upper, -cs, cs)).origin); - r_points.push_back(p_offset.translated_local(Vector3(p_linear_limit_upper, -cs, cs)).origin); - r_points.push_back(p_offset.translated_local(Vector3(p_linear_limit_upper, cs, cs)).origin); - r_points.push_back(p_offset.translated_local(Vector3(p_linear_limit_upper, cs, cs)).origin); - r_points.push_back(p_offset.translated_local(Vector3(p_linear_limit_upper, cs, -cs)).origin); - r_points.push_back(p_offset.translated_local(Vector3(p_linear_limit_upper, cs, -cs)).origin); - r_points.push_back(p_offset.translated_local(Vector3(p_linear_limit_upper, -cs, -cs)).origin); - - r_points.push_back(p_offset.translated_local(Vector3(p_linear_limit_lower, -cs, -cs)).origin); - r_points.push_back(p_offset.translated_local(Vector3(p_linear_limit_lower, -cs, cs)).origin); - r_points.push_back(p_offset.translated_local(Vector3(p_linear_limit_lower, -cs, cs)).origin); - r_points.push_back(p_offset.translated_local(Vector3(p_linear_limit_lower, cs, cs)).origin); - r_points.push_back(p_offset.translated_local(Vector3(p_linear_limit_lower, cs, cs)).origin); - r_points.push_back(p_offset.translated_local(Vector3(p_linear_limit_lower, cs, -cs)).origin); - r_points.push_back(p_offset.translated_local(Vector3(p_linear_limit_lower, cs, -cs)).origin); - r_points.push_back(p_offset.translated_local(Vector3(p_linear_limit_lower, -cs, -cs)).origin); - - } else { - r_points.push_back(p_offset.translated_local(Vector3(+cs * 2, 0, 0)).origin); - r_points.push_back(p_offset.translated_local(Vector3(-cs * 2, 0, 0)).origin); - } - - if (r_body_a_points) { - JointGizmosDrawer::draw_circle( - Vector3::AXIS_X, - BODY_A_RADIUS, - p_offset, - JointGizmosDrawer::look_body_toward(Vector3::AXIS_X, p_trs_joint, p_trs_body_a), - p_angular_limit_lower, - p_angular_limit_upper, - *r_body_a_points); - } - - if (r_body_b_points) { - JointGizmosDrawer::draw_circle( - Vector3::AXIS_X, - BODY_B_RADIUS, - p_offset, - JointGizmosDrawer::look_body_toward(Vector3::AXIS_X, p_trs_joint, p_trs_body_b), - p_angular_limit_lower, - p_angular_limit_upper, - *r_body_b_points, - true); - } -} - -void Joint3DGizmoPlugin::CreateConeTwistJointGizmo(const Transform3D &p_offset, const Transform3D &p_trs_joint, const Transform3D &p_trs_body_a, const Transform3D &p_trs_body_b, real_t p_swing, real_t p_twist, Vector *r_body_a_points, Vector *r_body_b_points) { - if (r_body_a_points) { - JointGizmosDrawer::draw_cone( - p_offset, - JointGizmosDrawer::look_body(p_trs_joint, p_trs_body_a), - p_swing, - p_twist, - *r_body_a_points); - } - - if (r_body_b_points) { - JointGizmosDrawer::draw_cone( - p_offset, - JointGizmosDrawer::look_body(p_trs_joint, p_trs_body_b), - p_swing, - p_twist, - *r_body_b_points); - } -} - -void Joint3DGizmoPlugin::CreateGeneric6DOFJointGizmo( - const Transform3D &p_offset, - const Transform3D &p_trs_joint, - const Transform3D &p_trs_body_a, - const Transform3D &p_trs_body_b, - real_t p_angular_limit_lower_x, - real_t p_angular_limit_upper_x, - real_t p_linear_limit_lower_x, - real_t p_linear_limit_upper_x, - bool p_enable_angular_limit_x, - bool p_enable_linear_limit_x, - real_t p_angular_limit_lower_y, - real_t p_angular_limit_upper_y, - real_t p_linear_limit_lower_y, - real_t p_linear_limit_upper_y, - bool p_enable_angular_limit_y, - bool p_enable_linear_limit_y, - real_t p_angular_limit_lower_z, - real_t p_angular_limit_upper_z, - real_t p_linear_limit_lower_z, - real_t p_linear_limit_upper_z, - bool p_enable_angular_limit_z, - bool p_enable_linear_limit_z, - Vector &r_points, - Vector *r_body_a_points, - Vector *r_body_b_points) { - float cs = 0.25; - - for (int ax = 0; ax < 3; ax++) { - float ll = 0; - float ul = 0; - float lll = 0; - float lul = 0; - - int a1 = 0; - int a2 = 0; - int a3 = 0; - bool enable_ang = false; - bool enable_lin = false; - - switch (ax) { - case 0: - ll = p_angular_limit_lower_x; - ul = p_angular_limit_upper_x; - lll = -p_linear_limit_lower_x; - lul = -p_linear_limit_upper_x; - enable_ang = p_enable_angular_limit_x; - enable_lin = p_enable_linear_limit_x; - a1 = 0; - a2 = 1; - a3 = 2; - break; - case 1: - ll = p_angular_limit_lower_y; - ul = p_angular_limit_upper_y; - lll = -p_linear_limit_lower_y; - lul = -p_linear_limit_upper_y; - enable_ang = p_enable_angular_limit_y; - enable_lin = p_enable_linear_limit_y; - a1 = 1; - a2 = 2; - a3 = 0; - break; - case 2: - ll = p_angular_limit_lower_z; - ul = p_angular_limit_upper_z; - lll = -p_linear_limit_lower_z; - lul = -p_linear_limit_upper_z; - enable_ang = p_enable_angular_limit_z; - enable_lin = p_enable_linear_limit_z; - a1 = 2; - a2 = 0; - a3 = 1; - break; - } - -#define ADD_VTX(x, y, z) \ - { \ - Vector3 v; \ - v[a1] = (x); \ - v[a2] = (y); \ - v[a3] = (z); \ - r_points.push_back(p_offset.translated_local(v).origin); \ - } - - if (enable_lin && lll >= lul) { - ADD_VTX(lul, 0, 0); - ADD_VTX(lll, 0, 0); - - ADD_VTX(lul, -cs, -cs); - ADD_VTX(lul, -cs, cs); - ADD_VTX(lul, -cs, cs); - ADD_VTX(lul, cs, cs); - ADD_VTX(lul, cs, cs); - ADD_VTX(lul, cs, -cs); - ADD_VTX(lul, cs, -cs); - ADD_VTX(lul, -cs, -cs); - - ADD_VTX(lll, -cs, -cs); - ADD_VTX(lll, -cs, cs); - ADD_VTX(lll, -cs, cs); - ADD_VTX(lll, cs, cs); - ADD_VTX(lll, cs, cs); - ADD_VTX(lll, cs, -cs); - ADD_VTX(lll, cs, -cs); - ADD_VTX(lll, -cs, -cs); - - } else { - ADD_VTX(+cs * 2, 0, 0); - ADD_VTX(-cs * 2, 0, 0); - } - - if (!enable_ang) { - ll = 0; - ul = -1; - } - - if (r_body_a_points) { - JointGizmosDrawer::draw_circle( - static_cast(ax), - BODY_A_RADIUS, - p_offset, - JointGizmosDrawer::look_body_toward(static_cast(ax), p_trs_joint, p_trs_body_a), - ll, - ul, - *r_body_a_points, - true); - } - - if (r_body_b_points) { - JointGizmosDrawer::draw_circle( - static_cast(ax), - BODY_B_RADIUS, - p_offset, - JointGizmosDrawer::look_body_toward(static_cast(ax), p_trs_joint, p_trs_body_b), - ll, - ul, - *r_body_b_points); - } - } - -#undef ADD_VTX -} - -//// - -FogVolumeGizmoPlugin::FogVolumeGizmoPlugin() { - Color gizmo_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/fog_volume", Color(0.5, 0.7, 1)); - create_material("shape_material", gizmo_color); - gizmo_color.a = 0.15; - create_material("shape_material_internal", gizmo_color); - - create_handle_material("handles"); -} - -bool FogVolumeGizmoPlugin::has_gizmo(Node3D *p_spatial) { - return (Object::cast_to(p_spatial) != nullptr); -} - -String FogVolumeGizmoPlugin::get_gizmo_name() const { - return "FogVolume"; -} - -int FogVolumeGizmoPlugin::get_priority() const { - return -1; -} - -String FogVolumeGizmoPlugin::get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const { - return "Size"; -} - -Variant FogVolumeGizmoPlugin::get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const { - return Vector3(p_gizmo->get_node_3d()->call("get_size")); -} - -void FogVolumeGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, Camera3D *p_camera, const Point2 &p_point) { - Node3D *sn = p_gizmo->get_node_3d(); - - Transform3D gt = sn->get_global_transform(); - Transform3D gi = gt.affine_inverse(); - - Vector3 ray_from = p_camera->project_ray_origin(p_point); - Vector3 ray_dir = p_camera->project_ray_normal(p_point); - - Vector3 sg[2] = { gi.xform(ray_from), gi.xform(ray_from + ray_dir * 4096) }; - - Vector3 axis; - axis[p_id] = 1.0; - Vector3 ra, rb; - Geometry3D::get_closest_points_between_segments(Vector3(), axis * 4096, sg[0], sg[1], ra, rb); - float d = ra[p_id] * 2; - if (Node3DEditor::get_singleton()->is_snap_enabled()) { - d = Math::snapped(d, Node3DEditor::get_singleton()->get_translate_snap()); - } - - if (d < 0.001) { - d = 0.001; - } - - Vector3 he = sn->call("get_size"); - he[p_id] = d; - sn->call("set_size", he); -} - -void FogVolumeGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, const Variant &p_restore, bool p_cancel) { - Node3D *sn = p_gizmo->get_node_3d(); - - if (p_cancel) { - sn->call("set_size", p_restore); - return; - } - - EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton(); - ur->create_action(TTR("Change Fog Volume Size")); - ur->add_do_method(sn, "set_size", sn->call("get_size")); - ur->add_undo_method(sn, "set_size", p_restore); - ur->commit_action(); -} - -void FogVolumeGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) { - Node3D *cs = p_gizmo->get_node_3d(); - - p_gizmo->clear(); - - if (RS::FogVolumeShape(int(p_gizmo->get_node_3d()->call("get_shape"))) != RS::FOG_VOLUME_SHAPE_WORLD) { - const Ref material = - get_material("shape_material", p_gizmo); - const Ref material_internal = - get_material("shape_material_internal", p_gizmo); - - Ref handles_material = get_material("handles"); - - Vector lines; - AABB aabb; - aabb.size = cs->call("get_size").operator Vector3(); - aabb.position = aabb.size / -2; - - for (int i = 0; i < 12; i++) { - Vector3 a, b; - aabb.get_edge(i, a, b); - lines.push_back(a); - lines.push_back(b); - } - - Vector handles; - - for (int i = 0; i < 3; i++) { - Vector3 ax; - ax[i] = cs->call("get_size").operator Vector3()[i] / 2; - handles.push_back(ax); - } - - p_gizmo->add_lines(lines, material); - p_gizmo->add_collision_segments(lines); - p_gizmo->add_handles(handles, handles_material); - } -} - -///// diff --git a/editor/plugins/node_3d_editor_gizmos.h b/editor/plugins/node_3d_editor_gizmos.h index 8cb0fe54d93..ae2214de988 100644 --- a/editor/plugins/node_3d_editor_gizmos.h +++ b/editor/plugins/node_3d_editor_gizmos.h @@ -214,520 +214,4 @@ public: virtual ~EditorNode3DGizmoPlugin(); }; -class Light3DGizmoPlugin : public EditorNode3DGizmoPlugin { - GDCLASS(Light3DGizmoPlugin, EditorNode3DGizmoPlugin); - -public: - bool has_gizmo(Node3D *p_spatial) override; - String get_gizmo_name() const override; - int get_priority() const override; - - String get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const override; - Variant get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const override; - void set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, Camera3D *p_camera, const Point2 &p_point) override; - void commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, const Variant &p_restore, bool p_cancel = false) override; - void redraw(EditorNode3DGizmo *p_gizmo) override; - - Light3DGizmoPlugin(); -}; - -class AudioStreamPlayer3DGizmoPlugin : public EditorNode3DGizmoPlugin { - GDCLASS(AudioStreamPlayer3DGizmoPlugin, EditorNode3DGizmoPlugin); - -public: - bool has_gizmo(Node3D *p_spatial) override; - String get_gizmo_name() const override; - int get_priority() const override; - - String get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const override; - Variant get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const override; - void set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, Camera3D *p_camera, const Point2 &p_point) override; - void commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, const Variant &p_restore, bool p_cancel = false) override; - void redraw(EditorNode3DGizmo *p_gizmo) override; - - AudioStreamPlayer3DGizmoPlugin(); -}; - -class AudioListener3DGizmoPlugin : public EditorNode3DGizmoPlugin { - GDCLASS(AudioListener3DGizmoPlugin, EditorNode3DGizmoPlugin); - -public: - bool has_gizmo(Node3D *p_spatial) override; - String get_gizmo_name() const override; - int get_priority() const override; - - void redraw(EditorNode3DGizmo *p_gizmo) override; - - AudioListener3DGizmoPlugin(); -}; - -class Camera3DGizmoPlugin : public EditorNode3DGizmoPlugin { - GDCLASS(Camera3DGizmoPlugin, EditorNode3DGizmoPlugin); - -private: - static Size2i _get_viewport_size(Camera3D *p_camera); - -public: - bool has_gizmo(Node3D *p_spatial) override; - String get_gizmo_name() const override; - int get_priority() const override; - - String get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const override; - Variant get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const override; - void set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, Camera3D *p_camera, const Point2 &p_point) override; - void commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, const Variant &p_restore, bool p_cancel = false) override; - void redraw(EditorNode3DGizmo *p_gizmo) override; - - Camera3DGizmoPlugin(); -}; - -class MeshInstance3DGizmoPlugin : public EditorNode3DGizmoPlugin { - GDCLASS(MeshInstance3DGizmoPlugin, EditorNode3DGizmoPlugin); - -public: - bool has_gizmo(Node3D *p_spatial) override; - String get_gizmo_name() const override; - int get_priority() const override; - bool can_be_hidden() const override; - void redraw(EditorNode3DGizmo *p_gizmo) override; - - MeshInstance3DGizmoPlugin(); -}; - -class OccluderInstance3DGizmoPlugin : public EditorNode3DGizmoPlugin { - GDCLASS(OccluderInstance3DGizmoPlugin, EditorNode3DGizmoPlugin); - -public: - bool has_gizmo(Node3D *p_spatial) override; - String get_gizmo_name() const override; - int get_priority() const override; - void redraw(EditorNode3DGizmo *p_gizmo) override; - - String get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const override; - Variant get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const override; - void set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, Camera3D *p_camera, const Point2 &p_point) override; - void commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, const Variant &p_restore, bool p_cancel = false) override; - - OccluderInstance3DGizmoPlugin(); -}; - -class Sprite3DGizmoPlugin : public EditorNode3DGizmoPlugin { - GDCLASS(Sprite3DGizmoPlugin, EditorNode3DGizmoPlugin); - -public: - bool has_gizmo(Node3D *p_spatial) override; - String get_gizmo_name() const override; - int get_priority() const override; - bool can_be_hidden() const override; - void redraw(EditorNode3DGizmo *p_gizmo) override; - - Sprite3DGizmoPlugin(); -}; - -class Label3DGizmoPlugin : public EditorNode3DGizmoPlugin { - GDCLASS(Label3DGizmoPlugin, EditorNode3DGizmoPlugin); - -public: - bool has_gizmo(Node3D *p_spatial) override; - String get_gizmo_name() const override; - int get_priority() const override; - bool can_be_hidden() const override; - void redraw(EditorNode3DGizmo *p_gizmo) override; - - Label3DGizmoPlugin(); -}; - -class Marker3DGizmoPlugin : public EditorNode3DGizmoPlugin { - GDCLASS(Marker3DGizmoPlugin, EditorNode3DGizmoPlugin); - - Ref pos3d_mesh; - -public: - bool has_gizmo(Node3D *p_spatial) override; - String get_gizmo_name() const override; - int get_priority() const override; - void redraw(EditorNode3DGizmo *p_gizmo) override; - - Marker3DGizmoPlugin(); -}; - -class PhysicalBone3DGizmoPlugin : public EditorNode3DGizmoPlugin { - GDCLASS(PhysicalBone3DGizmoPlugin, EditorNode3DGizmoPlugin); - -public: - bool has_gizmo(Node3D *p_spatial) override; - String get_gizmo_name() const override; - int get_priority() const override; - void redraw(EditorNode3DGizmo *p_gizmo) override; - - PhysicalBone3DGizmoPlugin(); -}; - -class RayCast3DGizmoPlugin : public EditorNode3DGizmoPlugin { - GDCLASS(RayCast3DGizmoPlugin, EditorNode3DGizmoPlugin); - -public: - bool has_gizmo(Node3D *p_spatial) override; - String get_gizmo_name() const override; - int get_priority() const override; - void redraw(EditorNode3DGizmo *p_gizmo) override; - - RayCast3DGizmoPlugin(); -}; - -class ShapeCast3DGizmoPlugin : public EditorNode3DGizmoPlugin { - GDCLASS(ShapeCast3DGizmoPlugin, EditorNode3DGizmoPlugin); - -public: - bool has_gizmo(Node3D *p_spatial) override; - String get_gizmo_name() const override; - int get_priority() const override; - void redraw(EditorNode3DGizmo *p_gizmo) override; - - ShapeCast3DGizmoPlugin(); -}; - -class SpringArm3DGizmoPlugin : public EditorNode3DGizmoPlugin { - GDCLASS(SpringArm3DGizmoPlugin, EditorNode3DGizmoPlugin); - -public: - bool has_gizmo(Node3D *p_spatial) override; - String get_gizmo_name() const override; - int get_priority() const override; - void redraw(EditorNode3DGizmo *p_gizmo) override; - - SpringArm3DGizmoPlugin(); -}; - -class VehicleWheel3DGizmoPlugin : public EditorNode3DGizmoPlugin { - GDCLASS(VehicleWheel3DGizmoPlugin, EditorNode3DGizmoPlugin); - -public: - bool has_gizmo(Node3D *p_spatial) override; - String get_gizmo_name() const override; - int get_priority() const override; - void redraw(EditorNode3DGizmo *p_gizmo) override; - - VehicleWheel3DGizmoPlugin(); -}; - -class SoftBody3DGizmoPlugin : public EditorNode3DGizmoPlugin { - GDCLASS(SoftBody3DGizmoPlugin, EditorNode3DGizmoPlugin); - -public: - bool has_gizmo(Node3D *p_spatial) override; - String get_gizmo_name() const override; - int get_priority() const override; - bool is_selectable_when_hidden() const override; - void redraw(EditorNode3DGizmo *p_gizmo) override; - - String get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const override; - Variant get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const override; - void commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, const Variant &p_restore, bool p_cancel = false) override; - bool is_handle_highlighted(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const override; - - SoftBody3DGizmoPlugin(); -}; - -class VisibleOnScreenNotifier3DGizmoPlugin : public EditorNode3DGizmoPlugin { - GDCLASS(VisibleOnScreenNotifier3DGizmoPlugin, EditorNode3DGizmoPlugin); - -public: - bool has_gizmo(Node3D *p_spatial) override; - String get_gizmo_name() const override; - int get_priority() const override; - void redraw(EditorNode3DGizmo *p_gizmo) override; - - String get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const override; - Variant get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const override; - void set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, Camera3D *p_camera, const Point2 &p_point) override; - void commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, const Variant &p_restore, bool p_cancel = false) override; - - VisibleOnScreenNotifier3DGizmoPlugin(); -}; - -class CPUParticles3DGizmoPlugin : public EditorNode3DGizmoPlugin { - GDCLASS(CPUParticles3DGizmoPlugin, EditorNode3DGizmoPlugin); - -public: - bool has_gizmo(Node3D *p_spatial) override; - String get_gizmo_name() const override; - int get_priority() const override; - bool is_selectable_when_hidden() const override; - void redraw(EditorNode3DGizmo *p_gizmo) override; - CPUParticles3DGizmoPlugin(); -}; - -class GPUParticles3DGizmoPlugin : public EditorNode3DGizmoPlugin { - GDCLASS(GPUParticles3DGizmoPlugin, EditorNode3DGizmoPlugin); - -public: - bool has_gizmo(Node3D *p_spatial) override; - String get_gizmo_name() const override; - int get_priority() const override; - bool is_selectable_when_hidden() const override; - void redraw(EditorNode3DGizmo *p_gizmo) override; - - String get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const override; - Variant get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const override; - void set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, Camera3D *p_camera, const Point2 &p_point) override; - void commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, const Variant &p_restore, bool p_cancel = false) override; - - GPUParticles3DGizmoPlugin(); -}; - -class GPUParticlesCollision3DGizmoPlugin : public EditorNode3DGizmoPlugin { - GDCLASS(GPUParticlesCollision3DGizmoPlugin, EditorNode3DGizmoPlugin); - -public: - bool has_gizmo(Node3D *p_spatial) override; - String get_gizmo_name() const override; - int get_priority() const override; - void redraw(EditorNode3DGizmo *p_gizmo) override; - - String get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const override; - Variant get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const override; - void set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, Camera3D *p_camera, const Point2 &p_point) override; - void commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, const Variant &p_restore, bool p_cancel = false) override; - - GPUParticlesCollision3DGizmoPlugin(); -}; - -class ReflectionProbeGizmoPlugin : public EditorNode3DGizmoPlugin { - GDCLASS(ReflectionProbeGizmoPlugin, EditorNode3DGizmoPlugin); - -public: - bool has_gizmo(Node3D *p_spatial) override; - String get_gizmo_name() const override; - int get_priority() const override; - void redraw(EditorNode3DGizmo *p_gizmo) override; - - String get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const override; - Variant get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const override; - void set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, Camera3D *p_camera, const Point2 &p_point) override; - void commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, const Variant &p_restore, bool p_cancel = false) override; - - ReflectionProbeGizmoPlugin(); -}; - -class DecalGizmoPlugin : public EditorNode3DGizmoPlugin { - GDCLASS(DecalGizmoPlugin, EditorNode3DGizmoPlugin); - -public: - bool has_gizmo(Node3D *p_spatial) override; - String get_gizmo_name() const override; - int get_priority() const override; - void redraw(EditorNode3DGizmo *p_gizmo) override; - - String get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const override; - Variant get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const override; - void set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, Camera3D *p_camera, const Point2 &p_point) override; - void commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, const Variant &p_restore, bool p_cancel = false) override; - - DecalGizmoPlugin(); -}; - -class VoxelGIGizmoPlugin : public EditorNode3DGizmoPlugin { - GDCLASS(VoxelGIGizmoPlugin, EditorNode3DGizmoPlugin); - -public: - bool has_gizmo(Node3D *p_spatial) override; - String get_gizmo_name() const override; - int get_priority() const override; - void redraw(EditorNode3DGizmo *p_gizmo) override; - - String get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const override; - Variant get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const override; - void set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, Camera3D *p_camera, const Point2 &p_point) override; - void commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, const Variant &p_restore, bool p_cancel = false) override; - - VoxelGIGizmoPlugin(); -}; - -class LightmapGIGizmoPlugin : public EditorNode3DGizmoPlugin { - GDCLASS(LightmapGIGizmoPlugin, EditorNode3DGizmoPlugin); - -public: - bool has_gizmo(Node3D *p_spatial) override; - String get_gizmo_name() const override; - int get_priority() const override; - void redraw(EditorNode3DGizmo *p_gizmo) override; - - LightmapGIGizmoPlugin(); -}; - -class LightmapProbeGizmoPlugin : public EditorNode3DGizmoPlugin { - GDCLASS(LightmapProbeGizmoPlugin, EditorNode3DGizmoPlugin); - -public: - bool has_gizmo(Node3D *p_spatial) override; - String get_gizmo_name() const override; - int get_priority() const override; - void redraw(EditorNode3DGizmo *p_gizmo) override; - - LightmapProbeGizmoPlugin(); -}; - -class CollisionObject3DGizmoPlugin : public EditorNode3DGizmoPlugin { - GDCLASS(CollisionObject3DGizmoPlugin, EditorNode3DGizmoPlugin); - -public: - bool has_gizmo(Node3D *p_spatial) override; - String get_gizmo_name() const override; - int get_priority() const override; - void redraw(EditorNode3DGizmo *p_gizmo) override; - - CollisionObject3DGizmoPlugin(); -}; - -class CollisionShape3DGizmoPlugin : public EditorNode3DGizmoPlugin { - GDCLASS(CollisionShape3DGizmoPlugin, EditorNode3DGizmoPlugin); - -public: - bool has_gizmo(Node3D *p_spatial) override; - String get_gizmo_name() const override; - int get_priority() const override; - void redraw(EditorNode3DGizmo *p_gizmo) override; - - String get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const override; - Variant get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const override; - void set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, Camera3D *p_camera, const Point2 &p_point) override; - void commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, const Variant &p_restore, bool p_cancel = false) override; - - CollisionShape3DGizmoPlugin(); -}; - -class CollisionPolygon3DGizmoPlugin : public EditorNode3DGizmoPlugin { - GDCLASS(CollisionPolygon3DGizmoPlugin, EditorNode3DGizmoPlugin); - -public: - bool has_gizmo(Node3D *p_spatial) override; - String get_gizmo_name() const override; - int get_priority() const override; - void redraw(EditorNode3DGizmo *p_gizmo) override; - CollisionPolygon3DGizmoPlugin(); -}; - -class NavigationRegion3DGizmoPlugin : public EditorNode3DGizmoPlugin { - GDCLASS(NavigationRegion3DGizmoPlugin, EditorNode3DGizmoPlugin); - - struct _EdgeKey { - Vector3 from; - Vector3 to; - - static uint32_t hash(const _EdgeKey &p_key) { - return HashMapHasherDefault::hash(p_key.from) ^ HashMapHasherDefault::hash(p_key.to); - } - - bool operator==(const _EdgeKey &p_with) const { - return HashMapComparatorDefault::compare(from, p_with.from) && HashMapComparatorDefault::compare(to, p_with.to); - } - }; - -public: - bool has_gizmo(Node3D *p_spatial) override; - String get_gizmo_name() const override; - int get_priority() const override; - void redraw(EditorNode3DGizmo *p_gizmo) override; - - NavigationRegion3DGizmoPlugin(); -}; - -class NavigationLink3DGizmoPlugin : public EditorNode3DGizmoPlugin { - GDCLASS(NavigationLink3DGizmoPlugin, EditorNode3DGizmoPlugin); - -public: - bool has_gizmo(Node3D *p_spatial) override; - String get_gizmo_name() const override; - int get_priority() const override; - void redraw(EditorNode3DGizmo *p_gizmo) override; - - String get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const override; - Variant get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const override; - void set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, Camera3D *p_camera, const Point2 &p_point) override; - void commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, const Variant &p_restore, bool p_cancel = false) override; - - NavigationLink3DGizmoPlugin(); -}; - -class JointGizmosDrawer { -public: - static Basis look_body(const Transform3D &p_joint_transform, const Transform3D &p_body_transform); - static Basis look_body_toward(Vector3::Axis p_axis, const Transform3D &joint_transform, const Transform3D &body_transform); - static Basis look_body_toward_x(const Transform3D &p_joint_transform, const Transform3D &p_body_transform); - static Basis look_body_toward_y(const Transform3D &p_joint_transform, const Transform3D &p_body_transform); - /// Special function just used for physics joints, it returns a basis constrained toward Joint Z axis - /// with axis X and Y that are looking toward the body and oriented toward up - static Basis look_body_toward_z(const Transform3D &p_joint_transform, const Transform3D &p_body_transform); - - // Draw circle around p_axis - static void draw_circle(Vector3::Axis p_axis, real_t p_radius, const Transform3D &p_offset, const Basis &p_base, real_t p_limit_lower, real_t p_limit_upper, Vector &r_points, bool p_inverse = false); - static void draw_cone(const Transform3D &p_offset, const Basis &p_base, real_t p_swing, real_t p_twist, Vector &r_points); -}; - -class Joint3DGizmoPlugin : public EditorNode3DGizmoPlugin { - GDCLASS(Joint3DGizmoPlugin, EditorNode3DGizmoPlugin); - - Timer *update_timer = nullptr; - uint64_t update_idx = 0; - - void incremental_update_gizmos(); - -public: - bool has_gizmo(Node3D *p_spatial) override; - String get_gizmo_name() const override; - int get_priority() const override; - void redraw(EditorNode3DGizmo *p_gizmo) override; - - static void CreatePinJointGizmo(const Transform3D &p_offset, Vector &r_cursor_points); - static void CreateHingeJointGizmo(const Transform3D &p_offset, const Transform3D &p_trs_joint, const Transform3D &p_trs_body_a, const Transform3D &p_trs_body_b, real_t p_limit_lower, real_t p_limit_upper, bool p_use_limit, Vector &r_common_points, Vector *r_body_a_points, Vector *r_body_b_points); - static void CreateSliderJointGizmo(const Transform3D &p_offset, const Transform3D &p_trs_joint, const Transform3D &p_trs_body_a, const Transform3D &p_trs_body_b, real_t p_angular_limit_lower, real_t p_angular_limit_upper, real_t p_linear_limit_lower, real_t p_linear_limit_upper, Vector &r_points, Vector *r_body_a_points, Vector *r_body_b_points); - static void CreateConeTwistJointGizmo(const Transform3D &p_offset, const Transform3D &p_trs_joint, const Transform3D &p_trs_body_a, const Transform3D &p_trs_body_b, real_t p_swing, real_t p_twist, Vector *r_body_a_points, Vector *r_body_b_points); - static void CreateGeneric6DOFJointGizmo( - const Transform3D &p_offset, - const Transform3D &p_trs_joint, - const Transform3D &p_trs_body_a, - const Transform3D &p_trs_body_b, - real_t p_angular_limit_lower_x, - real_t p_angular_limit_upper_x, - real_t p_linear_limit_lower_x, - real_t p_linear_limit_upper_x, - bool p_enable_angular_limit_x, - bool p_enable_linear_limit_x, - real_t p_angular_limit_lower_y, - real_t p_angular_limit_upper_y, - real_t p_linear_limit_lower_y, - real_t p_linear_limit_upper_y, - bool p_enable_angular_limit_y, - bool p_enable_linear_limit_y, - real_t p_angular_limit_lower_z, - real_t p_angular_limit_upper_z, - real_t p_linear_limit_lower_z, - real_t p_linear_limit_upper_z, - bool p_enable_angular_limit_z, - bool p_enable_linear_limit_z, - Vector &r_points, - Vector *r_body_a_points, - Vector *r_body_b_points); - - Joint3DGizmoPlugin(); -}; - -class FogVolumeGizmoPlugin : public EditorNode3DGizmoPlugin { - GDCLASS(FogVolumeGizmoPlugin, EditorNode3DGizmoPlugin); - -public: - bool has_gizmo(Node3D *p_spatial) override; - String get_gizmo_name() const override; - int get_priority() const override; - void redraw(EditorNode3DGizmo *p_gizmo) override; - - String get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const override; - Variant get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const override; - void set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, Camera3D *p_camera, const Point2 &p_point) override; - void commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, const Variant &p_restore, bool p_cancel = false) override; - - FogVolumeGizmoPlugin(); -}; - #endif // NODE_3D_EDITOR_GIZMOS_H diff --git a/editor/plugins/node_3d_editor_plugin.cpp b/editor/plugins/node_3d_editor_plugin.cpp index 7225c1b6581..00382e1a185 100644 --- a/editor/plugins/node_3d_editor_plugin.cpp +++ b/editor/plugins/node_3d_editor_plugin.cpp @@ -42,6 +42,37 @@ #include "editor/editor_undo_redo_manager.h" #include "editor/gui/editor_spin_slider.h" #include "editor/plugins/animation_player_editor_plugin.h" +#include "editor/plugins/gizmos/audio_listener_3d_gizmo_plugin.h" +#include "editor/plugins/gizmos/audio_stream_player_3d_gizmo_plugin.h" +#include "editor/plugins/gizmos/camera_3d_gizmo_plugin.h" +#include "editor/plugins/gizmos/collision_object_3d_gizmo_plugin.h" +#include "editor/plugins/gizmos/collision_polygon_3d_gizmo_plugin.h" +#include "editor/plugins/gizmos/collision_shape_3d_gizmo_plugin.h" +#include "editor/plugins/gizmos/cpu_particles_3d_gizmo_plugin.h" +#include "editor/plugins/gizmos/decal_gizmo_plugin.h" +#include "editor/plugins/gizmos/fog_volume_gizmo_plugin.h" +#include "editor/plugins/gizmos/gpu_particles_3d_gizmo_plugin.h" +#include "editor/plugins/gizmos/gpu_particles_collision_3d_gizmo_plugin.h" +#include "editor/plugins/gizmos/joint_3d_gizmo_plugin.h" +#include "editor/plugins/gizmos/label_3d_gizmo_plugin.h" +#include "editor/plugins/gizmos/light_3d_gizmo_plugin.h" +#include "editor/plugins/gizmos/lightmap_gi_gizmo_plugin.h" +#include "editor/plugins/gizmos/lightmap_probe_gizmo_plugin.h" +#include "editor/plugins/gizmos/marker_3d_gizmo_plugin.h" +#include "editor/plugins/gizmos/mesh_instance_3d_gizmo_plugin.h" +#include "editor/plugins/gizmos/navigation_link_3d_gizmo_plugin.h" +#include "editor/plugins/gizmos/navigation_region_3d_gizmo_plugin.h" +#include "editor/plugins/gizmos/occluder_instance_3d_gizmo_plugin.h" +#include "editor/plugins/gizmos/physics_bone_3d_gizmo_plugin.h" +#include "editor/plugins/gizmos/ray_cast_3d_gizmo_plugin.h" +#include "editor/plugins/gizmos/reflection_probe_gizmo_plugin.h" +#include "editor/plugins/gizmos/shape_cast_3d_gizmo_plugin.h" +#include "editor/plugins/gizmos/soft_body_3d_gizmo_plugin.h" +#include "editor/plugins/gizmos/spring_arm_3d_gizmo_plugin.h" +#include "editor/plugins/gizmos/sprite_3d_gizmo_plugin.h" +#include "editor/plugins/gizmos/vehicle_body_3d_gizmo_plugin.h" +#include "editor/plugins/gizmos/visible_on_screen_notifier_3d_gizmo_plugin.h" +#include "editor/plugins/gizmos/voxel_gi_gizmo_plugin.h" #include "editor/plugins/node_3d_editor_gizmos.h" #include "editor/scene_tree_dock.h" #include "scene/3d/camera_3d.h"