2014-02-10 02:10:30 +01:00
/*************************************************************************/
/* shader_editor_plugin.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
2017-08-27 14:16:55 +02:00
/* https://godotengine.org */
2014-02-10 02:10:30 +01:00
/*************************************************************************/
2022-01-03 21:27:34 +01:00
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
2014-02-10 02:10:30 +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. */
/*************************************************************************/
2018-01-05 00:50:27 +01:00
2014-02-10 02:10:30 +01:00
# include "shader_editor_plugin.h"
2016-03-09 00:00:52 +01:00
2017-08-26 17:46:49 +02:00
# include "core/io/resource_loader.h"
# include "core/io/resource_saver.h"
# include "core/os/keyboard.h"
# include "core/os/os.h"
2021-11-15 10:39:00 +01:00
# include "core/version_generated.gen.h"
2017-03-05 16:44:50 +01:00
# include "editor/editor_node.h"
2020-01-12 08:24:15 +01:00
# include "editor/editor_scale.h"
2017-03-05 14:21:25 +01:00
# include "editor/editor_settings.h"
2022-05-27 11:02:55 +02:00
# include "editor/filesystem_dock.h"
# include "editor/plugins/visual_shader_editor_plugin.h"
2021-01-01 16:04:47 +01:00
# include "editor/project_settings_editor.h"
2022-05-27 11:02:55 +02:00
# include "editor/shader_create_dialog.h"
# include "scene/gui/split_container.h"
2020-03-03 14:36:29 +01:00
# include "servers/display_server.h"
2022-06-29 11:31:18 +02:00
# include "servers/rendering/shader_preprocessor.h"
2020-03-27 19:21:27 +01:00
# include "servers/rendering/shader_types.h"
2014-02-10 02:10:30 +01:00
2022-08-03 14:19:31 +02:00
/*** SHADER SYNTAX HIGHLIGHTER ****/
Dictionary GDShaderSyntaxHighlighter : : _get_line_syntax_highlighting_impl ( int p_line ) {
Dictionary color_map ;
for ( const Point2i & region : disabled_branch_regions ) {
if ( p_line > = region . x & & p_line < = region . y ) {
Dictionary highlighter_info ;
highlighter_info [ " color " ] = disabled_branch_color ;
color_map [ 0 ] = highlighter_info ;
return color_map ;
}
}
return CodeHighlighter : : _get_line_syntax_highlighting_impl ( p_line ) ;
}
void GDShaderSyntaxHighlighter : : add_disabled_branch_region ( const Point2i & p_region ) {
ERR_FAIL_COND ( p_region . x < 0 ) ;
ERR_FAIL_COND ( p_region . y < 0 ) ;
for ( int i = 0 ; i < disabled_branch_regions . size ( ) ; i + + ) {
ERR_FAIL_COND_MSG ( disabled_branch_regions [ i ] . x = = p_region . x , " Branch region with a start line ' " + itos ( p_region . x ) + " ' already exists. " ) ;
}
Point2i disabled_branch_region ;
disabled_branch_region . x = p_region . x ;
disabled_branch_region . y = p_region . y ;
disabled_branch_regions . push_back ( disabled_branch_region ) ;
clear_highlighting_cache ( ) ;
}
void GDShaderSyntaxHighlighter : : clear_disabled_branch_regions ( ) {
disabled_branch_regions . clear ( ) ;
clear_highlighting_cache ( ) ;
}
void GDShaderSyntaxHighlighter : : set_disabled_branch_color ( const Color & p_color ) {
disabled_branch_color = p_color ;
clear_highlighting_cache ( ) ;
}
2017-08-26 17:46:49 +02:00
/*** SHADER SCRIPT EDITOR ****/
2014-02-10 02:10:30 +01:00
2021-01-01 16:04:47 +01:00
static bool saved_warnings_enabled = false ;
static bool saved_treat_warning_as_errors = false ;
2022-05-13 15:04:37 +02:00
static HashMap < ShaderWarning : : Code , bool > saved_warnings ;
2021-01-01 16:04:47 +01:00
static uint32_t saved_warning_flags = 0U ;
2022-01-19 06:31:39 +01:00
void ShaderTextEditor : : _notification ( int p_what ) {
switch ( p_what ) {
case NOTIFICATION_THEME_CHANGED : {
if ( is_visible_in_tree ( ) ) {
_load_theme_settings ( ) ;
if ( warnings . size ( ) > 0 & & last_compile_result = = OK ) {
warnings_panel - > clear ( ) ;
_update_warning_panel ( ) ;
}
}
} break ;
}
}
2014-02-10 02:10:30 +01:00
Ref < Shader > ShaderTextEditor : : get_edited_shader ( ) const {
return shader ;
}
2020-05-14 14:29:06 +02:00
2022-03-08 11:39:16 +01:00
Ref < ShaderInclude > ShaderTextEditor : : get_edited_shader_include ( ) const {
return shader_inc ;
}
2017-03-05 16:44:50 +01:00
void ShaderTextEditor : : set_edited_shader ( const Ref < Shader > & p_shader ) {
2022-03-08 11:39:16 +01:00
set_edited_shader ( p_shader , p_shader - > get_code ( ) ) ;
}
void ShaderTextEditor : : set_edited_shader ( const Ref < Shader > & p_shader , const String & p_code ) {
2019-03-04 23:37:05 +01:00
if ( shader = = p_shader ) {
return ;
}
2022-06-29 11:31:18 +02:00
if ( shader . is_valid ( ) ) {
shader - > disconnect ( SNAME ( " changed " ) , callable_mp ( this , & ShaderTextEditor : : _shader_changed ) ) ;
}
2017-03-05 16:44:50 +01:00
shader = p_shader ;
2022-03-08 11:39:16 +01:00
shader_inc = Ref < ShaderInclude > ( ) ;
set_edited_code ( p_code ) ;
2022-06-29 11:31:18 +02:00
if ( shader . is_valid ( ) ) {
shader - > connect ( SNAME ( " changed " ) , callable_mp ( this , & ShaderTextEditor : : _shader_changed ) ) ;
}
2022-03-08 11:39:16 +01:00
}
void ShaderTextEditor : : set_edited_shader_include ( const Ref < ShaderInclude > & p_shader_inc ) {
set_edited_shader_include ( p_shader_inc , p_shader_inc - > get_code ( ) ) ;
}
2014-02-10 02:10:30 +01:00
2022-06-29 11:31:18 +02:00
void ShaderTextEditor : : _shader_changed ( ) {
// This function is used for dependencies (include changing changes main shader and forces it to revalidate)
if ( block_shader_changed ) {
return ;
}
dependencies_version + + ;
_validate_script ( ) ;
}
2022-03-08 11:39:16 +01:00
void ShaderTextEditor : : set_edited_shader_include ( const Ref < ShaderInclude > & p_shader_inc , const String & p_code ) {
if ( shader_inc = = p_shader_inc ) {
return ;
}
2022-06-29 11:31:18 +02:00
if ( shader_inc . is_valid ( ) ) {
shader_inc - > disconnect ( SNAME ( " changed " ) , callable_mp ( this , & ShaderTextEditor : : _shader_changed ) ) ;
}
2022-03-08 11:39:16 +01:00
shader_inc = p_shader_inc ;
shader = Ref < Shader > ( ) ;
set_edited_code ( p_code ) ;
2022-06-29 11:31:18 +02:00
if ( shader_inc . is_valid ( ) ) {
shader_inc - > connect ( SNAME ( " changed " ) , callable_mp ( this , & ShaderTextEditor : : _shader_changed ) ) ;
}
2022-03-08 11:39:16 +01:00
}
void ShaderTextEditor : : set_edited_code ( const String & p_code ) {
2014-02-10 02:10:30 +01:00
_load_theme_settings ( ) ;
2022-03-08 11:39:16 +01:00
get_text_editor ( ) - > set_text ( p_code ) ;
2020-07-24 16:50:35 +02:00
get_text_editor ( ) - > clear_undo_history ( ) ;
2021-07-17 23:22:52 +02:00
get_text_editor ( ) - > call_deferred ( SNAME ( " set_h_scroll " ) , 0 ) ;
get_text_editor ( ) - > call_deferred ( SNAME ( " set_v_scroll " ) , 0 ) ;
2022-07-28 18:28:38 +02:00
get_text_editor ( ) - > tag_saved_version ( ) ;
2014-02-10 02:10:30 +01:00
2019-02-23 21:52:49 +01:00
_validate_script ( ) ;
2014-02-10 02:10:30 +01:00
_line_col_changed ( ) ;
}
2018-10-08 21:26:45 +02:00
void ShaderTextEditor : : reload_text ( ) {
ERR_FAIL_COND ( shader . is_null ( ) ) ;
2020-07-24 16:50:35 +02:00
CodeEdit * te = get_text_editor ( ) ;
2021-07-08 19:35:56 +02:00
int column = te - > get_caret_column ( ) ;
int row = te - > get_caret_line ( ) ;
2018-10-08 21:26:45 +02:00
int h = te - > get_h_scroll ( ) ;
int v = te - > get_v_scroll ( ) ;
te - > set_text ( shader - > get_code ( ) ) ;
2021-07-08 19:35:56 +02:00
te - > set_caret_line ( row ) ;
te - > set_caret_column ( column ) ;
2018-10-08 21:26:45 +02:00
te - > set_h_scroll ( h ) ;
te - > set_v_scroll ( v ) ;
te - > tag_saved_version ( ) ;
update_line_and_column ( ) ;
}
2021-01-01 16:04:47 +01:00
void ShaderTextEditor : : set_warnings_panel ( RichTextLabel * p_warnings_panel ) {
warnings_panel = p_warnings_panel ;
}
2014-02-10 02:10:30 +01:00
void ShaderTextEditor : : _load_theme_settings ( ) {
2020-09-10 22:25:00 +02:00
CodeEdit * text_editor = get_text_editor ( ) ;
2021-08-15 19:14:46 +02:00
Color updated_marked_line_color = EDITOR_GET ( " text_editor/theme/highlighting/mark_color " ) ;
2020-09-10 22:25:00 +02:00
if ( updated_marked_line_color ! = marked_line_color ) {
for ( int i = 0 ; i < text_editor - > get_line_count ( ) ; i + + ) {
if ( text_editor - > get_line_background_color ( i ) = = marked_line_color ) {
text_editor - > set_line_background_color ( i , updated_marked_line_color ) ;
}
}
marked_line_color = updated_marked_line_color ;
}
2020-05-03 18:08:15 +02:00
2021-08-15 19:14:46 +02:00
syntax_highlighter - > set_number_color ( EDITOR_GET ( " text_editor/theme/highlighting/number_color " ) ) ;
syntax_highlighter - > set_symbol_color ( EDITOR_GET ( " text_editor/theme/highlighting/symbol_color " ) ) ;
syntax_highlighter - > set_function_color ( EDITOR_GET ( " text_editor/theme/highlighting/function_color " ) ) ;
syntax_highlighter - > set_member_variable_color ( EDITOR_GET ( " text_editor/theme/highlighting/member_variable_color " ) ) ;
2014-02-10 02:10:30 +01:00
2019-11-11 20:28:25 +01:00
syntax_highlighter - > clear_keyword_colors ( ) ;
2021-08-15 19:14:46 +02:00
const Color keyword_color = EDITOR_GET ( " text_editor/theme/highlighting/keyword_color " ) ;
const Color control_flow_keyword_color = EDITOR_GET ( " text_editor/theme/highlighting/control_flow_keyword_color " ) ;
2019-11-11 20:28:25 +01:00
2022-03-08 11:39:16 +01:00
List < String > keywords ;
ShaderLanguage : : get_keyword_list ( & keywords ) ;
2021-07-24 15:46:25 +02:00
for ( const String & E : keywords ) {
2021-07-16 05:45:57 +02:00
if ( ShaderLanguage : : is_control_flow_keyword ( E ) ) {
syntax_highlighter - > add_keyword_color ( E , control_flow_keyword_color ) ;
2021-04-08 16:12:22 +02:00
} else {
2021-07-16 05:45:57 +02:00
syntax_highlighter - > add_keyword_color ( E , keyword_color ) ;
2021-04-08 16:12:22 +02:00
}
2019-11-11 20:28:25 +01:00
}
2016-10-07 16:31:18 +02:00
2022-03-08 11:39:16 +01:00
List < String > pp_keywords ;
2022-06-29 11:31:18 +02:00
ShaderPreprocessor : : get_keyword_list ( & pp_keywords , false ) ;
2022-03-08 11:39:16 +01:00
for ( const String & E : pp_keywords ) {
syntax_highlighter - > add_keyword_color ( E , keyword_color ) ;
}
2019-11-11 20:28:25 +01:00
// Colorize built-ins like `COLOR` differently to make them easier
// to distinguish from keywords at a quick glance.
List < String > built_ins ;
2022-07-25 07:19:48 +02:00
if ( shader_inc . is_valid ( ) ) {
for ( int i = 0 ; i < RenderingServer : : SHADER_MAX ; i + + ) {
for ( const KeyValue < StringName , ShaderLanguage : : FunctionInfo > & E : ShaderTypes : : get_singleton ( ) - > get_functions ( RenderingServer : : ShaderMode ( i ) ) ) {
for ( const KeyValue < StringName , ShaderLanguage : : BuiltInInfo > & F : E . value . built_ins ) {
built_ins . push_back ( F . key ) ;
}
}
const Vector < ShaderLanguage : : ModeInfo > & modes = ShaderTypes : : get_singleton ( ) - > get_modes ( RenderingServer : : ShaderMode ( i ) ) ;
for ( int j = 0 ; j < modes . size ( ) ; j + + ) {
const ShaderLanguage : : ModeInfo & info = modes [ j ] ;
if ( ! info . options . is_empty ( ) ) {
for ( int k = 0 ; k < info . options . size ( ) ; k + + ) {
built_ins . push_back ( String ( info . name ) + " _ " + String ( info . options [ k ] ) ) ;
}
} else {
built_ins . push_back ( String ( info . name ) ) ;
}
}
}
} else if ( shader . is_valid ( ) ) {
2021-08-09 22:13:42 +02:00
for ( const KeyValue < StringName , ShaderLanguage : : FunctionInfo > & E : ShaderTypes : : get_singleton ( ) - > get_functions ( RenderingServer : : ShaderMode ( shader - > get_mode ( ) ) ) ) {
for ( const KeyValue < StringName , ShaderLanguage : : BuiltInInfo > & F : E . value . built_ins ) {
built_ins . push_back ( F . key ) ;
2016-10-07 16:31:18 +02:00
}
}
2021-12-21 15:21:55 +01:00
const Vector < ShaderLanguage : : ModeInfo > & modes = ShaderTypes : : get_singleton ( ) - > get_modes ( RenderingServer : : ShaderMode ( shader - > get_mode ( ) ) ) ;
for ( int i = 0 ; i < modes . size ( ) ; i + + ) {
const ShaderLanguage : : ModeInfo & info = modes [ i ] ;
if ( ! info . options . is_empty ( ) ) {
for ( int j = 0 ; j < info . options . size ( ) ; j + + ) {
built_ins . push_back ( String ( info . name ) + " _ " + String ( info . options [ j ] ) ) ;
}
} else {
built_ins . push_back ( String ( info . name ) ) ;
}
2016-10-07 16:31:18 +02:00
}
}
2014-02-10 02:10:30 +01:00
2021-11-15 23:40:57 +01:00
const Color user_type_color = EDITOR_GET ( " text_editor/theme/highlighting/user_type_color " ) ;
2019-11-11 20:28:25 +01:00
2021-07-24 15:46:25 +02:00
for ( const String & E : built_ins ) {
2021-11-15 23:40:57 +01:00
syntax_highlighter - > add_keyword_color ( E , user_type_color ) ;
2014-02-10 02:10:30 +01:00
}
2019-11-11 20:28:25 +01:00
// Colorize comments.
2021-08-15 19:14:46 +02:00
const Color comment_color = EDITOR_GET ( " text_editor/theme/highlighting/comment_color " ) ;
2020-05-03 18:08:15 +02:00
syntax_highlighter - > clear_color_regions ( ) ;
syntax_highlighter - > add_color_region ( " /* " , " */ " , comment_color , false ) ;
2020-07-28 21:16:24 +02:00
syntax_highlighter - > add_color_region ( " // " , " " , comment_color , true ) ;
2022-08-03 14:19:31 +02:00
syntax_highlighter - > set_disabled_branch_color ( comment_color ) ;
2021-01-01 16:04:47 +01:00
2020-09-10 22:25:40 +02:00
text_editor - > clear_comment_delimiters ( ) ;
text_editor - > add_comment_delimiter ( " /* " , " */ " , false ) ;
text_editor - > add_comment_delimiter ( " // " , " " , true ) ;
2021-06-28 18:14:44 +02:00
if ( ! text_editor - > has_auto_brace_completion_open_key ( " /* " ) ) {
text_editor - > add_auto_brace_completion_pair ( " /* " , " */ " ) ;
}
2022-03-08 11:39:16 +01:00
// Colorize preprocessor include strings.
const Color string_color = EDITOR_GET ( " text_editor/theme/highlighting/string_color " ) ;
syntax_highlighter - > add_color_region ( " \" " , " \" " , string_color , false ) ;
2021-01-01 16:04:47 +01:00
if ( warnings_panel ) {
2022-03-08 11:39:16 +01:00
// Warnings panel.
2022-02-08 10:14:58 +01:00
warnings_panel - > add_theme_font_override ( " normal_font " , EditorNode : : get_singleton ( ) - > get_gui_base ( ) - > get_theme_font ( SNAME ( " main " ) , SNAME ( " EditorFonts " ) ) ) ;
warnings_panel - > add_theme_font_size_override ( " normal_font_size " , EditorNode : : get_singleton ( ) - > get_gui_base ( ) - > get_theme_font_size ( SNAME ( " main_size " ) , SNAME ( " EditorFonts " ) ) ) ;
2021-01-01 16:04:47 +01:00
}
2014-02-10 02:10:30 +01:00
}
2017-04-07 04:36:37 +02:00
void ShaderTextEditor : : _check_shader_mode ( ) {
2020-07-24 16:50:35 +02:00
String type = ShaderLanguage : : get_shader_type ( get_text_editor ( ) - > get_text ( ) ) ;
2017-04-07 04:36:37 +02:00
Shader : : Mode mode ;
if ( type = = " canvas_item " ) {
mode = Shader : : MODE_CANVAS_ITEM ;
} else if ( type = = " particles " ) {
mode = Shader : : MODE_PARTICLES ;
2021-10-03 13:28:55 +02:00
} else if ( type = = " sky " ) {
mode = Shader : : MODE_SKY ;
} else if ( type = = " fog " ) {
mode = Shader : : MODE_FOG ;
2017-04-07 04:36:37 +02:00
} else {
mode = Shader : : MODE_SPATIAL ;
}
if ( shader - > get_mode ( ) ! = mode ) {
2022-06-29 11:31:18 +02:00
set_block_shader_changed ( true ) ;
2020-07-24 16:50:35 +02:00
shader - > set_code ( get_text_editor ( ) - > get_text ( ) ) ;
2022-06-29 11:31:18 +02:00
set_block_shader_changed ( false ) ;
2017-04-07 04:36:37 +02:00
_load_theme_settings ( ) ;
}
}
2022-04-03 18:56:43 +02:00
static ShaderLanguage : : DataType _get_global_shader_uniform_type ( const StringName & p_variable ) {
RS : : GlobalShaderUniformType gvt = RS : : get_singleton ( ) - > global_shader_uniform_get_type ( p_variable ) ;
return ( ShaderLanguage : : DataType ) RS : : global_shader_uniform_type_get_shader_datatype ( gvt ) ;
2020-04-17 04:52:00 +02:00
}
2022-06-29 11:31:18 +02:00
static String complete_from_path ;
static void _complete_include_paths_search ( EditorFileSystemDirectory * p_efsd , List < ScriptLanguage : : CodeCompletionOption > * r_options ) {
if ( ! p_efsd ) {
return ;
}
for ( int i = 0 ; i < p_efsd - > get_file_count ( ) ; i + + ) {
if ( p_efsd - > get_file_type ( i ) = = SNAME ( " ShaderInclude " ) ) {
String path = p_efsd - > get_file_path ( i ) ;
if ( path . begins_with ( complete_from_path ) ) {
path = path . replace_first ( complete_from_path , " " ) ;
}
r_options - > push_back ( ScriptLanguage : : CodeCompletionOption ( path , ScriptLanguage : : CODE_COMPLETION_KIND_FILE_PATH ) ) ;
}
}
for ( int j = 0 ; j < p_efsd - > get_subdir_count ( ) ; j + + ) {
_complete_include_paths_search ( p_efsd - > get_subdir ( j ) , r_options ) ;
}
}
static void _complete_include_paths ( List < ScriptLanguage : : CodeCompletionOption > * r_options ) {
_complete_include_paths_search ( EditorFileSystem : : get_singleton ( ) - > get_filesystem ( ) , r_options ) ;
}
2022-03-26 16:48:43 +01:00
void ShaderTextEditor : : _code_complete_script ( const String & p_code , List < ScriptLanguage : : CodeCompletionOption > * r_options ) {
2022-06-29 11:31:18 +02:00
List < ScriptLanguage : : CodeCompletionOption > pp_options ;
ShaderPreprocessor preprocessor ;
String code ;
complete_from_path = ( shader . is_valid ( ) ? shader - > get_path ( ) : shader_inc - > get_path ( ) ) . get_base_dir ( ) ;
if ( ! complete_from_path . ends_with ( " / " ) ) {
complete_from_path + = " / " ;
}
2022-08-03 14:19:31 +02:00
preprocessor . preprocess ( p_code , " " , code , nullptr , nullptr , nullptr , nullptr , & pp_options , _complete_include_paths ) ;
2022-06-29 11:31:18 +02:00
complete_from_path = String ( ) ;
if ( pp_options . size ( ) ) {
for ( const ScriptLanguage : : CodeCompletionOption & E : pp_options ) {
r_options - > push_back ( E ) ;
}
return ;
}
2016-10-07 16:31:18 +02:00
ShaderLanguage sl ;
String calltip ;
2021-08-08 07:04:20 +02:00
ShaderLanguage : : ShaderCompileInfo info ;
2022-04-03 18:56:43 +02:00
info . global_shader_uniform_type_func = _get_global_shader_uniform_type ;
2022-03-08 11:39:16 +01:00
if ( shader . is_null ( ) ) {
info . is_include = true ;
2022-07-25 07:19:48 +02:00
sl . complete ( code , info , r_options , calltip ) ;
2022-03-08 11:39:16 +01:00
get_text_editor ( ) - > set_code_hint ( calltip ) ;
return ;
}
_check_shader_mode ( ) ;
2021-08-08 07:04:20 +02:00
info . functions = ShaderTypes : : get_singleton ( ) - > get_functions ( RenderingServer : : ShaderMode ( shader - > get_mode ( ) ) ) ;
info . render_modes = ShaderTypes : : get_singleton ( ) - > get_modes ( RenderingServer : : ShaderMode ( shader - > get_mode ( ) ) ) ;
info . shader_types = ShaderTypes : : get_singleton ( ) - > get_types ( ) ;
2022-07-25 07:19:48 +02:00
sl . complete ( code , info , r_options , calltip ) ;
2020-07-24 16:50:35 +02:00
get_text_editor ( ) - > set_code_hint ( calltip ) ;
2016-10-07 16:31:18 +02:00
}
2014-02-10 02:10:30 +01:00
2016-10-07 16:31:18 +02:00
void ShaderTextEditor : : _validate_script ( ) {
2022-06-29 11:31:18 +02:00
emit_signal ( SNAME ( " script_changed " ) ) ; // Ensure to notify that it changed, so it is applied
2022-03-08 11:39:16 +01:00
String code ;
2014-02-10 02:10:30 +01:00
2022-03-08 11:39:16 +01:00
if ( shader . is_valid ( ) ) {
_check_shader_mode ( ) ;
code = shader - > get_code ( ) ;
} else {
code = shader_inc - > get_code ( ) ;
}
2021-08-08 07:04:20 +02:00
2022-06-29 11:31:18 +02:00
ShaderPreprocessor preprocessor ;
String code_pp ;
String error_pp ;
List < ShaderPreprocessor : : FilePosition > err_positions ;
2022-08-03 14:19:31 +02:00
List < ShaderPreprocessor : : Region > regions ;
String filename ;
if ( shader . is_valid ( ) ) {
filename = shader - > get_path ( ) ;
} else if ( shader_inc . is_valid ( ) ) {
filename = shader_inc - > get_path ( ) ;
}
last_compile_result = preprocessor . preprocess ( code , filename , code_pp , & error_pp , & err_positions , & regions ) ;
2016-10-07 16:31:18 +02:00
2022-06-29 11:31:18 +02:00
for ( int i = 0 ; i < get_text_editor ( ) - > get_line_count ( ) ; i + + ) {
get_text_editor ( ) - > set_line_background_color ( i , Color ( 0 , 0 , 0 , 0 ) ) ;
2022-03-08 11:39:16 +01:00
}
2022-08-03 14:19:31 +02:00
syntax_highlighter - > clear_disabled_branch_regions ( ) ;
for ( const ShaderPreprocessor : : Region & region : regions ) {
if ( ! region . enabled ) {
if ( filename ! = region . file ) {
continue ;
}
syntax_highlighter - > add_disabled_branch_region ( Point2i ( region . from_line , region . to_line ) ) ;
}
}
2022-06-29 11:31:18 +02:00
set_error ( " " ) ;
2022-07-23 10:32:04 +02:00
set_error_count ( 0 ) ;
2014-02-10 02:10:30 +01:00
2022-01-19 06:31:39 +01:00
if ( last_compile_result ! = OK ) {
2022-06-29 11:31:18 +02:00
//preprocessor error
ERR_FAIL_COND ( err_positions . size ( ) = = 0 ) ;
2022-07-23 08:38:59 +02:00
String error_text = error_pp ;
2022-06-29 11:31:18 +02:00
int error_line = err_positions . front ( ) - > get ( ) . line ;
if ( err_positions . size ( ) = = 1 ) {
// Error in main file
error_text = " error( " + itos ( error_line ) + " ): " + error_text ;
} else {
error_text = " error( " + itos ( error_line ) + " ) in include " + err_positions . back ( ) - > get ( ) . file . get_file ( ) + " : " + itos ( err_positions . back ( ) - > get ( ) . line ) + " : " + error_text ;
set_error_count ( err_positions . size ( ) - 1 ) ;
}
2014-02-10 02:10:30 +01:00
set_error ( error_text ) ;
2022-06-29 11:31:18 +02:00
set_error_pos ( error_line - 1 , 0 ) ;
2020-07-24 16:50:35 +02:00
for ( int i = 0 ; i < get_text_editor ( ) - > get_line_count ( ) ; i + + ) {
2020-09-10 22:25:00 +02:00
get_text_editor ( ) - > set_line_background_color ( i , Color ( 0 , 0 , 0 , 0 ) ) ;
2020-05-14 16:41:43 +02:00
}
2022-06-29 11:31:18 +02:00
get_text_editor ( ) - > set_line_background_color ( error_line - 1 , marked_line_color ) ;
set_warning_count ( 0 ) ;
2014-02-10 02:10:30 +01:00
} else {
2022-06-29 11:31:18 +02:00
ShaderLanguage sl ;
sl . enable_warning_checking ( saved_warnings_enabled ) ;
uint32_t flags = saved_warning_flags ;
if ( shader . is_null ( ) ) {
if ( flags & ShaderWarning : : UNUSED_CONSTANT ) {
flags & = ~ ( ShaderWarning : : UNUSED_CONSTANT ) ;
}
if ( flags & ShaderWarning : : UNUSED_FUNCTION ) {
flags & = ~ ( ShaderWarning : : UNUSED_FUNCTION ) ;
}
if ( flags & ShaderWarning : : UNUSED_STRUCT ) {
flags & = ~ ( ShaderWarning : : UNUSED_STRUCT ) ;
}
if ( flags & ShaderWarning : : UNUSED_UNIFORM ) {
flags & = ~ ( ShaderWarning : : UNUSED_UNIFORM ) ;
}
if ( flags & ShaderWarning : : UNUSED_VARYING ) {
flags & = ~ ( ShaderWarning : : UNUSED_VARYING ) ;
}
2020-05-14 16:41:43 +02:00
}
2022-06-29 11:31:18 +02:00
sl . set_warning_flags ( flags ) ;
2014-02-10 02:10:30 +01:00
2022-06-29 11:31:18 +02:00
ShaderLanguage : : ShaderCompileInfo info ;
2022-04-03 18:56:43 +02:00
info . global_shader_uniform_type_func = _get_global_shader_uniform_type ;
2022-06-29 11:31:18 +02:00
if ( shader . is_null ( ) ) {
info . is_include = true ;
} else {
Shader : : Mode mode = shader - > get_mode ( ) ;
info . functions = ShaderTypes : : get_singleton ( ) - > get_functions ( RenderingServer : : ShaderMode ( mode ) ) ;
info . render_modes = ShaderTypes : : get_singleton ( ) - > get_modes ( RenderingServer : : ShaderMode ( mode ) ) ;
info . shader_types = ShaderTypes : : get_singleton ( ) - > get_types ( ) ;
}
code = code_pp ;
//compiler error
last_compile_result = sl . compile ( code , info ) ;
if ( last_compile_result ! = OK ) {
String error_text ;
int error_line ;
Vector < ShaderLanguage : : FilePosition > include_positions = sl . get_include_positions ( ) ;
if ( include_positions . size ( ) > 1 ) {
//error is in an include
error_line = include_positions [ 0 ] . line ;
error_text = " error( " + itos ( error_line ) + " ) in include " + include_positions [ include_positions . size ( ) - 1 ] . file + " : " + itos ( include_positions [ include_positions . size ( ) - 1 ] . line ) + " : " + sl . get_error_text ( ) ;
set_error_count ( include_positions . size ( ) - 1 ) ;
} else {
error_line = sl . get_error_line ( ) ;
error_text = " error( " + itos ( error_line ) + " ): " + sl . get_error_text ( ) ;
set_error_count ( 0 ) ;
}
set_error ( error_text ) ;
set_error_pos ( error_line - 1 , 0 ) ;
get_text_editor ( ) - > set_line_background_color ( error_line - 1 , marked_line_color ) ;
} else {
set_error ( " " ) ;
}
if ( warnings . size ( ) > 0 | | last_compile_result ! = OK ) {
warnings_panel - > clear ( ) ;
}
warnings . clear ( ) ;
for ( List < ShaderWarning > : : Element * E = sl . get_warnings_ptr ( ) ; E ; E = E - > next ( ) ) {
warnings . push_back ( E - > get ( ) ) ;
}
if ( warnings . size ( ) > 0 & & last_compile_result = = OK ) {
warnings . sort_custom < WarningsComparator > ( ) ;
_update_warning_panel ( ) ;
} else {
set_warning_count ( 0 ) ;
}
2021-01-01 16:04:47 +01:00
}
2022-06-29 11:31:18 +02:00
emit_signal ( SNAME ( " script_validated " ) , last_compile_result = = OK ) ; // Notify that validation finished, to update the list of scripts
2014-02-10 02:10:30 +01:00
}
2021-01-01 16:04:47 +01:00
void ShaderTextEditor : : _update_warning_panel ( ) {
int warning_count = 0 ;
warnings_panel - > push_table ( 2 ) ;
for ( int i = 0 ; i < warnings . size ( ) ; i + + ) {
ShaderWarning & w = warnings [ i ] ;
if ( warning_count = = 0 ) {
if ( saved_treat_warning_as_errors ) {
String error_text = " error( " + itos ( w . get_line ( ) ) + " ): " + w . get_message ( ) + " " + TTR ( " Warnings should be fixed to prevent errors. " ) ;
set_error_pos ( w . get_line ( ) - 1 , 0 ) ;
set_error ( error_text ) ;
get_text_editor ( ) - > set_line_background_color ( w . get_line ( ) - 1 , marked_line_color ) ;
}
}
warning_count + + ;
2021-12-22 08:15:12 +01:00
int line = w . get_line ( ) ;
2021-01-01 16:04:47 +01:00
// First cell.
warnings_panel - > push_cell ( ) ;
2021-07-17 23:22:52 +02:00
warnings_panel - > push_color ( warnings_panel - > get_theme_color ( SNAME ( " warning_color " ) , SNAME ( " Editor " ) ) ) ;
2021-12-22 08:15:12 +01:00
if ( line ! = - 1 ) {
warnings_panel - > push_meta ( line - 1 ) ;
warnings_panel - > add_text ( TTR ( " Line " ) + " " + itos ( line ) ) ;
warnings_panel - > add_text ( " ( " + w . get_name ( ) + " ): " ) ;
warnings_panel - > pop ( ) ; // Meta goto.
} else {
warnings_panel - > add_text ( w . get_name ( ) + " : " ) ;
}
2021-01-01 16:04:47 +01:00
warnings_panel - > pop ( ) ; // Color.
warnings_panel - > pop ( ) ; // Cell.
// Second cell.
warnings_panel - > push_cell ( ) ;
warnings_panel - > add_text ( w . get_message ( ) ) ;
warnings_panel - > pop ( ) ; // Cell.
}
warnings_panel - > pop ( ) ; // Table.
2021-05-18 05:09:19 +02:00
set_warning_count ( warning_count ) ;
2021-01-01 16:04:47 +01:00
}
2014-02-10 02:10:30 +01:00
void ShaderTextEditor : : _bind_methods ( ) {
2022-06-29 11:31:18 +02:00
ADD_SIGNAL ( MethodInfo ( " script_validated " , PropertyInfo ( Variant : : BOOL , " valid " ) ) ) ;
2014-02-10 02:10:30 +01:00
}
ShaderTextEditor : : ShaderTextEditor ( ) {
2021-06-18 00:03:09 +02:00
syntax_highlighter . instantiate ( ) ;
2020-07-24 16:50:35 +02:00
get_text_editor ( ) - > set_syntax_highlighter ( syntax_highlighter ) ;
2014-02-10 02:10:30 +01:00
}
/*** SCRIPT EDITOR ******/
void ShaderEditor : : _menu_option ( int p_option ) {
2017-03-05 16:44:50 +01:00
switch ( p_option ) {
2014-02-10 02:10:30 +01:00
case EDIT_UNDO : {
2020-07-24 16:50:35 +02:00
shader_editor - > get_text_editor ( ) - > undo ( ) ;
2014-02-10 02:10:30 +01:00
} break ;
case EDIT_REDO : {
2020-07-24 16:50:35 +02:00
shader_editor - > get_text_editor ( ) - > redo ( ) ;
2014-02-10 02:10:30 +01:00
} break ;
case EDIT_CUT : {
2020-07-24 16:50:35 +02:00
shader_editor - > get_text_editor ( ) - > cut ( ) ;
2014-02-10 02:10:30 +01:00
} break ;
case EDIT_COPY : {
2020-07-24 16:50:35 +02:00
shader_editor - > get_text_editor ( ) - > copy ( ) ;
2014-02-10 02:10:30 +01:00
} break ;
case EDIT_PASTE : {
2020-07-24 16:50:35 +02:00
shader_editor - > get_text_editor ( ) - > paste ( ) ;
2014-02-10 02:10:30 +01:00
} break ;
case EDIT_SELECT_ALL : {
2020-07-24 16:50:35 +02:00
shader_editor - > get_text_editor ( ) - > select_all ( ) ;
2017-11-11 05:07:41 +01:00
} break ;
case EDIT_MOVE_LINE_UP : {
2018-05-26 00:49:35 +02:00
shader_editor - > move_lines_up ( ) ;
2017-11-11 05:07:41 +01:00
} break ;
case EDIT_MOVE_LINE_DOWN : {
2018-05-26 00:49:35 +02:00
shader_editor - > move_lines_down ( ) ;
2017-11-11 05:07:41 +01:00
} break ;
case EDIT_INDENT_LEFT : {
2020-05-14 16:41:43 +02:00
if ( shader . is_null ( ) ) {
2017-11-11 05:07:41 +01:00
return ;
2020-05-14 16:41:43 +02:00
}
2021-06-15 16:05:01 +02:00
shader_editor - > get_text_editor ( ) - > unindent_lines ( ) ;
2017-11-11 05:07:41 +01:00
} break ;
case EDIT_INDENT_RIGHT : {
2020-05-14 16:41:43 +02:00
if ( shader . is_null ( ) ) {
2017-11-11 05:07:41 +01:00
return ;
2020-05-14 16:41:43 +02:00
}
2021-06-15 16:05:01 +02:00
shader_editor - > get_text_editor ( ) - > indent_lines ( ) ;
2017-11-11 05:07:41 +01:00
} break ;
case EDIT_DELETE_LINE : {
2018-05-26 00:49:35 +02:00
shader_editor - > delete_lines ( ) ;
2014-02-10 02:10:30 +01:00
} break ;
2021-06-29 12:09:07 +02:00
case EDIT_DUPLICATE_SELECTION : {
shader_editor - > duplicate_selection ( ) ;
2017-11-11 05:07:41 +01:00
} break ;
case EDIT_TOGGLE_COMMENT : {
2020-05-14 16:41:43 +02:00
if ( shader . is_null ( ) ) {
2017-11-11 05:07:41 +01:00
return ;
2020-05-14 16:41:43 +02:00
}
2017-11-11 05:07:41 +01:00
2019-02-04 20:17:44 +01:00
shader_editor - > toggle_inline_comment ( " // " ) ;
2017-11-11 05:07:41 +01:00
} break ;
case EDIT_COMPLETE : {
2020-09-13 22:14:20 +02:00
shader_editor - > get_text_editor ( ) - > request_code_completion ( ) ;
2017-11-11 05:07:41 +01:00
} break ;
2014-02-10 02:10:30 +01:00
case SEARCH_FIND : {
2017-11-11 05:07:41 +01:00
shader_editor - > get_find_replace_bar ( ) - > popup_search ( ) ;
2014-02-10 02:10:30 +01:00
} break ;
case SEARCH_FIND_NEXT : {
2017-11-11 05:07:41 +01:00
shader_editor - > get_find_replace_bar ( ) - > search_next ( ) ;
2016-05-28 18:25:45 +02:00
} break ;
case SEARCH_FIND_PREV : {
2017-11-11 05:07:41 +01:00
shader_editor - > get_find_replace_bar ( ) - > search_prev ( ) ;
2014-02-10 02:10:30 +01:00
} break ;
case SEARCH_REPLACE : {
2017-11-11 05:07:41 +01:00
shader_editor - > get_find_replace_bar ( ) - > popup_replace ( ) ;
2014-02-10 02:10:30 +01:00
} break ;
case SEARCH_GOTO_LINE : {
2020-07-24 16:50:35 +02:00
goto_line_dialog - > popup_find_line ( shader_editor - > get_text_editor ( ) ) ;
2014-02-10 02:10:30 +01:00
} break ;
2019-04-20 01:51:25 +02:00
case BOOKMARK_TOGGLE : {
shader_editor - > toggle_bookmark ( ) ;
} break ;
case BOOKMARK_GOTO_NEXT : {
shader_editor - > goto_next_bookmark ( ) ;
} break ;
case BOOKMARK_GOTO_PREV : {
shader_editor - > goto_prev_bookmark ( ) ;
} break ;
case BOOKMARK_REMOVE_ALL : {
shader_editor - > remove_all_bookmarks ( ) ;
} break ;
2019-08-02 16:03:45 +02:00
case HELP_DOCS : {
2021-11-15 10:39:00 +01:00
OS : : get_singleton ( ) - > shell_open ( vformat ( " %s/tutorials/shaders/shader_reference/index.html " , VERSION_DOCS_URL ) ) ;
2019-08-02 16:03:45 +02:00
} break ;
2014-02-10 02:10:30 +01:00
}
2017-11-11 05:07:41 +01:00
if ( p_option ! = SEARCH_FIND & & p_option ! = SEARCH_REPLACE & & p_option ! = SEARCH_GOTO_LINE ) {
2021-07-17 23:22:52 +02:00
shader_editor - > get_text_editor ( ) - > call_deferred ( SNAME ( " grab_focus " ) ) ;
2017-11-11 05:07:41 +01:00
}
2014-02-10 02:10:30 +01:00
}
void ShaderEditor : : _notification ( int p_what ) {
2022-03-15 16:05:12 +01:00
switch ( p_what ) {
case NOTIFICATION_ENTER_TREE :
case NOTIFICATION_THEME_CHANGED : {
PopupMenu * popup = help_menu - > get_popup ( ) ;
2022-04-24 17:21:14 +02:00
popup - > set_item_icon ( popup - > get_item_index ( HELP_DOCS ) , get_theme_icon ( SNAME ( " ExternalLink " ) , SNAME ( " EditorIcons " ) ) ) ;
2022-03-15 16:05:12 +01:00
} break ;
case NOTIFICATION_WM_WINDOW_FOCUS_IN : {
_check_for_external_edit ( ) ;
} break ;
2014-02-10 02:10:30 +01:00
}
}
2016-04-29 13:39:04 +02:00
void ShaderEditor : : _editor_settings_changed ( ) {
2020-07-30 13:22:09 +02:00
shader_editor - > update_editor_settings ( ) ;
2022-02-08 10:14:58 +01:00
shader_editor - > get_text_editor ( ) - > add_theme_constant_override ( " line_spacing " , EditorSettings : : get_singleton ( ) - > get ( " text_editor/appearance/whitespace/line_spacing " ) ) ;
2020-07-26 16:57:23 +02:00
shader_editor - > get_text_editor ( ) - > set_draw_breakpoints_gutter ( false ) ;
2020-07-30 13:22:09 +02:00
shader_editor - > get_text_editor ( ) - > set_draw_executing_lines_gutter ( false ) ;
2016-04-29 13:39:04 +02:00
}
2014-02-10 02:10:30 +01:00
2021-01-01 16:04:47 +01:00
void ShaderEditor : : _show_warnings_panel ( bool p_show ) {
warnings_panel - > set_visible ( p_show ) ;
}
void ShaderEditor : : _warning_clicked ( Variant p_line ) {
if ( p_line . get_type ( ) = = Variant : : INT ) {
2021-07-08 19:35:56 +02:00
shader_editor - > get_text_editor ( ) - > set_caret_line ( p_line . operator int64_t ( ) ) ;
2021-01-01 16:04:47 +01:00
}
}
2014-02-10 02:10:30 +01:00
void ShaderEditor : : _bind_methods ( ) {
2021-01-01 16:04:47 +01:00
ClassDB : : bind_method ( " _show_warnings_panel " , & ShaderEditor : : _show_warnings_panel ) ;
ClassDB : : bind_method ( " _warning_clicked " , & ShaderEditor : : _warning_clicked ) ;
2022-06-29 11:31:18 +02:00
ADD_SIGNAL ( MethodInfo ( " validation_changed " ) ) ;
2014-02-10 02:10:30 +01:00
}
void ShaderEditor : : ensure_select_current ( ) {
}
2018-10-27 17:24:41 +02:00
void ShaderEditor : : goto_line_selection ( int p_line , int p_begin , int p_end ) {
shader_editor - > goto_line_selection ( p_line , p_begin , p_end ) ;
}
2021-01-01 16:04:47 +01:00
void ShaderEditor : : _project_settings_changed ( ) {
_update_warnings ( true ) ;
}
void ShaderEditor : : _update_warnings ( bool p_validate ) {
bool changed = false ;
bool warnings_enabled = GLOBAL_GET ( " debug/shader_language/warnings/enable " ) . booleanize ( ) ;
if ( warnings_enabled ! = saved_warnings_enabled ) {
saved_warnings_enabled = warnings_enabled ;
changed = true ;
}
bool treat_warning_as_errors = GLOBAL_GET ( " debug/shader_language/warnings/treat_warnings_as_errors " ) . booleanize ( ) ;
if ( treat_warning_as_errors ! = saved_treat_warning_as_errors ) {
saved_treat_warning_as_errors = treat_warning_as_errors ;
changed = true ;
}
bool update_flags = false ;
for ( int i = 0 ; i < ShaderWarning : : WARNING_MAX ; i + + ) {
ShaderWarning : : Code code = ( ShaderWarning : : Code ) i ;
bool value = GLOBAL_GET ( " debug/shader_language/warnings/ " + ShaderWarning : : get_name_from_code ( code ) . to_lower ( ) ) ;
if ( saved_warnings [ code ] ! = value ) {
saved_warnings [ code ] = value ;
update_flags = true ;
changed = true ;
}
}
if ( update_flags ) {
saved_warning_flags = ( uint32_t ) ShaderWarning : : get_flags_from_codemap ( saved_warnings ) ;
}
if ( p_validate & & changed & & shader_editor & & shader_editor - > get_edited_shader ( ) . is_valid ( ) ) {
shader_editor - > validate_script ( ) ;
}
}
2018-10-08 21:26:45 +02:00
void ShaderEditor : : _check_for_external_edit ( ) {
2022-03-08 11:39:16 +01:00
bool use_autoreload = bool ( EDITOR_GET ( " text_editor/behavior/files/auto_reload_scripts_on_external_change " ) ) ;
if ( shader_inc . is_valid ( ) ) {
if ( shader_inc - > get_last_modified_time ( ) ! = FileAccess : : get_modified_time ( shader_inc - > get_path ( ) ) ) {
if ( use_autoreload ) {
_reload_shader_include_from_disk ( ) ;
} else {
disk_changed - > call_deferred ( SNAME ( " popup_centered " ) ) ;
}
}
2018-10-08 21:26:45 +02:00
return ;
}
2022-03-08 11:39:16 +01:00
if ( shader . is_null ( ) | | shader - > is_built_in ( ) ) {
2018-10-08 21:26:45 +02:00
return ;
}
if ( shader - > get_last_modified_time ( ) ! = FileAccess : : get_modified_time ( shader - > get_path ( ) ) ) {
if ( use_autoreload ) {
_reload_shader_from_disk ( ) ;
} else {
2021-07-17 23:22:52 +02:00
disk_changed - > call_deferred ( SNAME ( " popup_centered " ) ) ;
2018-10-08 21:26:45 +02:00
}
}
}
void ShaderEditor : : _reload_shader_from_disk ( ) {
2021-02-11 18:18:45 +01:00
Ref < Shader > rel_shader = ResourceLoader : : load ( shader - > get_path ( ) , shader - > get_class ( ) , ResourceFormatLoader : : CACHE_MODE_IGNORE ) ;
2018-10-08 21:26:45 +02:00
ERR_FAIL_COND ( ! rel_shader . is_valid ( ) ) ;
2022-06-29 11:31:18 +02:00
shader_editor - > set_block_shader_changed ( true ) ;
2018-10-08 21:26:45 +02:00
shader - > set_code ( rel_shader - > get_code ( ) ) ;
2022-06-29 11:31:18 +02:00
shader_editor - > set_block_shader_changed ( false ) ;
2018-10-08 21:26:45 +02:00
shader - > set_last_modified_time ( rel_shader - > get_last_modified_time ( ) ) ;
shader_editor - > reload_text ( ) ;
}
2022-03-08 11:39:16 +01:00
void ShaderEditor : : _reload_shader_include_from_disk ( ) {
Ref < ShaderInclude > rel_shader_include = ResourceLoader : : load ( shader_inc - > get_path ( ) , shader_inc - > get_class ( ) , ResourceFormatLoader : : CACHE_MODE_IGNORE ) ;
ERR_FAIL_COND ( ! rel_shader_include . is_valid ( ) ) ;
2022-06-29 11:31:18 +02:00
shader_editor - > set_block_shader_changed ( true ) ;
2022-03-08 11:39:16 +01:00
shader_inc - > set_code ( rel_shader_include - > get_code ( ) ) ;
2022-06-29 11:31:18 +02:00
shader_editor - > set_block_shader_changed ( false ) ;
2022-03-08 11:39:16 +01:00
shader_inc - > set_last_modified_time ( rel_shader_include - > get_last_modified_time ( ) ) ;
shader_editor - > reload_text ( ) ;
}
void ShaderEditor : : _reload ( ) {
if ( shader . is_valid ( ) ) {
_reload_shader_from_disk ( ) ;
} else if ( shader_inc . is_valid ( ) ) {
_reload_shader_include_from_disk ( ) ;
}
}
2017-03-05 16:44:50 +01:00
void ShaderEditor : : edit ( const Ref < Shader > & p_shader ) {
2020-05-14 16:41:43 +02:00
if ( p_shader . is_null ( ) | | ! p_shader - > is_text_shader ( ) ) {
2014-02-10 02:10:30 +01:00
return ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
2020-05-14 16:41:43 +02:00
if ( shader = = p_shader ) {
2019-03-04 23:37:05 +01:00
return ;
2020-05-14 16:41:43 +02:00
}
2019-03-04 23:37:05 +01:00
2017-03-05 16:44:50 +01:00
shader = p_shader ;
2022-03-08 11:39:16 +01:00
shader_inc = Ref < ShaderInclude > ( ) ;
shader_editor - > set_edited_shader ( shader ) ;
}
void ShaderEditor : : edit ( const Ref < ShaderInclude > & p_shader_inc ) {
if ( p_shader_inc . is_null ( ) ) {
return ;
}
2014-02-10 02:10:30 +01:00
2022-03-08 11:39:16 +01:00
if ( shader_inc = = p_shader_inc ) {
return ;
}
2014-02-10 02:10:30 +01:00
2022-03-08 11:39:16 +01:00
shader_inc = p_shader_inc ;
shader = Ref < Shader > ( ) ;
shader_editor - > set_edited_shader_include ( p_shader_inc ) ;
2014-02-10 02:10:30 +01:00
}
2018-10-08 21:26:45 +02:00
void ShaderEditor : : save_external_data ( const String & p_str ) {
2022-03-08 11:39:16 +01:00
if ( shader . is_null ( ) & & shader_inc . is_null ( ) ) {
2018-10-08 21:26:45 +02:00
disk_changed - > hide ( ) ;
2014-02-10 02:10:30 +01:00
return ;
2018-10-08 21:26:45 +02:00
}
2014-02-10 02:10:30 +01:00
2018-10-08 21:26:45 +02:00
apply_shaders ( ) ;
2022-03-08 11:39:16 +01:00
Ref < Shader > edited_shader = shader_editor - > get_edited_shader ( ) ;
if ( edited_shader . is_valid ( ) ) {
2022-06-03 01:33:42 +02:00
ResourceSaver : : save ( edited_shader ) ;
2022-03-08 11:39:16 +01:00
}
if ( shader . is_valid ( ) & & shader ! = edited_shader ) {
2022-06-03 01:33:42 +02:00
ResourceSaver : : save ( shader ) ;
2014-02-10 02:10:30 +01:00
}
2018-10-08 21:26:45 +02:00
2022-03-08 11:39:16 +01:00
Ref < ShaderInclude > edited_shader_inc = shader_editor - > get_edited_shader_include ( ) ;
if ( edited_shader_inc . is_valid ( ) ) {
2022-06-03 01:33:42 +02:00
ResourceSaver : : save ( edited_shader_inc ) ;
2022-03-08 11:39:16 +01:00
}
if ( shader_inc . is_valid ( ) & & shader_inc ! = edited_shader_inc ) {
2022-06-03 01:33:42 +02:00
ResourceSaver : : save ( shader_inc ) ;
2022-03-08 11:39:16 +01:00
}
2022-07-28 18:28:38 +02:00
shader_editor - > get_text_editor ( ) - > tag_saved_version ( ) ;
2022-03-08 11:39:16 +01:00
2018-10-08 21:26:45 +02:00
disk_changed - > hide ( ) ;
2014-02-10 02:10:30 +01:00
}
2022-03-08 11:39:16 +01:00
void ShaderEditor : : validate_script ( ) {
shader_editor - > _validate_script ( ) ;
}
2022-07-28 18:28:38 +02:00
bool ShaderEditor : : is_unsaved ( ) const {
return shader_editor - > get_text_editor ( ) - > get_saved_version ( ) ! = shader_editor - > get_text_editor ( ) - > get_version ( ) ;
}
2017-03-05 16:44:50 +01:00
void ShaderEditor : : apply_shaders ( ) {
2022-03-08 11:39:16 +01:00
String editor_code = shader_editor - > get_text_editor ( ) - > get_text ( ) ;
2014-08-14 15:31:38 +02:00
if ( shader . is_valid ( ) ) {
2019-03-04 23:37:05 +01:00
String shader_code = shader - > get_code ( ) ;
2022-06-29 11:31:18 +02:00
if ( shader_code ! = editor_code | | dependencies_version ! = shader_editor - > get_dependencies_version ( ) ) {
shader_editor - > set_block_shader_changed ( true ) ;
2019-03-04 23:37:05 +01:00
shader - > set_code ( editor_code ) ;
2022-06-29 11:31:18 +02:00
shader_editor - > set_block_shader_changed ( false ) ;
2019-03-04 23:37:05 +01:00
shader - > set_edited ( true ) ;
}
2014-08-14 15:31:38 +02:00
}
2022-03-08 11:39:16 +01:00
if ( shader_inc . is_valid ( ) ) {
String shader_inc_code = shader_inc - > get_code ( ) ;
2022-06-29 11:31:18 +02:00
if ( shader_inc_code ! = editor_code | | dependencies_version ! = shader_editor - > get_dependencies_version ( ) ) {
shader_editor - > set_block_shader_changed ( true ) ;
2022-03-08 11:39:16 +01:00
shader_inc - > set_code ( editor_code ) ;
2022-06-29 11:31:18 +02:00
shader_editor - > set_block_shader_changed ( false ) ;
2022-03-08 11:39:16 +01:00
shader_inc - > set_edited ( true ) ;
}
}
2022-06-29 11:31:18 +02:00
dependencies_version = shader_editor - > get_dependencies_version ( ) ;
2014-02-10 02:10:30 +01:00
}
2017-11-11 05:07:41 +01:00
void ShaderEditor : : _text_edit_gui_input ( const Ref < InputEvent > & ev ) {
Ref < InputEventMouseButton > mb = ev ;
2014-02-10 02:10:30 +01:00
2017-11-11 05:07:41 +01:00
if ( mb . is_valid ( ) ) {
2021-08-13 23:31:57 +02:00
if ( mb - > get_button_index ( ) = = MouseButton : : RIGHT & & mb - > is_pressed ( ) ) {
2020-07-24 16:50:35 +02:00
CodeEdit * tx = shader_editor - > get_text_editor ( ) ;
2021-07-10 12:41:38 +02:00
Point2i pos = tx - > get_line_column_at_pos ( mb - > get_global_position ( ) - tx - > get_global_position ( ) ) ;
int row = pos . y ;
int col = pos . x ;
2021-08-15 19:14:46 +02:00
tx - > set_move_caret_on_right_click_enabled ( EditorSettings : : get_singleton ( ) - > get ( " text_editor/behavior/navigation/move_caret_on_right_click " ) ) ;
2017-12-20 02:36:47 +01:00
2021-07-08 19:35:56 +02:00
if ( tx - > is_move_caret_on_right_click_enabled ( ) ) {
2021-07-09 13:42:55 +02:00
if ( tx - > has_selection ( ) ) {
2017-12-20 02:36:47 +01:00
int from_line = tx - > get_selection_from_line ( ) ;
int to_line = tx - > get_selection_to_line ( ) ;
int from_column = tx - > get_selection_from_column ( ) ;
int to_column = tx - > get_selection_to_column ( ) ;
if ( row < from_line | | row > to_line | | ( row = = from_line & & col < from_column ) | | ( row = = to_line & & col > to_column ) ) {
2018-09-13 03:38:39 +02:00
// Right click is outside the selected text
2017-12-20 02:36:47 +01:00
tx - > deselect ( ) ;
}
}
2021-07-09 13:42:55 +02:00
if ( ! tx - > has_selection ( ) ) {
2021-07-08 19:35:56 +02:00
tx - > set_caret_line ( row , true , false ) ;
tx - > set_caret_column ( col ) ;
2017-12-20 02:36:47 +01:00
}
}
2021-07-09 13:42:55 +02:00
_make_context_menu ( tx - > has_selection ( ) , get_local_mouse_position ( ) ) ;
2017-11-11 05:07:41 +01:00
}
}
2019-06-22 20:22:52 +02:00
Ref < InputEventKey > k = ev ;
2021-07-08 19:35:56 +02:00
if ( k . is_valid ( ) & & k - > is_pressed ( ) & & k - > is_action ( " ui_menu " , true ) ) {
2020-07-24 16:50:35 +02:00
CodeEdit * tx = shader_editor - > get_text_editor ( ) ;
2021-07-08 19:35:56 +02:00
tx - > adjust_viewport_to_caret ( ) ;
2021-07-09 13:42:55 +02:00
_make_context_menu ( tx - > has_selection ( ) , ( get_global_transform ( ) . inverse ( ) * tx - > get_global_transform ( ) ) . xform ( tx - > get_caret_draw_pos ( ) ) ) ;
2019-06-22 20:22:52 +02:00
context_menu - > grab_focus ( ) ;
}
2017-11-11 05:07:41 +01:00
}
2019-05-21 10:07:48 +02:00
void ShaderEditor : : _update_bookmark_list ( ) {
2019-08-09 03:36:51 +02:00
bookmarks_menu - > clear ( ) ;
2019-05-21 10:07:48 +02:00
2019-08-09 03:36:51 +02:00
bookmarks_menu - > add_shortcut ( ED_GET_SHORTCUT ( " script_text_editor/toggle_bookmark " ) , BOOKMARK_TOGGLE ) ;
bookmarks_menu - > add_shortcut ( ED_GET_SHORTCUT ( " script_text_editor/remove_all_bookmarks " ) , BOOKMARK_REMOVE_ALL ) ;
bookmarks_menu - > add_shortcut ( ED_GET_SHORTCUT ( " script_text_editor/goto_next_bookmark " ) , BOOKMARK_GOTO_NEXT ) ;
bookmarks_menu - > add_shortcut ( ED_GET_SHORTCUT ( " script_text_editor/goto_previous_bookmark " ) , BOOKMARK_GOTO_PREV ) ;
2019-05-21 10:07:48 +02:00
2022-08-05 03:41:48 +02:00
PackedInt32Array bookmark_list = shader_editor - > get_text_editor ( ) - > get_bookmarked_lines ( ) ;
2019-05-21 10:07:48 +02:00
if ( bookmark_list . size ( ) = = 0 ) {
return ;
}
2019-08-09 03:36:51 +02:00
bookmarks_menu - > add_separator ( ) ;
2019-05-21 10:07:48 +02:00
for ( int i = 0 ; i < bookmark_list . size ( ) ; i + + ) {
2020-07-24 16:50:35 +02:00
String line = shader_editor - > get_text_editor ( ) - > get_line ( bookmark_list [ i ] ) . strip_edges ( ) ;
2019-05-21 10:07:48 +02:00
// Limit the size of the line if too big.
if ( line . length ( ) > 50 ) {
line = line . substr ( 0 , 50 ) ;
}
2019-08-09 03:36:51 +02:00
bookmarks_menu - > add_item ( String : : num ( ( int ) bookmark_list [ i ] + 1 ) + " - \" " + line + " \" " ) ;
2022-03-12 01:06:45 +01:00
bookmarks_menu - > set_item_metadata ( - 1 , bookmark_list [ i ] ) ;
2019-05-21 10:07:48 +02:00
}
}
void ShaderEditor : : _bookmark_item_pressed ( int p_idx ) {
if ( p_idx < 4 ) { // Any item before the separator.
2019-08-09 03:36:51 +02:00
_menu_option ( bookmarks_menu - > get_item_id ( p_idx ) ) ;
2019-05-21 10:07:48 +02:00
} else {
2019-08-09 03:36:51 +02:00
shader_editor - > goto_line ( bookmarks_menu - > get_item_metadata ( p_idx ) ) ;
2019-05-21 10:07:48 +02:00
}
}
2019-06-22 20:22:52 +02:00
void ShaderEditor : : _make_context_menu ( bool p_selection , Vector2 p_position ) {
2017-11-11 05:07:41 +01:00
context_menu - > clear ( ) ;
if ( p_selection ) {
2020-12-07 12:32:00 +01:00
context_menu - > add_shortcut ( ED_GET_SHORTCUT ( " ui_cut " ) , EDIT_CUT ) ;
context_menu - > add_shortcut ( ED_GET_SHORTCUT ( " ui_copy " ) , EDIT_COPY ) ;
2017-11-11 05:07:41 +01:00
}
2020-12-07 12:32:00 +01:00
context_menu - > add_shortcut ( ED_GET_SHORTCUT ( " ui_paste " ) , EDIT_PASTE ) ;
2017-11-11 05:07:41 +01:00
context_menu - > add_separator ( ) ;
2020-12-07 12:32:00 +01:00
context_menu - > add_shortcut ( ED_GET_SHORTCUT ( " ui_text_select_all " ) , EDIT_SELECT_ALL ) ;
context_menu - > add_shortcut ( ED_GET_SHORTCUT ( " ui_undo " ) , EDIT_UNDO ) ;
context_menu - > add_shortcut ( ED_GET_SHORTCUT ( " ui_redo " ) , EDIT_REDO ) ;
2017-11-11 05:07:41 +01:00
context_menu - > add_separator ( ) ;
context_menu - > add_shortcut ( ED_GET_SHORTCUT ( " script_text_editor/indent_left " ) , EDIT_INDENT_LEFT ) ;
context_menu - > add_shortcut ( ED_GET_SHORTCUT ( " script_text_editor/indent_right " ) , EDIT_INDENT_RIGHT ) ;
context_menu - > add_shortcut ( ED_GET_SHORTCUT ( " script_text_editor/toggle_comment " ) , EDIT_TOGGLE_COMMENT ) ;
2019-05-21 10:07:48 +02:00
context_menu - > add_shortcut ( ED_GET_SHORTCUT ( " script_text_editor/toggle_bookmark " ) , BOOKMARK_TOGGLE ) ;
2017-11-11 05:07:41 +01:00
2021-08-31 17:43:35 +02:00
context_menu - > set_position ( get_screen_position ( ) + p_position ) ;
2021-11-20 09:04:57 +01:00
context_menu - > reset_size ( ) ;
2017-11-11 05:07:41 +01:00
context_menu - > popup ( ) ;
}
2022-01-27 10:36:51 +01:00
ShaderEditor : : ShaderEditor ( ) {
2021-01-01 16:04:47 +01:00
GLOBAL_DEF ( " debug/shader_language/warnings/enable " , true ) ;
GLOBAL_DEF ( " debug/shader_language/warnings/treat_warnings_as_errors " , false ) ;
for ( int i = 0 ; i < ( int ) ShaderWarning : : WARNING_MAX ; i + + ) {
GLOBAL_DEF ( " debug/shader_language/warnings/ " + ShaderWarning : : get_name_from_code ( ( ShaderWarning : : Code ) i ) . to_lower ( ) , true ) ;
}
_update_warnings ( false ) ;
2017-11-11 05:07:41 +01:00
shader_editor = memnew ( ShaderTextEditor ) ;
2022-03-08 11:39:16 +01:00
2022-06-29 11:31:18 +02:00
shader_editor - > connect ( " script_validated " , callable_mp ( this , & ShaderEditor : : _script_validated ) ) ;
2017-11-11 05:07:41 +01:00
shader_editor - > set_v_size_flags ( SIZE_EXPAND_FILL ) ;
2022-02-08 10:14:58 +01:00
shader_editor - > add_theme_constant_override ( " separation " , 0 ) ;
2022-03-19 01:02:57 +01:00
shader_editor - > set_anchors_and_offsets_preset ( Control : : PRESET_FULL_RECT ) ;
2017-11-11 05:07:41 +01:00
2021-01-01 16:04:47 +01:00
shader_editor - > connect ( " show_warnings_panel " , callable_mp ( this , & ShaderEditor : : _show_warnings_panel ) ) ;
2020-02-21 18:28:45 +01:00
shader_editor - > connect ( " script_changed " , callable_mp ( this , & ShaderEditor : : apply_shaders ) ) ;
EditorSettings : : get_singleton ( ) - > connect ( " settings_changed " , callable_mp ( this , & ShaderEditor : : _editor_settings_changed ) ) ;
2021-01-01 16:04:47 +01:00
ProjectSettingsEditor : : get_singleton ( ) - > connect ( " confirmed " , callable_mp ( this , & ShaderEditor : : _project_settings_changed ) ) ;
2017-11-11 05:07:41 +01:00
2020-09-18 21:45:47 +02:00
shader_editor - > get_text_editor ( ) - > set_code_hint_draw_below ( EditorSettings : : get_singleton ( ) - > get ( " text_editor/completion/put_callhint_tooltip_below_current_line " ) ) ;
2017-11-11 05:07:41 +01:00
2021-07-01 18:10:54 +02:00
shader_editor - > get_text_editor ( ) - > set_symbol_lookup_on_click_enabled ( true ) ;
2020-07-24 16:50:35 +02:00
shader_editor - > get_text_editor ( ) - > set_context_menu_enabled ( false ) ;
shader_editor - > get_text_editor ( ) - > connect ( " gui_input " , callable_mp ( this , & ShaderEditor : : _text_edit_gui_input ) ) ;
2017-11-11 05:07:41 +01:00
shader_editor - > update_editor_settings ( ) ;
context_menu = memnew ( PopupMenu ) ;
add_child ( context_menu ) ;
2020-02-21 18:28:45 +01:00
context_menu - > connect ( " id_pressed " , callable_mp ( this , & ShaderEditor : : _menu_option ) ) ;
2017-11-11 05:07:41 +01:00
VBoxContainer * main_container = memnew ( VBoxContainer ) ;
HBoxContainer * hbc = memnew ( HBoxContainer ) ;
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
edit_menu = memnew ( MenuButton ) ;
2020-09-17 03:40:00 +02:00
edit_menu - > set_shortcut_context ( this ) ;
2016-05-04 03:25:37 +02:00
edit_menu - > set_text ( TTR ( " Edit " ) ) ;
2018-07-30 00:26:43 +02:00
edit_menu - > set_switch_on_hover ( true ) ;
2020-03-12 13:37:40 +01:00
2020-12-07 12:32:00 +01:00
edit_menu - > get_popup ( ) - > add_shortcut ( ED_GET_SHORTCUT ( " ui_undo " ) , EDIT_UNDO ) ;
edit_menu - > get_popup ( ) - > add_shortcut ( ED_GET_SHORTCUT ( " ui_redo " ) , EDIT_REDO ) ;
2017-11-11 05:07:41 +01:00
edit_menu - > get_popup ( ) - > add_separator ( ) ;
2020-12-07 12:32:00 +01:00
edit_menu - > get_popup ( ) - > add_shortcut ( ED_GET_SHORTCUT ( " ui_cut " ) , EDIT_CUT ) ;
edit_menu - > get_popup ( ) - > add_shortcut ( ED_GET_SHORTCUT ( " ui_copy " ) , EDIT_COPY ) ;
edit_menu - > get_popup ( ) - > add_shortcut ( ED_GET_SHORTCUT ( " ui_paste " ) , EDIT_PASTE ) ;
2017-11-11 05:07:41 +01:00
edit_menu - > get_popup ( ) - > add_separator ( ) ;
2020-12-07 12:32:00 +01:00
edit_menu - > get_popup ( ) - > add_shortcut ( ED_GET_SHORTCUT ( " ui_text_select_all " ) , EDIT_SELECT_ALL ) ;
2014-02-10 02:10:30 +01:00
edit_menu - > get_popup ( ) - > add_separator ( ) ;
2017-11-11 05:07:41 +01:00
edit_menu - > get_popup ( ) - > add_shortcut ( ED_GET_SHORTCUT ( " script_text_editor/move_up " ) , EDIT_MOVE_LINE_UP ) ;
edit_menu - > get_popup ( ) - > add_shortcut ( ED_GET_SHORTCUT ( " script_text_editor/move_down " ) , EDIT_MOVE_LINE_DOWN ) ;
edit_menu - > get_popup ( ) - > add_shortcut ( ED_GET_SHORTCUT ( " script_text_editor/indent_left " ) , EDIT_INDENT_LEFT ) ;
edit_menu - > get_popup ( ) - > add_shortcut ( ED_GET_SHORTCUT ( " script_text_editor/indent_right " ) , EDIT_INDENT_RIGHT ) ;
edit_menu - > get_popup ( ) - > add_shortcut ( ED_GET_SHORTCUT ( " script_text_editor/delete_line " ) , EDIT_DELETE_LINE ) ;
edit_menu - > get_popup ( ) - > add_shortcut ( ED_GET_SHORTCUT ( " script_text_editor/toggle_comment " ) , EDIT_TOGGLE_COMMENT ) ;
2021-06-29 12:09:07 +02:00
edit_menu - > get_popup ( ) - > add_shortcut ( ED_GET_SHORTCUT ( " script_text_editor/duplicate_selection " ) , EDIT_DUPLICATE_SELECTION ) ;
2014-02-10 02:10:30 +01:00
edit_menu - > get_popup ( ) - > add_separator ( ) ;
2020-12-07 12:32:00 +01:00
edit_menu - > get_popup ( ) - > add_shortcut ( ED_GET_SHORTCUT ( " ui_text_completion_query " ) , EDIT_COMPLETE ) ;
2020-02-21 18:28:45 +01:00
edit_menu - > get_popup ( ) - > connect ( " id_pressed " , callable_mp ( this , & ShaderEditor : : _menu_option ) ) ;
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
search_menu = memnew ( MenuButton ) ;
2020-09-17 03:40:00 +02:00
search_menu - > set_shortcut_context ( this ) ;
2016-05-04 03:25:37 +02:00
search_menu - > set_text ( TTR ( " Search " ) ) ;
2018-07-30 00:26:43 +02:00
search_menu - > set_switch_on_hover ( true ) ;
2020-03-12 13:37:40 +01:00
2017-11-11 05:07:41 +01:00
search_menu - > get_popup ( ) - > add_shortcut ( ED_GET_SHORTCUT ( " script_text_editor/find " ) , SEARCH_FIND ) ;
search_menu - > get_popup ( ) - > add_shortcut ( ED_GET_SHORTCUT ( " script_text_editor/find_next " ) , SEARCH_FIND_NEXT ) ;
search_menu - > get_popup ( ) - > add_shortcut ( ED_GET_SHORTCUT ( " script_text_editor/find_previous " ) , SEARCH_FIND_PREV ) ;
search_menu - > get_popup ( ) - > add_shortcut ( ED_GET_SHORTCUT ( " script_text_editor/replace " ) , SEARCH_REPLACE ) ;
2020-02-21 18:28:45 +01:00
search_menu - > get_popup ( ) - > connect ( " id_pressed " , callable_mp ( this , & ShaderEditor : : _menu_option ) ) ;
2014-02-10 02:10:30 +01:00
2019-08-09 03:36:51 +02:00
MenuButton * goto_menu = memnew ( MenuButton ) ;
2020-09-17 03:40:00 +02:00
goto_menu - > set_shortcut_context ( this ) ;
2019-08-09 03:36:51 +02:00
goto_menu - > set_text ( TTR ( " Go To " ) ) ;
goto_menu - > set_switch_on_hover ( true ) ;
2020-02-21 18:28:45 +01:00
goto_menu - > get_popup ( ) - > connect ( " id_pressed " , callable_mp ( this , & ShaderEditor : : _menu_option ) ) ;
2019-08-09 03:36:51 +02:00
goto_menu - > get_popup ( ) - > add_shortcut ( ED_GET_SHORTCUT ( " script_text_editor/goto_line " ) , SEARCH_GOTO_LINE ) ;
goto_menu - > get_popup ( ) - > add_separator ( ) ;
bookmarks_menu = memnew ( PopupMenu ) ;
bookmarks_menu - > set_name ( " Bookmarks " ) ;
goto_menu - > get_popup ( ) - > add_child ( bookmarks_menu ) ;
goto_menu - > get_popup ( ) - > add_submenu_item ( TTR ( " Bookmarks " ) , " Bookmarks " ) ;
2019-05-21 10:07:48 +02:00
_update_bookmark_list ( ) ;
2020-03-12 13:37:40 +01:00
bookmarks_menu - > connect ( " about_to_popup " , callable_mp ( this , & ShaderEditor : : _update_bookmark_list ) ) ;
2020-02-21 18:28:45 +01:00
bookmarks_menu - > connect ( " index_pressed " , callable_mp ( this , & ShaderEditor : : _bookmark_item_pressed ) ) ;
2019-04-20 01:51:25 +02:00
2019-08-02 16:03:45 +02:00
help_menu = memnew ( MenuButton ) ;
help_menu - > set_text ( TTR ( " Help " ) ) ;
help_menu - > set_switch_on_hover ( true ) ;
2022-03-15 16:05:12 +01:00
help_menu - > get_popup ( ) - > add_item ( TTR ( " Online Docs " ) , HELP_DOCS ) ;
2020-02-21 18:28:45 +01:00
help_menu - > get_popup ( ) - > connect ( " id_pressed " , callable_mp ( this , & ShaderEditor : : _menu_option ) ) ;
2019-08-02 16:03:45 +02:00
2017-11-11 05:07:41 +01:00
add_child ( main_container ) ;
main_container - > add_child ( hbc ) ;
hbc - > add_child ( search_menu ) ;
hbc - > add_child ( edit_menu ) ;
2019-08-09 03:36:51 +02:00
hbc - > add_child ( goto_menu ) ;
2019-08-02 16:03:45 +02:00
hbc - > add_child ( help_menu ) ;
2022-01-27 10:36:51 +01:00
hbc - > add_theme_style_override ( " panel " , EditorNode : : get_singleton ( ) - > get_gui_base ( ) - > get_theme_stylebox ( SNAME ( " ScriptEditorPanel " ) , SNAME ( " EditorStyles " ) ) ) ;
2021-01-01 16:04:47 +01:00
VSplitContainer * editor_box = memnew ( VSplitContainer ) ;
main_container - > add_child ( editor_box ) ;
2022-03-19 01:02:57 +01:00
editor_box - > set_anchors_and_offsets_preset ( Control : : PRESET_FULL_RECT ) ;
2021-01-01 16:04:47 +01:00
editor_box - > set_v_size_flags ( SIZE_EXPAND_FILL ) ;
editor_box - > add_child ( shader_editor ) ;
2021-06-03 01:05:41 +02:00
FindReplaceBar * bar = memnew ( FindReplaceBar ) ;
main_container - > add_child ( bar ) ;
bar - > hide ( ) ;
shader_editor - > set_find_replace_bar ( bar ) ;
2021-01-01 16:04:47 +01:00
warnings_panel = memnew ( RichTextLabel ) ;
warnings_panel - > set_custom_minimum_size ( Size2 ( 0 , 100 * EDSCALE ) ) ;
warnings_panel - > set_h_size_flags ( SIZE_EXPAND_FILL ) ;
warnings_panel - > set_meta_underline ( true ) ;
warnings_panel - > set_selection_enabled ( true ) ;
warnings_panel - > set_focus_mode ( FOCUS_CLICK ) ;
warnings_panel - > hide ( ) ;
warnings_panel - > connect ( " meta_clicked " , callable_mp ( this , & ShaderEditor : : _warning_clicked ) ) ;
editor_box - > add_child ( warnings_panel ) ;
shader_editor - > set_warnings_panel ( warnings_panel ) ;
2017-11-11 05:07:41 +01:00
2014-02-10 02:10:30 +01:00
goto_line_dialog = memnew ( GotoLineDialog ) ;
add_child ( goto_line_dialog ) ;
2018-10-08 21:26:45 +02:00
disk_changed = memnew ( ConfirmationDialog ) ;
VBoxContainer * vbc = memnew ( VBoxContainer ) ;
disk_changed - > add_child ( vbc ) ;
Label * dl = memnew ( Label ) ;
Fix various typos with codespell
Found via `codespell -q 3 -S ./thirdparty,*.po,./DONORS.md -L ackward,ang,ans,ba,beng,cas,childs,childrens,dof,doubleclick,fave,findn,hist,inout,leapyear,lod,nd,numer,ois,ony,paket,seeked,sinc,switchs,te,uint`
2021-07-07 17:17:32 +02:00
dl - > set_text ( TTR ( " This shader has been modified on disk. \n What action should be taken? " ) ) ;
2018-10-08 21:26:45 +02:00
vbc - > add_child ( dl ) ;
2022-03-08 11:39:16 +01:00
disk_changed - > connect ( " confirmed " , callable_mp ( this , & ShaderEditor : : _reload ) ) ;
2022-07-08 02:31:19 +02:00
disk_changed - > set_ok_button_text ( TTR ( " Reload " ) ) ;
2018-10-08 21:26:45 +02:00
2020-07-09 01:02:38 +02:00
disk_changed - > add_button ( TTR ( " Resave " ) , ! DisplayServer : : get_singleton ( ) - > get_swap_cancel_ok ( ) , " resave " ) ;
2020-02-21 18:28:45 +01:00
disk_changed - > connect ( " custom_action " , callable_mp ( this , & ShaderEditor : : save_external_data ) ) ;
2018-10-08 21:26:45 +02:00
add_child ( disk_changed ) ;
2016-04-29 13:39:04 +02:00
_editor_settings_changed ( ) ;
2014-02-10 02:10:30 +01:00
}
2022-05-27 11:02:55 +02:00
void ShaderEditorPlugin : : _update_shader_list ( ) {
shader_list - > clear ( ) ;
for ( uint32_t i = 0 ; i < edited_shaders . size ( ) ; i + + ) {
2022-07-28 18:28:38 +02:00
Ref < Resource > shader = edited_shaders [ i ] . shader ;
if ( shader . is_null ( ) ) {
shader = edited_shaders [ i ] . shader_inc ;
2022-03-08 11:39:16 +01:00
}
2022-05-27 11:02:55 +02:00
2022-07-28 18:28:38 +02:00
String path = shader - > get_path ( ) ;
String text = path . get_file ( ) ;
if ( text . is_empty ( ) ) {
// This appears for newly created built-in shaders before saving the scene.
text = TTR ( " [unsaved] " ) ;
} else if ( shader - > is_built_in ( ) ) {
const String & shader_name = shader - > get_name ( ) ;
if ( ! shader_name . is_empty ( ) ) {
text = vformat ( " %s (%s) " , shader_name , text . get_slice ( " :: " , 0 ) ) ;
2022-03-08 11:39:16 +01:00
}
2022-05-27 11:02:55 +02:00
}
2022-07-28 18:28:38 +02:00
bool unsaved = false ;
if ( edited_shaders [ i ] . shader_editor ) {
unsaved = edited_shaders [ i ] . shader_editor - > is_unsaved ( ) ;
}
// TODO: Handle visual shaders too.
if ( unsaved ) {
text + = " (*) " ;
}
String _class = shader - > get_class ( ) ;
2022-05-27 11:02:55 +02:00
if ( ! shader_list - > has_theme_icon ( _class , SNAME ( " EditorIcons " ) ) ) {
2022-03-08 11:39:16 +01:00
_class = " TextFile " ;
2022-05-27 11:02:55 +02:00
}
Ref < Texture2D > icon = shader_list - > get_theme_icon ( _class , SNAME ( " EditorIcons " ) ) ;
shader_list - > add_item ( text , icon ) ;
shader_list - > set_item_tooltip ( shader_list - > get_item_count ( ) - 1 , path ) ;
}
if ( shader_tabs - > get_tab_count ( ) ) {
shader_list - > select ( shader_tabs - > get_current_tab ( ) ) ;
}
for ( int i = 1 ; i < FILE_MAX ; i + + ) {
file_menu - > get_popup ( ) - > set_item_disabled ( file_menu - > get_popup ( ) - > get_item_index ( i ) , edited_shaders . size ( ) = = 0 ) ;
}
2022-06-29 11:31:18 +02:00
_update_shader_list_status ( ) ;
}
void ShaderEditorPlugin : : _update_shader_list_status ( ) {
for ( int i = 0 ; i < shader_list - > get_item_count ( ) ; i + + ) {
ShaderEditor * se = Object : : cast_to < ShaderEditor > ( shader_tabs - > get_tab_control ( i ) ) ;
if ( se ) {
if ( se - > was_compilation_successful ( ) ) {
shader_list - > set_item_tag_icon ( i , Ref < Texture2D > ( ) ) ;
} else {
shader_list - > set_item_tag_icon ( i , shader_list - > get_theme_icon ( SNAME ( " Error " ) , SNAME ( " EditorIcons " ) ) ) ;
}
}
}
2022-05-27 11:02:55 +02:00
}
2014-02-10 02:10:30 +01:00
void ShaderEditorPlugin : : edit ( Object * p_object ) {
2022-05-27 11:02:55 +02:00
EditedShader es ;
2022-03-08 11:39:16 +01:00
ShaderInclude * si = Object : : cast_to < ShaderInclude > ( p_object ) ;
if ( si ! = nullptr ) {
for ( uint32_t i = 0 ; i < edited_shaders . size ( ) ; i + + ) {
if ( edited_shaders [ i ] . shader_inc . ptr ( ) = = si ) {
shader_tabs - > set_current_tab ( i ) ;
shader_list - > select ( i ) ;
return ;
}
}
es . shader_inc = Ref < ShaderInclude > ( si ) ;
2022-05-27 11:02:55 +02:00
es . shader_editor = memnew ( ShaderEditor ) ;
2022-03-08 11:39:16 +01:00
es . shader_editor - > edit ( si ) ;
2022-05-27 11:02:55 +02:00
shader_tabs - > add_child ( es . shader_editor ) ;
2022-07-28 18:28:38 +02:00
es . shader_editor - > connect ( " validation_changed " , callable_mp ( this , & ShaderEditorPlugin : : _update_shader_list ) ) ;
2022-03-08 11:39:16 +01:00
} else {
Shader * s = Object : : cast_to < Shader > ( p_object ) ;
for ( uint32_t i = 0 ; i < edited_shaders . size ( ) ; i + + ) {
if ( edited_shaders [ i ] . shader . ptr ( ) = = s ) {
shader_tabs - > set_current_tab ( i ) ;
shader_list - > select ( i ) ;
return ;
}
}
es . shader = Ref < Shader > ( s ) ;
Ref < VisualShader > vs = es . shader ;
if ( vs . is_valid ( ) ) {
es . visual_shader_editor = memnew ( VisualShaderEditor ) ;
shader_tabs - > add_child ( es . visual_shader_editor ) ;
2022-07-23 08:38:59 +02:00
es . visual_shader_editor - > edit ( vs . ptr ( ) ) ;
2022-03-08 11:39:16 +01:00
} else {
es . shader_editor = memnew ( ShaderEditor ) ;
shader_tabs - > add_child ( es . shader_editor ) ;
2022-07-23 08:38:59 +02:00
es . shader_editor - > edit ( s ) ;
2022-07-28 18:28:38 +02:00
es . shader_editor - > connect ( " validation_changed " , callable_mp ( this , & ShaderEditorPlugin : : _update_shader_list ) ) ;
2022-03-08 11:39:16 +01:00
}
2022-05-27 11:02:55 +02:00
}
2022-03-08 11:39:16 +01:00
2022-05-27 11:02:55 +02:00
shader_tabs - > set_current_tab ( shader_tabs - > get_tab_count ( ) - 1 ) ;
edited_shaders . push_back ( es ) ;
_update_shader_list ( ) ;
2014-02-10 02:10:30 +01:00
}
bool ShaderEditorPlugin : : handles ( Object * p_object ) const {
2022-03-08 11:39:16 +01:00
return Object : : cast_to < Shader > ( p_object ) ! = nullptr | | Object : : cast_to < ShaderInclude > ( p_object ) ! = nullptr ;
2014-02-10 02:10:30 +01:00
}
void ShaderEditorPlugin : : make_visible ( bool p_visible ) {
if ( p_visible ) {
2022-05-27 11:02:55 +02:00
EditorNode : : get_singleton ( ) - > make_bottom_panel_item_visible ( main_split ) ;
2014-02-10 02:10:30 +01:00
}
}
void ShaderEditorPlugin : : selected_notify ( ) {
2022-05-27 11:02:55 +02:00
}
ShaderEditor * ShaderEditorPlugin : : get_shader_editor ( const Ref < Shader > & p_for_shader ) {
for ( uint32_t i = 0 ; i < edited_shaders . size ( ) ; i + + ) {
if ( edited_shaders [ i ] . shader = = p_for_shader ) {
return edited_shaders [ i ] . shader_editor ;
}
}
return nullptr ;
2014-02-10 02:10:30 +01:00
}
2022-07-16 08:59:20 +02:00
VisualShaderEditor * ShaderEditorPlugin : : get_visual_shader_editor ( const Ref < Shader > & p_for_shader ) {
for ( uint32_t i = 0 ; i < edited_shaders . size ( ) ; i + + ) {
if ( edited_shaders [ i ] . shader = = p_for_shader ) {
return edited_shaders [ i ] . visual_shader_editor ;
}
}
return nullptr ;
}
2014-02-10 02:10:30 +01:00
void ShaderEditorPlugin : : save_external_data ( ) {
2022-05-27 11:02:55 +02:00
for ( uint32_t i = 0 ; i < edited_shaders . size ( ) ; i + + ) {
if ( edited_shaders [ i ] . shader_editor ) {
edited_shaders [ i ] . shader_editor - > save_external_data ( ) ;
}
}
2022-07-28 18:28:38 +02:00
_update_shader_list ( ) ;
2014-02-10 02:10:30 +01:00
}
void ShaderEditorPlugin : : apply_changes ( ) {
2022-05-27 11:02:55 +02:00
for ( uint32_t i = 0 ; i < edited_shaders . size ( ) ; i + + ) {
if ( edited_shaders [ i ] . shader_editor ) {
edited_shaders [ i ] . shader_editor - > apply_shaders ( ) ;
}
}
}
void ShaderEditorPlugin : : _shader_selected ( int p_index ) {
2022-03-08 11:39:16 +01:00
if ( edited_shaders [ p_index ] . shader_editor ) {
edited_shaders [ p_index ] . shader_editor - > validate_script ( ) ;
}
2022-05-27 11:02:55 +02:00
shader_tabs - > set_current_tab ( p_index ) ;
}
2022-07-28 18:28:38 +02:00
void ShaderEditorPlugin : : _shader_list_clicked ( int p_item , Vector2 p_local_mouse_pos , MouseButton p_mouse_button_index ) {
if ( p_mouse_button_index = = MouseButton : : MIDDLE ) {
_close_shader ( p_item ) ;
}
}
2022-05-27 11:02:55 +02:00
void ShaderEditorPlugin : : _close_shader ( int p_index ) {
int index = shader_tabs - > get_current_tab ( ) ;
ERR_FAIL_INDEX ( index , shader_tabs - > get_tab_count ( ) ) ;
Control * c = shader_tabs - > get_tab_control ( index ) ;
memdelete ( c ) ;
edited_shaders . remove_at ( index ) ;
_update_shader_list ( ) ;
2022-07-16 08:59:20 +02:00
EditorNode : : get_singleton ( ) - > get_undo_redo ( ) - > clear_history ( ) ; // To prevent undo on deleted graphs.
2022-05-27 11:02:55 +02:00
}
void ShaderEditorPlugin : : _resource_saved ( Object * obj ) {
// May have been renamed on save.
for ( uint32_t i = 0 ; i < edited_shaders . size ( ) ; i + + ) {
if ( edited_shaders [ i ] . shader . ptr ( ) = = obj ) {
_update_shader_list ( ) ;
return ;
}
}
}
void ShaderEditorPlugin : : _menu_item_pressed ( int p_index ) {
switch ( p_index ) {
case FILE_NEW : {
2022-03-08 11:39:16 +01:00
String base_path = FileSystemDock : : get_singleton ( ) - > get_current_path ( ) . get_base_dir ( ) ;
2022-05-27 11:02:55 +02:00
shader_create_dialog - > config ( base_path . plus_file ( " new_shader " ) , false , false , 0 ) ;
shader_create_dialog - > popup_centered ( ) ;
} break ;
2022-03-08 11:39:16 +01:00
case FILE_NEW_INCLUDE : {
String base_path = FileSystemDock : : get_singleton ( ) - > get_current_path ( ) . get_base_dir ( ) ;
shader_create_dialog - > config ( base_path . plus_file ( " new_shader " ) , false , false , 2 ) ;
shader_create_dialog - > popup_centered ( ) ;
} break ;
2022-05-27 11:02:55 +02:00
case FILE_OPEN : {
InspectorDock : : get_singleton ( ) - > open_resource ( " Shader " ) ;
} break ;
2022-03-08 11:39:16 +01:00
case FILE_OPEN_INCLUDE : {
InspectorDock : : get_singleton ( ) - > open_resource ( " ShaderInclude " ) ;
} break ;
2022-05-27 11:02:55 +02:00
case FILE_SAVE : {
int index = shader_tabs - > get_current_tab ( ) ;
ERR_FAIL_INDEX ( index , shader_tabs - > get_tab_count ( ) ) ;
2022-03-08 11:39:16 +01:00
if ( edited_shaders [ index ] . shader . is_valid ( ) ) {
EditorNode : : get_singleton ( ) - > save_resource ( edited_shaders [ index ] . shader ) ;
} else {
EditorNode : : get_singleton ( ) - > save_resource ( edited_shaders [ index ] . shader_inc ) ;
}
2022-05-27 11:02:55 +02:00
} break ;
case FILE_SAVE_AS : {
int index = shader_tabs - > get_current_tab ( ) ;
ERR_FAIL_INDEX ( index , shader_tabs - > get_tab_count ( ) ) ;
2022-03-08 11:39:16 +01:00
String path ;
if ( edited_shaders [ index ] . shader . is_valid ( ) ) {
path = edited_shaders [ index ] . shader - > get_path ( ) ;
if ( ! path . is_resource_file ( ) ) {
path = " " ;
}
EditorNode : : get_singleton ( ) - > save_resource_as ( edited_shaders [ index ] . shader , path ) ;
} else {
path = edited_shaders [ index ] . shader_inc - > get_path ( ) ;
if ( ! path . is_resource_file ( ) ) {
path = " " ;
}
EditorNode : : get_singleton ( ) - > save_resource_as ( edited_shaders [ index ] . shader_inc , path ) ;
2022-05-27 11:02:55 +02:00
}
} break ;
case FILE_INSPECT : {
int index = shader_tabs - > get_current_tab ( ) ;
ERR_FAIL_INDEX ( index , shader_tabs - > get_tab_count ( ) ) ;
2022-03-08 11:39:16 +01:00
if ( edited_shaders [ index ] . shader . is_valid ( ) ) {
EditorNode : : get_singleton ( ) - > push_item ( edited_shaders [ index ] . shader . ptr ( ) ) ;
} else {
EditorNode : : get_singleton ( ) - > push_item ( edited_shaders [ index ] . shader_inc . ptr ( ) ) ;
}
2022-05-27 11:02:55 +02:00
} break ;
case FILE_CLOSE : {
_close_shader ( shader_tabs - > get_current_tab ( ) ) ;
} break ;
}
}
void ShaderEditorPlugin : : _shader_created ( Ref < Shader > p_shader ) {
EditorNode : : get_singleton ( ) - > push_item ( p_shader . ptr ( ) ) ;
2014-02-10 02:10:30 +01:00
}
2022-03-08 11:39:16 +01:00
void ShaderEditorPlugin : : _shader_include_created ( Ref < ShaderInclude > p_shader_inc ) {
EditorNode : : get_singleton ( ) - > push_item ( p_shader_inc . ptr ( ) ) ;
}
2022-01-27 10:36:51 +01:00
ShaderEditorPlugin : : ShaderEditorPlugin ( ) {
2022-05-27 11:02:55 +02:00
main_split = memnew ( HSplitContainer ) ;
VBoxContainer * vb = memnew ( VBoxContainer ) ;
HBoxContainer * file_hb = memnew ( HBoxContainer ) ;
vb - > add_child ( file_hb ) ;
file_menu = memnew ( MenuButton ) ;
file_menu - > set_text ( TTR ( " File " ) ) ;
file_menu - > get_popup ( ) - > add_item ( TTR ( " New Shader " ) , FILE_NEW ) ;
2022-03-08 11:39:16 +01:00
file_menu - > get_popup ( ) - > add_item ( TTR ( " New Shader Include " ) , FILE_NEW_INCLUDE ) ;
2022-05-27 11:02:55 +02:00
file_menu - > get_popup ( ) - > add_separator ( ) ;
2022-03-08 11:39:16 +01:00
file_menu - > get_popup ( ) - > add_item ( TTR ( " Load Shader File " ) , FILE_OPEN ) ;
file_menu - > get_popup ( ) - > add_item ( TTR ( " Load Shader Include File " ) , FILE_OPEN_INCLUDE ) ;
file_menu - > get_popup ( ) - > add_item ( TTR ( " Save File " ) , FILE_SAVE ) ;
file_menu - > get_popup ( ) - > add_item ( TTR ( " Save File As " ) , FILE_SAVE_AS ) ;
2022-05-27 11:02:55 +02:00
file_menu - > get_popup ( ) - > add_separator ( ) ;
2022-03-08 11:39:16 +01:00
file_menu - > get_popup ( ) - > add_item ( TTR ( " Open File in Inspector " ) , FILE_INSPECT ) ;
2022-05-27 11:02:55 +02:00
file_menu - > get_popup ( ) - > add_separator ( ) ;
2022-03-08 11:39:16 +01:00
file_menu - > get_popup ( ) - > add_item ( TTR ( " Close File " ) , FILE_CLOSE ) ;
2022-05-27 11:02:55 +02:00
file_menu - > get_popup ( ) - > connect ( " id_pressed " , callable_mp ( this , & ShaderEditorPlugin : : _menu_item_pressed ) ) ;
file_hb - > add_child ( file_menu ) ;
2022-06-29 11:31:18 +02:00
for ( int i = 2 ; i < FILE_MAX ; i + + ) {
2022-05-27 11:02:55 +02:00
file_menu - > get_popup ( ) - > set_item_disabled ( file_menu - > get_popup ( ) - > get_item_index ( i ) , true ) ;
}
shader_list = memnew ( ItemList ) ;
shader_list - > set_v_size_flags ( Control : : SIZE_EXPAND_FILL ) ;
vb - > add_child ( shader_list ) ;
shader_list - > connect ( " item_selected " , callable_mp ( this , & ShaderEditorPlugin : : _shader_selected ) ) ;
2022-07-28 18:28:38 +02:00
shader_list - > connect ( " item_clicked " , callable_mp ( this , & ShaderEditorPlugin : : _shader_list_clicked ) ) ;
2022-05-27 11:02:55 +02:00
main_split - > add_child ( vb ) ;
vb - > set_custom_minimum_size ( Size2 ( 200 , 300 ) * EDSCALE ) ;
shader_tabs = memnew ( TabContainer ) ;
shader_tabs - > set_tabs_visible ( false ) ;
shader_tabs - > set_h_size_flags ( Control : : SIZE_EXPAND_FILL ) ;
main_split - > add_child ( shader_tabs ) ;
Ref < StyleBoxEmpty > empty ;
empty . instantiate ( ) ;
shader_tabs - > add_theme_style_override ( " panel " , empty ) ;
button = EditorNode : : get_singleton ( ) - > add_bottom_panel_item ( TTR ( " Shader Editor " ) , main_split ) ;
2014-02-10 02:10:30 +01:00
2022-05-27 11:02:55 +02:00
// Defer connect because Editor class is not in the binding system yet.
2022-07-28 22:56:41 +02:00
EditorNode : : get_singleton ( ) - > call_deferred ( " connect " , " resource_saved " , callable_mp ( this , & ShaderEditorPlugin : : _resource_saved ) , CONNECT_DEFERRED ) ;
2020-11-24 10:12:55 +01:00
2022-05-27 11:02:55 +02:00
shader_create_dialog = memnew ( ShaderCreateDialog ) ;
vb - > add_child ( shader_create_dialog ) ;
shader_create_dialog - > connect ( " shader_created " , callable_mp ( this , & ShaderEditorPlugin : : _shader_created ) ) ;
2022-03-08 11:39:16 +01:00
shader_create_dialog - > connect ( " shader_include_created " , callable_mp ( this , & ShaderEditorPlugin : : _shader_include_created ) ) ;
2014-02-10 02:10:30 +01:00
}
ShaderEditorPlugin : : ~ ShaderEditorPlugin ( ) {
}