From 85deed92072d4380851f0793b876286003f154ce Mon Sep 17 00:00:00 2001 From: Yuri Roubinsky Date: Fri, 14 Jan 2022 19:46:41 +0300 Subject: [PATCH] Backport some changes to 3.x shaders --- servers/visual/shader_language.cpp | 568 +++++++++++++++++------------ servers/visual/shader_language.h | 17 +- servers/visual/shader_types.cpp | 10 +- 3 files changed, 355 insertions(+), 240 deletions(-) diff --git a/servers/visual/shader_language.cpp b/servers/visual/shader_language.cpp index 538352aa400..0d92f30ad38 100644 --- a/servers/visual/shader_language.cpp +++ b/servers/visual/shader_language.cpp @@ -212,7 +212,7 @@ const char *ShaderLanguage::token_names[TK_MAX] = { String ShaderLanguage::get_token_text(Token p_token) { String name = token_names[p_token.type]; - if (p_token.type == TK_INT_CONSTANT || p_token.type == TK_REAL_CONSTANT) { + if (p_token.is_integer_constant() || p_token.type == TK_REAL_CONSTANT) { name += "(" + rtos(p_token.constant) + ")"; } else if (p_token.type == TK_IDENTIFIER) { name += "(" + String(p_token.text) + ")"; @@ -515,51 +515,100 @@ ShaderLanguage::Token ShaderLanguage::_get_token() { if (_is_number(GETCHAR(0)) || (GETCHAR(0) == '.' && _is_number(GETCHAR(1)))) { // parse number + bool hexa_found = false; bool period_found = false; bool exponent_found = false; - bool hexa_found = false; - bool sign_found = false; bool float_suffix_found = false; + bool uint_suffix_found = false; + bool end_suffix_found = false; + + enum { + CASE_ALL, + CASE_HEXA_PERIOD, + CASE_EXPONENT, + CASE_SIGN_AFTER_EXPONENT, + CASE_NONE, + CASE_MAX, + } lut_case = CASE_ALL; + + static bool suffix_lut[CASE_MAX][127]; + + if (!is_const_suffix_lut_initialized) { + is_const_suffix_lut_initialized = true; + + for (int i = 0; i < 127; i++) { + char t = char(i); + + suffix_lut[CASE_ALL][i] = t == '.' || t == 'x' || t == 'e' || t == 'f' || t == 'u' || t == '-' || t == '+'; + suffix_lut[CASE_HEXA_PERIOD][i] = t == 'e' || t == 'f'; + suffix_lut[CASE_EXPONENT][i] = t == 'f' || t == '-' || t == '+'; + suffix_lut[CASE_SIGN_AFTER_EXPONENT][i] = t == 'f'; + suffix_lut[CASE_NONE][i] = false; + } + } String str; int i = 0; while (true) { - if (GETCHAR(i) == '.') { - if (period_found || exponent_found || hexa_found || float_suffix_found) { - return _make_token(TK_ERROR, "Invalid numeric constant"); + const CharType symbol = String::char_lowercase(GETCHAR(i)); + bool error = false; + + if (_is_number(symbol)) { + if (end_suffix_found) { + error = true; } - period_found = true; - } else if (GETCHAR(i) == 'x') { - if (hexa_found || str.length() != 1 || str[0] != '0') { - return _make_token(TK_ERROR, "Invalid numeric constant"); - } - hexa_found = true; - } else if (GETCHAR(i) == 'e' && !hexa_found) { - if (exponent_found || float_suffix_found) { - return _make_token(TK_ERROR, "Invalid numeric constant"); - } - exponent_found = true; - } else if (GETCHAR(i) == 'f' && !hexa_found) { - if (exponent_found) { - return _make_token(TK_ERROR, "Invalid numeric constant"); - } - float_suffix_found = true; - } else if (_is_number(GETCHAR(i))) { - if (float_suffix_found) { - return _make_token(TK_ERROR, "Invalid numeric constant"); - } - } else if (hexa_found && _is_hex(GETCHAR(i))) { - } else if ((GETCHAR(i) == '-' || GETCHAR(i) == '+') && exponent_found) { - if (sign_found) { - return _make_token(TK_ERROR, "Invalid numeric constant"); - } - sign_found = true; } else { - break; + if (symbol < 0x7F && suffix_lut[lut_case][symbol]) { + if (symbol == 'x') { + hexa_found = true; + lut_case = CASE_HEXA_PERIOD; + } else if (symbol == '.') { + period_found = true; + lut_case = CASE_HEXA_PERIOD; + } else if (symbol == 'e' && !hexa_found) { + exponent_found = true; + lut_case = CASE_EXPONENT; + } else if (symbol == 'f' && !hexa_found) { + if (!period_found && !exponent_found) { + error = true; + } + float_suffix_found = true; + end_suffix_found = true; + lut_case = CASE_NONE; + } else if (symbol == 'u') { + uint_suffix_found = true; + end_suffix_found = true; + lut_case = CASE_NONE; + } else if (symbol == '-' || symbol == '+') { + if (exponent_found) { + lut_case = CASE_SIGN_AFTER_EXPONENT; + } else { + break; + } + } + } else if (!hexa_found || !_is_hex(symbol)) { + if (_is_text_char(symbol)) { + error = true; + } else { + break; + } + } } - str += CharType(GETCHAR(i)); + if (error) { + if (hexa_found) { + return _make_token(TK_ERROR, "Invalid (hexadecimal) numeric constant"); + } + if (period_found || exponent_found || float_suffix_found) { + return _make_token(TK_ERROR, "Invalid (float) numeric constant"); + } + if (uint_suffix_found) { + return _make_token(TK_ERROR, "Invalid (unsigned integer) numeric constant"); + } + return _make_token(TK_ERROR, "Invalid (integer) numeric constant"); + } + str += symbol; i++; } @@ -572,6 +621,9 @@ ShaderLanguage::Token ShaderLanguage::_get_token() { } } else if (period_found || exponent_found || float_suffix_found) { //floats + if (exponent_found && (!_is_number(last_char) && last_char != 'f')) { // checks for eg: "2E", "2E-", "2E+" + return _make_token(TK_ERROR, "Invalid (float) numeric constant"); + } if (period_found) { if (float_suffix_found) { //checks for eg "1.f" or "1.99f" notations @@ -603,11 +655,18 @@ ShaderLanguage::Token ShaderLanguage::_get_token() { } } else { //integers - if (!_is_number(last_char)) { - return _make_token(TK_ERROR, "Invalid (integer) numeric constant"); + if (uint_suffix_found) { + // Strip the suffix. + str = str.left(str.length() - 1); + // Compensate reading cursor position. + char_idx += 1; } if (!str.is_valid_integer()) { - return _make_token(TK_ERROR, "Invalid numeric constant"); + if (uint_suffix_found) { + return _make_token(TK_ERROR, "Invalid (usigned integer) numeric constant"); + } else { + return _make_token(TK_ERROR, "Invalid (integer) numeric constant"); + } } } @@ -615,6 +674,8 @@ ShaderLanguage::Token ShaderLanguage::_get_token() { Token tk; if (period_found || exponent_found || float_suffix_found) { tk.type = TK_REAL_CONSTANT; + } else if (uint_suffix_found) { + tk.type = TK_UINT_CONSTANT; } else { tk.type = TK_INT_CONSTANT; } @@ -880,8 +941,9 @@ void ShaderLanguage::clear() { completion_type = COMPLETION_NONE; completion_block = nullptr; completion_function = StringName(); - completion_class = SubClassTag::TAG_GLOBAL; + completion_class = TAG_GLOBAL; completion_struct = StringName(); + completion_base = TYPE_VOID; error_line = 0; tk_line = 1; @@ -896,7 +958,7 @@ void ShaderLanguage::clear() { } } -bool ShaderLanguage::_find_identifier(const BlockNode *p_block, const Map &p_builtin_types, const StringName &p_identifier, DataType *r_data_type, IdentifierType *r_type, bool *r_is_const, int *r_array_size, StringName *r_struct_name) { +bool ShaderLanguage::_find_identifier(const BlockNode *p_block, const Map &p_builtin_types, const StringName &p_identifier, DataType *r_data_type, IdentifierType *r_type, bool *r_is_const, int *r_array_size, StringName *r_struct_name, ConstantNode::Value *r_constant_value) { if (p_builtin_types.has(p_identifier)) { if (r_data_type) { *r_data_type = p_builtin_types[p_identifier].type; @@ -993,12 +1055,17 @@ bool ShaderLanguage::_find_identifier(const BlockNode *p_block, const Mapconstants[p_identifier].array_size; } - if (r_type) { - *r_type = IDENTIFIER_CONSTANT; - } if (r_struct_name) { *r_struct_name = shader->constants[p_identifier].type_str; } + if (r_constant_value) { + if (shader->constants[p_identifier].initializer && shader->constants[p_identifier].initializer->values.size() == 1) { + *r_constant_value = shader->constants[p_identifier].initializer->values[0]; + } + } + if (r_type) { + *r_type = IDENTIFIER_CONSTANT; + } return true; } @@ -2119,6 +2186,8 @@ const ShaderLanguage::BuiltinFuncOutArgs ShaderLanguage::builtin_func_out_args[] { nullptr, 0 } }; +bool ShaderLanguage::is_const_suffix_lut_initialized = false; + bool ShaderLanguage::_validate_function_call(BlockNode *p_block, OperatorNode *p_func, DataType *r_ret_type, StringName *r_ret_type_str) { ERR_FAIL_COND_V(p_func->op != OP_CALL && p_func->op != OP_CONSTRUCT, false); @@ -2471,6 +2540,10 @@ bool ShaderLanguage::is_token_operator_assign(TokenType p_type) { p_type == TK_OP_ASSIGN_BIT_XOR); } +bool ShaderLanguage::is_token_hint(TokenType p_type) { + return int(p_type) > int(TK_RENDER_MODE) && int(p_type) < int(TK_SHADER_TYPE); +} + bool ShaderLanguage::convert_constant(ConstantNode *p_constant, DataType p_to_type, ConstantNode::Value *p_value) { if (p_constant->datatype == p_to_type) { if (p_value) { @@ -2898,6 +2971,69 @@ bool ShaderLanguage::_validate_assign(Node *p_node, const Map 0) { + _set_error("Array size is already defined!"); + return ERR_PARSE_ERROR; + } + TkPos pos = _get_tkpos(); + Token tk = _get_token(); + + int array_size = 0; + + if (!tk.is_integer_constant() || ((int)tk.constant) <= 0) { + _set_tkpos(pos); + Node *n = _parse_and_reduce_expression(p_block, Map()); + if (n) { + if (n->type == Node::TYPE_VARIABLE) { + VariableNode *vn = static_cast(n); + if (vn) { + ConstantNode::Value v; + DataType data_type; + bool is_const = false; + + _find_identifier(p_block, Map(), vn->name, &data_type, nullptr, &is_const, nullptr, nullptr, &v); + + if (is_const) { + if (data_type == TYPE_INT) { + int32_t value = v.sint; + if (value > 0) { + array_size = value; + } + } else if (data_type == TYPE_UINT) { + uint32_t value = v.uint; + if (value > 0U) { + array_size = value; + } + } + } + } + } else if (n->type == Node::TYPE_OPERATOR) { + _set_error("Array size expressions are not yet implemented."); + return ERR_PARSE_ERROR; + } + } + } else if (((int)tk.constant) > 0) { + array_size = (uint32_t)tk.constant; + } + + if (array_size <= 0) { + _set_error("Expected single integer constant > 0"); + return ERR_PARSE_ERROR; + } + + tk = _get_token(); + if (tk.type != TK_BRACKET_CLOSE) { + _set_error("Expected ']'"); + return ERR_PARSE_ERROR; + } + + if (r_array_size) { + *r_array_size = array_size; + } + return OK; +} + ShaderLanguage::Node *ShaderLanguage::_parse_array_constructor(BlockNode *p_block, const Map &p_builtin_types, DataType p_type, const StringName &p_struct_name, int p_array_size) { DataType type = TYPE_VOID; String struct_name = ""; @@ -3071,6 +3207,14 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons constant->datatype = TYPE_INT; expr = constant; + } else if (tk.type == TK_UINT_CONSTANT) { + ConstantNode *constant = alloc_node(); + ConstantNode::Value v; + v.uint = tk.constant; + constant->values.push_back(v); + constant->datatype = TYPE_UINT; + expr = constant; + } else if (tk.type == TK_TRUE) { //handle true constant ConstantNode *constant = alloc_node(); @@ -3174,141 +3318,6 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons if (!nexpr) { return nullptr; } - - DataType type = pstruct->members[i]->get_datatype(); - String struct_name = pstruct->members[i]->struct_name; - int array_size = pstruct->members[i]->array_size; - - DataType type2; - String struct_name2 = ""; - int array_size2 = 0; - - bool auto_size = false; - - tk = _get_token(); - - if (tk.type == TK_CURLY_BRACKET_OPEN) { - auto_size = true; - } else { - if (shader->structs.has(tk.text)) { - type2 = TYPE_STRUCT; - struct_name2 = tk.text; - } else { - if (!is_token_variable_datatype(tk.type)) { - _set_error("Invalid data type for array"); - return nullptr; - } - type2 = get_token_datatype(tk.type); - } - - tk = _get_token(); - if (tk.type == TK_BRACKET_OPEN) { - TkPos pos2 = _get_tkpos(); - tk = _get_token(); - if (tk.type == TK_BRACKET_CLOSE) { - array_size2 = array_size; - tk = _get_token(); - } else { - _set_tkpos(pos2); - - Node *n = _parse_and_reduce_expression(p_block, p_builtin_types); - if (!n || n->type != Node::TYPE_CONSTANT || n->get_datatype() != TYPE_INT) { - _set_error("Expected single integer constant > 0"); - return nullptr; - } - - ConstantNode *cnode = (ConstantNode *)n; - if (cnode->values.size() == 1) { - array_size2 = cnode->values[0].sint; - if (array_size2 <= 0) { - _set_error("Expected single integer constant > 0"); - return nullptr; - } - } else { - _set_error("Expected single integer constant > 0"); - return nullptr; - } - - tk = _get_token(); - if (tk.type != TK_BRACKET_CLOSE) { - _set_error("Expected ']'"); - return nullptr; - } else { - tk = _get_token(); - } - } - } else { - _set_error("Expected '['"); - return nullptr; - } - - if (type != type2 || struct_name != struct_name2 || array_size != array_size2) { - String error_str = "Cannot convert from '"; - if (type2 == TYPE_STRUCT) { - error_str += struct_name2; - } else { - error_str += get_datatype_name(type2); - } - error_str += "["; - error_str += itos(array_size2); - error_str += "]'"; - error_str += " to '"; - if (type == TYPE_STRUCT) { - error_str += struct_name; - } else { - error_str += get_datatype_name(type); - } - error_str += "["; - error_str += itos(array_size); - error_str += "]'"; - _set_error(error_str); - return nullptr; - } - } - - ArrayConstructNode *an = alloc_node(); - an->datatype = type; - an->struct_name = struct_name; - - if (tk.type == TK_PARENTHESIS_OPEN || auto_size) { // initialization - while (true) { - Node *n = _parse_and_reduce_expression(p_block, p_builtin_types); - if (!n) { - return nullptr; - } - - if (type != n->get_datatype() || struct_name != n->get_datatype_name()) { - _set_error("Invalid assignment of '" + (n->get_datatype() == TYPE_STRUCT ? n->get_datatype_name() : get_datatype_name(n->get_datatype())) + "' to '" + (type == TYPE_STRUCT ? struct_name : get_datatype_name(type)) + "'"); - return nullptr; - } - - tk = _get_token(); - if (tk.type == TK_COMMA) { - an->initializer.push_back(n); - continue; - } else if (!auto_size && tk.type == TK_PARENTHESIS_CLOSE) { - an->initializer.push_back(n); - break; - } else if (auto_size && tk.type == TK_CURLY_BRACKET_CLOSE) { - an->initializer.push_back(n); - break; - } else { - if (auto_size) { - _set_error("Expected '}' or ','"); - } else { - _set_error("Expected ')' or ','"); - } - return nullptr; - } - } - if (an->initializer.size() != array_size) { - _set_error("Array size mismatch"); - return nullptr; - } - } else { - _set_error("Expected array initialization!"); - return nullptr; - } } else { nexpr = _parse_and_reduce_expression(p_block, p_builtin_types); if (!nexpr) { @@ -4771,7 +4780,7 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const Map 0 or ']'"); return ERR_PARSE_ERROR; } @@ -5219,7 +5228,7 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const Map &p_funct return ERR_PARSE_ERROR; } - tk = _get_token(); + StringName shader_type_identifier; + _get_completable_identifier(nullptr, COMPLETION_SHADER_TYPE, shader_type_identifier); - if (tk.type != TK_IDENTIFIER) { + if (shader_type_identifier == StringName()) { _set_error("Expected identifier after 'shader_type', indicating type of shader. Valid types are: " + _get_shader_type_list(p_shader_types)); return ERR_PARSE_ERROR; } - - String shader_type_identifier; - - shader_type_identifier = tk.text; - if (!p_shader_types.has(shader_type_identifier)) { _set_error("Invalid shader type. Valid types are: " + _get_shader_type_list(p_shader_types)); return ERR_PARSE_ERROR; @@ -5770,53 +5775,70 @@ Error ShaderLanguage::_parse_shader(const Map &p_funct return ERR_PARSE_ERROR; } - tk = _get_token(); - if (tk.type != TK_IDENTIFIER) { - _set_error("Expected identifier!"); - return ERR_PARSE_ERROR; - } + bool first = true; + bool fixed_array_size = false; + int array_size = 0; - MemberNode *member = alloc_node(); - member->precision = precision; - member->datatype = type; - member->struct_name = struct_name; - member->name = tk.text; - - if (member_names.has(member->name)) { - _set_error("Redefinition of '" + String(member->name) + "'"); - return ERR_PARSE_ERROR; - } - member_names.insert(member->name); - - tk = _get_token(); - if (tk.type == TK_BRACKET_OPEN) { + do { tk = _get_token(); - if (tk.type == TK_INT_CONSTANT && tk.constant > 0) { - member->array_size = (int)tk.constant; - tk = _get_token(); - if (tk.type == TK_BRACKET_CLOSE) { - tk = _get_token(); - if (tk.type != TK_SEMICOLON) { - _set_error("Expected ';'"); - return ERR_PARSE_ERROR; - } - } else { - _set_error("Expected ']'"); + if (first) { + first = false; + + if (tk.type != TK_IDENTIFIER && tk.type != TK_BRACKET_OPEN) { + _set_error("Expected identifier or '['."); return ERR_PARSE_ERROR; } - } else { - _set_error("Expected single integer constant > 0"); + + if (tk.type == TK_BRACKET_OPEN) { + Error error = _parse_array_size(nullptr, &array_size); + if (error != OK) { + return error; + } + fixed_array_size = true; + tk = _get_token(); + } + } + + if (tk.type != TK_IDENTIFIER) { + _set_error("Expected identifier!"); return ERR_PARSE_ERROR; } - } - st_node->members.push_back(member); - if (tk.type != TK_SEMICOLON) { - _set_error("Expected ']' or ';'"); - return ERR_PARSE_ERROR; - } - member_count++; + MemberNode *member = alloc_node(); + member->precision = precision; + member->datatype = type; + member->struct_name = struct_name; + member->name = tk.text; + member->array_size = array_size; + + if (member_names.has(member->name)) { + _set_error("Redefinition of '" + String(member->name) + "'"); + return ERR_PARSE_ERROR; + } + member_names.insert(member->name); + tk = _get_token(); + + if (tk.type == TK_BRACKET_OPEN) { + Error error = _parse_array_size(nullptr, &member->array_size); + if (error != OK) { + return error; + } + tk = _get_token(); + } + + if (!fixed_array_size) { + array_size = 0; + } + + if (tk.type != TK_SEMICOLON && tk.type != TK_COMMA) { + _set_error("Expected ',' or ';' after struct member."); + return ERR_PARSE_ERROR; + } + + st_node->members.push_back(member); + member_count++; + } while (tk.type == TK_COMMA); // another member } } if (member_count == 0) { @@ -5934,9 +5956,19 @@ Error ShaderLanguage::_parse_shader(const Map &p_funct tk = _get_token(); if (tk.type == TK_COLON) { + completion_type = COMPLETION_HINT; + completion_base = type; + //hint tk = _get_token(); + completion_line = tk.line; + + if (!is_token_hint(tk.type)) { + _set_error("Expected valid type hint after ':'."); + return ERR_PARSE_ERROR; + } + if (tk.type == TK_HINT_WHITE_TEXTURE) { uniform2.hint = ShaderNode::Uniform::HINT_WHITE; } else if (tk.type == TK_HINT_BLACK_TEXTURE) { @@ -5977,7 +6009,7 @@ Error ShaderLanguage::_parse_shader(const Map &p_funct tk = _get_token(); } - if (tk.type != TK_REAL_CONSTANT && tk.type != TK_INT_CONSTANT) { + if (tk.type != TK_REAL_CONSTANT && !tk.is_integer_constant()) { _set_error("Expected integer constant"); return ERR_PARSE_ERROR; } @@ -6001,7 +6033,7 @@ Error ShaderLanguage::_parse_shader(const Map &p_funct tk = _get_token(); } - if (tk.type != TK_REAL_CONSTANT && tk.type != TK_INT_CONSTANT) { + if (tk.type != TK_REAL_CONSTANT && !tk.is_integer_constant()) { _set_error("Expected integer constant after ','"); return ERR_PARSE_ERROR; } @@ -6014,7 +6046,7 @@ Error ShaderLanguage::_parse_shader(const Map &p_funct if (tk.type == TK_COMMA) { tk = _get_token(); - if (tk.type != TK_REAL_CONSTANT && tk.type != TK_INT_CONSTANT) { + if (tk.type != TK_REAL_CONSTANT && !tk.is_integer_constant()) { _set_error("Expected integer constant after ','"); return ERR_PARSE_ERROR; } @@ -6033,10 +6065,6 @@ Error ShaderLanguage::_parse_shader(const Map &p_funct _set_error("Expected ','"); return ERR_PARSE_ERROR; } - - } else { - _set_error("Expected valid type hint after ':'."); - return ERR_PARSE_ERROR; } if (uniform2.hint != ShaderNode::Uniform::HINT_RANGE && uniform2.hint != ShaderNode::Uniform::HINT_NONE && uniform2.hint != ShaderNode::Uniform::HINT_COLOR && type <= TYPE_MAT4) { @@ -6074,6 +6102,8 @@ Error ShaderLanguage::_parse_shader(const Map &p_funct _set_error("Expected ';'"); return ERR_PARSE_ERROR; } + + completion_type = COMPLETION_NONE; } else { // varying ShaderNode::Varying varying; varying.type = type; @@ -6094,7 +6124,7 @@ Error ShaderLanguage::_parse_shader(const Map &p_funct return ERR_PARSE_ERROR; } tk = _get_token(); - if (tk.type == TK_INT_CONSTANT && tk.constant > 0) { + if (tk.is_integer_constant() && tk.constant > 0) { varying.array_size = (int)tk.constant; tk = _get_token(); @@ -6118,6 +6148,10 @@ Error ShaderLanguage::_parse_shader(const Map &p_funct } } break; + case TK_SHADER_TYPE: { + _set_error("Shader type is already defined."); + return ERR_PARSE_ERROR; + } break; default: { //function or constant variable @@ -6216,7 +6250,7 @@ Error ShaderLanguage::_parse_shader(const Map &p_funct if (tk.type == TK_BRACKET_CLOSE) { unknown_size = true; tk = _get_token(); - } else if (tk.type == TK_INT_CONSTANT && ((int)tk.constant) > 0) { + } else if (tk.is_integer_constant() && ((int)tk.constant) > 0) { constant.array_size = (int)tk.constant; tk = _get_token(); if (tk.type != TK_BRACKET_CLOSE) { @@ -6493,6 +6527,13 @@ Error ShaderLanguage::_parse_shader(const Map &p_funct } } + for (int i = 0; i < shader->functions.size(); i++) { + if (!shader->functions[i].callable && shader->functions[i].name == name) { + _set_error("Redefinition of '" + String(name) + "'"); + return ERR_PARSE_ERROR; + } + } + ShaderNode::Function function; function.callable = !p_functions.has(name); @@ -6865,9 +6906,17 @@ Error ShaderLanguage::complete(const String &p_code, const Map::Element *E = p_shader_types.front(); E; E = E->next()) { + ScriptCodeCompletionOption option(E->get(), ScriptCodeCompletionOption::KIND_PLAIN_TEXT); + r_options->push_back(option); + } + + return OK; + } break; case COMPLETION_RENDER_MODE: { for (int i = 0; i < p_render_modes.size(); i++) { - ScriptCodeCompletionOption option(p_render_modes[i], ScriptCodeCompletionOption::KIND_ENUM); + ScriptCodeCompletionOption option(p_render_modes[i], ScriptCodeCompletionOption::KIND_PLAIN_TEXT); r_options->push_back(option); } @@ -6886,6 +6935,19 @@ Error ShaderLanguage::complete(const String &p_code, const Map::Element *E = p_functions.front(); E; E = E->next()) { + if (!E->get().main_function) { + continue; + } + bool found = false; + for (int i = 0; i < shader->functions.size(); i++) { + if (shader->functions[i].name == E->key()) { + found = true; + break; + } + } + if (found) { + continue; + } ScriptCodeCompletionOption option(E->key(), ScriptCodeCompletionOption::KIND_FUNCTION); r_options->push_back(option); } @@ -6940,7 +7002,9 @@ Error ShaderLanguage::complete(const String &p_code, const Mapkey(), kind); } } - + for (Map::Element *E = shader->constants.front(); E; E = E->next()) { + matches.insert(E->key(), ScriptCodeCompletionOption::KIND_CONSTANT); + } for (OrderedHashMap::Element E = shader->varyings.front(); E; E = E.next()) { matches.insert(E.key(), ScriptCodeCompletionOption::KIND_VARIABLE); } @@ -7143,6 +7207,38 @@ Error ShaderLanguage::complete(const String &p_code, const Mappush_back(option); + } else if ((completion_base == DataType::TYPE_INT || completion_base == DataType::TYPE_FLOAT)) { + ScriptCodeCompletionOption option("hint_range", ScriptCodeCompletionOption::KIND_PLAIN_TEXT); + + if (completion_base == DataType::TYPE_INT) { + option.insert_text = "hint_range(0, 100, 1)"; + } else { + option.insert_text = "hint_range(0.0, 1.0, 0.1)"; + } + + r_options->push_back(option); + } else if ((int(completion_base) > int(TYPE_MAT4) && int(completion_base) < int(TYPE_STRUCT))) { + static Vector options; + + if (options.empty()) { + options.push_back("hint_albedo"); + options.push_back("hint_aniso"); + options.push_back("hint_black"); + options.push_back("hint_black_albedo"); + options.push_back("hint_normal"); + options.push_back("hint_white"); + } + + for (int i = 0; i < options.size(); i++) { + ScriptCodeCompletionOption option(options[i], ScriptCodeCompletionOption::KIND_PLAIN_TEXT); + r_options->push_back(option); + } + } + } break; } return ERR_PARSE_ERROR; diff --git a/servers/visual/shader_language.h b/servers/visual/shader_language.h index 80f79f7f934..97bfe504c0c 100644 --- a/servers/visual/shader_language.h +++ b/servers/visual/shader_language.h @@ -54,6 +54,7 @@ public: TK_FALSE, TK_REAL_CONSTANT, TK_INT_CONSTANT, + TK_UINT_CONSTANT, TK_TYPE_VOID, TK_TYPE_BOOL, TK_TYPE_BVEC2, @@ -695,6 +696,7 @@ public: enum CompletionType { COMPLETION_NONE, + COMPLETION_SHADER_TYPE, COMPLETION_RENDER_MODE, COMPLETION_MAIN_FUNCTION, COMPLETION_IDENTIFIER, @@ -702,6 +704,7 @@ public: COMPLETION_CALL_ARGUMENTS, COMPLETION_INDEX, COMPLETION_STRUCT, + COMPLETION_HINT, }; struct Token { @@ -709,6 +712,9 @@ public: StringName text; double constant; uint16_t line; + bool is_integer_constant() const { + return type == TK_INT_CONSTANT || type == TK_UINT_CONSTANT; + } }; static String get_operator_text(Operator p_op); @@ -726,6 +732,7 @@ public: static bool is_token_nonvoid_datatype(TokenType p_type); static bool is_token_operator(TokenType p_type); static bool is_token_operator_assign(TokenType p_type); + static bool is_token_hint(TokenType p_type); static bool convert_constant(ConstantNode *p_constant, DataType p_to_type, ConstantNode::Value *p_value = nullptr); static DataType get_scalar_type(DataType p_type); @@ -754,6 +761,11 @@ public: struct FunctionInfo { Map built_ins; bool can_discard; + bool main_function; + + FunctionInfo() : + can_discard(false), main_function(false) { + } }; static bool has_builtin(const Map &p_functions, const StringName &p_name); @@ -817,7 +829,7 @@ private: IDENTIFIER_CONSTANT, }; - bool _find_identifier(const BlockNode *p_block, const Map &p_builtin_types, const StringName &p_identifier, DataType *r_data_type = nullptr, IdentifierType *r_type = nullptr, bool *r_is_const = nullptr, int *r_array_size = nullptr, StringName *r_struct_name = nullptr); + bool _find_identifier(const BlockNode *p_block, const Map &p_builtin_types, const StringName &p_identifier, DataType *r_data_type = nullptr, IdentifierType *r_type = nullptr, bool *r_is_const = nullptr, int *r_array_size = nullptr, StringName *r_struct_name = nullptr, ConstantNode::Value *r_constant_value = nullptr); bool _is_operator_assign(Operator p_op) const; bool _validate_assign(Node *p_node, const Map &p_builtin_types, String *r_message = nullptr); bool _validate_operator(OperatorNode *p_op, DataType *r_ret_type = nullptr); @@ -849,6 +861,8 @@ private: static const BuiltinFuncDef builtin_func_defs[]; static const BuiltinFuncOutArgs builtin_func_out_args[]; + static bool is_const_suffix_lut_initialized; + Error _validate_datatype(DataType p_type); bool _compare_datatypes_in_nodes(Node *a, Node *b) const; @@ -857,6 +871,7 @@ private: bool _validate_varying_assign(ShaderNode::Varying &p_varying, String *r_message); Node *_parse_expression(BlockNode *p_block, const Map &p_builtin_types); + Error _parse_array_size(BlockNode *p_block, int *r_array_size); Node *_parse_array_constructor(BlockNode *p_block, const Map &p_builtin_types, DataType p_type, const StringName &p_struct_name, int p_array_size); ShaderLanguage::Node *_reduce_expression(BlockNode *p_block, ShaderLanguage::Node *p_node); diff --git a/servers/visual/shader_types.cpp b/servers/visual/shader_types.cpp index 41553c622f8..ab4e22ff3d7 100644 --- a/servers/visual/shader_types.cpp +++ b/servers/visual/shader_types.cpp @@ -68,7 +68,6 @@ ShaderTypes::ShaderTypes() { shader_modes[VS::SHADER_SPATIAL].functions["vertex"].built_ins["INSTANCE_CUSTOM"] = constt(ShaderLanguage::TYPE_VEC4); shader_modes[VS::SHADER_SPATIAL].functions["vertex"].built_ins["VERTEX_ID"] = constt(ShaderLanguage::TYPE_INT); shader_modes[VS::SHADER_SPATIAL].functions["vertex"].built_ins["ROUGHNESS"] = ShaderLanguage::TYPE_FLOAT; - shader_modes[VS::SHADER_SPATIAL].functions["vertex"].can_discard = false; //builtins shader_modes[VS::SHADER_SPATIAL].functions["vertex"].built_ins["WORLD_MATRIX"] = ShaderLanguage::TYPE_MAT4; @@ -82,6 +81,7 @@ ShaderTypes::ShaderTypes() { shader_modes[VS::SHADER_SPATIAL].functions["vertex"].built_ins["VIEW_RIGHT"] = constt(ShaderLanguage::TYPE_INT); shader_modes[VS::SHADER_SPATIAL].functions["vertex"].built_ins["VIEWPORT_SIZE"] = constt(ShaderLanguage::TYPE_VEC2); shader_modes[VS::SHADER_SPATIAL].functions["vertex"].built_ins["OUTPUT_IS_SRGB"] = constt(ShaderLanguage::TYPE_BOOL); + shader_modes[VS::SHADER_SPATIAL].functions["vertex"].main_function = true; shader_modes[VS::SHADER_SPATIAL].functions["fragment"].built_ins["VERTEX"] = constt(ShaderLanguage::TYPE_VEC3); shader_modes[VS::SHADER_SPATIAL].functions["fragment"].built_ins["FRAGCOORD"] = constt(ShaderLanguage::TYPE_VEC4); @@ -130,6 +130,7 @@ ShaderTypes::ShaderTypes() { shader_modes[VS::SHADER_SPATIAL].functions["fragment"].built_ins["INV_PROJECTION_MATRIX"] = constt(ShaderLanguage::TYPE_MAT4); shader_modes[VS::SHADER_SPATIAL].functions["fragment"].built_ins["VIEWPORT_SIZE"] = constt(ShaderLanguage::TYPE_VEC2); shader_modes[VS::SHADER_SPATIAL].functions["fragment"].can_discard = true; + shader_modes[VS::SHADER_SPATIAL].functions["fragment"].main_function = true; shader_modes[VS::SHADER_SPATIAL].functions["light"].built_ins["WORLD_MATRIX"] = constt(ShaderLanguage::TYPE_MAT4); shader_modes[VS::SHADER_SPATIAL].functions["light"].built_ins["INV_CAMERA_MATRIX"] = constt(ShaderLanguage::TYPE_MAT4); @@ -155,6 +156,7 @@ ShaderTypes::ShaderTypes() { shader_modes[VS::SHADER_SPATIAL].functions["light"].built_ins["OUTPUT_IS_SRGB"] = constt(ShaderLanguage::TYPE_BOOL); shader_modes[VS::SHADER_SPATIAL].functions["light"].built_ins["ALPHA"] = ShaderLanguage::TYPE_FLOAT; shader_modes[VS::SHADER_SPATIAL].functions["light"].can_discard = true; + shader_modes[VS::SHADER_SPATIAL].functions["light"].main_function = true; //order used puts first enum mode (default) first shader_modes[VS::SHADER_SPATIAL].modes.push_back("blend_mix"); @@ -218,7 +220,7 @@ ShaderTypes::ShaderTypes() { shader_modes[VS::SHADER_CANVAS_ITEM].functions["vertex"].built_ins["TEXTURE_PIXEL_SIZE"] = constt(ShaderLanguage::TYPE_VEC2); shader_modes[VS::SHADER_CANVAS_ITEM].functions["vertex"].built_ins["INSTANCE_ID"] = constt(ShaderLanguage::TYPE_INT); shader_modes[VS::SHADER_CANVAS_ITEM].functions["vertex"].built_ins["VERTEX_ID"] = constt(ShaderLanguage::TYPE_INT); - shader_modes[VS::SHADER_CANVAS_ITEM].functions["vertex"].can_discard = false; + shader_modes[VS::SHADER_CANVAS_ITEM].functions["vertex"].main_function = true; shader_modes[VS::SHADER_CANVAS_ITEM].functions["fragment"].built_ins["FRAGCOORD"] = constt(ShaderLanguage::TYPE_VEC4); shader_modes[VS::SHADER_CANVAS_ITEM].functions["fragment"].built_ins["NORMAL"] = ShaderLanguage::TYPE_VEC3; @@ -236,6 +238,7 @@ ShaderTypes::ShaderTypes() { shader_modes[VS::SHADER_CANVAS_ITEM].functions["fragment"].built_ins["AT_LIGHT_PASS"] = constt(ShaderLanguage::TYPE_BOOL); shader_modes[VS::SHADER_CANVAS_ITEM].functions["fragment"].built_ins["SCREEN_TEXTURE"] = constt(ShaderLanguage::TYPE_SAMPLER2D); shader_modes[VS::SHADER_CANVAS_ITEM].functions["fragment"].can_discard = true; + shader_modes[VS::SHADER_CANVAS_ITEM].functions["fragment"].main_function = true; shader_modes[VS::SHADER_CANVAS_ITEM].functions["light"].built_ins["FRAGCOORD"] = constt(ShaderLanguage::TYPE_VEC4); shader_modes[VS::SHADER_CANVAS_ITEM].functions["light"].built_ins["NORMAL"] = constt(ShaderLanguage::TYPE_VEC3); @@ -254,6 +257,7 @@ ShaderTypes::ShaderTypes() { shader_modes[VS::SHADER_CANVAS_ITEM].functions["light"].built_ins["SHADOW_COLOR"] = ShaderLanguage::TYPE_VEC4; shader_modes[VS::SHADER_CANVAS_ITEM].functions["light"].built_ins["POINT_COORD"] = constt(ShaderLanguage::TYPE_VEC2); shader_modes[VS::SHADER_CANVAS_ITEM].functions["light"].can_discard = true; + shader_modes[VS::SHADER_CANVAS_ITEM].functions["light"].main_function = true; shader_modes[VS::SHADER_CANVAS_ITEM].modes.push_back("skip_vertex_transform"); @@ -283,7 +287,7 @@ ShaderTypes::ShaderTypes() { shader_modes[VS::SHADER_PARTICLES].functions["vertex"].built_ins["INDEX"] = constt(ShaderLanguage::TYPE_INT); shader_modes[VS::SHADER_PARTICLES].functions["vertex"].built_ins["EMISSION_TRANSFORM"] = constt(ShaderLanguage::TYPE_MAT4); shader_modes[VS::SHADER_PARTICLES].functions["vertex"].built_ins["RANDOM_SEED"] = constt(ShaderLanguage::TYPE_UINT); - shader_modes[VS::SHADER_PARTICLES].functions["vertex"].can_discard = false; + shader_modes[VS::SHADER_PARTICLES].functions["vertex"].main_function = true; shader_modes[VS::SHADER_PARTICLES].modes.push_back("disable_force"); shader_modes[VS::SHADER_PARTICLES].modes.push_back("disable_velocity");