From 01de6513ac12c10139817deeecb357c023b00710 Mon Sep 17 00:00:00 2001 From: Yuri Roubinsky Date: Thu, 13 Feb 2020 17:50:20 +0300 Subject: [PATCH] Fix bugs in shader swizzling --- servers/visual/shader_language.cpp | 121 ++++++++++++++++++++++++++++- servers/visual/shader_language.h | 4 +- 2 files changed, 123 insertions(+), 2 deletions(-) diff --git a/servers/visual/shader_language.cpp b/servers/visual/shader_language.cpp index a5b028b15b9..61664893024 100644 --- a/servers/visual/shader_language.cpp +++ b/servers/visual/shader_language.cpp @@ -2933,6 +2933,13 @@ bool ShaderLanguage::_validate_assign(Node *p_node, const Maptype == Node::TYPE_MEMBER) { MemberNode *member = static_cast(p_node); + + if (member->has_swizzling_duplicates) { + if (r_message) + *r_message = RTR("Swizzling assignment contains duplicates."); + return false; + } + return _validate_assign(member->owner, p_builtin_types, r_message); } else if (p_node->type == Node::TYPE_VARIABLE) { @@ -3710,9 +3717,17 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons String ident = identifier; bool ok = true; + bool repeated = false; DataType member_type = TYPE_VOID; StringName member_struct_name = ""; int array_size = 0; + + Set position_symbols; + Set color_symbols; + Set texture_symbols; + + bool mix_error = false; + switch (dt) { case TYPE_STRUCT: { ok = false; @@ -3758,8 +3773,39 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons switch (c[i]) { case 'r': case 'g': + if (position_symbols.size() > 0 || texture_symbols.size() > 0) { + mix_error = true; + break; + } + if (!color_symbols.has(c[i])) { + color_symbols.insert(c[i]); + } else { + repeated = true; + } + break; case 'x': case 'y': + if (color_symbols.size() > 0 || texture_symbols.size() > 0) { + mix_error = true; + break; + } + if (!position_symbols.has(c[i])) { + position_symbols.insert(c[i]); + } else { + repeated = true; + } + break; + case 's': + case 't': + if (color_symbols.size() > 0 || position_symbols.size() > 0) { + mix_error = true; + break; + } + if (!texture_symbols.has(c[i])) { + texture_symbols.insert(c[i]); + } else { + repeated = true; + } break; default: ok = false; @@ -3794,9 +3840,41 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons case 'r': case 'g': case 'b': + if (position_symbols.size() > 0 || texture_symbols.size() > 0) { + mix_error = true; + break; + } + if (!color_symbols.has(c[i])) { + color_symbols.insert(c[i]); + } else { + repeated = true; + } + break; case 'x': case 'y': case 'z': + if (color_symbols.size() > 0 || texture_symbols.size() > 0) { + mix_error = true; + break; + } + if (!position_symbols.has(c[i])) { + position_symbols.insert(c[i]); + } else { + repeated = true; + } + break; + case 's': + case 't': + case 'p': + if (color_symbols.size() > 0 || position_symbols.size() > 0) { + mix_error = true; + break; + } + if (!texture_symbols.has(c[i])) { + texture_symbols.insert(c[i]); + } else { + repeated = true; + } break; default: ok = false; @@ -3832,10 +3910,43 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons case 'g': case 'b': case 'a': + if (position_symbols.size() > 0 || texture_symbols.size() > 0) { + mix_error = true; + break; + } + if (!color_symbols.has(c[i])) { + color_symbols.insert(c[i]); + } else { + repeated = true; + } + break; case 'x': case 'y': case 'z': case 'w': + if (color_symbols.size() > 0 || texture_symbols.size() > 0) { + mix_error = true; + break; + } + if (!position_symbols.has(c[i])) { + position_symbols.insert(c[i]); + } else { + repeated = true; + } + break; + case 's': + case 't': + case 'p': + case 'q': + if (color_symbols.size() > 0 || position_symbols.size() > 0) { + mix_error = true; + break; + } + if (!texture_symbols.has(c[i])) { + texture_symbols.insert(c[i]); + } else { + repeated = true; + } break; default: ok = false; @@ -3850,8 +3961,12 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons } } - if (!ok) { + if (mix_error) { + _set_error("Cannot combine symbols from different sets in expression ." + ident); + return NULL; + } + if (!ok) { _set_error("Invalid member for " + (dt == TYPE_STRUCT ? st : get_datatype_name(dt)) + " expression: ." + ident); return NULL; } @@ -3865,6 +3980,8 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons mn->array_size = array_size; mn->name = ident; mn->owner = expr; + mn->has_swizzling_duplicates = repeated; + if (array_size > 0) { tk = _get_token(); @@ -6684,6 +6801,7 @@ Error ShaderLanguage::complete(const String &p_code, const Mappush_back(ScriptCodeCompletionOption(String::chr(colv[i]), ScriptCodeCompletionOption::KIND_PLAIN_TEXT)); r_options->push_back(ScriptCodeCompletionOption(String::chr(coordv[i]), ScriptCodeCompletionOption::KIND_PLAIN_TEXT)); + r_options->push_back(ScriptCodeCompletionOption(String::chr(coordt[i]), ScriptCodeCompletionOption::KIND_PLAIN_TEXT)); } } break; diff --git a/servers/visual/shader_language.h b/servers/visual/shader_language.h index e56fb35a8b1..5a69a846503 100644 --- a/servers/visual/shader_language.h +++ b/servers/visual/shader_language.h @@ -538,6 +538,7 @@ public: StringName name; Node *owner; Node *index_expression; + bool has_swizzling_duplicates; virtual DataType get_datatype() const { return datatype; } virtual String get_datatype_name() const { return String(struct_name); } @@ -549,7 +550,8 @@ public: datatype(TYPE_VOID), array_size(0), owner(NULL), - index_expression(NULL) {} + index_expression(NULL), + has_swizzling_duplicates(false) {} }; struct StructNode : public Node {