2022-03-15 13:29:32 +01:00
/*************************************************************************/
/* nav_region.cpp */
/*************************************************************************/
2023-12-18 00:18:53 +01:00
/* This file is part of: */
/* PANDEMONIUM ENGINE */
/* https://github.com/Relintai/pandemonium_engine */
2022-03-15 13:29:32 +01:00
/*************************************************************************/
2023-12-18 00:18:53 +01:00
/* Copyright (c) 2022-present Péter Magyar. */
2022-03-15 13:29:32 +01:00
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
2023-12-18 00:18:53 +01:00
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
2022-03-15 13:29:32 +01:00
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
# include "nav_region.h"
# include "nav_map.h"
void NavRegion : : set_map ( NavMap * p_map ) {
2023-06-09 16:43:14 +02:00
if ( map = = p_map ) {
return ;
}
2022-03-15 13:29:32 +01:00
map = p_map ;
polygons_dirty = true ;
2022-07-28 22:34:28 +02:00
if ( ! map ) {
connections . clear ( ) ;
}
}
2023-09-04 20:22:28 +02:00
void NavRegion : : set_enabled ( bool p_enabled ) {
if ( enabled = = p_enabled ) {
return ;
}
enabled = p_enabled ;
// TODO: This should not require a full rebuild as the region has not really changed.
polygons_dirty = true ;
} ;
2023-06-09 20:54:05 +02:00
void NavRegion : : set_use_edge_connections ( bool p_enabled ) {
if ( use_edge_connections ! = p_enabled ) {
use_edge_connections = p_enabled ;
polygons_dirty = true ;
}
}
2022-03-15 13:29:32 +01:00
void NavRegion : : set_transform ( Transform p_transform ) {
2023-06-09 16:43:14 +02:00
if ( transform = = p_transform ) {
return ;
}
2022-03-15 13:29:32 +01:00
transform = p_transform ;
polygons_dirty = true ;
}
void NavRegion : : set_mesh ( Ref < NavigationMesh > p_mesh ) {
mesh = p_mesh ;
polygons_dirty = true ;
}
2022-07-28 22:34:28 +02:00
int NavRegion : : get_connections_count ( ) const {
if ( ! map ) {
return 0 ;
}
return connections . size ( ) ;
}
Vector3 NavRegion : : get_connection_pathway_start ( int p_connection_id ) const {
ERR_FAIL_COND_V ( ! map , Vector3 ( ) ) ;
ERR_FAIL_INDEX_V ( p_connection_id , connections . size ( ) , Vector3 ( ) ) ;
return connections [ p_connection_id ] . pathway_start ;
}
Vector3 NavRegion : : get_connection_pathway_end ( int p_connection_id ) const {
ERR_FAIL_COND_V ( ! map , Vector3 ( ) ) ;
ERR_FAIL_INDEX_V ( p_connection_id , connections . size ( ) , Vector3 ( ) ) ;
return connections [ p_connection_id ] . pathway_end ;
}
2022-03-15 13:29:32 +01:00
bool NavRegion : : sync ( ) {
bool something_changed = polygons_dirty /* || something_dirty? */ ;
update_polygons ( ) ;
return something_changed ;
}
void NavRegion : : update_polygons ( ) {
if ( ! polygons_dirty ) {
return ;
}
polygons . clear ( ) ;
polygons_dirty = false ;
2022-07-28 22:34:28 +02:00
if ( map = = nullptr ) {
2022-03-15 13:29:32 +01:00
return ;
}
2022-07-28 22:34:28 +02:00
if ( mesh . is_null ( ) ) {
2022-03-15 13:29:32 +01:00
return ;
2022-07-28 22:34:28 +02:00
}
2022-03-15 13:29:32 +01:00
2023-09-02 13:15:19 +02:00
# ifdef DEBUG_ENABLED
2023-09-02 13:07:00 +02:00
if ( ! Math : : is_equal_approx ( double ( map - > get_cell_size ( ) ) , double ( mesh - > get_cell_size ( ) ) ) ) {
2023-09-02 13:43:37 +02:00
ERR_PRINT_ONCE ( vformat ( " Navigation map synchronization error. 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 ( map - > get_cell_size ( ) ) , double ( mesh - > get_cell_size ( ) ) ) ) ;
2023-09-02 13:07:00 +02:00
}
2023-09-04 18:34:15 +02:00
if ( ! Math : : is_equal_approx ( double ( map - > get_cell_height ( ) ) , double ( mesh - > get_cell_height ( ) ) ) ) {
ERR_PRINT_ONCE ( " Navigation map synchronization error. Attempted to update a navigation region with a navigation mesh that uses a different `cell_height` than the `cell_height` set on the navigation map. " ) ;
}
2023-09-02 13:15:19 +02:00
if ( map & & Math : : rad2deg ( map - > get_up ( ) . angle_to ( transform . basis . get_column ( 1 ) ) ) > = 90.0f ) {
2023-09-02 13:43:37 +02:00
ERR_PRINT_ONCE ( vformat ( " Navigation map synchronization error. 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 ( map - > get_cell_height ( ) ) , double ( mesh - > get_cell_height ( ) ) ) ) ;
2023-09-02 13:15:19 +02:00
}
# endif // DEBUG_ENABLED
2022-03-15 13:29:32 +01:00
PoolVector < Vector3 > vertices = mesh - > get_vertices ( ) ;
int len = vertices . size ( ) ;
2022-07-28 22:34:28 +02:00
if ( len = = 0 ) {
2022-03-15 13:29:32 +01:00
return ;
2022-07-28 22:34:28 +02:00
}
2022-03-15 13:29:32 +01:00
PoolVector < Vector3 > : : Read vertices_r = vertices . read ( ) ;
polygons . resize ( mesh - > get_polygon_count ( ) ) ;
// Build
for ( size_t i ( 0 ) ; i < polygons . size ( ) ; i + + ) {
gd : : Polygon & p = polygons [ i ] ;
p . owner = this ;
Vector < int > mesh_poly = mesh - > get_polygon ( i ) ;
const int * indices = mesh_poly . ptr ( ) ;
bool valid ( true ) ;
p . points . resize ( mesh_poly . size ( ) ) ;
p . edges . resize ( mesh_poly . size ( ) ) ;
Vector3 center ;
2023-06-09 08:53:00 +02:00
real_t sum ( 0 ) ;
2022-03-15 13:29:32 +01:00
for ( int j ( 0 ) ; j < mesh_poly . size ( ) ; j + + ) {
int idx = indices [ j ] ;
if ( idx < 0 | | idx > = len ) {
valid = false ;
break ;
}
Vector3 point_position = transform . xform ( vertices_r [ idx ] ) ;
p . points [ j ] . pos = point_position ;
p . points [ j ] . key = map - > get_point_key ( point_position ) ;
center + = point_position ; // Composing the center of the polygon
if ( j > = 2 ) {
Vector3 epa = transform . xform ( vertices_r [ indices [ j - 2 ] ] ) ;
Vector3 epb = transform . xform ( vertices_r [ indices [ j - 1 ] ] ) ;
sum + = map - > get_up ( ) . dot ( ( epb - epa ) . cross ( point_position - epa ) ) ;
}
}
if ( ! valid ) {
ERR_BREAK_MSG ( ! valid , " The navigation mesh set in this region is not valid! " ) ;
}
p . clockwise = sum > 0 ;
if ( mesh_poly . size ( ) ! = 0 ) {
2023-06-09 08:53:00 +02:00
p . center = center / real_t ( mesh_poly . size ( ) ) ;
2022-03-15 13:29:32 +01:00
}
}
}
2022-07-28 22:34:28 +02:00
NavRegion : : NavRegion ( ) {
map = nullptr ;
navigation_layers = 1 ;
enter_cost = 0.0 ;
travel_cost = 1.0 ;
polygons_dirty = true ;
2023-09-04 20:22:28 +02:00
enabled = true ;
2023-06-09 20:54:05 +02:00
use_edge_connections = true ;
2022-07-28 22:34:28 +02:00
}
NavRegion : : ~ NavRegion ( ) { }