diff --git a/doc/classes/NavigationServer.xml b/doc/classes/NavigationServer.xml index 7f9698bcf..639119cca 100644 --- a/doc/classes/NavigationServer.xml +++ b/doc/classes/NavigationServer.xml @@ -430,6 +430,11 @@ Emitted when a navigation map is updated, when a region moves or is modified. + + + Emitted when navigation debug settings are changed. Only available in debug builds. + + diff --git a/doc/classes/ProjectSettings.xml b/doc/classes/ProjectSettings.xml index 74a2277f4..1877a253e 100644 --- a/doc/classes/ProjectSettings.xml +++ b/doc/classes/ProjectSettings.xml @@ -532,9 +532,39 @@ Color of the disabled navigation geometry, visible when "Visible Navigation" is enabled in the Debug menu. + + Color to display edge connections between navigation regions, visible when "Visible Navigation" is enabled in the Debug menu. + + + If enabled, displays edge connections between navigation regions when "Visible Navigation" is enabled in the Debug menu. + + + If enabled, displays edge connections between navigation regions through geometry when "Visible Navigation" is enabled in the Debug menu. + + + If enabled, displays navigation mesh polygon edges when "Visible Navigation" is enabled in the Debug menu. + + + If enabled, displays navigation mesh polygon edges through geometry when "Visible Navigation" is enabled in the Debug menu. + + + If enabled, colorizes each navigation mesh polygon face with a random color when "Visible Navigation" is enabled in the Debug menu. + Color of the navigation geometry, visible when "Visible Navigation" is enabled in the Debug menu. + + Color to display enabled navigation mesh polygon edges, visible when "Visible Navigation" is enabled in the Debug menu. + + + Color to display disabled navigation mesh polygon edges, visible when "Visible Navigation" is enabled in the Debug menu. + + + Color to display enabled navigation mesh polygon faces, visible when "Visible Navigation" is enabled in the Debug menu. + + + Color to display disabled navigation mesh polygon faces, visible when "Visible Navigation" is enabled in the Debug menu. + Custom image for the mouse cursor (limited to 256×256). diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp index ee5aee2df..6ec23ee6e 100644 --- a/editor/editor_node.cpp +++ b/editor/editor_node.cpp @@ -5668,6 +5668,19 @@ void EditorNode::_project_settings_changed() { tree->set_debug_navigation_color(GLOBAL_GET("debug/shapes/navigation/geometry_color")); tree->set_debug_navigation_disabled_color(GLOBAL_GET("debug/shapes/navigation/disabled_geometry_color")); +#ifdef DEBUG_ENABLED + NavigationServer::get_singleton_mut()->set_debug_navigation_edge_connection_color(GLOBAL_GET("debug/shapes/navigation/edge_connection_color")); + NavigationServer::get_singleton_mut()->set_debug_navigation_geometry_edge_color(GLOBAL_GET("debug/shapes/navigation/geometry_edge_color")); + NavigationServer::get_singleton_mut()->set_debug_navigation_geometry_face_color(GLOBAL_GET("debug/shapes/navigation/geometry_face_color")); + NavigationServer::get_singleton_mut()->set_debug_navigation_geometry_edge_disabled_color(GLOBAL_GET("debug/shapes/navigation/geometry_edge_disabled_color")); + NavigationServer::get_singleton_mut()->set_debug_navigation_geometry_face_disabled_color(GLOBAL_GET("debug/shapes/navigation/geometry_face_disabled_color")); + NavigationServer::get_singleton_mut()->set_debug_navigation_enable_edge_connections(GLOBAL_GET("debug/shapes/navigation/enable_edge_connections")); + NavigationServer::get_singleton_mut()->set_debug_navigation_enable_edge_connections_xray(GLOBAL_GET("debug/shapes/navigation/enable_edge_connections_xray")); + NavigationServer::get_singleton_mut()->set_debug_navigation_enable_edge_lines(GLOBAL_GET("debug/shapes/navigation/enable_edge_lines")); + NavigationServer::get_singleton_mut()->set_debug_navigation_enable_edge_lines_xray(GLOBAL_GET("debug/shapes/navigation/enable_edge_lines_xray")); + NavigationServer::get_singleton_mut()->set_debug_navigation_enable_geometry_face_random_color(GLOBAL_GET("debug/shapes/navigation/enable_geometry_face_random_color")); +#endif // DEBUG_ENABLED + _update_title(); } @@ -5851,7 +5864,11 @@ EditorNode::EditorNode() { RenderingServer::get_singleton()->textures_keep_original(true); RenderingServer::get_singleton()->set_debug_generate_wireframes(true); - NavigationServer::get_singleton()->set_active(false); // no nav by default if editor + if (NavigationServer::get_singleton()->get_debug_enabled()) { + NavigationServer::get_singleton()->set_active(true); + } else { + NavigationServer::get_singleton()->set_active(false); + } PhysicsServer::get_singleton()->set_active(false); // no physics by default if editor Physics2DServer::get_singleton()->set_active(false); // no physics by default if editor diff --git a/editor/spatial_editor_gizmos.cpp b/editor/spatial_editor_gizmos.cpp index 8a1f2f71c..831b99a4e 100644 --- a/editor/spatial_editor_gizmos.cpp +++ b/editor/spatial_editor_gizmos.cpp @@ -102,6 +102,7 @@ #include "scene/resources/sphere_shape.h" #include "scene/resources/surface_tool.h" #include "scene/resources/world_3d.h" +#include "servers/navigation_server.h" #include "servers/rendering_server.h" #ifdef MODULE_SKELETON_3D_ENABLED @@ -3541,11 +3542,6 @@ void CollisionPolygonSpatialGizmoPlugin::redraw(EditorSpatialGizmo *p_gizmo) { //// NavigationMeshSpatialGizmoPlugin::NavigationMeshSpatialGizmoPlugin() { - create_material("navigation_edge_material", EDITOR_DEF("editors/3d_gizmos/gizmo_colors/navigation_edge", Color(0.5, 1, 1))); - create_material("navigation_edge_material_disabled", EDITOR_DEF("editors/3d_gizmos/gizmo_colors/navigation_edge_disabled", Color(0.7, 0.7, 0.7))); - create_material("navigation_solid_material", EDITOR_DEF("editors/3d_gizmos/gizmo_colors/navigation_solid", Color(0.5, 1, 1, 0.4))); - create_material("navigation_solid_material_disabled", EDITOR_DEF("editors/3d_gizmos/gizmo_colors/navigation_solid_disabled", Color(0.7, 0.7, 0.7, 0.4))); - 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); @@ -3564,33 +3560,28 @@ int NavigationMeshSpatialGizmoPlugin::get_priority() const { } void NavigationMeshSpatialGizmoPlugin::redraw(EditorSpatialGizmo *p_gizmo) { - NavigationMeshInstance *navmesh = Object::cast_to(p_gizmo->get_spatial_node()); - - Ref edge_material = get_material("navigation_edge_material", p_gizmo); - Ref edge_material_disabled = get_material("navigation_edge_material_disabled", p_gizmo); - Ref solid_material = get_material("navigation_solid_material", p_gizmo); - Ref solid_material_disabled = get_material("navigation_solid_material_disabled", p_gizmo); + NavigationMeshInstance *navmesh_instance = Object::cast_to(p_gizmo->get_spatial_node()); p_gizmo->clear(); - Ref navmeshie = navmesh->get_navigation_mesh(); - if (navmeshie.is_null()) { + Ref navigationmesh = navmesh_instance->get_navigation_mesh(); + if (navigationmesh.is_null()) { return; } - AABB baking_aabb = navmeshie->get_filter_baking_aabb(); + AABB baking_aabb = navigationmesh->get_filter_baking_aabb(); if (!baking_aabb.has_no_volume()) { - Vector3 baking_aabb_offset = navmeshie->get_filter_baking_aabb_offset(); + 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); } } - PoolVector vertices = navmeshie->get_vertices(); + PoolVector vertices = navigationmesh->get_vertices(); PoolVector::Read vr = vertices.read(); List faces; - for (int i = 0; i < navmeshie->get_polygon_count(); i++) { - Vector p = navmeshie->get_polygon(i); + 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; @@ -3649,17 +3640,90 @@ void NavigationMeshSpatialGizmoPlugin::redraw(EditorSpatialGizmo *p_gizmo) { Ref tmesh = memnew(TriangleMesh); tmesh->create(tmeshfaces); - if (lines.size()) { - p_gizmo->add_lines(lines, navmesh->is_enabled() ? edge_material : edge_material_disabled); - } p_gizmo->add_collision_triangles(tmesh); - Ref m = memnew(ArrayMesh); - Array a; - a.resize(Mesh::ARRAY_MAX); - a[0] = tmeshfaces; - m->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, a); - m->surface_set_material(0, navmesh->is_enabled() ? solid_material : solid_material_disabled); - p_gizmo->add_mesh(m); + + 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 + bool enabled_geometry_face_random_color = NavigationServer::get_singleton()->get_debug_navigation_enable_geometry_face_random_color(); + if (enabled_geometry_face_random_color) { + Color debug_navigation_geometry_face_color = NavigationServer::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++) { + polygon_color = debug_navigation_geometry_face_color * (Color(Math::randf(), Math::randf(), Math::randf())); + + 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); + Ref debug_geometry_face_material = NavigationServer::get_singleton_mut()->get_debug_navigation_geometry_face_material(); + debug_mesh->surface_set_material(0, debug_geometry_face_material); + + // if enabled build geometry edge line surface + bool enabled_edge_lines = NavigationServer::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]]); + } + + Array line_mesh_array; + line_mesh_array.resize(Mesh::ARRAY_MAX); + line_mesh_array[Mesh::ARRAY_VERTEX] = line_vertex_array; + debug_mesh->add_surface_from_arrays(Mesh::PRIMITIVE_LINES, line_mesh_array); + Ref debug_geometry_edge_material = NavigationServer::get_singleton_mut()->get_debug_navigation_geometry_edge_material(); + debug_mesh->surface_set_material(1, debug_geometry_edge_material); + } + + if (!navmesh_instance->is_enabled()) { + if (debug_mesh.is_valid()) { + if (debug_mesh->get_surface_count() > 0) { + debug_mesh->surface_set_material(0, NavigationServer::get_singleton_mut()->get_debug_navigation_geometry_face_disabled_material()); + } + if (debug_mesh->get_surface_count() > 1) { + debug_mesh->surface_set_material(1, NavigationServer::get_singleton_mut()->get_debug_navigation_geometry_edge_disabled_material()); + } + } + } + + p_gizmo->add_mesh(debug_mesh); p_gizmo->add_collision_segments(lines); } diff --git a/main/main.cpp b/main/main.cpp index 98988e2a4..70a719160 100644 --- a/main/main.cpp +++ b/main/main.cpp @@ -1926,6 +1926,8 @@ bool Main::start() { } if (debug_navigation) { sml->set_debug_navigation_hint(true); + NavigationServer::get_singleton()->set_active(true); + NavigationServer::get_singleton_mut()->set_debug_enabled(true); } #endif diff --git a/scene/2d/navigation_region_2d.cpp b/scene/2d/navigation_region_2d.cpp index 583853f2b..257d7490c 100644 --- a/scene/2d/navigation_region_2d.cpp +++ b/scene/2d/navigation_region_2d.cpp @@ -30,14 +30,15 @@ #include "navigation_region_2d.h" -#include "core/core_string_names.h" #include "core/config/engine.h" +#include "core/core_string_names.h" #include "core/os/mutex.h" #include "navigation_2d.h" #include "scene/resources/navigation_mesh.h" +#include "scene/resources/navigation_polygon.h" #include "scene/resources/world_2d.h" #include "servers/navigation_2d_server.h" -#include "scene/resources/navigation_polygon.h" +#include "servers/navigation_server.h" #include "thirdparty/misc/triangulator.h" @@ -63,9 +64,11 @@ void NavigationRegion2D::set_enabled(bool p_enabled) { Navigation2DServer::get_singleton_mut()->connect("map_changed", this, "_map_changed"); } - if (Engine::get_singleton()->is_editor_hint() || get_tree()->is_debugging_navigation_hint()) { +#ifdef DEBUG_ENABLED + if (Engine::get_singleton()->is_editor_hint() || NavigationServer::get_singleton()->get_debug_enabled()) { update(); } +#endif // DEBUG_ENABLED } bool NavigationRegion2D::is_enabled() const { @@ -155,7 +158,8 @@ void NavigationRegion2D::_notification(int p_what) { } } break; case NOTIFICATION_DRAW: { - if (is_inside_tree() && (Engine::get_singleton()->is_editor_hint() || get_tree()->is_debugging_navigation_hint()) && navpoly.is_valid()) { +#ifdef DEBUG_ENABLED + if (is_inside_tree() && (Engine::get_singleton()->is_editor_hint() || NavigationServer::get_singleton()->get_debug_enabled()) && navpoly.is_valid()) { PoolVector verts = navpoly->get_vertices(); if (verts.size() < 3) { return; @@ -163,12 +167,12 @@ void NavigationRegion2D::_notification(int p_what) { Color color; if (enabled) { - color = get_tree()->get_debug_navigation_color(); + color = NavigationServer::get_singleton()->get_debug_navigation_geometry_face_color(); } else { - color = get_tree()->get_debug_navigation_disabled_color(); + color = NavigationServer::get_singleton()->get_debug_navigation_geometry_face_disabled_color(); } - Color doors_color = color.lightened(0.2); + Color doors_color = NavigationServer::get_singleton()->get_debug_navigation_edge_connection_color(); RandomPCG rand; @@ -216,6 +220,7 @@ void NavigationRegion2D::_notification(int p_what) { draw_arc(b, radius, angle - Math_PI / 2.0, angle + Math_PI / 2.0, 10, doors_color); } } +#endif // DEBUG_ENABLED } break; } } @@ -255,11 +260,13 @@ void NavigationRegion2D::_navpoly_changed() { } void NavigationRegion2D::_map_changed(RID p_map) { +#ifdef DEBUG_ENABLED if (navigation != nullptr && enabled && (navigation->get_rid() == p_map)) { update(); } else if (is_inside_tree() && enabled && (get_world_2d()->get_navigation_map() == p_map)) { update(); } +#endif // DEBUG_ENABLED } String NavigationRegion2D::get_configuration_warning() const { @@ -321,8 +328,18 @@ NavigationRegion2D::NavigationRegion2D() { Navigation2DServer::get_singleton()->region_set_enter_cost(region, get_enter_cost()); Navigation2DServer::get_singleton()->region_set_travel_cost(region, get_travel_cost()); + +#ifdef DEBUG_ENABLED + Navigation2DServer::get_singleton_mut()->connect("map_changed", this, "_map_changed"); + NavigationServer::get_singleton_mut()->connect("navigation_debug_changed", this, "_map_changed"); +#endif // DEBUG_ENABLED } NavigationRegion2D::~NavigationRegion2D() { Navigation2DServer::get_singleton()->free(region); + +#ifdef DEBUG_ENABLED + Navigation2DServer::get_singleton_mut()->disconnect("map_changed", this, "_map_changed"); + NavigationServer::get_singleton_mut()->disconnect("navigation_debug_changed", this, "_map_changed"); +#endif // DEBUG_ENABLED } diff --git a/scene/3d/navigation_mesh_instance.cpp b/scene/3d/navigation_mesh_instance.cpp index fc39c5188..2ab6d4eea 100644 --- a/scene/3d/navigation_mesh_instance.cpp +++ b/scene/3d/navigation_mesh_instance.cpp @@ -35,8 +35,8 @@ #include "navigation.h" #include "scene/resources/mesh.h" #include "scene/resources/navigation_mesh.h" -#include "servers/navigation_server.h" #include "scene/resources/world_3d.h" +#include "servers/navigation_server.h" void NavigationMeshInstance::set_enabled(bool p_enabled) { if (enabled == p_enabled) { @@ -58,14 +58,29 @@ void NavigationMeshInstance::set_enabled(bool p_enabled) { } } - if (debug_view) { - MeshInstance *dm = Object::cast_to(debug_view); - if (is_enabled()) { - dm->set_material_override(get_tree()->get_debug_navigation_material()); +#ifdef DEBUG_ENABLED + if (debug_instance.is_valid()) { + if (!is_enabled()) { + if (debug_mesh.is_valid()) { + if (debug_mesh->get_surface_count() > 0) { + RS::get_singleton()->instance_set_surface_material(debug_instance, 0, NavigationServer::get_singleton_mut()->get_debug_navigation_geometry_face_disabled_material()->get_rid()); + } + if (debug_mesh->get_surface_count() > 1) { + RS::get_singleton()->instance_set_surface_material(debug_instance, 1, NavigationServer::get_singleton_mut()->get_debug_navigation_geometry_edge_disabled_material()->get_rid()); + } + } } else { - dm->set_material_override(get_tree()->get_debug_navigation_disabled_material()); + if (debug_mesh.is_valid()) { + if (debug_mesh->get_surface_count() > 0) { + RS::get_singleton()->instance_set_surface_material(debug_instance, 0, RID()); + } + if (debug_mesh->get_surface_count() > 1) { + RS::get_singleton()->instance_set_surface_material(debug_instance, 1, RID()); + } + } } } +#endif // DEBUG_ENABLED update_gizmos(); } @@ -130,40 +145,47 @@ void NavigationMeshInstance::_notification(int p_what) { NavigationServer::get_singleton()->region_set_map(region, get_world_3d()->get_navigation_map()); } - if (navmesh.is_valid() && get_tree()->is_debugging_navigation_hint()) { - MeshInstance *dm = memnew(MeshInstance); - dm->set_mesh(navmesh->get_debug_mesh()); - if (is_enabled()) { - dm->set_material_override(get_tree()->get_debug_navigation_material()); - } else { - dm->set_material_override(get_tree()->get_debug_navigation_disabled_material()); - } - add_child(dm); - debug_view = dm; +#ifdef DEBUG_ENABLED + if (NavigationServer::get_singleton()->get_debug_enabled()) { + _update_debug_mesh(); } +#endif // DEBUG_ENABLED } break; case NOTIFICATION_TRANSFORM_CHANGED: { NavigationServer::get_singleton()->region_set_transform(region, get_global_transform()); +#ifdef DEBUG_ENABLED + if (is_inside_tree() && debug_instance.is_valid()) { + RS::get_singleton()->instance_set_transform(debug_instance, get_global_transform()); + } +#endif // DEBUG_ENABLED + } break; case NOTIFICATION_EXIT_TREE: { if (navigation) { NavigationServer::get_singleton()->region_set_map(region, RID()); } - if (debug_view) { - debug_view->queue_delete(); - debug_view = nullptr; - } navigation = nullptr; + +#ifdef DEBUG_ENABLED + if (debug_instance.is_valid()) { + RS::get_singleton()->instance_set_visible(debug_instance, false); + } + if (debug_edge_connections_instance.is_valid()) { + RS::get_singleton()->instance_set_visible(debug_edge_connections_instance, false); + } +#endif // DEBUG_ENABLED + } break; } } void NavigationMeshInstance::set_navigation_mesh(const Ref &p_navmesh) { - if (p_navmesh == navmesh) + if (p_navmesh == navmesh) { return; + } if (navmesh.is_valid()) { navmesh->remove_change_receptor(this); @@ -177,20 +199,21 @@ void NavigationMeshInstance::set_navigation_mesh(const Ref &p_na NavigationServer::get_singleton()->region_set_navmesh(region, p_navmesh); - if (debug_view == nullptr && is_inside_tree() && navmesh.is_valid() && get_tree()->is_debugging_navigation_hint()) { - MeshInstance *dm = memnew(MeshInstance); - dm->set_mesh(navmesh->get_debug_mesh()); - if (is_enabled()) { - dm->set_material_override(get_tree()->get_debug_navigation_material()); +#ifdef DEBUG_ENABLED + if (is_inside_tree() && NavigationServer::get_singleton()->get_debug_enabled()) { + if (navmesh.is_valid()) { + _update_debug_mesh(); + _update_debug_edge_connections_mesh(); } else { - dm->set_material_override(get_tree()->get_debug_navigation_disabled_material()); + if (debug_instance.is_valid()) { + RS::get_singleton()->instance_set_visible(debug_instance, false); + } + if (debug_edge_connections_instance.is_valid()) { + RS::get_singleton()->instance_set_visible(debug_edge_connections_instance, false); + } } - add_child(dm); - debug_view = dm; - } - if (debug_view && navmesh.is_valid()) { - Object::cast_to(debug_view)->set_mesh(navmesh->get_debug_mesh()); } +#endif // DEBUG_ENABLED emit_signal("navigation_mesh_changed"); @@ -250,6 +273,23 @@ void NavigationMeshInstance::_bake_finished(Ref p_nav_mesh) { emit_signal("bake_finished"); } +void NavigationMeshInstance::_navigation_changed() { + update_gizmos(); + update_configuration_warning(); + +#ifdef DEBUG_ENABLED + _update_debug_edge_connections_mesh(); +#endif // DEBUG_ENABLED +} + +#ifdef DEBUG_ENABLED +void NavigationMeshInstance::_navigation_map_changed(RID p_map) { + if (is_inside_tree() && p_map == get_world_3d()->get_navigation_map()) { + _update_debug_edge_connections_mesh(); + } +} +#endif // DEBUG_ENABLED + String NavigationMeshInstance::get_configuration_warning() const { if (!is_visible_in_tree() || !is_inside_tree()) { return String(); @@ -282,6 +322,11 @@ void NavigationMeshInstance::_bind_methods() { ClassDB::bind_method(D_METHOD("bake_navigation_mesh", "on_thread"), &NavigationMeshInstance::bake_navigation_mesh, DEFVAL(true)); ClassDB::bind_method(D_METHOD("_bake_finished", "nav_mesh"), &NavigationMeshInstance::_bake_finished); + ClassDB::bind_method(D_METHOD("_navigation_changed"), &NavigationMeshInstance::_navigation_changed); + + ClassDB::bind_method(D_METHOD("_update_debug_mesh"), &NavigationMeshInstance::_update_debug_mesh); + ClassDB::bind_method(D_METHOD("_update_debug_edge_connections_mesh"), &NavigationMeshInstance::_update_debug_edge_connections_mesh); + ClassDB::bind_method(D_METHOD("_navigation_map_changed"), &NavigationMeshInstance::_navigation_map_changed); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "navmesh", PROPERTY_HINT_RESOURCE_TYPE, "NavigationMesh"), "set_navigation_mesh", "get_navigation_mesh"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "enabled"), "set_enabled", "is_enabled"); @@ -310,6 +355,12 @@ NavigationMeshInstance::NavigationMeshInstance() { NavigationServer::get_singleton()->region_set_enter_cost(region, get_enter_cost()); NavigationServer::get_singleton()->region_set_travel_cost(region, get_travel_cost()); enabled = true; + +#ifdef DEBUG_ENABLED + NavigationServer::get_singleton_mut()->connect("map_changed", this, "_navigation_map_changed"); + NavigationServer::get_singleton_mut()->connect("navigation_debug_changed", this, "_update_debug_mesh"); + NavigationServer::get_singleton_mut()->connect("navigation_debug_changed", this, "_update_debug_edge_connections_mesh"); +#endif // DEBUG_ENABLED } NavigationMeshInstance::~NavigationMeshInstance() { @@ -317,4 +368,246 @@ NavigationMeshInstance::~NavigationMeshInstance() { navmesh->remove_change_receptor(this); } NavigationServer::get_singleton()->free(region); + +#ifdef DEBUG_ENABLED + NavigationServer::get_singleton_mut()->disconnect("map_changed", this, "_navigation_map_changed"); + NavigationServer::get_singleton_mut()->disconnect("navigation_debug_changed", this, "_update_debug_mesh"); + NavigationServer::get_singleton_mut()->disconnect("navigation_debug_changed", this, "_update_debug_edge_connections_mesh"); + + if (debug_instance.is_valid()) { + RenderingServer::get_singleton()->free(debug_instance); + } + if (debug_mesh.is_valid()) { + RenderingServer::get_singleton()->free(debug_mesh->get_rid()); + } + if (debug_edge_connections_instance.is_valid()) { + RenderingServer::get_singleton()->free(debug_edge_connections_instance); + } + if (debug_edge_connections_mesh.is_valid()) { + RenderingServer::get_singleton()->free(debug_edge_connections_mesh->get_rid()); + } +#endif // DEBUG_ENABLED } + +#ifdef DEBUG_ENABLED +void NavigationMeshInstance::_update_debug_mesh() { + if (!NavigationServer::get_singleton()->get_debug_enabled()) { + if (debug_instance.is_valid()) { + RS::get_singleton()->instance_set_visible(debug_instance, false); + } + return; + } + + if (!navmesh.is_valid()) { + if (debug_instance.is_valid()) { + RS::get_singleton()->instance_set_visible(debug_instance, false); + } + return; + } + + if (!debug_instance.is_valid()) { + debug_instance = RenderingServer::get_singleton()->instance_create(); + } + + if (!debug_mesh.is_valid()) { + debug_mesh = Ref(memnew(ArrayMesh)); + } + + debug_mesh->clear_surfaces(); + + bool enabled_geometry_face_random_color = NavigationServer::get_singleton()->get_debug_navigation_enable_geometry_face_random_color(); + bool enabled_edge_lines = NavigationServer::get_singleton()->get_debug_navigation_enable_edge_lines(); + + PoolVector vertices = navmesh->get_vertices(); + if (vertices.size() == 0) { + return; + } + + int polygon_count = navmesh->get_polygon_count(); + if (polygon_count == 0) { + return; + } + + Vector face_vertex_array; + face_vertex_array.resize(polygon_count * 3); + + Vector face_color_array; + if (enabled_geometry_face_random_color) { + face_color_array.resize(polygon_count * 3); + } + + Vector line_vertex_array; + if (enabled_edge_lines) { + line_vertex_array.resize(polygon_count * 6); + } + + Color debug_navigation_geometry_face_color = NavigationServer::get_singleton()->get_debug_navigation_geometry_face_color(); + + Ref face_material = NavigationServer::get_singleton_mut()->get_debug_navigation_geometry_face_material(); + Ref line_material = NavigationServer::get_singleton_mut()->get_debug_navigation_geometry_edge_material(); + + Color polygon_color = debug_navigation_geometry_face_color; + + for (int i = 0; i < polygon_count; i++) { + if (enabled_geometry_face_random_color) { + polygon_color = debug_navigation_geometry_face_color * (Color(Math::randf(), Math::randf(), Math::randf())); + } + + Vector polygon = navmesh->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]]); + if (enabled_geometry_face_random_color) { + face_color_array.push_back(polygon_color); + face_color_array.push_back(polygon_color); + face_color_array.push_back(polygon_color); + } + + if (enabled_edge_lines) { + 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]]); + } + } + + Array face_mesh_array; + face_mesh_array.resize(Mesh::ARRAY_MAX); + face_mesh_array[Mesh::ARRAY_VERTEX] = face_vertex_array; + if (enabled_geometry_face_random_color) { + face_mesh_array[Mesh::ARRAY_COLOR] = face_color_array; + } + debug_mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, face_mesh_array); + debug_mesh->surface_set_material(0, face_material); + + if (enabled_edge_lines) { + Array line_mesh_array; + line_mesh_array.resize(Mesh::ARRAY_MAX); + line_mesh_array[Mesh::ARRAY_VERTEX] = line_vertex_array; + debug_mesh->add_surface_from_arrays(Mesh::PRIMITIVE_LINES, line_mesh_array); + debug_mesh->surface_set_material(1, line_material); + } + + RS::get_singleton()->instance_set_base(debug_instance, debug_mesh->get_rid()); + if (is_inside_tree()) { + RS::get_singleton()->instance_set_scenario(debug_instance, get_world_3d()->get_scenario()); + RS::get_singleton()->instance_set_visible(debug_instance, is_visible_in_tree()); + } + if (!is_enabled()) { + if (debug_mesh.is_valid()) { + if (debug_mesh->get_surface_count() > 0) { + RS::get_singleton()->instance_set_surface_material(debug_instance, 0, NavigationServer::get_singleton_mut()->get_debug_navigation_geometry_face_disabled_material()->get_rid()); + } + if (debug_mesh->get_surface_count() > 1) { + RS::get_singleton()->instance_set_surface_material(debug_instance, 1, NavigationServer::get_singleton_mut()->get_debug_navigation_geometry_edge_disabled_material()->get_rid()); + } + } + } else { + if (debug_mesh.is_valid()) { + if (debug_mesh->get_surface_count() > 0) { + RS::get_singleton()->instance_set_surface_material(debug_instance, 0, RID()); + } + if (debug_mesh->get_surface_count() > 1) { + RS::get_singleton()->instance_set_surface_material(debug_instance, 1, RID()); + } + } + } +} +#endif // DEBUG_ENABLED + +#ifdef DEBUG_ENABLED +void NavigationMeshInstance::_update_debug_edge_connections_mesh() { + if (!NavigationServer::get_singleton()->get_debug_enabled()) { + if (debug_edge_connections_instance.is_valid()) { + RS::get_singleton()->instance_set_visible(debug_edge_connections_instance, false); + } + return; + } + + if (!is_inside_tree()) { + return; + } + + if (!navmesh.is_valid()) { + if (debug_edge_connections_instance.is_valid()) { + RS::get_singleton()->instance_set_visible(debug_edge_connections_instance, false); + } + return; + } + + if (!debug_edge_connections_instance.is_valid()) { + debug_edge_connections_instance = RenderingServer::get_singleton()->instance_create(); + } + + if (!debug_edge_connections_mesh.is_valid()) { + debug_edge_connections_mesh = Ref(memnew(ArrayMesh)); + } + + debug_edge_connections_mesh->clear_surfaces(); + + float edge_connection_margin = NavigationServer::get_singleton()->map_get_edge_connection_margin(get_world_3d()->get_navigation_map()); + float half_edge_connection_margin = edge_connection_margin * 0.5; + int connections_count = NavigationServer::get_singleton()->region_get_connections_count(region); + + if (connections_count == 0) { + RS::get_singleton()->instance_set_visible(debug_edge_connections_instance, false); + return; + } + + Vector vertex_array; + + for (int i = 0; i < connections_count; i++) { + Vector3 connection_pathway_start = NavigationServer::get_singleton()->region_get_connection_pathway_start(region, i); + Vector3 connection_pathway_end = NavigationServer::get_singleton()->region_get_connection_pathway_end(region, i); + + Vector3 direction_start_end = connection_pathway_start.direction_to(connection_pathway_end); + Vector3 direction_end_start = connection_pathway_end.direction_to(connection_pathway_start); + + Vector3 start_right_dir = direction_start_end.cross(Vector3(0, 1, 0)); + Vector3 start_left_dir = -start_right_dir; + + Vector3 end_right_dir = direction_end_start.cross(Vector3(0, 1, 0)); + Vector3 end_left_dir = -end_right_dir; + + Vector3 left_start_pos = connection_pathway_start + (start_left_dir * half_edge_connection_margin); + Vector3 right_start_pos = connection_pathway_start + (start_right_dir * half_edge_connection_margin); + Vector3 left_end_pos = connection_pathway_end + (end_right_dir * half_edge_connection_margin); + Vector3 right_end_pos = connection_pathway_end + (end_left_dir * half_edge_connection_margin); + + vertex_array.push_back(right_end_pos); + vertex_array.push_back(left_start_pos); + vertex_array.push_back(right_start_pos); + + vertex_array.push_back(left_end_pos); + vertex_array.push_back(right_end_pos); + vertex_array.push_back(right_start_pos); + } + + if (vertex_array.size() == 0) { + return; + } + + Ref edge_connections_material = NavigationServer::get_singleton_mut()->get_debug_navigation_edge_connections_material(); + + Array mesh_array; + mesh_array.resize(Mesh::ARRAY_MAX); + mesh_array[Mesh::ARRAY_VERTEX] = vertex_array; + + debug_edge_connections_mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, mesh_array); + debug_edge_connections_mesh->surface_set_material(0, edge_connections_material); + + RS::get_singleton()->instance_set_base(debug_edge_connections_instance, debug_edge_connections_mesh->get_rid()); + RS::get_singleton()->instance_set_visible(debug_edge_connections_instance, is_visible_in_tree()); + if (is_inside_tree()) { + RS::get_singleton()->instance_set_scenario(debug_edge_connections_instance, get_world_3d()->get_scenario()); + } + + bool enable_edge_connections = NavigationServer::get_singleton()->get_debug_navigation_enable_edge_connections(); + if (!enable_edge_connections) { + RS::get_singleton()->instance_set_visible(debug_edge_connections_instance, false); + } +} +#endif // DEBUG_ENABLED \ No newline at end of file diff --git a/scene/3d/navigation_mesh_instance.h b/scene/3d/navigation_mesh_instance.h index 748a243fd..4084e5a05 100644 --- a/scene/3d/navigation_mesh_instance.h +++ b/scene/3d/navigation_mesh_instance.h @@ -50,9 +50,20 @@ class NavigationMeshInstance : public Spatial { uint32_t navigation_layers = 1; Navigation *navigation = nullptr; - Node *debug_view = nullptr; Thread bake_thread; +#ifdef DEBUG_ENABLED + RID debug_instance; + RID debug_edge_connections_instance; + Ref debug_mesh; + Ref debug_edge_connections_mesh; + +private: + void _update_debug_mesh(); + void _update_debug_edge_connections_mesh(); + void _navigation_map_changed(RID p_map); +#endif // DEBUG_ENABLED + protected: void _notification(int p_what); static void _bind_methods(); @@ -80,6 +91,7 @@ public: /// sets the new navigation mesh and emits a signal void bake_navigation_mesh(bool p_on_thread); void _bake_finished(Ref p_nav_mesh); + void _navigation_changed(); String get_configuration_warning() const; diff --git a/scene/resources/navigation_mesh.cpp b/scene/resources/navigation_mesh.cpp index bfd39321b..4c6519eca 100644 --- a/scene/resources/navigation_mesh.cpp +++ b/scene/resources/navigation_mesh.cpp @@ -30,6 +30,8 @@ #include "navigation_mesh.h" +#include "servers/navigation_server.h" + void NavigationMesh::create_from_mesh(const Ref &p_mesh) { ERR_FAIL_COND(p_mesh.is_null()); @@ -420,6 +422,101 @@ Ref NavigationMesh::get_debug_mesh() { return debug_mesh; } +#ifdef DEBUG_ENABLED +Ref NavigationMesh::_get_debug_mesh() { + if (debug_mesh.is_valid()) { + // Blocks further updates for now, code below is intended for dynamic updates e.g. when settings change. + return debug_mesh; + } + + if (!debug_mesh.is_valid()) { + debug_mesh = Ref(memnew(ArrayMesh)); + } else { + debug_mesh->clear_surfaces(); + } + + if (vertices.size() == 0) { + return debug_mesh; + } + + int polygon_count = get_polygon_count(); + + if (polygon_count < 1) { + // no face, no play + return debug_mesh; + } + + // 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 = 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 + bool enabled_geometry_face_random_color = NavigationServer::get_singleton()->get_debug_navigation_enable_geometry_face_random_color(); + if (enabled_geometry_face_random_color) { + Color debug_navigation_geometry_face_color = NavigationServer::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++) { + polygon_color = debug_navigation_geometry_face_color * (Color(Math::randf(), Math::randf(), Math::randf())); + + Vector polygon = 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); + Ref debug_geometry_face_material = NavigationServer::get_singleton_mut()->get_debug_navigation_geometry_face_material(); + debug_mesh->surface_set_material(debug_mesh->get_surface_count(), debug_geometry_face_material); + + // if enabled build geometry edge line surface + bool enabled_edge_lines = NavigationServer::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 = 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]]); + } + + Array line_mesh_array; + line_mesh_array.resize(Mesh::ARRAY_MAX); + line_mesh_array[Mesh::ARRAY_VERTEX] = line_vertex_array; + debug_mesh->add_surface_from_arrays(Mesh::PRIMITIVE_LINES, line_mesh_array); + Ref debug_geometry_edge_material = NavigationServer::get_singleton_mut()->get_debug_navigation_geometry_edge_material(); + debug_mesh->surface_set_material(debug_mesh->get_surface_count() - 1, debug_geometry_edge_material); + } + + return debug_mesh; +} +#endif + void NavigationMesh::_bind_methods() { ClassDB::bind_method(D_METHOD("set_sample_partition_type", "sample_partition_type"), &NavigationMesh::set_sample_partition_type); ClassDB::bind_method(D_METHOD("get_sample_partition_type"), &NavigationMesh::get_sample_partition_type); diff --git a/scene/resources/navigation_mesh.h b/scene/resources/navigation_mesh.h index ba997e57b..cf3d28eaa 100644 --- a/scene/resources/navigation_mesh.h +++ b/scene/resources/navigation_mesh.h @@ -197,6 +197,10 @@ public: Ref get_debug_mesh(); +#ifdef DEBUG_ENABLED + Ref _get_debug_mesh(); +#endif + NavigationMesh(); }; diff --git a/servers/navigation_server.cpp b/servers/navigation_server.cpp index ee6f8404e..f2448d68b 100644 --- a/servers/navigation_server.cpp +++ b/servers/navigation_server.cpp @@ -34,6 +34,11 @@ #include "scene/3d/navigation_mesh_instance.h" #include "scene/resources/navigation_mesh.h" +#ifdef DEBUG_ENABLED +#include "core/config/project_settings.h" +#include "scene/resources/material.h" +#endif + NavigationServer *NavigationServer::singleton = nullptr; void NavigationServer::init() { @@ -103,6 +108,10 @@ void NavigationServer::_bind_methods() { ClassDB::bind_method(D_METHOD("process", "delta_time"), &NavigationServer::process); ADD_SIGNAL(MethodInfo("map_changed", PropertyInfo(Variant::RID, "map"))); + +#ifdef DEBUG_ENABLED + ADD_SIGNAL(MethodInfo("navigation_debug_changed")); +#endif // DEBUG_ENABLED } const NavigationServer *NavigationServer::get_singleton() { @@ -116,12 +125,266 @@ NavigationServer *NavigationServer::get_singleton_mut() { NavigationServer::NavigationServer() { ERR_FAIL_COND(singleton != nullptr); singleton = this; + +#ifdef DEBUG_ENABLED + _debug_enabled = true; + _debug_dirty = true; + + _debug_navigation_edge_connection_color = GLOBAL_DEF("debug/shapes/navigation/edge_connection_color", Color(1.0, 0.0, 1.0, 1.0)); + _debug_navigation_geometry_edge_color = GLOBAL_DEF("debug/shapes/navigation/geometry_edge_color", Color(0.5, 1.0, 1.0, 1.0)); + _debug_navigation_geometry_face_color = GLOBAL_DEF("debug/shapes/navigation/geometry_face_color", Color(0.5, 1.0, 1.0, 0.4)); + _debug_navigation_geometry_edge_disabled_color = GLOBAL_DEF("debug/shapes/navigation/geometry_edge_disabled_color", Color(0.5, 0.5, 0.5, 1.0)); + _debug_navigation_geometry_face_disabled_color = GLOBAL_DEF("debug/shapes/navigation/geometry_face_disabled_color", Color(0.5, 0.5, 0.5, 0.4)); + _debug_navigation_enable_edge_connections = GLOBAL_DEF("debug/shapes/navigation/enable_edge_connections", true); + _debug_navigation_enable_edge_connections_xray = GLOBAL_DEF("debug/shapes/navigation/enable_edge_connections_xray", true); + _debug_navigation_enable_edge_lines = GLOBAL_DEF("debug/shapes/navigation/enable_edge_lines", true); + _debug_navigation_enable_edge_lines_xray = GLOBAL_DEF("debug/shapes/navigation/enable_edge_lines_xray", true); + _debug_navigation_enable_geometry_face_random_color = GLOBAL_DEF("debug/shapes/navigation/enable_geometry_face_random_color", true); +#endif // DEBUG_ENABLED } NavigationServer::~NavigationServer() { singleton = nullptr; } +#ifdef DEBUG_ENABLED +void NavigationServer::_emit_navigation_debug_changed_signal() { + if (_debug_dirty) { + _debug_dirty = false; + emit_signal("navigation_debug_changed"); + } +} +#endif // DEBUG_ENABLED + +#ifdef DEBUG_ENABLED +Ref NavigationServer::get_debug_navigation_geometry_face_material() { + if (_debug_navigation_geometry_face_material.is_valid()) { + return _debug_navigation_geometry_face_material; + } + + bool enabled_geometry_face_random_color = get_debug_navigation_enable_geometry_face_random_color(); + + Color debug_navigation_geometry_face_color = get_debug_navigation_geometry_face_color(); + + Ref face_material = Ref(memnew(SpatialMaterial)); + face_material->set_flag(SpatialMaterial::FLAG_UNSHADED, true); + face_material->set_feature(SpatialMaterial::FEATURE_TRANSPARENT, true); + face_material->set_albedo(debug_navigation_geometry_face_color); + if (enabled_geometry_face_random_color) { + face_material->set_flag(SpatialMaterial::FLAG_SRGB_VERTEX_COLOR, true); + face_material->set_flag(SpatialMaterial::FLAG_ALBEDO_FROM_VERTEX_COLOR, true); + } + + _debug_navigation_geometry_face_material = face_material; + + return _debug_navigation_geometry_face_material; +} + +Ref NavigationServer::get_debug_navigation_geometry_edge_material() { + if (_debug_navigation_geometry_edge_material.is_valid()) { + return _debug_navigation_geometry_edge_material; + } + + bool enabled_edge_lines_xray = get_debug_navigation_enable_edge_lines_xray(); + + Color debug_navigation_geometry_edge_color = get_debug_navigation_geometry_edge_color(); + + Ref line_material = Ref(memnew(SpatialMaterial)); + line_material->set_flag(SpatialMaterial::FLAG_UNSHADED, true); + line_material->set_albedo(debug_navigation_geometry_edge_color); + if (enabled_edge_lines_xray) { + line_material->set_flag(SpatialMaterial::FLAG_DISABLE_DEPTH_TEST, true); + } + + _debug_navigation_geometry_edge_material = line_material; + + return _debug_navigation_geometry_edge_material; +} + +Ref NavigationServer::get_debug_navigation_geometry_face_disabled_material() { + if (_debug_navigation_geometry_face_disabled_material.is_valid()) { + return _debug_navigation_geometry_face_disabled_material; + } + + Color debug_navigation_geometry_face_disabled_color = get_debug_navigation_geometry_face_disabled_color(); + + Ref face_disabled_material = Ref(memnew(SpatialMaterial)); + face_disabled_material->set_flag(SpatialMaterial::FLAG_UNSHADED, true); + face_disabled_material->set_feature(SpatialMaterial::FEATURE_TRANSPARENT, true); + face_disabled_material->set_albedo(debug_navigation_geometry_face_disabled_color); + + _debug_navigation_geometry_face_disabled_material = face_disabled_material; + + return _debug_navigation_geometry_face_disabled_material; +} + +Ref NavigationServer::get_debug_navigation_geometry_edge_disabled_material() { + if (_debug_navigation_geometry_edge_disabled_material.is_valid()) { + return _debug_navigation_geometry_edge_disabled_material; + } + + bool enabled_edge_lines_xray = get_debug_navigation_enable_edge_lines_xray(); + + Color debug_navigation_geometry_edge_disabled_color = get_debug_navigation_geometry_edge_disabled_color(); + + Ref line_disabled_material = Ref(memnew(SpatialMaterial)); + line_disabled_material->set_flag(SpatialMaterial::FLAG_UNSHADED, true); + line_disabled_material->set_albedo(debug_navigation_geometry_edge_disabled_color); + if (enabled_edge_lines_xray) { + line_disabled_material->set_flag(SpatialMaterial::FLAG_DISABLE_DEPTH_TEST, true); + } + + _debug_navigation_geometry_edge_disabled_material = line_disabled_material; + + return _debug_navigation_geometry_edge_disabled_material; +} + +Ref NavigationServer::get_debug_navigation_edge_connections_material() { + if (_debug_navigation_edge_connections_material.is_valid()) { + return _debug_navigation_edge_connections_material; + } + + bool enabled_edge_connections_xray = get_debug_navigation_enable_edge_connections_xray(); + + Color debug_navigation_edge_connection_color = get_debug_navigation_edge_connection_color(); + + Ref edge_connections_material = Ref(memnew(SpatialMaterial)); + edge_connections_material->set_flag(SpatialMaterial::FLAG_UNSHADED, true); + edge_connections_material->set_albedo(debug_navigation_edge_connection_color); + if (enabled_edge_connections_xray) { + edge_connections_material->set_flag(SpatialMaterial::FLAG_DISABLE_DEPTH_TEST, true); + } + edge_connections_material->set_render_priority(SpatialMaterial::RENDER_PRIORITY_MAX - 2); + + _debug_navigation_edge_connections_material = edge_connections_material; + + return _debug_navigation_edge_connections_material; +} + +void NavigationServer::set_debug_navigation_edge_connection_color(const Color &p_color) { + _debug_navigation_edge_connection_color = p_color; + if (_debug_navigation_edge_connections_material.is_valid()) { + _debug_navigation_edge_connections_material->set_albedo(_debug_navigation_edge_connection_color); + } +} + +Color NavigationServer::get_debug_navigation_edge_connection_color() const { + return _debug_navigation_edge_connection_color; +} + +void NavigationServer::set_debug_navigation_geometry_edge_color(const Color &p_color) { + _debug_navigation_geometry_edge_color = p_color; + if (_debug_navigation_geometry_edge_material.is_valid()) { + _debug_navigation_geometry_edge_material->set_albedo(_debug_navigation_geometry_edge_color); + } +} + +Color NavigationServer::get_debug_navigation_geometry_edge_color() const { + return _debug_navigation_geometry_edge_color; +} + +void NavigationServer::set_debug_navigation_geometry_face_color(const Color &p_color) { + _debug_navigation_geometry_face_color = p_color; + if (_debug_navigation_geometry_face_material.is_valid()) { + _debug_navigation_geometry_face_material->set_albedo(_debug_navigation_geometry_face_color); + } +} + +Color NavigationServer::get_debug_navigation_geometry_face_color() const { + return _debug_navigation_geometry_face_color; +} + +void NavigationServer::set_debug_navigation_geometry_edge_disabled_color(const Color &p_color) { + _debug_navigation_geometry_edge_disabled_color = p_color; + if (_debug_navigation_geometry_edge_disabled_material.is_valid()) { + _debug_navigation_geometry_edge_disabled_material->set_albedo(_debug_navigation_geometry_edge_disabled_color); + } +} + +Color NavigationServer::get_debug_navigation_geometry_edge_disabled_color() const { + return _debug_navigation_geometry_edge_disabled_color; +} + +void NavigationServer::set_debug_navigation_geometry_face_disabled_color(const Color &p_color) { + _debug_navigation_geometry_face_disabled_color = p_color; + if (_debug_navigation_geometry_face_disabled_material.is_valid()) { + _debug_navigation_geometry_face_disabled_material->set_albedo(_debug_navigation_geometry_face_disabled_color); + } +} + +Color NavigationServer::get_debug_navigation_geometry_face_disabled_color() const { + return _debug_navigation_geometry_face_disabled_color; +} + +void NavigationServer::set_debug_navigation_enable_edge_connections(const bool p_value) { + _debug_navigation_enable_edge_connections = p_value; + _debug_dirty = true; + call_deferred("_emit_navigation_debug_changed_signal"); +} + +bool NavigationServer::get_debug_navigation_enable_edge_connections() const { + return _debug_navigation_enable_edge_connections; +} + +void NavigationServer::set_debug_navigation_enable_edge_connections_xray(const bool p_value) { + _debug_navigation_enable_edge_connections_xray = p_value; + if (_debug_navigation_edge_connections_material.is_valid()) { + _debug_navigation_edge_connections_material->set_flag(SpatialMaterial::FLAG_DISABLE_DEPTH_TEST, _debug_navigation_enable_edge_connections_xray); + } +} + +bool NavigationServer::get_debug_navigation_enable_edge_connections_xray() const { + return _debug_navigation_enable_edge_connections_xray; +} + +void NavigationServer::set_debug_navigation_enable_edge_lines(const bool p_value) { + _debug_navigation_enable_edge_lines = p_value; + _debug_dirty = true; + call_deferred("_emit_navigation_debug_changed_signal"); +} + +bool NavigationServer::get_debug_navigation_enable_edge_lines() const { + return _debug_navigation_enable_edge_lines; +} + +void NavigationServer::set_debug_navigation_enable_edge_lines_xray(const bool p_value) { + _debug_navigation_enable_edge_lines_xray = p_value; + if (_debug_navigation_geometry_edge_material.is_valid()) { + _debug_navigation_geometry_edge_material->set_flag(SpatialMaterial::FLAG_DISABLE_DEPTH_TEST, _debug_navigation_enable_edge_lines_xray); + } +} + +bool NavigationServer::get_debug_navigation_enable_edge_lines_xray() const { + return _debug_navigation_enable_edge_lines_xray; +} + +void NavigationServer::set_debug_navigation_enable_geometry_face_random_color(const bool p_value) { + _debug_navigation_enable_geometry_face_random_color = p_value; + _debug_dirty = true; + call_deferred("_emit_navigation_debug_changed_signal"); +} + +bool NavigationServer::get_debug_navigation_enable_geometry_face_random_color() const { + return _debug_navigation_enable_geometry_face_random_color; +} + +void NavigationServer::set_debug_enabled(bool p_enabled) { + if (_debug_enabled != p_enabled) { + _debug_dirty = true; + } + + _debug_enabled = p_enabled; + + if (_debug_dirty) { + call_deferred("_emit_navigation_debug_changed_signal"); + } +} + +bool NavigationServer::get_debug_enabled() const { + return _debug_enabled; +} +#endif // DEBUG_ENABLED + Vector NavigationServerManager::navigation_servers; int NavigationServerManager::default_server_id = -1; int NavigationServerManager::default_server_priority = -1; @@ -181,4 +444,4 @@ NavigationServer *NavigationServerManager::new_server(const String &p_name) { } else { return navigation_servers[id].create_callback(); } -} \ No newline at end of file +} diff --git a/servers/navigation_server.h b/servers/navigation_server.h index 715f751bd..9c1e8becf 100644 --- a/servers/navigation_server.h +++ b/servers/navigation_server.h @@ -36,6 +36,7 @@ #include "core/object/reference.h" class NavigationMesh; +class SpatialMaterial; /// This server uses the concept of internal mutability. /// All the constant functions can be called in multithread because internally @@ -217,6 +218,72 @@ public: NavigationServer(); virtual ~NavigationServer(); + +#ifdef DEBUG_ENABLED + + void set_debug_enabled(bool p_enabled); + bool get_debug_enabled() const; + + void set_debug_navigation_edge_connection_color(const Color &p_color); + Color get_debug_navigation_edge_connection_color() const; + + void set_debug_navigation_geometry_edge_color(const Color &p_color); + Color get_debug_navigation_geometry_edge_color() const; + + void set_debug_navigation_geometry_face_color(const Color &p_color); + Color get_debug_navigation_geometry_face_color() const; + + void set_debug_navigation_geometry_edge_disabled_color(const Color &p_color); + Color get_debug_navigation_geometry_edge_disabled_color() const; + + void set_debug_navigation_geometry_face_disabled_color(const Color &p_color); + Color get_debug_navigation_geometry_face_disabled_color() const; + + void set_debug_navigation_enable_edge_connections(const bool p_value); + bool get_debug_navigation_enable_edge_connections() const; + + void set_debug_navigation_enable_edge_connections_xray(const bool p_value); + bool get_debug_navigation_enable_edge_connections_xray() const; + + void set_debug_navigation_enable_edge_lines(const bool p_value); + bool get_debug_navigation_enable_edge_lines() const; + + void set_debug_navigation_enable_edge_lines_xray(const bool p_value); + bool get_debug_navigation_enable_edge_lines_xray() const; + + void set_debug_navigation_enable_geometry_face_random_color(const bool p_value); + bool get_debug_navigation_enable_geometry_face_random_color() const; + + Ref get_debug_navigation_geometry_face_material(); + Ref get_debug_navigation_geometry_edge_material(); + Ref get_debug_navigation_geometry_face_disabled_material(); + Ref get_debug_navigation_geometry_edge_disabled_material(); + Ref get_debug_navigation_edge_connections_material(); + + void _emit_navigation_debug_changed_signal(); + +protected: + bool _debug_enabled; + bool _debug_dirty; + + Color _debug_navigation_edge_connection_color; + Color _debug_navigation_geometry_edge_color; + Color _debug_navigation_geometry_face_color; + Color _debug_navigation_geometry_edge_disabled_color; + Color _debug_navigation_geometry_face_disabled_color; + bool _debug_navigation_enable_edge_connections; + bool _debug_navigation_enable_edge_connections_xray; + bool _debug_navigation_enable_edge_lines; + bool _debug_navigation_enable_edge_lines_xray; + bool _debug_navigation_enable_geometry_face_random_color; + + Ref _debug_navigation_geometry_edge_material; + Ref _debug_navigation_geometry_face_material; + Ref _debug_navigation_geometry_edge_disabled_material; + Ref _debug_navigation_geometry_face_disabled_material; + Ref _debug_navigation_edge_connections_material; + +#endif // DEBUG_ENABLED }; typedef NavigationServer *(*CreateNavigationServerCallback)();