Path: blob/master/modules/navigation_3d/nav_region_3d.cpp
10277 views
/**************************************************************************/1/* nav_region_3d.cpp */2/**************************************************************************/3/* This file is part of: */4/* GODOT ENGINE */5/* https://godotengine.org */6/**************************************************************************/7/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */8/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */9/* */10/* Permission is hereby granted, free of charge, to any person obtaining */11/* a copy of this software and associated documentation files (the */12/* "Software"), to deal in the Software without restriction, including */13/* without limitation the rights to use, copy, modify, merge, publish, */14/* distribute, sublicense, and/or sell copies of the Software, and to */15/* permit persons to whom the Software is furnished to do so, subject to */16/* the following conditions: */17/* */18/* The above copyright notice and this permission notice shall be */19/* included in all copies or substantial portions of the Software. */20/* */21/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */22/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */23/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */24/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */25/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */26/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */27/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */28/**************************************************************************/2930#include "nav_region_3d.h"3132#include "nav_map_3d.h"3334#include "3d/nav_mesh_queries_3d.h"35#include "3d/nav_region_builder_3d.h"36#include "3d/nav_region_iteration_3d.h"37#include "core/config/project_settings.h"3839using namespace Nav3D;4041void NavRegion3D::set_map(NavMap3D *p_map) {42if (map == p_map) {43return;44}4546cancel_async_thread_join();47cancel_sync_request();4849if (map) {50map->remove_region(this);51}5253map = p_map;54iteration_dirty = true;5556if (map) {57map->add_region(this);58request_sync();59if (iteration_build_thread_task_id != WorkerThreadPool::INVALID_TASK_ID) {60request_async_thread_join();61}62}63}6465void NavRegion3D::set_enabled(bool p_enabled) {66if (enabled == p_enabled) {67return;68}69enabled = p_enabled;70iteration_dirty = true;7172request_sync();73}7475void NavRegion3D::set_use_edge_connections(bool p_enabled) {76if (use_edge_connections != p_enabled) {77use_edge_connections = p_enabled;78iteration_dirty = true;79}8081request_sync();82}8384void NavRegion3D::set_transform(Transform3D p_transform) {85if (transform == p_transform) {86return;87}88transform = p_transform;89iteration_dirty = true;9091request_sync();9293#ifdef DEBUG_ENABLED94if (map && Math::rad_to_deg(map->get_up().angle_to(transform.basis.get_column(1))) >= 90.0f) {95ERR_PRINT_ONCE("Attempted to update a navigation region transform rotated 90 degrees or more away from the current navigation map UP orientation.");96}97#endif // DEBUG_ENABLED98}99100void NavRegion3D::set_navigation_mesh(Ref<NavigationMesh> p_navigation_mesh) {101#ifdef DEBUG_ENABLED102if (map && p_navigation_mesh.is_valid() && !Math::is_equal_approx(double(map->get_cell_size()), double(p_navigation_mesh->get_cell_size()))) {103ERR_PRINT_ONCE(vformat("Attempted to update a navigation region with a navigation mesh that uses a `cell_size` of %s while assigned to a navigation map set to a `cell_size` of %s. The cell size for navigation maps can be changed by using the NavigationServer map_set_cell_size() function. The cell size for default navigation maps can also be changed in the ProjectSettings.", double(p_navigation_mesh->get_cell_size()), double(map->get_cell_size())));104}105106if (map && p_navigation_mesh.is_valid() && !Math::is_equal_approx(double(map->get_cell_height()), double(p_navigation_mesh->get_cell_height()))) {107ERR_PRINT_ONCE(vformat("Attempted to update a navigation region with a navigation mesh that uses a `cell_height` of %s while assigned to a navigation map set to a `cell_height` of %s. The cell height for navigation maps can be changed by using the NavigationServer map_set_cell_height() function. The cell height for default navigation maps can also be changed in the ProjectSettings.", double(p_navigation_mesh->get_cell_height()), double(map->get_cell_height())));108}109#endif // DEBUG_ENABLED110111navmesh = p_navigation_mesh;112113iteration_dirty = true;114115request_sync();116}117118Vector3 NavRegion3D::get_closest_point_to_segment(const Vector3 &p_from, const Vector3 &p_to, bool p_use_collision) const {119RWLockRead read_lock(region_rwlock);120121return NavMeshQueries3D::polygons_get_closest_point_to_segment(122get_polygons(), p_from, p_to, p_use_collision);123}124125ClosestPointQueryResult NavRegion3D::get_closest_point_info(const Vector3 &p_point) const {126RWLockRead read_lock(region_rwlock);127128return NavMeshQueries3D::polygons_get_closest_point_info(get_polygons(), p_point);129}130131Vector3 NavRegion3D::get_random_point(uint32_t p_navigation_layers, bool p_uniformly) const {132RWLockRead read_lock(region_rwlock);133134if (!get_enabled()) {135return Vector3();136}137138return NavMeshQueries3D::polygons_get_random_point(get_polygons(), p_navigation_layers, p_uniformly);139}140141void NavRegion3D::set_navigation_layers(uint32_t p_navigation_layers) {142if (navigation_layers == p_navigation_layers) {143return;144}145navigation_layers = p_navigation_layers;146iteration_dirty = true;147148request_sync();149}150151void NavRegion3D::set_enter_cost(real_t p_enter_cost) {152real_t new_enter_cost = MAX(p_enter_cost, 0.0);153if (enter_cost == new_enter_cost) {154return;155}156enter_cost = new_enter_cost;157iteration_dirty = true;158159request_sync();160}161162void NavRegion3D::set_travel_cost(real_t p_travel_cost) {163real_t new_travel_cost = MAX(p_travel_cost, 0.0);164if (travel_cost == new_travel_cost) {165return;166}167travel_cost = new_travel_cost;168iteration_dirty = true;169170request_sync();171}172173void NavRegion3D::set_owner_id(ObjectID p_owner_id) {174if (owner_id == p_owner_id) {175return;176}177owner_id = p_owner_id;178iteration_dirty = true;179180request_sync();181}182183void NavRegion3D::scratch_polygons() {184iteration_dirty = true;185186request_sync();187}188189real_t NavRegion3D::get_surface_area() const {190RWLockRead read_lock(iteration_rwlock);191return iteration->get_surface_area();192}193194AABB NavRegion3D::get_bounds() const {195RWLockRead read_lock(iteration_rwlock);196return iteration->get_bounds();197}198199LocalVector<Nav3D::Polygon> const &NavRegion3D::get_polygons() const {200RWLockRead read_lock(iteration_rwlock);201return iteration->get_navmesh_polygons();202}203204bool NavRegion3D::sync() {205bool requires_map_update = false;206if (!map) {207return requires_map_update;208}209210if (iteration_dirty && !iteration_building && !iteration_ready) {211_build_iteration();212}213214if (iteration_ready) {215_sync_iteration();216requires_map_update = true;217}218219return requires_map_update;220}221222void NavRegion3D::sync_async_tasks() {223if (iteration_build_thread_task_id != WorkerThreadPool::INVALID_TASK_ID) {224if (WorkerThreadPool::get_singleton()->is_task_completed(iteration_build_thread_task_id)) {225WorkerThreadPool::get_singleton()->wait_for_task_completion(iteration_build_thread_task_id);226227iteration_build_thread_task_id = WorkerThreadPool::INVALID_TASK_ID;228iteration_building = false;229iteration_ready = true;230request_sync();231}232}233}234235void NavRegion3D::_build_iteration() {236if (!iteration_dirty || iteration_building || iteration_ready) {237return;238}239240iteration_dirty = false;241iteration_building = true;242iteration_ready = false;243244iteration_build.reset();245246if (navmesh.is_valid()) {247navmesh->get_data(iteration_build.navmesh_data.vertices, iteration_build.navmesh_data.polygons);248}249250iteration_build.map_cell_size = map->get_merge_rasterizer_cell_size();251252Ref<NavRegionIteration3D> new_iteration;253new_iteration.instantiate();254255new_iteration->navigation_layers = get_navigation_layers();256new_iteration->enter_cost = get_enter_cost();257new_iteration->travel_cost = get_travel_cost();258new_iteration->owner_object_id = get_owner_id();259new_iteration->owner_type = get_type();260new_iteration->owner_rid = get_self();261new_iteration->enabled = get_enabled();262new_iteration->transform = get_transform();263new_iteration->owner_use_edge_connections = get_use_edge_connections();264265iteration_build.region_iteration = new_iteration;266267if (use_async_iterations) {268iteration_build_thread_task_id = WorkerThreadPool::get_singleton()->add_native_task(&NavRegion3D::_build_iteration_threaded, &iteration_build, true, SNAME("NavRegionBuilder3D"));269request_async_thread_join();270} else {271NavRegionBuilder3D::build_iteration(iteration_build);272273iteration_building = false;274iteration_ready = true;275}276}277278void NavRegion3D::_build_iteration_threaded(void *p_arg) {279NavRegionIterationBuild3D *_iteration_build = static_cast<NavRegionIterationBuild3D *>(p_arg);280281NavRegionBuilder3D::build_iteration(*_iteration_build);282}283284void NavRegion3D::_sync_iteration() {285if (iteration_building || !iteration_ready) {286return;287}288289performance_data.pm_polygon_count = iteration_build.performance_data.pm_polygon_count;290performance_data.pm_edge_count = iteration_build.performance_data.pm_edge_count;291performance_data.pm_edge_merge_count = iteration_build.performance_data.pm_edge_merge_count;292293RWLockWrite write_lock(iteration_rwlock);294ERR_FAIL_COND(iteration.is_null());295iteration = Ref<NavRegionIteration3D>();296DEV_ASSERT(iteration.is_null());297iteration = iteration_build.region_iteration;298iteration_build.region_iteration = Ref<NavRegionIteration3D>();299DEV_ASSERT(iteration_build.region_iteration.is_null());300iteration_id = iteration_id % UINT32_MAX + 1;301302iteration_ready = false;303304cancel_async_thread_join();305}306307Ref<NavRegionIteration3D> NavRegion3D::get_iteration() {308RWLockRead read_lock(iteration_rwlock);309return iteration;310}311312void NavRegion3D::request_async_thread_join() {313DEV_ASSERT(map);314if (map && !async_list_element.in_list()) {315map->add_region_async_thread_join_request(&async_list_element);316}317}318319void NavRegion3D::cancel_async_thread_join() {320if (map && async_list_element.in_list()) {321map->remove_region_async_thread_join_request(&async_list_element);322}323}324325void NavRegion3D::request_sync() {326if (map && !sync_dirty_request_list_element.in_list()) {327map->add_region_sync_dirty_request(&sync_dirty_request_list_element);328}329}330331void NavRegion3D::cancel_sync_request() {332if (map && sync_dirty_request_list_element.in_list()) {333map->remove_region_sync_dirty_request(&sync_dirty_request_list_element);334}335}336337void NavRegion3D::set_use_async_iterations(bool p_enabled) {338if (use_async_iterations == p_enabled) {339return;340}341#ifdef THREADS_ENABLED342use_async_iterations = p_enabled;343#endif344}345346bool NavRegion3D::get_use_async_iterations() const {347return use_async_iterations;348}349350NavRegion3D::NavRegion3D() :351sync_dirty_request_list_element(this), async_list_element(this) {352type = NavigationUtilities::PathSegmentType::PATH_SEGMENT_TYPE_REGION;353iteration_build.region = this;354iteration.instantiate();355356#ifdef THREADS_ENABLED357use_async_iterations = GLOBAL_GET("navigation/world/region_use_async_iterations");358#else359use_async_iterations = false;360#endif361}362363NavRegion3D::~NavRegion3D() {364cancel_async_thread_join();365cancel_sync_request();366367if (iteration_build_thread_task_id != WorkerThreadPool::INVALID_TASK_ID) {368WorkerThreadPool::get_singleton()->wait_for_task_completion(iteration_build_thread_task_id);369iteration_build_thread_task_id = WorkerThreadPool::INVALID_TASK_ID;370}371372iteration_build.region = nullptr;373iteration_build.region_iteration = Ref<NavRegionIteration3D>();374iteration = Ref<NavRegionIteration3D>();375}376377378