2014-02-10 02:10:30 +01:00
/**************************************************************************/
2018-08-22 00:06:52 +02:00
/* mesh_library_editor_plugin.cpp */
2014-02-10 02:10:30 +01:00
/**************************************************************************/
/* 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-05 00:50:27 +01:00
2018-08-22 00:06:52 +02:00
# include "mesh_library_editor_plugin.h"
2016-03-09 00:00:52 +01:00
2023-04-05 17:14:46 +02:00
# include "editor/editor_interface.h"
2017-03-05 14:21:25 +01:00
# include "editor/editor_node.h"
# include "editor/editor_settings.h"
2023-09-13 13:14:07 +02:00
# include "editor/editor_string_names.h"
2023-04-07 18:59:49 +02:00
# include "editor/gui/editor_file_dialog.h"
2022-11-19 12:45:49 +01:00
# include "editor/inspector_dock.h"
2023-04-07 18:59:49 +02:00
# include "editor/plugins/node_3d_editor_plugin.h"
2014-02-10 02:10:30 +01:00
# include "main/main.h"
2020-03-26 22:49:16 +01:00
# include "scene/3d/mesh_instance_3d.h"
# include "scene/3d/navigation_region_3d.h"
2024-02-26 07:15:31 +01:00
# include "scene/3d/physics/physics_body_3d.h"
# include "scene/3d/physics/static_body_3d.h"
2022-11-19 12:45:49 +01:00
# include "scene/gui/menu_button.h"
2020-03-04 02:51:12 +01:00
# include "scene/main/window.h"
2014-02-10 02:10:30 +01:00
# include "scene/resources/packed_scene.h"
2018-08-22 08:10:54 +02:00
void MeshLibraryEditor : : edit ( const Ref < MeshLibrary > & p_mesh_library ) {
mesh_library = p_mesh_library ;
2020-05-14 16:41:43 +02:00
if ( mesh_library . is_valid ( ) ) {
2018-08-22 08:10:54 +02:00
menu - > get_popup ( ) - > set_item_disabled ( menu - > get_popup ( ) - > get_item_index ( MENU_OPTION_UPDATE_FROM_SCENE ) , ! mesh_library - > has_meta ( " _editor_source_scene " ) ) ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
}
2021-09-01 01:17:33 +02:00
void MeshLibraryEditor : : _menu_remove_confirm ( ) {
2017-08-15 16:41:17 +02:00
switch ( option ) {
case MENU_OPTION_REMOVE_ITEM : {
2018-08-22 08:10:54 +02:00
mesh_library - > remove_item ( to_erase ) ;
2017-08-15 16:41:17 +02:00
} break ;
2019-04-09 17:08:36 +02:00
default : {
} ;
2014-02-10 02:10:30 +01:00
}
}
2021-09-01 01:17:33 +02:00
void MeshLibraryEditor : : _menu_update_confirm ( bool p_apply_xforms ) {
cd_update - > hide ( ) ;
apply_xforms = p_apply_xforms ;
String existing = mesh_library - > get_meta ( " _editor_source_scene " ) ;
2021-12-09 10:42:46 +01:00
ERR_FAIL_COND ( existing . is_empty ( ) ) ;
2021-09-01 01:17:33 +02:00
_import_scene_cbk ( existing ) ;
}
void MeshLibraryEditor : : _import_scene ( Node * p_scene , Ref < MeshLibrary > p_library , bool p_merge , bool p_apply_xforms ) {
2020-05-14 16:41:43 +02:00
if ( ! p_merge ) {
2014-02-10 02:10:30 +01:00
p_library - > clear ( ) ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
2022-05-13 15:04:37 +02:00
HashMap < int , MeshInstance3D * > mesh_instances ;
2019-01-31 18:04:36 +01:00
2017-08-15 16:41:17 +02:00
for ( int i = 0 ; i < p_scene - > get_child_count ( ) ; i + + ) {
2023-11-27 16:49:49 +01:00
_import_scene_parse_node ( p_library , mesh_instances , p_scene - > get_child ( i ) , p_merge , p_apply_xforms ) ;
2017-08-15 16:41:17 +02:00
}
//generate previews!
2020-05-14 11:00:19 +02:00
if ( true ) {
2020-03-17 07:33:00 +01:00
Vector < Ref < Mesh > > meshes ;
2020-10-17 07:08:21 +02:00
Vector < Transform3D > transforms ;
2017-08-28 05:03:34 +02:00
Vector < int > ids = p_library - > get_item_list ( ) ;
2017-08-15 16:41:17 +02:00
for ( int i = 0 ; i < ids . size ( ) ; i + + ) {
2019-01-31 18:04:36 +01:00
if ( mesh_instances . find ( ids [ i ] ) ) {
meshes . push_back ( p_library - > get_item_mesh ( ids [ i ] ) ) ;
transforms . push_back ( mesh_instances [ ids [ i ] ] - > get_transform ( ) ) ;
}
2017-08-15 16:41:17 +02:00
}
2014-02-10 02:10:30 +01:00
2022-10-18 16:43:37 +02:00
Vector < Ref < Texture2D > > textures = EditorInterface : : get_singleton ( ) - > make_mesh_previews ( meshes , & transforms , EDITOR_GET ( " editors/grid_map/preview_size " ) ) ;
2019-01-31 18:04:36 +01:00
int j = 0 ;
2017-08-28 05:03:34 +02:00
for ( int i = 0 ; i < ids . size ( ) ; i + + ) {
2019-01-31 18:04:36 +01:00
if ( mesh_instances . find ( ids [ i ] ) ) {
p_library - > set_item_preview ( ids [ i ] , textures [ j ] ) ;
j + + ;
}
2017-08-28 05:03:34 +02:00
}
2014-02-10 02:10:30 +01:00
}
}
2017-08-15 16:41:17 +02:00
void MeshLibraryEditor : : _import_scene_cbk ( const String & p_str ) {
Ref < PackedScene > ps = ResourceLoader : : load ( p_str , " PackedScene " ) ;
2014-02-10 02:10:30 +01:00
ERR_FAIL_COND ( ps . is_null ( ) ) ;
2021-06-18 00:03:09 +02:00
Node * scene = ps - > instantiate ( ) ;
2014-02-10 02:10:30 +01:00
2023-09-09 17:24:40 +02:00
ERR_FAIL_NULL_MSG ( scene , " Cannot create an instance from PackedScene ' " + p_str + " '. " ) ;
2019-07-23 09:14:31 +02:00
2021-09-01 01:17:33 +02:00
_import_scene ( scene , mesh_library , option = = MENU_OPTION_UPDATE_FROM_SCENE , apply_xforms ) ;
2014-02-10 02:10:30 +01:00
memdelete ( scene ) ;
2018-08-22 08:10:54 +02:00
mesh_library - > set_meta ( " _editor_source_scene " , p_str ) ;
2021-09-01 01:17:33 +02:00
2017-08-15 16:41:17 +02:00
menu - > get_popup ( ) - > set_item_disabled ( menu - > get_popup ( ) - > get_item_index ( MENU_OPTION_UPDATE_FROM_SCENE ) , false ) ;
2014-02-10 02:10:30 +01:00
}
2023-11-27 16:49:49 +01:00
void MeshLibraryEditor : : _import_scene_parse_node ( Ref < MeshLibrary > p_library , HashMap < int , MeshInstance3D * > & p_mesh_instances , Node * p_node , bool p_merge , bool p_apply_xforms ) {
MeshInstance3D * mesh_instance_node = Object : : cast_to < MeshInstance3D > ( p_node ) ;
if ( ! mesh_instance_node ) {
// No MeshInstance so search deeper ...
for ( int i = 0 ; i < p_node - > get_child_count ( ) ; i + + ) {
_import_scene_parse_node ( p_library , p_mesh_instances , p_node - > get_child ( i ) , p_merge , p_apply_xforms ) ;
}
return ;
}
Ref < Mesh > source_mesh = mesh_instance_node - > get_mesh ( ) ;
if ( source_mesh . is_null ( ) ) {
return ;
}
int item_id = p_library - > find_item_by_name ( mesh_instance_node - > get_name ( ) ) ;
if ( item_id < 0 ) {
item_id = p_library - > get_last_unused_item_id ( ) ;
p_library - > create_item ( item_id ) ;
p_library - > set_item_name ( item_id , mesh_instance_node - > get_name ( ) ) ;
} else if ( ! p_merge ) {
WARN_PRINT ( vformat ( " MeshLibrary export found a MeshInstance3D with a duplicated name '%s' in the exported scene that overrides a previously parsed MeshInstance3D item with the same name. " , mesh_instance_node - > get_name ( ) ) ) ;
}
p_mesh_instances [ item_id ] = mesh_instance_node ;
Ref < Mesh > item_mesh = source_mesh - > duplicate ( ) ;
for ( int i = 0 ; i < item_mesh - > get_surface_count ( ) ; i + + ) {
Ref < Material > surface_override_material = mesh_instance_node - > get_surface_override_material ( i ) ;
if ( surface_override_material . is_valid ( ) ) {
item_mesh - > surface_set_material ( i , surface_override_material ) ;
}
}
p_library - > set_item_mesh ( item_id , item_mesh ) ;
Transform3D item_mesh_transform ;
if ( p_apply_xforms ) {
item_mesh_transform = mesh_instance_node - > get_transform ( ) ;
}
p_library - > set_item_mesh_transform ( item_id , item_mesh_transform ) ;
Vector < MeshLibrary : : ShapeData > collisions ;
for ( int i = 0 ; i < mesh_instance_node - > get_child_count ( ) ; i + + ) {
StaticBody3D * static_body_node = Object : : cast_to < StaticBody3D > ( mesh_instance_node - > get_child ( i ) ) ;
if ( ! static_body_node ) {
continue ;
}
List < uint32_t > shapes ;
static_body_node - > get_shape_owners ( & shapes ) ;
for ( uint32_t & E : shapes ) {
if ( static_body_node - > is_shape_owner_disabled ( E ) ) {
continue ;
}
Transform3D shape_transform ;
if ( p_apply_xforms ) {
shape_transform = mesh_instance_node - > get_transform ( ) ;
}
shape_transform * = static_body_node - > get_transform ( ) * static_body_node - > shape_owner_get_transform ( E ) ;
for ( int k = 0 ; k < static_body_node - > shape_owner_get_shape_count ( E ) ; k + + ) {
Ref < Shape3D > collision_shape = static_body_node - > shape_owner_get_shape ( E , k ) ;
if ( ! collision_shape . is_valid ( ) ) {
continue ;
}
MeshLibrary : : ShapeData shape_data ;
shape_data . shape = collision_shape ;
shape_data . local_transform = shape_transform ;
collisions . push_back ( shape_data ) ;
}
}
}
p_library - > set_item_shapes ( item_id , collisions ) ;
for ( int i = 0 ; i < mesh_instance_node - > get_child_count ( ) ; i + + ) {
NavigationRegion3D * navigation_region_node = Object : : cast_to < NavigationRegion3D > ( mesh_instance_node - > get_child ( i ) ) ;
if ( ! navigation_region_node ) {
continue ;
}
Ref < NavigationMesh > navigation_mesh = navigation_region_node - > get_navigation_mesh ( ) ;
if ( ! navigation_mesh . is_null ( ) ) {
Transform3D navigation_mesh_transform = navigation_region_node - > get_transform ( ) ;
p_library - > set_item_navigation_mesh ( item_id , navigation_mesh ) ;
p_library - > set_item_navigation_mesh_transform ( item_id , navigation_mesh_transform ) ;
break ;
}
}
}
2021-09-01 01:17:33 +02:00
Error MeshLibraryEditor : : update_library_file ( Node * p_base_scene , Ref < MeshLibrary > ml , bool p_merge , bool p_apply_xforms ) {
_import_scene ( p_base_scene , ml , p_merge , p_apply_xforms ) ;
2014-02-10 02:10:30 +01:00
return OK ;
}
void MeshLibraryEditor : : _menu_cbk ( int p_option ) {
2017-08-15 16:41:17 +02:00
option = p_option ;
switch ( p_option ) {
2014-02-10 02:10:30 +01:00
case MENU_OPTION_ADD_ITEM : {
2018-08-22 08:10:54 +02:00
mesh_library - > create_item ( mesh_library - > get_last_unused_item_id ( ) ) ;
2014-02-10 02:10:30 +01:00
} break ;
case MENU_OPTION_REMOVE_ITEM : {
2021-11-17 21:08:55 +01:00
String p = InspectorDock : : get_inspector_singleton ( ) - > get_selected_path ( ) ;
2023-02-12 11:39:55 +01:00
if ( p . begins_with ( " item " ) & & p . get_slice_count ( " / " ) > = 2 ) {
to_erase = p . get_slice ( " / " , 1 ) . to_int ( ) ;
2021-09-01 01:17:33 +02:00
cd_remove - > set_text ( vformat ( TTR ( " Remove item %d? " ) , to_erase ) ) ;
cd_remove - > popup_centered ( Size2 ( 300 , 60 ) ) ;
2014-02-10 02:10:30 +01:00
}
} break ;
case MENU_OPTION_IMPORT_FROM_SCENE : {
2021-09-01 01:17:33 +02:00
apply_xforms = false ;
file - > popup_file_dialog ( ) ;
} break ;
case MENU_OPTION_IMPORT_FROM_SCENE_APPLY_XFORMS : {
apply_xforms = true ;
2020-07-11 18:45:19 +02:00
file - > popup_file_dialog ( ) ;
2014-02-10 02:10:30 +01:00
} break ;
2017-08-15 16:41:17 +02:00
case MENU_OPTION_UPDATE_FROM_SCENE : {
2021-09-01 01:17:33 +02:00
cd_update - > set_text ( vformat ( TTR ( " Update from existing scene?: \n %s " ) , String ( mesh_library - > get_meta ( " _editor_source_scene " ) ) ) ) ;
cd_update - > popup_centered ( Size2 ( 500 , 60 ) ) ;
2017-08-15 16:41:17 +02:00
} break ;
2014-02-10 02:10:30 +01:00
}
}
2022-01-27 10:36:51 +01:00
MeshLibraryEditor : : MeshLibraryEditor ( ) {
2017-08-15 16:41:17 +02:00
file = memnew ( EditorFileDialog ) ;
2020-03-06 18:00:16 +01:00
file - > set_file_mode ( EditorFileDialog : : FILE_MODE_OPEN_FILE ) ;
2014-02-10 02:10:30 +01:00
//not for now?
List < String > extensions ;
2017-08-15 16:41:17 +02:00
ResourceLoader : : get_recognized_extensions_for_type ( " PackedScene " , & extensions ) ;
2014-02-10 02:10:30 +01:00
file - > clear_filters ( ) ;
2016-05-04 03:25:37 +02:00
file - > set_title ( TTR ( " Import Scene " ) ) ;
2024-04-15 15:18:34 +02:00
for ( const String & extension : extensions ) {
file - > add_filter ( " *. " + extension , extension . to_upper ( ) ) ;
2014-02-10 02:10:30 +01:00
}
add_child ( file ) ;
2020-02-21 18:28:45 +01:00
file - > connect ( " file_selected " , callable_mp ( this , & MeshLibraryEditor : : _import_scene_cbk ) ) ;
2014-02-10 02:10:30 +01:00
2018-08-22 00:06:52 +02:00
menu = memnew ( MenuButton ) ;
2020-03-26 22:49:16 +01:00
Node3DEditor : : get_singleton ( ) - > add_control_to_menu_panel ( menu ) ;
2018-08-22 00:06:52 +02:00
menu - > set_position ( Point2 ( 1 , 1 ) ) ;
2022-03-24 21:28:19 +01:00
menu - > set_text ( TTR ( " MeshLibrary " ) ) ;
2023-09-13 13:14:07 +02:00
menu - > set_icon ( EditorNode : : get_singleton ( ) - > get_editor_theme ( ) - > get_icon ( SNAME ( " MeshLibrary " ) , EditorStringName ( EditorIcons ) ) ) ;
2018-08-22 00:06:52 +02:00
menu - > get_popup ( ) - > add_item ( TTR ( " Add Item " ) , MENU_OPTION_ADD_ITEM ) ;
menu - > get_popup ( ) - > add_item ( TTR ( " Remove Selected Item " ) , MENU_OPTION_REMOVE_ITEM ) ;
menu - > get_popup ( ) - > add_separator ( ) ;
2021-09-01 01:17:33 +02:00
menu - > get_popup ( ) - > add_item ( TTR ( " Import from Scene (Ignore Transforms) " ) , MENU_OPTION_IMPORT_FROM_SCENE ) ;
menu - > get_popup ( ) - > add_item ( TTR ( " Import from Scene (Apply Transforms) " ) , MENU_OPTION_IMPORT_FROM_SCENE_APPLY_XFORMS ) ;
2018-08-22 00:06:52 +02:00
menu - > get_popup ( ) - > add_item ( TTR ( " Update from Scene " ) , MENU_OPTION_UPDATE_FROM_SCENE ) ;
menu - > get_popup ( ) - > set_item_disabled ( menu - > get_popup ( ) - > get_item_index ( MENU_OPTION_UPDATE_FROM_SCENE ) , true ) ;
2024-05-14 14:13:31 +02:00
menu - > get_popup ( ) - > connect ( SceneStringName ( id_pressed ) , callable_mp ( this , & MeshLibraryEditor : : _menu_cbk ) ) ;
2018-08-22 00:06:52 +02:00
menu - > hide ( ) ;
2021-09-01 01:17:33 +02:00
cd_remove = memnew ( ConfirmationDialog ) ;
add_child ( cd_remove ) ;
2024-05-14 09:40:21 +02:00
cd_remove - > get_ok_button ( ) - > connect ( SceneStringName ( pressed ) , callable_mp ( this , & MeshLibraryEditor : : _menu_remove_confirm ) ) ;
2021-09-01 01:17:33 +02:00
cd_update = memnew ( ConfirmationDialog ) ;
add_child ( cd_update ) ;
2022-07-08 02:31:19 +02:00
cd_update - > set_ok_button_text ( TTR ( " Apply without Transforms " ) ) ;
2024-05-14 09:40:21 +02:00
cd_update - > get_ok_button ( ) - > connect ( SceneStringName ( pressed ) , callable_mp ( this , & MeshLibraryEditor : : _menu_update_confirm ) . bind ( false ) ) ;
cd_update - > add_button ( TTR ( " Apply with Transforms " ) ) - > connect ( SceneStringName ( pressed ) , callable_mp ( this , & MeshLibraryEditor : : _menu_update_confirm ) . bind ( true ) ) ;
2014-02-10 02:10:30 +01:00
}
void MeshLibraryEditorPlugin : : edit ( Object * p_node ) {
2017-08-24 22:58:51 +02:00
if ( Object : : cast_to < MeshLibrary > ( p_node ) ) {
2018-08-22 08:10:54 +02:00
mesh_library_editor - > edit ( Object : : cast_to < MeshLibrary > ( p_node ) ) ;
mesh_library_editor - > show ( ) ;
2020-05-14 16:41:43 +02:00
} else {
2023-06-11 18:52:49 +02:00
mesh_library_editor - > edit ( Ref < MeshLibrary > ( ) ) ;
2018-08-22 08:10:54 +02:00
mesh_library_editor - > hide ( ) ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
}
2017-08-15 16:41:17 +02:00
bool MeshLibraryEditorPlugin : : handles ( Object * p_node ) const {
return p_node - > is_class ( " MeshLibrary " ) ;
2014-02-10 02:10:30 +01:00
}
2017-08-15 16:41:17 +02:00
void MeshLibraryEditorPlugin : : make_visible ( bool p_visible ) {
2018-08-22 00:06:52 +02:00
if ( p_visible ) {
2018-08-22 08:10:54 +02:00
mesh_library_editor - > show ( ) ;
mesh_library_editor - > get_menu_button ( ) - > show ( ) ;
2018-08-22 00:06:52 +02:00
} else {
2018-08-22 08:10:54 +02:00
mesh_library_editor - > hide ( ) ;
mesh_library_editor - > get_menu_button ( ) - > hide ( ) ;
2018-08-22 00:06:52 +02:00
}
2014-02-10 02:10:30 +01:00
}
2022-01-27 10:36:51 +01:00
MeshLibraryEditorPlugin : : MeshLibraryEditorPlugin ( ) {
mesh_library_editor = memnew ( MeshLibraryEditor ) ;
2014-02-10 02:10:30 +01:00
2024-08-20 00:08:31 +02:00
EditorNode : : get_singleton ( ) - > get_gui_base ( ) - > add_child ( mesh_library_editor ) ;
2020-12-22 17:24:29 +01:00
mesh_library_editor - > set_anchors_and_offsets_preset ( Control : : PRESET_TOP_WIDE ) ;
2018-08-22 08:10:54 +02:00
mesh_library_editor - > set_end ( Point2 ( 0 , 22 ) ) ;
mesh_library_editor - > hide ( ) ;
2014-02-10 02:10:30 +01:00
}