diff --git a/servers/rendering/shader_language.cpp b/servers/rendering/shader_language.cpp index 9aa54d0bb775d6..b275cc4cb6e648 100644 --- a/servers/rendering/shader_language.cpp +++ b/servers/rendering/shader_language.cpp @@ -3085,6 +3085,19 @@ const ShaderLanguage::BuiltinFuncConstArgs ShaderLanguage::builtin_func_const_ar { nullptr, 0, 0, 0 } }; +const ShaderLanguage::BuiltinFuncFragLight ShaderLanguage::builtin_func_fragment_light_only[] = { + { "dFdx" }, + { "dFdxCoarse" }, + { "dFdxFine" }, + { "dFdy" }, + { "dFdyCoarse" }, + { "dFdyFine" }, + { "fwidth" }, + { "fwidthCoarse" }, + { "fwidthFine" }, + { nullptr } +}; + bool ShaderLanguage::is_const_suffix_lut_initialized = false; bool ShaderLanguage::_validate_function_call(BlockNode *p_block, const FunctionInfo &p_function_info, OperatorNode *p_func, DataType *r_ret_type, StringName *r_ret_type_str, bool *r_is_custom_function) { @@ -3137,6 +3150,7 @@ bool ShaderLanguage::_validate_function_call(BlockNode *p_block, const FunctionI if (argcount <= 4) { // test builtins int idx = 0; + bool is_non_frag_light = current_function != "fragment" && current_function != "light"; while (builtin_func_defs[idx].name) { if (completion_class != builtin_func_defs[idx].tag) { @@ -3178,6 +3192,16 @@ bool ShaderLanguage::_validate_function_call(BlockNode *p_block, const FunctionI } if (!fail) { + if (is_non_frag_light) { + int idx2 = 0; + while (builtin_func_fragment_light_only[idx2].name) { + if (name == builtin_func_fragment_light_only[arg_idx].name) { + _set_error(vformat(RTR("'%s' cannot be used outside of the '%s' or '%s' processor functions."), String(name), "fragment", "light")); + return false; + } + idx2++; + } + } { int constarg_idx = 0; while (builtin_func_const_args[constarg_idx].name) { @@ -10324,11 +10348,33 @@ Error ShaderLanguage::complete(const String &p_code, const ShaderCompileInfo &p_ } } + bool is_non_frag_light = current_function != "fragment" && current_function != "light"; + while (builtin_func_defs[idx].name) { if (low_end && builtin_func_defs[idx].high_end) { idx++; continue; } + + if (is_non_frag_light) { + bool found = false; + { + int idx2 = 0; + while (builtin_func_fragment_light_only[idx2].name) { + if (String(builtin_func_fragment_light_only[idx2].name) == builtin_func_defs[idx].name) { + found = true; + break; + } + idx2++; + } + } + + if (found) { + idx++; + continue; + } + } + matches.insert(String(builtin_func_defs[idx].name), ScriptLanguage::CODE_COMPLETION_KIND_FUNCTION); idx++; } @@ -10498,7 +10544,7 @@ Error ShaderLanguage::complete(const String &p_code, const ShaderCompileInfo &p_ int idx2 = 0; HashSet out_args; while (builtin_func_out_args[idx2].name != nullptr) { - if (builtin_func_out_args[idx2].name == builtin_func_defs[idx].name) { + if (String(builtin_func_out_args[idx2].name) == builtin_func_defs[idx].name) { for (int i = 0; i < BuiltinFuncOutArgs::MAX_ARGS; i++) { int arg = builtin_func_out_args[idx2].arguments[i]; if (arg == -1) { diff --git a/servers/rendering/shader_language.h b/servers/rendering/shader_language.h index 5615d7f457fdeb..31e3071202695f 100644 --- a/servers/rendering/shader_language.h +++ b/servers/rendering/shader_language.h @@ -1059,6 +1059,10 @@ class ShaderLanguage { int max; }; + struct BuiltinFuncFragLight { + const char *name; + }; + CompletionType completion_type; ShaderNode::Uniform::Hint current_uniform_hint = ShaderNode::Uniform::HINT_NONE; TextureFilter current_uniform_filter = FILTER_DEFAULT; @@ -1083,6 +1087,7 @@ class ShaderLanguage { static const BuiltinFuncDef builtin_func_defs[]; static const BuiltinFuncOutArgs builtin_func_out_args[]; static const BuiltinFuncConstArgs builtin_func_const_args[]; + static const BuiltinFuncFragLight builtin_func_fragment_light_only[]; static bool is_const_suffix_lut_initialized;