2016-06-18 12:46:12 +00:00
/**************************************************************************/
/* navigation_polygon_editor_plugin.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
2018-01-04 23:50:27 +00:00
2015-02-14 15:09:52 +00:00
# include "navigation_polygon_editor_plugin.h"
2022-08-29 10:10:32 +00:00
# include "editor/editor_node.h"
2023-12-03 17:27:17 +00:00
# include "editor/editor_settings.h"
2022-08-29 10:10:32 +00:00
# include "editor/editor_undo_redo_manager.h"
2023-08-17 16:32:30 +00:00
# include "scene/2d/navigation_region_2d.h"
# include "scene/gui/dialogs.h"
2022-08-29 10:10:32 +00:00
2017-09-06 16:41:14 +00:00
Ref < NavigationPolygon > NavigationPolygonEditor : : _ensure_navpoly ( ) const {
Ref < NavigationPolygon > navpoly = node - > get_navigation_polygon ( ) ;
2024-06-09 20:21:41 +00:00
if ( navpoly . is_null ( ) ) {
navpoly . instantiate ( ) ;
2017-09-06 16:41:14 +00:00
node - > set_navigation_polygon ( navpoly ) ;
2015-02-14 15:09:52 +00:00
}
2017-09-06 16:41:14 +00:00
return navpoly ;
2015-02-14 15:09:52 +00:00
}
2017-09-06 16:41:14 +00:00
Node2D * NavigationPolygonEditor : : _get_node ( ) const {
return node ;
2015-02-14 15:09:52 +00:00
}
2017-09-06 16:41:14 +00:00
void NavigationPolygonEditor : : _set_node ( Node * p_polygon ) {
2020-02-28 07:05:04 +00:00
node = Object : : cast_to < NavigationRegion2D > ( p_polygon ) ;
2023-12-03 17:27:17 +00:00
if ( node ) {
Ref < NavigationPolygon > navpoly = node - > get_navigation_polygon ( ) ;
if ( navpoly . is_valid ( ) & & navpoly - > get_outline_count ( ) > 0 & & navpoly - > get_polygon_count ( ) = = 0 ) {
// We have outlines drawn / added by the user but no polygons were created for this navmesh yet so let's bake once immediately.
_rebake_timer_timeout ( ) ;
}
}
2015-02-14 15:09:52 +00:00
}
2017-09-06 16:41:14 +00:00
int NavigationPolygonEditor : : _get_polygon_count ( ) const {
Ref < NavigationPolygon > navpoly = node - > get_navigation_polygon ( ) ;
2020-05-14 14:41:43 +00:00
if ( navpoly . is_valid ( ) ) {
2017-09-06 16:41:14 +00:00
return navpoly - > get_outline_count ( ) ;
2020-05-14 14:41:43 +00:00
} else {
2017-09-06 16:41:14 +00:00
return 0 ;
2020-05-14 14:41:43 +00:00
}
2015-02-14 15:09:52 +00:00
}
2017-09-06 16:41:14 +00:00
Variant NavigationPolygonEditor : : _get_polygon ( int p_idx ) const {
Ref < NavigationPolygon > navpoly = node - > get_navigation_polygon ( ) ;
2020-05-14 14:41:43 +00:00
if ( navpoly . is_valid ( ) ) {
2017-09-06 16:41:14 +00:00
return navpoly - > get_outline ( p_idx ) ;
2020-05-14 14:41:43 +00:00
} else {
2017-09-06 16:41:14 +00:00
return Variant ( Vector < Vector2 > ( ) ) ;
2020-05-14 14:41:43 +00:00
}
2015-02-14 15:09:52 +00:00
}
2017-09-06 16:41:14 +00:00
void NavigationPolygonEditor : : _set_polygon ( int p_idx , const Variant & p_polygon ) const {
Ref < NavigationPolygon > navpoly = _ensure_navpoly ( ) ;
navpoly - > set_outline ( p_idx , p_polygon ) ;
2023-12-03 17:27:17 +00:00
if ( rebake_timer & & _rebake_timer_delay > = 0.0 ) {
rebake_timer - > start ( ) ;
}
2015-02-14 15:09:52 +00:00
}
2017-09-06 16:41:14 +00:00
void NavigationPolygonEditor : : _action_add_polygon ( const Variant & p_polygon ) {
Ref < NavigationPolygon > navpoly = _ensure_navpoly ( ) ;
2022-12-23 22:53:16 +00:00
EditorUndoRedoManager * undo_redo = EditorUndoRedoManager : : get_singleton ( ) ;
2017-09-06 16:41:14 +00:00
undo_redo - > add_do_method ( navpoly . ptr ( ) , " add_outline " , p_polygon ) ;
undo_redo - > add_undo_method ( navpoly . ptr ( ) , " remove_outline " , navpoly - > get_outline_count ( ) ) ;
2023-12-03 17:27:17 +00:00
if ( rebake_timer & & _rebake_timer_delay > = 0.0 ) {
rebake_timer - > start ( ) ;
}
2015-02-14 15:09:52 +00:00
}
2017-09-06 16:41:14 +00:00
void NavigationPolygonEditor : : _action_remove_polygon ( int p_idx ) {
Ref < NavigationPolygon > navpoly = _ensure_navpoly ( ) ;
2022-12-23 22:53:16 +00:00
EditorUndoRedoManager * undo_redo = EditorUndoRedoManager : : get_singleton ( ) ;
2017-09-06 16:41:14 +00:00
undo_redo - > add_do_method ( navpoly . ptr ( ) , " remove_outline " , p_idx ) ;
undo_redo - > add_undo_method ( navpoly . ptr ( ) , " add_outline_at_index " , navpoly - > get_outline ( p_idx ) , p_idx ) ;
2023-12-03 17:27:17 +00:00
if ( rebake_timer & & _rebake_timer_delay > = 0.0 ) {
rebake_timer - > start ( ) ;
}
2015-02-14 15:09:52 +00:00
}
2017-09-06 16:41:14 +00:00
void NavigationPolygonEditor : : _action_set_polygon ( int p_idx , const Variant & p_previous , const Variant & p_polygon ) {
Ref < NavigationPolygon > navpoly = _ensure_navpoly ( ) ;
2022-12-23 22:53:16 +00:00
EditorUndoRedoManager * undo_redo = EditorUndoRedoManager : : get_singleton ( ) ;
2017-09-06 16:41:14 +00:00
undo_redo - > add_do_method ( navpoly . ptr ( ) , " set_outline " , p_idx , p_polygon ) ;
undo_redo - > add_undo_method ( navpoly . ptr ( ) , " set_outline " , p_idx , p_previous ) ;
2023-12-03 17:27:17 +00:00
if ( rebake_timer & & _rebake_timer_delay > = 0.0 ) {
rebake_timer - > start ( ) ;
}
2015-02-14 15:09:52 +00:00
}
2017-09-06 16:41:14 +00:00
bool NavigationPolygonEditor : : _has_resource ( ) const {
return node & & node - > get_navigation_polygon ( ) . is_valid ( ) ;
2015-02-14 15:09:52 +00:00
}
2017-09-06 16:41:14 +00:00
void NavigationPolygonEditor : : _create_resource ( ) {
2020-05-14 14:41:43 +00:00
if ( ! node ) {
2017-09-06 16:41:14 +00:00
return ;
2020-05-14 14:41:43 +00:00
}
2015-02-14 15:09:52 +00:00
2022-12-23 22:53:16 +00:00
EditorUndoRedoManager * undo_redo = EditorUndoRedoManager : : get_singleton ( ) ;
2017-09-06 16:41:14 +00:00
undo_redo - > create_action ( TTR ( " Create Navigation Polygon " ) ) ;
undo_redo - > add_do_method ( node , " set_navigation_polygon " , Ref < NavigationPolygon > ( memnew ( NavigationPolygon ) ) ) ;
2022-05-02 23:43:50 +00:00
undo_redo - > add_undo_method ( node , " set_navigation_polygon " , Variant ( Ref < RefCounted > ( ) ) ) ;
2017-09-06 16:41:14 +00:00
undo_redo - > commit_action ( ) ;
2015-02-14 15:09:52 +00:00
2017-09-06 16:41:14 +00:00
_menu_option ( MODE_CREATE ) ;
2015-02-14 15:09:52 +00:00
}
2023-08-17 16:32:30 +00:00
NavigationPolygonEditor : : NavigationPolygonEditor ( ) {
bake_hbox = memnew ( HBoxContainer ) ;
add_child ( bake_hbox ) ;
button_bake = memnew ( Button ) ;
button_bake - > set_flat ( true ) ;
bake_hbox - > add_child ( button_bake ) ;
button_bake - > set_toggle_mode ( true ) ;
button_bake - > set_text ( TTR ( " Bake NavigationPolygon " ) ) ;
button_bake - > set_tooltip_text ( TTR ( " Bakes the NavigationPolygon by first parsing the scene for source geometry and then creating the navigation polygon vertices and polygons. " ) ) ;
2024-05-14 07:40:21 +00:00
button_bake - > connect ( SceneStringName ( pressed ) , callable_mp ( this , & NavigationPolygonEditor : : _bake_pressed ) ) ;
2023-08-17 16:32:30 +00:00
button_reset = memnew ( Button ) ;
button_reset - > set_flat ( true ) ;
bake_hbox - > add_child ( button_reset ) ;
button_reset - > set_text ( TTR ( " Clear NavigationPolygon " ) ) ;
button_reset - > set_tooltip_text ( TTR ( " Clears the internal NavigationPolygon outlines, vertices and polygons. " ) ) ;
2024-05-14 07:40:21 +00:00
button_reset - > connect ( SceneStringName ( pressed ) , callable_mp ( this , & NavigationPolygonEditor : : _clear_pressed ) ) ;
2023-08-17 16:32:30 +00:00
bake_info = memnew ( Label ) ;
bake_hbox - > add_child ( bake_info ) ;
2023-12-03 17:27:17 +00:00
rebake_timer = memnew ( Timer ) ;
add_child ( rebake_timer ) ;
rebake_timer - > set_one_shot ( true ) ;
_rebake_timer_delay = EDITOR_GET ( " editors/polygon_editor/auto_bake_delay " ) ;
if ( _rebake_timer_delay > = 0.0 ) {
rebake_timer - > set_wait_time ( _rebake_timer_delay ) ;
}
rebake_timer - > connect ( " timeout " , callable_mp ( this , & NavigationPolygonEditor : : _rebake_timer_timeout ) ) ;
2023-08-17 16:32:30 +00:00
err_dialog = memnew ( AcceptDialog ) ;
add_child ( err_dialog ) ;
node = nullptr ;
}
void NavigationPolygonEditor : : _notification ( int p_what ) {
switch ( p_what ) {
case NOTIFICATION_ENTER_TREE : {
2024-10-09 22:21:47 +00:00
button_bake - > set_button_icon ( get_editor_theme_icon ( SNAME ( " Bake " ) ) ) ;
button_reset - > set_button_icon ( get_editor_theme_icon ( SNAME ( " Reload " ) ) ) ;
2023-08-17 16:32:30 +00:00
} break ;
2023-12-03 17:27:17 +00:00
case EditorSettings : : NOTIFICATION_EDITOR_SETTINGS_CHANGED : {
if ( rebake_timer ) {
_rebake_timer_delay = EDITOR_GET ( " editors/polygon_editor/auto_bake_delay " ) ;
if ( _rebake_timer_delay > = 0.0 ) {
rebake_timer - > set_wait_time ( _rebake_timer_delay ) ;
}
}
} break ;
2023-08-17 16:32:30 +00:00
}
}
void NavigationPolygonEditor : : _bake_pressed ( ) {
2023-12-03 17:27:17 +00:00
if ( rebake_timer ) {
rebake_timer - > stop ( ) ;
}
2023-08-17 16:32:30 +00:00
button_bake - > set_pressed ( false ) ;
ERR_FAIL_NULL ( node ) ;
Ref < NavigationPolygon > navigation_polygon = node - > get_navigation_polygon ( ) ;
2023-12-03 17:27:17 +00:00
if ( navigation_polygon . is_null ( ) ) {
2023-08-17 16:32:30 +00:00
err_dialog - > set_text ( TTR ( " A NavigationPolygon resource must be set or created for this node to work. " ) ) ;
err_dialog - > popup_centered ( ) ;
return ;
}
node - > bake_navigation_polygon ( true ) ;
node - > queue_redraw ( ) ;
}
void NavigationPolygonEditor : : _clear_pressed ( ) {
2023-12-03 17:27:17 +00:00
if ( rebake_timer ) {
rebake_timer - > stop ( ) ;
}
2023-08-17 16:32:30 +00:00
if ( node ) {
if ( node - > get_navigation_polygon ( ) . is_valid ( ) ) {
node - > get_navigation_polygon ( ) - > clear ( ) ;
2024-06-10 17:32:06 +00:00
// Needed to update all the region internals.
node - > set_navigation_polygon ( node - > get_navigation_polygon ( ) ) ;
2023-08-17 16:32:30 +00:00
}
}
button_bake - > set_pressed ( false ) ;
bake_info - > set_text ( " " ) ;
if ( node ) {
node - > queue_redraw ( ) ;
}
}
void NavigationPolygonEditor : : _update_polygon_editing_state ( ) {
if ( ! _get_node ( ) ) {
return ;
}
if ( node ! = nullptr & & node - > get_navigation_polygon ( ) . is_valid ( ) ) {
bake_hbox - > show ( ) ;
} else {
bake_hbox - > hide ( ) ;
}
}
2015-02-14 15:09:52 +00:00
2023-12-03 17:27:17 +00:00
void NavigationPolygonEditor : : _rebake_timer_timeout ( ) {
if ( ! node ) {
return ;
}
Ref < NavigationPolygon > navigation_polygon = node - > get_navigation_polygon ( ) ;
if ( ! navigation_polygon . is_valid ( ) ) {
return ;
}
node - > bake_navigation_polygon ( true ) ;
node - > queue_redraw ( ) ;
}
2022-01-27 09:36:51 +00:00
NavigationPolygonEditorPlugin : : NavigationPolygonEditorPlugin ( ) :
AbstractPolygon2DEditorPlugin ( memnew ( NavigationPolygonEditor ) , " NavigationRegion2D " ) {
2015-02-14 15:09:52 +00:00
}