node_3d_editor_gizmos.cpp 40 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228
  1. /**************************************************************************/
  2. /* node_3d_editor_gizmos.cpp */
  3. /**************************************************************************/
  4. /* This file is part of: */
  5. /* GODOT ENGINE */
  6. /* https://godotengine.org */
  7. /**************************************************************************/
  8. /* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
  9. /* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
  10. /* */
  11. /* Permission is hereby granted, free of charge, to any person obtaining */
  12. /* a copy of this software and associated documentation files (the */
  13. /* "Software"), to deal in the Software without restriction, including */
  14. /* without limitation the rights to use, copy, modify, merge, publish, */
  15. /* distribute, sublicense, and/or sell copies of the Software, and to */
  16. /* permit persons to whom the Software is furnished to do so, subject to */
  17. /* the following conditions: */
  18. /* */
  19. /* The above copyright notice and this permission notice shall be */
  20. /* included in all copies or substantial portions of the Software. */
  21. /* */
  22. /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
  23. /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
  24. /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
  25. /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
  26. /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
  27. /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
  28. /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
  29. /**************************************************************************/
  30. #include "node_3d_editor_gizmos.h"
  31. #include "core/math/geometry_2d.h"
  32. #include "core/math/geometry_3d.h"
  33. #include "editor/editor_node.h"
  34. #include "editor/editor_settings.h"
  35. #include "editor/editor_string_names.h"
  36. #include "editor/plugins/node_3d_editor_plugin.h"
  37. #include "scene/resources/3d/primitive_meshes.h"
  38. #define HANDLE_HALF_SIZE 9.5
  39. bool EditorNode3DGizmo::is_editable() const {
  40. ERR_FAIL_NULL_V(spatial_node, false);
  41. Node *edited_root = spatial_node->get_tree()->get_edited_scene_root();
  42. if (spatial_node == edited_root) {
  43. return true;
  44. }
  45. if (spatial_node->get_owner() == edited_root) {
  46. return true;
  47. }
  48. if (edited_root->is_editable_instance(spatial_node->get_owner())) {
  49. return true;
  50. }
  51. return false;
  52. }
  53. void EditorNode3DGizmo::clear() {
  54. ERR_FAIL_NULL(RenderingServer::get_singleton());
  55. for (int i = 0; i < instances.size(); i++) {
  56. if (instances[i].instance.is_valid()) {
  57. RS::get_singleton()->free(instances[i].instance);
  58. }
  59. }
  60. billboard_handle = false;
  61. collision_segments.clear();
  62. collision_mesh = Ref<TriangleMesh>();
  63. instances.clear();
  64. handles.clear();
  65. handle_ids.clear();
  66. secondary_handles.clear();
  67. secondary_handle_ids.clear();
  68. }
  69. void EditorNode3DGizmo::redraw() {
  70. if (!GDVIRTUAL_CALL(_redraw)) {
  71. ERR_FAIL_NULL(gizmo_plugin);
  72. gizmo_plugin->redraw(this);
  73. }
  74. _update_bvh();
  75. if (Node3DEditor::get_singleton()->is_current_selected_gizmo(this)) {
  76. Node3DEditor::get_singleton()->update_transform_gizmo();
  77. }
  78. }
  79. String EditorNode3DGizmo::get_handle_name(int p_id, bool p_secondary) const {
  80. String ret;
  81. if (GDVIRTUAL_CALL(_get_handle_name, p_id, p_secondary, ret)) {
  82. return ret;
  83. }
  84. ERR_FAIL_NULL_V(gizmo_plugin, "");
  85. return gizmo_plugin->get_handle_name(this, p_id, p_secondary);
  86. }
  87. bool EditorNode3DGizmo::is_handle_highlighted(int p_id, bool p_secondary) const {
  88. bool success;
  89. if (GDVIRTUAL_CALL(_is_handle_highlighted, p_id, p_secondary, success)) {
  90. return success;
  91. }
  92. ERR_FAIL_NULL_V(gizmo_plugin, false);
  93. return gizmo_plugin->is_handle_highlighted(this, p_id, p_secondary);
  94. }
  95. Variant EditorNode3DGizmo::get_handle_value(int p_id, bool p_secondary) const {
  96. Variant value;
  97. if (GDVIRTUAL_CALL(_get_handle_value, p_id, p_secondary, value)) {
  98. return value;
  99. }
  100. ERR_FAIL_NULL_V(gizmo_plugin, Variant());
  101. return gizmo_plugin->get_handle_value(this, p_id, p_secondary);
  102. }
  103. void EditorNode3DGizmo::begin_handle_action(int p_id, bool p_secondary) {
  104. if (GDVIRTUAL_CALL(_begin_handle_action, p_id, p_secondary)) {
  105. return;
  106. }
  107. ERR_FAIL_NULL(gizmo_plugin);
  108. gizmo_plugin->begin_handle_action(this, p_id, p_secondary);
  109. }
  110. void EditorNode3DGizmo::set_handle(int p_id, bool p_secondary, Camera3D *p_camera, const Point2 &p_point) {
  111. if (GDVIRTUAL_CALL(_set_handle, p_id, p_secondary, p_camera, p_point)) {
  112. return;
  113. }
  114. ERR_FAIL_NULL(gizmo_plugin);
  115. gizmo_plugin->set_handle(this, p_id, p_secondary, p_camera, p_point);
  116. }
  117. void EditorNode3DGizmo::commit_handle(int p_id, bool p_secondary, const Variant &p_restore, bool p_cancel) {
  118. if (GDVIRTUAL_CALL(_commit_handle, p_id, p_secondary, p_restore, p_cancel)) {
  119. return;
  120. }
  121. ERR_FAIL_NULL(gizmo_plugin);
  122. gizmo_plugin->commit_handle(this, p_id, p_secondary, p_restore, p_cancel);
  123. }
  124. int EditorNode3DGizmo::subgizmos_intersect_ray(Camera3D *p_camera, const Vector2 &p_point) const {
  125. int id;
  126. if (GDVIRTUAL_CALL(_subgizmos_intersect_ray, p_camera, p_point, id)) {
  127. return id;
  128. }
  129. ERR_FAIL_NULL_V(gizmo_plugin, -1);
  130. return gizmo_plugin->subgizmos_intersect_ray(this, p_camera, p_point);
  131. }
  132. Vector<int> EditorNode3DGizmo::subgizmos_intersect_frustum(const Camera3D *p_camera, const Vector<Plane> &p_frustum) const {
  133. TypedArray<Plane> frustum;
  134. frustum.resize(p_frustum.size());
  135. for (int i = 0; i < p_frustum.size(); i++) {
  136. frustum[i] = p_frustum[i];
  137. }
  138. Vector<int> ret;
  139. if (GDVIRTUAL_CALL(_subgizmos_intersect_frustum, p_camera, frustum, ret)) {
  140. return ret;
  141. }
  142. ERR_FAIL_NULL_V(gizmo_plugin, Vector<int>());
  143. return gizmo_plugin->subgizmos_intersect_frustum(this, p_camera, p_frustum);
  144. }
  145. Transform3D EditorNode3DGizmo::get_subgizmo_transform(int p_id) const {
  146. Transform3D ret;
  147. if (GDVIRTUAL_CALL(_get_subgizmo_transform, p_id, ret)) {
  148. return ret;
  149. }
  150. ERR_FAIL_NULL_V(gizmo_plugin, Transform3D());
  151. return gizmo_plugin->get_subgizmo_transform(this, p_id);
  152. }
  153. void EditorNode3DGizmo::set_subgizmo_transform(int p_id, Transform3D p_transform) {
  154. if (GDVIRTUAL_CALL(_set_subgizmo_transform, p_id, p_transform)) {
  155. return;
  156. }
  157. ERR_FAIL_NULL(gizmo_plugin);
  158. gizmo_plugin->set_subgizmo_transform(this, p_id, p_transform);
  159. }
  160. void EditorNode3DGizmo::commit_subgizmos(const Vector<int> &p_ids, const Vector<Transform3D> &p_restore, bool p_cancel) {
  161. TypedArray<Transform3D> restore;
  162. restore.resize(p_restore.size());
  163. for (int i = 0; i < p_restore.size(); i++) {
  164. restore[i] = p_restore[i];
  165. }
  166. if (GDVIRTUAL_CALL(_commit_subgizmos, p_ids, restore, p_cancel)) {
  167. return;
  168. }
  169. ERR_FAIL_NULL(gizmo_plugin);
  170. gizmo_plugin->commit_subgizmos(this, p_ids, p_restore, p_cancel);
  171. }
  172. void EditorNode3DGizmo::set_node_3d(Node3D *p_node) {
  173. ERR_FAIL_NULL(p_node);
  174. spatial_node = p_node;
  175. }
  176. void EditorNode3DGizmo::Instance::create_instance(Node3D *p_base, bool p_hidden) {
  177. instance = RS::get_singleton()->instance_create2(mesh->get_rid(), p_base->get_world_3d()->get_scenario());
  178. RS::get_singleton()->instance_attach_object_instance_id(instance, p_base->get_instance_id());
  179. if (skin_reference.is_valid()) {
  180. RS::get_singleton()->instance_attach_skeleton(instance, skin_reference->get_skeleton());
  181. }
  182. if (extra_margin) {
  183. RS::get_singleton()->instance_set_extra_visibility_margin(instance, 1);
  184. }
  185. RS::get_singleton()->instance_geometry_set_cast_shadows_setting(instance, RS::SHADOW_CASTING_SETTING_OFF);
  186. int layer = p_hidden ? 0 : 1 << Node3DEditorViewport::GIZMO_EDIT_LAYER;
  187. RS::get_singleton()->instance_set_layer_mask(instance, layer); //gizmos are 26
  188. RS::get_singleton()->instance_geometry_set_flag(instance, RS::INSTANCE_FLAG_IGNORE_OCCLUSION_CULLING, true);
  189. RS::get_singleton()->instance_geometry_set_flag(instance, RS::INSTANCE_FLAG_USE_BAKED_LIGHT, false);
  190. }
  191. void EditorNode3DGizmo::add_mesh(const Ref<Mesh> &p_mesh, const Ref<Material> &p_material, const Transform3D &p_xform, const Ref<SkinReference> &p_skin_reference) {
  192. ERR_FAIL_NULL(spatial_node);
  193. ERR_FAIL_COND_MSG(p_mesh.is_null(), "EditorNode3DGizmo.add_mesh() requires a valid Mesh resource.");
  194. Instance ins;
  195. ins.mesh = p_mesh;
  196. ins.skin_reference = p_skin_reference;
  197. ins.material = p_material;
  198. ins.xform = p_xform;
  199. if (valid) {
  200. ins.create_instance(spatial_node, hidden);
  201. RS::get_singleton()->instance_set_transform(ins.instance, spatial_node->get_global_transform() * ins.xform);
  202. if (ins.material.is_valid()) {
  203. RS::get_singleton()->instance_geometry_set_material_override(ins.instance, p_material->get_rid());
  204. }
  205. }
  206. instances.push_back(ins);
  207. }
  208. void EditorNode3DGizmo::_update_bvh() {
  209. ERR_FAIL_NULL(spatial_node);
  210. Transform3D transform = spatial_node->get_global_transform();
  211. float effective_icon_size = selectable_icon_size > 0.0f ? selectable_icon_size : 0.0f;
  212. Vector3 icon_size_vector3 = Vector3(effective_icon_size, effective_icon_size, effective_icon_size);
  213. AABB aabb(spatial_node->get_position() - icon_size_vector3 * 100.0f, icon_size_vector3 * 200.0f);
  214. for (const Vector3 &segment_end : collision_segments) {
  215. aabb.expand_to(transform.xform(segment_end));
  216. }
  217. if (collision_mesh.is_valid()) {
  218. for (const Face3 &face : collision_mesh->get_faces()) {
  219. aabb.expand_to(transform.xform(face.vertex[0]));
  220. aabb.expand_to(transform.xform(face.vertex[1]));
  221. aabb.expand_to(transform.xform(face.vertex[2]));
  222. }
  223. }
  224. Node3DEditor::get_singleton()->update_gizmo_bvh_node(
  225. bvh_node_id,
  226. aabb);
  227. }
  228. void EditorNode3DGizmo::add_lines(const Vector<Vector3> &p_lines, const Ref<Material> &p_material, bool p_billboard, const Color &p_modulate) {
  229. add_vertices(p_lines, p_material, Mesh::PRIMITIVE_LINES, p_billboard, p_modulate);
  230. }
  231. void EditorNode3DGizmo::add_vertices(const Vector<Vector3> &p_vertices, const Ref<Material> &p_material, Mesh::PrimitiveType p_primitive_type, bool p_billboard, const Color &p_modulate) {
  232. if (p_vertices.is_empty()) {
  233. return;
  234. }
  235. ERR_FAIL_NULL(spatial_node);
  236. Instance ins;
  237. Ref<ArrayMesh> mesh = memnew(ArrayMesh);
  238. Array a;
  239. a.resize(Mesh::ARRAY_MAX);
  240. a[Mesh::ARRAY_VERTEX] = p_vertices;
  241. Vector<Color> color;
  242. color.resize(p_vertices.size());
  243. const Color vertex_color = (is_selected() ? Color(1, 1, 1, 0.8) : Color(1, 1, 1, 0.2)) * p_modulate;
  244. {
  245. Color *w = color.ptrw();
  246. for (int i = 0; i < p_vertices.size(); i++) {
  247. w[i] = vertex_color;
  248. }
  249. }
  250. a[Mesh::ARRAY_COLOR] = color;
  251. mesh->add_surface_from_arrays(p_primitive_type, a);
  252. mesh->surface_set_material(0, p_material);
  253. if (p_billboard) {
  254. float md = 0;
  255. for (int i = 0; i < p_vertices.size(); i++) {
  256. md = MAX(0, p_vertices[i].length());
  257. }
  258. if (md) {
  259. mesh->set_custom_aabb(AABB(Vector3(-md, -md, -md), Vector3(md, md, md) * 2.0));
  260. }
  261. }
  262. ins.mesh = mesh;
  263. if (valid) {
  264. ins.create_instance(spatial_node, hidden);
  265. RS::get_singleton()->instance_set_transform(ins.instance, spatial_node->get_global_transform());
  266. }
  267. instances.push_back(ins);
  268. }
  269. void EditorNode3DGizmo::add_unscaled_billboard(const Ref<Material> &p_material, real_t p_scale, const Color &p_modulate) {
  270. ERR_FAIL_NULL(spatial_node);
  271. Instance ins;
  272. Vector<Vector3> vs = {
  273. Vector3(-p_scale, p_scale, 0),
  274. Vector3(p_scale, p_scale, 0),
  275. Vector3(p_scale, -p_scale, 0),
  276. Vector3(-p_scale, -p_scale, 0)
  277. };
  278. Vector<Vector2> uv = {
  279. Vector2(0, 0),
  280. Vector2(1, 0),
  281. Vector2(1, 1),
  282. Vector2(0, 1)
  283. };
  284. Vector<Color> colors = {
  285. p_modulate,
  286. p_modulate,
  287. p_modulate,
  288. p_modulate
  289. };
  290. Vector<int> indices = { 0, 1, 2, 0, 2, 3 };
  291. Ref<ArrayMesh> mesh = memnew(ArrayMesh);
  292. Array a;
  293. a.resize(Mesh::ARRAY_MAX);
  294. a[Mesh::ARRAY_VERTEX] = vs;
  295. a[Mesh::ARRAY_TEX_UV] = uv;
  296. a[Mesh::ARRAY_INDEX] = indices;
  297. a[Mesh::ARRAY_COLOR] = colors;
  298. mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, a);
  299. mesh->surface_set_material(0, p_material);
  300. float md = 0;
  301. for (int i = 0; i < vs.size(); i++) {
  302. md = MAX(0, vs[i].length());
  303. }
  304. if (md) {
  305. mesh->set_custom_aabb(AABB(Vector3(-md, -md, -md), Vector3(md, md, md) * 2.0));
  306. }
  307. selectable_icon_size = p_scale;
  308. mesh->set_custom_aabb(AABB(Vector3(-selectable_icon_size, -selectable_icon_size, -selectable_icon_size) * 100.0f, Vector3(selectable_icon_size, selectable_icon_size, selectable_icon_size) * 200.0f));
  309. ins.mesh = mesh;
  310. if (valid) {
  311. ins.create_instance(spatial_node, hidden);
  312. RS::get_singleton()->instance_set_transform(ins.instance, spatial_node->get_global_transform());
  313. }
  314. selectable_icon_size = p_scale;
  315. instances.push_back(ins);
  316. }
  317. void EditorNode3DGizmo::add_collision_triangles(const Ref<TriangleMesh> &p_tmesh) {
  318. collision_mesh = p_tmesh;
  319. }
  320. void EditorNode3DGizmo::add_collision_segments(const Vector<Vector3> &p_lines) {
  321. int from = collision_segments.size();
  322. collision_segments.resize(from + p_lines.size());
  323. for (int i = 0; i < p_lines.size(); i++) {
  324. collision_segments.write[from + i] = p_lines[i];
  325. }
  326. }
  327. void EditorNode3DGizmo::add_handles(const Vector<Vector3> &p_handles, const Ref<Material> &p_material, const Vector<int> &p_ids, bool p_billboard, bool p_secondary) {
  328. billboard_handle = p_billboard;
  329. if (!is_selected() || !is_editable()) {
  330. return;
  331. }
  332. ERR_FAIL_NULL(spatial_node);
  333. Vector<Vector3> &handle_list = p_secondary ? secondary_handles : handles;
  334. Vector<int> &id_list = p_secondary ? secondary_handle_ids : handle_ids;
  335. if (p_ids.is_empty()) {
  336. ERR_FAIL_COND_MSG(!id_list.is_empty(), "IDs must be provided for all handles, as handles with IDs already exist.");
  337. } else {
  338. ERR_FAIL_COND_MSG(p_handles.size() != p_ids.size(), "The number of IDs should be the same as the number of handles.");
  339. }
  340. bool is_current_hover_gizmo = Node3DEditor::get_singleton()->get_current_hover_gizmo() == this;
  341. bool current_hover_handle_secondary;
  342. int current_hover_handle = Node3DEditor::get_singleton()->get_current_hover_gizmo_handle(current_hover_handle_secondary);
  343. Instance ins;
  344. Ref<ArrayMesh> mesh = memnew(ArrayMesh);
  345. Array a;
  346. a.resize(RS::ARRAY_MAX);
  347. a[RS::ARRAY_VERTEX] = p_handles;
  348. Vector<Color> colors;
  349. {
  350. colors.resize(p_handles.size());
  351. Color *w = colors.ptrw();
  352. for (int i = 0; i < p_handles.size(); i++) {
  353. int id = p_ids.is_empty() ? i : p_ids[i];
  354. Color col(1, 1, 1, 1);
  355. if (is_handle_highlighted(id, p_secondary)) {
  356. col = Color(0, 0, 1, 0.9);
  357. }
  358. if (!is_current_hover_gizmo || current_hover_handle != id || p_secondary != current_hover_handle_secondary) {
  359. col.a = 0.8;
  360. }
  361. w[i] = col;
  362. }
  363. }
  364. a[RS::ARRAY_COLOR] = colors;
  365. mesh->add_surface_from_arrays(Mesh::PRIMITIVE_POINTS, a);
  366. mesh->surface_set_material(0, p_material);
  367. if (p_billboard) {
  368. float md = 0;
  369. for (int i = 0; i < p_handles.size(); i++) {
  370. md = MAX(0, p_handles[i].length());
  371. }
  372. if (md) {
  373. mesh->set_custom_aabb(AABB(Vector3(-md, -md, -md), Vector3(md, md, md) * 2.0));
  374. }
  375. }
  376. ins.mesh = mesh;
  377. ins.extra_margin = true;
  378. if (valid) {
  379. ins.create_instance(spatial_node, hidden);
  380. RS::get_singleton()->instance_set_transform(ins.instance, spatial_node->get_global_transform());
  381. }
  382. instances.push_back(ins);
  383. int current_size = handle_list.size();
  384. handle_list.resize(current_size + p_handles.size());
  385. for (int i = 0; i < p_handles.size(); i++) {
  386. handle_list.write[current_size + i] = p_handles[i];
  387. }
  388. if (!p_ids.is_empty()) {
  389. current_size = id_list.size();
  390. id_list.resize(current_size + p_ids.size());
  391. for (int i = 0; i < p_ids.size(); i++) {
  392. id_list.write[current_size + i] = p_ids[i];
  393. }
  394. }
  395. }
  396. void EditorNode3DGizmo::add_solid_box(const Ref<Material> &p_material, Vector3 p_size, Vector3 p_position, const Transform3D &p_xform) {
  397. ERR_FAIL_NULL(spatial_node);
  398. BoxMesh box_mesh;
  399. box_mesh.set_size(p_size);
  400. Array arrays = box_mesh.surface_get_arrays(0);
  401. PackedVector3Array vertex = arrays[RS::ARRAY_VERTEX];
  402. Vector3 *w = vertex.ptrw();
  403. for (int i = 0; i < vertex.size(); ++i) {
  404. w[i] += p_position;
  405. }
  406. arrays[RS::ARRAY_VERTEX] = vertex;
  407. Ref<ArrayMesh> m = memnew(ArrayMesh);
  408. m->add_surface_from_arrays(box_mesh.surface_get_primitive_type(0), arrays);
  409. add_mesh(m, p_material, p_xform);
  410. }
  411. bool EditorNode3DGizmo::intersect_frustum(const Camera3D *p_camera, const Vector<Plane> &p_frustum) {
  412. ERR_FAIL_NULL_V(spatial_node, false);
  413. ERR_FAIL_COND_V(!valid, false);
  414. if (hidden && !gizmo_plugin->is_selectable_when_hidden()) {
  415. return false;
  416. }
  417. if (selectable_icon_size > 0.0f) {
  418. Vector3 origin = spatial_node->get_global_transform().get_origin();
  419. const Plane *p = p_frustum.ptr();
  420. int fc = p_frustum.size();
  421. bool any_out = false;
  422. for (int j = 0; j < fc; j++) {
  423. if (p[j].is_point_over(origin)) {
  424. any_out = true;
  425. break;
  426. }
  427. }
  428. return !any_out;
  429. }
  430. if (collision_segments.size()) {
  431. const Plane *p = p_frustum.ptr();
  432. int fc = p_frustum.size();
  433. int vc = collision_segments.size();
  434. const Vector3 *vptr = collision_segments.ptr();
  435. Transform3D t = spatial_node->get_global_transform();
  436. bool any_out = false;
  437. for (int j = 0; j < fc; j++) {
  438. for (int i = 0; i < vc; i++) {
  439. Vector3 v = t.xform(vptr[i]);
  440. if (p[j].is_point_over(v)) {
  441. any_out = true;
  442. break;
  443. }
  444. }
  445. if (any_out) {
  446. break;
  447. }
  448. }
  449. if (!any_out) {
  450. return true;
  451. }
  452. }
  453. if (collision_mesh.is_valid()) {
  454. Transform3D t = spatial_node->get_global_transform();
  455. Vector3 mesh_scale = t.get_basis().get_scale();
  456. t.orthonormalize();
  457. Transform3D it = t.affine_inverse();
  458. Vector<Plane> transformed_frustum;
  459. int plane_count = p_frustum.size();
  460. transformed_frustum.resize(plane_count);
  461. for (int i = 0; i < plane_count; i++) {
  462. transformed_frustum.write[i] = it.xform(p_frustum[i]);
  463. }
  464. Vector<Vector3> convex_points = Geometry3D::compute_convex_mesh_points(transformed_frustum.ptr(), plane_count);
  465. if (collision_mesh->inside_convex_shape(transformed_frustum.ptr(), plane_count, convex_points.ptr(), convex_points.size(), mesh_scale)) {
  466. return true;
  467. }
  468. }
  469. return false;
  470. }
  471. void EditorNode3DGizmo::handles_intersect_ray(Camera3D *p_camera, const Vector2 &p_point, bool p_shift_pressed, int &r_id, bool &r_secondary) {
  472. r_id = -1;
  473. r_secondary = false;
  474. ERR_FAIL_NULL(spatial_node);
  475. ERR_FAIL_COND(!valid);
  476. if (hidden) {
  477. return;
  478. }
  479. Transform3D camera_xform = p_camera->get_global_transform();
  480. Transform3D t = spatial_node->get_global_transform();
  481. if (billboard_handle) {
  482. t.set_look_at(t.origin, t.origin - camera_xform.basis.get_column(2), camera_xform.basis.get_column(1));
  483. }
  484. float min_d = 1e20;
  485. for (int i = 0; i < secondary_handles.size(); i++) {
  486. Vector3 hpos = t.xform(secondary_handles[i]);
  487. Vector2 p = p_camera->unproject_position(hpos);
  488. if (p.distance_to(p_point) < HANDLE_HALF_SIZE) {
  489. real_t dp = p_camera->get_transform().origin.distance_to(hpos);
  490. if (dp < min_d) {
  491. min_d = dp;
  492. if (secondary_handle_ids.is_empty()) {
  493. r_id = i;
  494. } else {
  495. r_id = secondary_handle_ids[i];
  496. }
  497. r_secondary = true;
  498. }
  499. }
  500. }
  501. if (r_id != -1 && p_shift_pressed) {
  502. return;
  503. }
  504. min_d = 1e20;
  505. for (int i = 0; i < handles.size(); i++) {
  506. Vector3 hpos = t.xform(handles[i]);
  507. Vector2 p = p_camera->unproject_position(hpos);
  508. if (p.distance_to(p_point) < HANDLE_HALF_SIZE) {
  509. real_t dp = p_camera->get_transform().origin.distance_to(hpos);
  510. if (dp < min_d) {
  511. min_d = dp;
  512. if (handle_ids.is_empty()) {
  513. r_id = i;
  514. } else {
  515. r_id = handle_ids[i];
  516. }
  517. r_secondary = false;
  518. }
  519. }
  520. }
  521. }
  522. bool EditorNode3DGizmo::intersect_ray(Camera3D *p_camera, const Point2 &p_point, Vector3 &r_pos, Vector3 &r_normal) {
  523. ERR_FAIL_NULL_V(spatial_node, false);
  524. ERR_FAIL_COND_V(!valid, false);
  525. if (hidden && !gizmo_plugin->is_selectable_when_hidden()) {
  526. return false;
  527. }
  528. if (selectable_icon_size > 0.0f) {
  529. Transform3D t = spatial_node->get_global_transform();
  530. Vector3 camera_position = p_camera->get_camera_transform().origin;
  531. if (!camera_position.is_equal_approx(t.origin)) {
  532. t.set_look_at(t.origin, camera_position);
  533. }
  534. float scale = t.origin.distance_to(p_camera->get_camera_transform().origin);
  535. if (p_camera->get_projection() == Camera3D::PROJECTION_ORTHOGONAL) {
  536. float aspect = p_camera->get_viewport()->get_visible_rect().size.aspect();
  537. float size = p_camera->get_size();
  538. scale = size / aspect;
  539. }
  540. Point2 center = p_camera->unproject_position(t.origin);
  541. Transform3D orig_camera_transform = p_camera->get_camera_transform();
  542. if (!orig_camera_transform.origin.is_equal_approx(t.origin) &&
  543. ABS(orig_camera_transform.basis.get_column(Vector3::AXIS_Z).dot(Vector3(0, 1, 0))) < 0.99) {
  544. p_camera->look_at(t.origin);
  545. }
  546. Vector3 c0 = t.xform(Vector3(selectable_icon_size, selectable_icon_size, 0) * scale);
  547. Vector3 c1 = t.xform(Vector3(-selectable_icon_size, -selectable_icon_size, 0) * scale);
  548. Point2 p0 = p_camera->unproject_position(c0);
  549. Point2 p1 = p_camera->unproject_position(c1);
  550. p_camera->set_global_transform(orig_camera_transform);
  551. Rect2 rect(p0, (p1 - p0).abs());
  552. rect.set_position(center - rect.get_size() / 2.0);
  553. if (rect.has_point(p_point)) {
  554. r_pos = t.origin;
  555. r_normal = -p_camera->project_ray_normal(p_point);
  556. return true;
  557. }
  558. }
  559. if (collision_segments.size()) {
  560. Plane camp(-p_camera->get_transform().basis.get_column(2).normalized(), p_camera->get_transform().origin);
  561. int vc = collision_segments.size();
  562. const Vector3 *vptr = collision_segments.ptr();
  563. Transform3D t = spatial_node->get_global_transform();
  564. if (billboard_handle) {
  565. t.set_look_at(t.origin, t.origin - p_camera->get_transform().basis.get_column(2), p_camera->get_transform().basis.get_column(1));
  566. }
  567. Vector3 cp;
  568. float cpd = 1e20;
  569. for (int i = 0; i < vc / 2; i++) {
  570. Vector3 a = t.xform(vptr[i * 2 + 0]);
  571. Vector3 b = t.xform(vptr[i * 2 + 1]);
  572. Vector2 s[2];
  573. s[0] = p_camera->unproject_position(a);
  574. s[1] = p_camera->unproject_position(b);
  575. Vector2 p = Geometry2D::get_closest_point_to_segment(p_point, s);
  576. float pd = p.distance_to(p_point);
  577. if (pd < cpd) {
  578. float d = s[0].distance_to(s[1]);
  579. Vector3 tcp;
  580. if (d > 0) {
  581. float d2 = s[0].distance_to(p) / d;
  582. tcp = a + (b - a) * d2;
  583. } else {
  584. tcp = a;
  585. }
  586. if (camp.distance_to(tcp) < p_camera->get_near()) {
  587. continue;
  588. }
  589. cp = tcp;
  590. cpd = pd;
  591. }
  592. }
  593. if (cpd < 8) {
  594. r_pos = cp;
  595. r_normal = -p_camera->project_ray_normal(p_point);
  596. return true;
  597. }
  598. }
  599. if (collision_mesh.is_valid()) {
  600. Transform3D gt = spatial_node->get_global_transform();
  601. if (billboard_handle) {
  602. gt.set_look_at(gt.origin, gt.origin - p_camera->get_transform().basis.get_column(2), p_camera->get_transform().basis.get_column(1));
  603. }
  604. Transform3D ai = gt.affine_inverse();
  605. Vector3 ray_from = ai.xform(p_camera->project_ray_origin(p_point));
  606. Vector3 ray_dir = ai.basis.xform(p_camera->project_ray_normal(p_point)).normalized();
  607. Vector3 rpos, rnorm;
  608. if (collision_mesh->intersect_ray(ray_from, ray_dir, rpos, rnorm)) {
  609. r_pos = gt.xform(rpos);
  610. r_normal = gt.basis.xform(rnorm).normalized();
  611. return true;
  612. }
  613. }
  614. return false;
  615. }
  616. bool EditorNode3DGizmo::is_subgizmo_selected(int p_id) const {
  617. Node3DEditor *ed = Node3DEditor::get_singleton();
  618. ERR_FAIL_NULL_V(ed, false);
  619. return ed->is_current_selected_gizmo(this) && ed->is_subgizmo_selected(p_id);
  620. }
  621. Vector<int> EditorNode3DGizmo::get_subgizmo_selection() const {
  622. Vector<int> ret;
  623. Node3DEditor *ed = Node3DEditor::get_singleton();
  624. ERR_FAIL_NULL_V(ed, ret);
  625. if (ed->is_current_selected_gizmo(this)) {
  626. ret = ed->get_subgizmo_selection();
  627. }
  628. return ret;
  629. }
  630. void EditorNode3DGizmo::create() {
  631. ERR_FAIL_NULL(spatial_node);
  632. ERR_FAIL_COND(valid);
  633. valid = true;
  634. for (int i = 0; i < instances.size(); i++) {
  635. instances.write[i].create_instance(spatial_node, hidden);
  636. }
  637. bvh_node_id = Node3DEditor::get_singleton()->insert_gizmo_bvh_node(
  638. spatial_node,
  639. AABB(spatial_node->get_position(), Vector3(0, 0, 0)));
  640. transform();
  641. }
  642. void EditorNode3DGizmo::transform() {
  643. ERR_FAIL_NULL(spatial_node);
  644. ERR_FAIL_COND(!valid);
  645. for (int i = 0; i < instances.size(); i++) {
  646. RS::get_singleton()->instance_set_transform(instances[i].instance, spatial_node->get_global_transform() * instances[i].xform);
  647. }
  648. _update_bvh();
  649. }
  650. void EditorNode3DGizmo::free() {
  651. ERR_FAIL_NULL(RenderingServer::get_singleton());
  652. ERR_FAIL_NULL(spatial_node);
  653. ERR_FAIL_COND(!valid);
  654. for (int i = 0; i < instances.size(); i++) {
  655. if (instances[i].instance.is_valid()) {
  656. RS::get_singleton()->free(instances[i].instance);
  657. }
  658. instances.write[i].instance = RID();
  659. }
  660. clear();
  661. Node3DEditor::get_singleton()->remove_gizmo_bvh_node(bvh_node_id);
  662. bvh_node_id = DynamicBVH::ID();
  663. valid = false;
  664. }
  665. void EditorNode3DGizmo::set_hidden(bool p_hidden) {
  666. hidden = p_hidden;
  667. int layer = hidden ? 0 : 1 << Node3DEditorViewport::GIZMO_EDIT_LAYER;
  668. for (int i = 0; i < instances.size(); ++i) {
  669. RS::get_singleton()->instance_set_layer_mask(instances[i].instance, layer);
  670. }
  671. }
  672. void EditorNode3DGizmo::set_plugin(EditorNode3DGizmoPlugin *p_plugin) {
  673. gizmo_plugin = p_plugin;
  674. }
  675. void EditorNode3DGizmo::_bind_methods() {
  676. ClassDB::bind_method(D_METHOD("add_lines", "lines", "material", "billboard", "modulate"), &EditorNode3DGizmo::add_lines, DEFVAL(false), DEFVAL(Color(1, 1, 1)));
  677. ClassDB::bind_method(D_METHOD("add_mesh", "mesh", "material", "transform", "skeleton"), &EditorNode3DGizmo::add_mesh, DEFVAL(Variant()), DEFVAL(Transform3D()), DEFVAL(Ref<SkinReference>()));
  678. ClassDB::bind_method(D_METHOD("add_collision_segments", "segments"), &EditorNode3DGizmo::add_collision_segments);
  679. ClassDB::bind_method(D_METHOD("add_collision_triangles", "triangles"), &EditorNode3DGizmo::add_collision_triangles);
  680. ClassDB::bind_method(D_METHOD("add_unscaled_billboard", "material", "default_scale", "modulate"), &EditorNode3DGizmo::add_unscaled_billboard, DEFVAL(1), DEFVAL(Color(1, 1, 1)));
  681. ClassDB::bind_method(D_METHOD("add_handles", "handles", "material", "ids", "billboard", "secondary"), &EditorNode3DGizmo::add_handles, DEFVAL(false), DEFVAL(false));
  682. ClassDB::bind_method(D_METHOD("set_node_3d", "node"), &EditorNode3DGizmo::_set_node_3d);
  683. ClassDB::bind_method(D_METHOD("get_node_3d"), &EditorNode3DGizmo::get_node_3d);
  684. ClassDB::bind_method(D_METHOD("get_plugin"), &EditorNode3DGizmo::get_plugin);
  685. ClassDB::bind_method(D_METHOD("clear"), &EditorNode3DGizmo::clear);
  686. ClassDB::bind_method(D_METHOD("set_hidden", "hidden"), &EditorNode3DGizmo::set_hidden);
  687. ClassDB::bind_method(D_METHOD("is_subgizmo_selected", "id"), &EditorNode3DGizmo::is_subgizmo_selected);
  688. ClassDB::bind_method(D_METHOD("get_subgizmo_selection"), &EditorNode3DGizmo::get_subgizmo_selection);
  689. GDVIRTUAL_BIND(_redraw);
  690. GDVIRTUAL_BIND(_get_handle_name, "id", "secondary");
  691. GDVIRTUAL_BIND(_is_handle_highlighted, "id", "secondary");
  692. GDVIRTUAL_BIND(_get_handle_value, "id", "secondary");
  693. GDVIRTUAL_BIND(_begin_handle_action, "id", "secondary");
  694. GDVIRTUAL_BIND(_set_handle, "id", "secondary", "camera", "point");
  695. GDVIRTUAL_BIND(_commit_handle, "id", "secondary", "restore", "cancel");
  696. GDVIRTUAL_BIND(_subgizmos_intersect_ray, "camera", "point");
  697. GDVIRTUAL_BIND(_subgizmos_intersect_frustum, "camera", "frustum");
  698. GDVIRTUAL_BIND(_set_subgizmo_transform, "id", "transform");
  699. GDVIRTUAL_BIND(_get_subgizmo_transform, "id");
  700. GDVIRTUAL_BIND(_commit_subgizmos, "ids", "restores", "cancel");
  701. }
  702. EditorNode3DGizmo::EditorNode3DGizmo() {
  703. valid = false;
  704. billboard_handle = false;
  705. hidden = false;
  706. selected = false;
  707. spatial_node = nullptr;
  708. gizmo_plugin = nullptr;
  709. selectable_icon_size = -1.0f;
  710. }
  711. EditorNode3DGizmo::~EditorNode3DGizmo() {
  712. if (gizmo_plugin != nullptr) {
  713. gizmo_plugin->unregister_gizmo(this);
  714. }
  715. clear();
  716. }
  717. /////
  718. void EditorNode3DGizmoPlugin::create_material(const String &p_name, const Color &p_color, bool p_billboard, bool p_on_top, bool p_use_vertex_color) {
  719. Color instantiated_color = EDITOR_GET("editors/3d_gizmos/gizmo_colors/instantiated");
  720. Vector<Ref<StandardMaterial3D>> mats;
  721. for (int i = 0; i < 4; i++) {
  722. bool selected = i % 2 == 1;
  723. bool instantiated = i < 2;
  724. Ref<StandardMaterial3D> material = Ref<StandardMaterial3D>(memnew(StandardMaterial3D));
  725. Color color = instantiated ? instantiated_color : p_color;
  726. if (!selected) {
  727. color.a *= 0.3;
  728. }
  729. material->set_albedo(color);
  730. material->set_shading_mode(StandardMaterial3D::SHADING_MODE_UNSHADED);
  731. material->set_transparency(StandardMaterial3D::TRANSPARENCY_ALPHA);
  732. material->set_render_priority(StandardMaterial3D::RENDER_PRIORITY_MIN + 1);
  733. material->set_cull_mode(StandardMaterial3D::CULL_DISABLED);
  734. material->set_flag(StandardMaterial3D::FLAG_DISABLE_FOG, true);
  735. if (p_use_vertex_color) {
  736. material->set_flag(StandardMaterial3D::FLAG_ALBEDO_FROM_VERTEX_COLOR, true);
  737. material->set_flag(StandardMaterial3D::FLAG_SRGB_VERTEX_COLOR, true);
  738. }
  739. if (p_billboard) {
  740. material->set_billboard_mode(StandardMaterial3D::BILLBOARD_ENABLED);
  741. }
  742. if (p_on_top && selected) {
  743. material->set_on_top_of_alpha();
  744. }
  745. mats.push_back(material);
  746. }
  747. materials[p_name] = mats;
  748. }
  749. void EditorNode3DGizmoPlugin::create_icon_material(const String &p_name, const Ref<Texture2D> &p_texture, bool p_on_top, const Color &p_albedo) {
  750. Color instantiated_color = EDITOR_GET("editors/3d_gizmos/gizmo_colors/instantiated");
  751. Vector<Ref<StandardMaterial3D>> icons;
  752. for (int i = 0; i < 4; i++) {
  753. bool selected = i % 2 == 1;
  754. bool instantiated = i < 2;
  755. Ref<StandardMaterial3D> icon = Ref<StandardMaterial3D>(memnew(StandardMaterial3D));
  756. Color color = instantiated ? instantiated_color : p_albedo;
  757. if (!selected) {
  758. color.r *= 0.6;
  759. color.g *= 0.6;
  760. color.b *= 0.6;
  761. }
  762. icon->set_albedo(color);
  763. icon->set_shading_mode(StandardMaterial3D::SHADING_MODE_UNSHADED);
  764. icon->set_flag(StandardMaterial3D::FLAG_ALBEDO_FROM_VERTEX_COLOR, true);
  765. icon->set_flag(StandardMaterial3D::FLAG_SRGB_VERTEX_COLOR, true);
  766. icon->set_flag(StandardMaterial3D::FLAG_DISABLE_FOG, true);
  767. icon->set_transparency(StandardMaterial3D::TRANSPARENCY_ALPHA_SCISSOR);
  768. icon->set_alpha_scissor_threshold(0.1);
  769. icon->set_texture(StandardMaterial3D::TEXTURE_ALBEDO, p_texture);
  770. icon->set_flag(StandardMaterial3D::FLAG_FIXED_SIZE, true);
  771. icon->set_billboard_mode(StandardMaterial3D::BILLBOARD_ENABLED);
  772. icon->set_render_priority(StandardMaterial3D::RENDER_PRIORITY_MIN);
  773. if (p_on_top && selected) {
  774. icon->set_on_top_of_alpha();
  775. }
  776. icons.push_back(icon);
  777. }
  778. materials[p_name] = icons;
  779. }
  780. void EditorNode3DGizmoPlugin::create_handle_material(const String &p_name, bool p_billboard, const Ref<Texture2D> &p_icon) {
  781. Ref<StandardMaterial3D> handle_material = Ref<StandardMaterial3D>(memnew(StandardMaterial3D));
  782. handle_material->set_shading_mode(StandardMaterial3D::SHADING_MODE_UNSHADED);
  783. handle_material->set_flag(StandardMaterial3D::FLAG_USE_POINT_SIZE, true);
  784. Ref<Texture2D> handle_t = p_icon.is_valid() ? p_icon : EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("Editor3DHandle"), EditorStringName(EditorIcons));
  785. handle_material->set_point_size(handle_t->get_width());
  786. handle_material->set_texture(StandardMaterial3D::TEXTURE_ALBEDO, handle_t);
  787. handle_material->set_albedo(Color(1, 1, 1));
  788. handle_material->set_flag(StandardMaterial3D::FLAG_ALBEDO_FROM_VERTEX_COLOR, true);
  789. handle_material->set_flag(StandardMaterial3D::FLAG_SRGB_VERTEX_COLOR, true);
  790. handle_material->set_flag(StandardMaterial3D::FLAG_DISABLE_FOG, true);
  791. handle_material->set_on_top_of_alpha();
  792. if (p_billboard) {
  793. handle_material->set_billboard_mode(StandardMaterial3D::BILLBOARD_ENABLED);
  794. handle_material->set_on_top_of_alpha();
  795. }
  796. handle_material->set_transparency(StandardMaterial3D::TRANSPARENCY_ALPHA);
  797. materials[p_name] = Vector<Ref<StandardMaterial3D>>();
  798. materials[p_name].push_back(handle_material);
  799. }
  800. void EditorNode3DGizmoPlugin::add_material(const String &p_name, Ref<StandardMaterial3D> p_material) {
  801. materials[p_name] = Vector<Ref<StandardMaterial3D>>();
  802. materials[p_name].push_back(p_material);
  803. }
  804. Ref<StandardMaterial3D> EditorNode3DGizmoPlugin::get_material(const String &p_name, const Ref<EditorNode3DGizmo> &p_gizmo) {
  805. ERR_FAIL_COND_V(!materials.has(p_name), Ref<StandardMaterial3D>());
  806. ERR_FAIL_COND_V(materials[p_name].is_empty(), Ref<StandardMaterial3D>());
  807. if (p_gizmo.is_null() || materials[p_name].size() == 1) {
  808. return materials[p_name][0];
  809. }
  810. int index = (p_gizmo->is_selected() ? 1 : 0) + (p_gizmo->is_editable() ? 2 : 0);
  811. Ref<StandardMaterial3D> mat = materials[p_name][index];
  812. bool on_top_mat = mat->get_flag(StandardMaterial3D::FLAG_DISABLE_DEPTH_TEST);
  813. if (!on_top_mat && current_state == ON_TOP && p_gizmo->is_selected()) {
  814. mat = mat->duplicate();
  815. mat->set_flag(StandardMaterial3D::FLAG_DISABLE_DEPTH_TEST, true);
  816. }
  817. return mat;
  818. }
  819. String EditorNode3DGizmoPlugin::get_gizmo_name() const {
  820. String ret;
  821. if (GDVIRTUAL_CALL(_get_gizmo_name, ret)) {
  822. return ret;
  823. }
  824. WARN_PRINT_ONCE("A 3D editor gizmo has no name defined (it will appear as \"Unnamed Gizmo\" in the \"View > Gizmos\" menu). To resolve this, override the `_get_gizmo_name()` function to return a String in the script that extends EditorNode3DGizmoPlugin.");
  825. return TTR("Unnamed Gizmo");
  826. }
  827. int EditorNode3DGizmoPlugin::get_priority() const {
  828. int ret;
  829. if (GDVIRTUAL_CALL(_get_priority, ret)) {
  830. return ret;
  831. }
  832. return 0;
  833. }
  834. Ref<EditorNode3DGizmo> EditorNode3DGizmoPlugin::get_gizmo(Node3D *p_spatial) {
  835. if (get_script_instance() && get_script_instance()->has_method("_get_gizmo")) {
  836. return get_script_instance()->call("_get_gizmo", p_spatial);
  837. }
  838. Ref<EditorNode3DGizmo> ref = create_gizmo(p_spatial);
  839. if (ref.is_null()) {
  840. return ref;
  841. }
  842. ref->set_plugin(this);
  843. ref->set_node_3d(p_spatial);
  844. ref->set_hidden(current_state == HIDDEN);
  845. current_gizmos.insert(ref.ptr());
  846. return ref;
  847. }
  848. void EditorNode3DGizmoPlugin::_bind_methods() {
  849. ClassDB::bind_method(D_METHOD("create_material", "name", "color", "billboard", "on_top", "use_vertex_color"), &EditorNode3DGizmoPlugin::create_material, DEFVAL(false), DEFVAL(false), DEFVAL(false));
  850. ClassDB::bind_method(D_METHOD("create_icon_material", "name", "texture", "on_top", "color"), &EditorNode3DGizmoPlugin::create_icon_material, DEFVAL(false), DEFVAL(Color(1, 1, 1, 1)));
  851. ClassDB::bind_method(D_METHOD("create_handle_material", "name", "billboard", "texture"), &EditorNode3DGizmoPlugin::create_handle_material, DEFVAL(false), DEFVAL(Variant()));
  852. ClassDB::bind_method(D_METHOD("add_material", "name", "material"), &EditorNode3DGizmoPlugin::add_material);
  853. ClassDB::bind_method(D_METHOD("get_material", "name", "gizmo"), &EditorNode3DGizmoPlugin::get_material, DEFVAL(Ref<EditorNode3DGizmo>()));
  854. GDVIRTUAL_BIND(_has_gizmo, "for_node_3d");
  855. GDVIRTUAL_BIND(_create_gizmo, "for_node_3d");
  856. GDVIRTUAL_BIND(_get_gizmo_name);
  857. GDVIRTUAL_BIND(_get_priority);
  858. GDVIRTUAL_BIND(_can_be_hidden);
  859. GDVIRTUAL_BIND(_is_selectable_when_hidden);
  860. GDVIRTUAL_BIND(_redraw, "gizmo");
  861. GDVIRTUAL_BIND(_get_handle_name, "gizmo", "handle_id", "secondary");
  862. GDVIRTUAL_BIND(_is_handle_highlighted, "gizmo", "handle_id", "secondary");
  863. GDVIRTUAL_BIND(_get_handle_value, "gizmo", "handle_id", "secondary");
  864. GDVIRTUAL_BIND(_begin_handle_action, "gizmo", "handle_id", "secondary");
  865. GDVIRTUAL_BIND(_set_handle, "gizmo", "handle_id", "secondary", "camera", "screen_pos");
  866. GDVIRTUAL_BIND(_commit_handle, "gizmo", "handle_id", "secondary", "restore", "cancel");
  867. GDVIRTUAL_BIND(_subgizmos_intersect_ray, "gizmo", "camera", "screen_pos");
  868. GDVIRTUAL_BIND(_subgizmos_intersect_frustum, "gizmo", "camera", "frustum_planes");
  869. GDVIRTUAL_BIND(_get_subgizmo_transform, "gizmo", "subgizmo_id");
  870. GDVIRTUAL_BIND(_set_subgizmo_transform, "gizmo", "subgizmo_id", "transform");
  871. GDVIRTUAL_BIND(_commit_subgizmos, "gizmo", "ids", "restores", "cancel");
  872. }
  873. bool EditorNode3DGizmoPlugin::has_gizmo(Node3D *p_spatial) {
  874. bool success = false;
  875. GDVIRTUAL_CALL(_has_gizmo, p_spatial, success);
  876. return success;
  877. }
  878. Ref<EditorNode3DGizmo> EditorNode3DGizmoPlugin::create_gizmo(Node3D *p_spatial) {
  879. Ref<EditorNode3DGizmo> ret;
  880. if (GDVIRTUAL_CALL(_create_gizmo, p_spatial, ret)) {
  881. return ret;
  882. }
  883. Ref<EditorNode3DGizmo> ref;
  884. if (has_gizmo(p_spatial)) {
  885. ref.instantiate();
  886. }
  887. return ref;
  888. }
  889. bool EditorNode3DGizmoPlugin::can_be_hidden() const {
  890. bool ret = true;
  891. GDVIRTUAL_CALL(_can_be_hidden, ret);
  892. return ret;
  893. }
  894. bool EditorNode3DGizmoPlugin::is_selectable_when_hidden() const {
  895. bool ret = false;
  896. GDVIRTUAL_CALL(_is_selectable_when_hidden, ret);
  897. return ret;
  898. }
  899. void EditorNode3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
  900. GDVIRTUAL_CALL(_redraw, p_gizmo);
  901. }
  902. bool EditorNode3DGizmoPlugin::is_handle_highlighted(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const {
  903. bool ret = false;
  904. GDVIRTUAL_CALL(_is_handle_highlighted, Ref<EditorNode3DGizmo>(p_gizmo), p_id, p_secondary, ret);
  905. return ret;
  906. }
  907. String EditorNode3DGizmoPlugin::get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const {
  908. String ret;
  909. GDVIRTUAL_CALL(_get_handle_name, Ref<EditorNode3DGizmo>(p_gizmo), p_id, p_secondary, ret);
  910. return ret;
  911. }
  912. Variant EditorNode3DGizmoPlugin::get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const {
  913. Variant ret;
  914. GDVIRTUAL_CALL(_get_handle_value, Ref<EditorNode3DGizmo>(p_gizmo), p_id, p_secondary, ret);
  915. return ret;
  916. }
  917. void EditorNode3DGizmoPlugin::begin_handle_action(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) {
  918. GDVIRTUAL_CALL(_begin_handle_action, Ref<EditorNode3DGizmo>(p_gizmo), p_id, p_secondary);
  919. }
  920. void EditorNode3DGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, Camera3D *p_camera, const Point2 &p_point) {
  921. GDVIRTUAL_CALL(_set_handle, Ref<EditorNode3DGizmo>(p_gizmo), p_id, p_secondary, p_camera, p_point);
  922. }
  923. void EditorNode3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, const Variant &p_restore, bool p_cancel) {
  924. GDVIRTUAL_CALL(_commit_handle, Ref<EditorNode3DGizmo>(p_gizmo), p_id, p_secondary, p_restore, p_cancel);
  925. }
  926. int EditorNode3DGizmoPlugin::subgizmos_intersect_ray(const EditorNode3DGizmo *p_gizmo, Camera3D *p_camera, const Vector2 &p_point) const {
  927. int ret = -1;
  928. GDVIRTUAL_CALL(_subgizmos_intersect_ray, Ref<EditorNode3DGizmo>(p_gizmo), p_camera, p_point, ret);
  929. return ret;
  930. }
  931. Vector<int> EditorNode3DGizmoPlugin::subgizmos_intersect_frustum(const EditorNode3DGizmo *p_gizmo, const Camera3D *p_camera, const Vector<Plane> &p_frustum) const {
  932. TypedArray<Plane> frustum;
  933. frustum.resize(p_frustum.size());
  934. for (int i = 0; i < p_frustum.size(); i++) {
  935. frustum[i] = p_frustum[i];
  936. }
  937. Vector<int> ret;
  938. GDVIRTUAL_CALL(_subgizmos_intersect_frustum, Ref<EditorNode3DGizmo>(p_gizmo), p_camera, frustum, ret);
  939. return ret;
  940. }
  941. Transform3D EditorNode3DGizmoPlugin::get_subgizmo_transform(const EditorNode3DGizmo *p_gizmo, int p_id) const {
  942. Transform3D ret;
  943. GDVIRTUAL_CALL(_get_subgizmo_transform, Ref<EditorNode3DGizmo>(p_gizmo), p_id, ret);
  944. return ret;
  945. }
  946. void EditorNode3DGizmoPlugin::set_subgizmo_transform(const EditorNode3DGizmo *p_gizmo, int p_id, Transform3D p_transform) {
  947. GDVIRTUAL_CALL(_set_subgizmo_transform, Ref<EditorNode3DGizmo>(p_gizmo), p_id, p_transform);
  948. }
  949. void EditorNode3DGizmoPlugin::commit_subgizmos(const EditorNode3DGizmo *p_gizmo, const Vector<int> &p_ids, const Vector<Transform3D> &p_restore, bool p_cancel) {
  950. TypedArray<Transform3D> restore;
  951. restore.resize(p_restore.size());
  952. for (int i = 0; i < p_restore.size(); i++) {
  953. restore[i] = p_restore[i];
  954. }
  955. GDVIRTUAL_CALL(_commit_subgizmos, Ref<EditorNode3DGizmo>(p_gizmo), p_ids, restore, p_cancel);
  956. }
  957. void EditorNode3DGizmoPlugin::set_state(int p_state) {
  958. current_state = p_state;
  959. for (EditorNode3DGizmo *current : current_gizmos) {
  960. current->set_hidden(current_state == HIDDEN);
  961. }
  962. }
  963. int EditorNode3DGizmoPlugin::get_state() const {
  964. return current_state;
  965. }
  966. void EditorNode3DGizmoPlugin::unregister_gizmo(EditorNode3DGizmo *p_gizmo) {
  967. current_gizmos.erase(p_gizmo);
  968. }
  969. EditorNode3DGizmoPlugin::EditorNode3DGizmoPlugin() {
  970. current_state = VISIBLE;
  971. }
  972. EditorNode3DGizmoPlugin::~EditorNode3DGizmoPlugin() {
  973. for (EditorNode3DGizmo *current : current_gizmos) {
  974. current->set_plugin(nullptr);
  975. current->get_node_3d()->remove_gizmo(current);
  976. }
  977. if (Node3DEditor::get_singleton()) {
  978. Node3DEditor::get_singleton()->update_all_gizmos();
  979. }
  980. }
  981. //////